@checksub_team/peaks_timeline 1.16.1 → 2.0.0-alpha.2
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 +4716 -4409
- package/peaks.js.d.ts +5 -5
- package/src/{timeline-axis.js → components/axis.js} +244 -244
- package/src/{data-retriever.js → components/data-retriever.js} +117 -117
- package/src/{default-segment-marker.js → components/default-segment-marker.js} +132 -132
- package/src/{invoker.js → components/invoker.js} +81 -81
- package/src/components/line-group.js +692 -0
- package/src/components/line-groups.js +585 -0
- package/src/{line-indicator.js → components/line-indicator.js} +308 -303
- package/src/{marker-factories.js → components/marker-factories.js} +1 -1
- package/src/{mode-layer.js → components/mode-layer.js} +8 -12
- package/src/{playhead-layer.js → components/playhead-layer.js} +3 -3
- package/src/{segment-marker.js → components/segment-marker.js} +2 -2
- package/src/{segment-shape.js → components/segment-shape.js} +508 -508
- package/src/{segments-group.js → components/segments-group.js} +805 -801
- package/src/{source-group.js → components/source-group.js} +1661 -1640
- package/src/{sources-layer.js → components/sources-layer.js} +716 -730
- package/src/{waveform-builder.js → components/waveform-builder.js} +2 -2
- package/src/{waveform-shape.js → components/waveform-shape.js} +214 -214
- package/src/keyboard-handler.js +9 -9
- package/src/line-handler.js +179 -0
- package/src/main.js +110 -71
- package/src/models/line.js +156 -0
- package/src/{segment.js → models/segment.js} +420 -419
- package/src/{source.js → models/source.js} +1311 -1315
- package/src/player.js +2 -2
- package/src/{timeline-segments.js → segment-handler.js} +435 -435
- package/src/{timeline-sources.js → source-handler.js} +521 -514
- package/src/utils.js +5 -1
- package/src/{timeline-zoomview.js → view.js} +136 -137
- package/src/line.js +0 -690
- package/src/lines.js +0 -427
- /package/src/{data.js → components/data.js} +0 -0
- /package/src/{loader.js → components/loader.js} +0 -0
- /package/src/{mouse-drag-handler.js → components/mouse-drag-handler.js} +0 -0
- /package/src/{svgs.js → components/svgs.js} +0 -0
package/src/main.js
CHANGED
|
@@ -9,22 +9,24 @@
|
|
|
9
9
|
define([
|
|
10
10
|
'colors.css',
|
|
11
11
|
'eventemitter2',
|
|
12
|
-
'./
|
|
13
|
-
'./
|
|
12
|
+
'./segment-handler',
|
|
13
|
+
'./source-handler',
|
|
14
|
+
'./line-handler',
|
|
14
15
|
'./keyboard-handler',
|
|
15
16
|
'./player',
|
|
16
|
-
'./
|
|
17
|
-
'./
|
|
17
|
+
'./view',
|
|
18
|
+
'./components/marker-factories',
|
|
18
19
|
'./utils'
|
|
19
20
|
], function(
|
|
20
21
|
Colors,
|
|
21
22
|
EventEmitter,
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
SegmentHandler,
|
|
24
|
+
SourceHandler,
|
|
25
|
+
LineHandler,
|
|
24
26
|
KeyboardHandler,
|
|
25
27
|
Player,
|
|
28
|
+
View,
|
|
26
29
|
MarkerFactories,
|
|
27
|
-
TimelineZoomView,
|
|
28
30
|
Utils) {
|
|
29
31
|
'use strict';
|
|
30
32
|
|
|
@@ -133,6 +135,11 @@ define([
|
|
|
133
135
|
*/
|
|
134
136
|
randomizeSegmentColor: true,
|
|
135
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Block mouse clicks if a control key is pressed
|
|
140
|
+
*/
|
|
141
|
+
blockUpdatingOnMouseClickWithCtrlKey: false,
|
|
142
|
+
|
|
136
143
|
/**
|
|
137
144
|
* Block mouse clicks if a meta key is pressed
|
|
138
145
|
*/
|
|
@@ -183,11 +190,7 @@ define([
|
|
|
183
190
|
/**
|
|
184
191
|
*
|
|
185
192
|
*/
|
|
186
|
-
template:
|
|
187
|
-
'<div class="timeline">',
|
|
188
|
-
'<div class="zoom-container"></div>',
|
|
189
|
-
'</div>'
|
|
190
|
-
].join(''),
|
|
193
|
+
template: '<div class="timeline"></div>',
|
|
191
194
|
|
|
192
195
|
/**
|
|
193
196
|
* An object containing an AudioContext, used when creating waveform data
|
|
@@ -204,28 +207,6 @@ define([
|
|
|
204
207
|
createSegmentMarker: MarkerFactories.createSegmentMarker,
|
|
205
208
|
createSegmentLabel: MarkerFactories.createSegmentLabel,
|
|
206
209
|
|
|
207
|
-
/**
|
|
208
|
-
* External sources information.
|
|
209
|
-
*
|
|
210
|
-
* ```js
|
|
211
|
-
* sources: {
|
|
212
|
-
* id: 'unique-identifier-for-this-source',
|
|
213
|
-
* title: 'Source #1',
|
|
214
|
-
* url: 'https://my-website/my-resource.mp3',
|
|
215
|
-
* dataUri: {
|
|
216
|
-
* arraybuffer: 'url/to/data.dat',
|
|
217
|
-
* json: 'url/to/data.json'
|
|
218
|
-
* },
|
|
219
|
-
* start: 1.03,
|
|
220
|
-
* end: 5.06,
|
|
221
|
-
* color: #0000ff,
|
|
222
|
-
* wrapped: false, //show only a line or peaks/preview
|
|
223
|
-
* position: 0 //position in the timeline (here on the first line)
|
|
224
|
-
* }
|
|
225
|
-
* ```
|
|
226
|
-
*/
|
|
227
|
-
sources: null,
|
|
228
|
-
|
|
229
210
|
/**
|
|
230
211
|
* Height of a line, in pixels.
|
|
231
212
|
* This height will correspond to the height of the background when the element is unwrapped.
|
|
@@ -409,7 +390,26 @@ define([
|
|
|
409
390
|
* Indicates whether or not sources can be dragged
|
|
410
391
|
* from one line to another
|
|
411
392
|
*/
|
|
412
|
-
canMoveSourcesBetweenLines: true
|
|
393
|
+
canMoveSourcesBetweenLines: true,
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Delay in milliseconds before a new line is created
|
|
397
|
+
* when dragging a source between 2 lines.
|
|
398
|
+
*/
|
|
399
|
+
automaticLineCreationDelay: 100,
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Default type of line indicator.
|
|
403
|
+
* Can be 'default', 'volume', 'noVolume', 'visibility', 'noVisibility'.
|
|
404
|
+
* This will be used when a new line is automatically created by a component.
|
|
405
|
+
*/
|
|
406
|
+
defaultLineIndicatorType: 'default',
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Default text of the line indicator.
|
|
410
|
+
* This will be used when a new line is automatically created by a component.
|
|
411
|
+
*/
|
|
412
|
+
defaultLineIndicatorText: ''
|
|
413
413
|
};
|
|
414
414
|
|
|
415
415
|
/**
|
|
@@ -467,32 +467,31 @@ define([
|
|
|
467
467
|
});
|
|
468
468
|
|
|
469
469
|
/*
|
|
470
|
-
Setup the layout
|
|
470
|
+
* Setup the layout
|
|
471
471
|
*/
|
|
472
|
-
if (!instance.options.
|
|
473
|
-
callback(new TypeError('Peaks.init(): The
|
|
472
|
+
if (!instance.options.container) {
|
|
473
|
+
callback(new TypeError('Peaks.init(): The container option must be a valid DOM object'));
|
|
474
474
|
return;
|
|
475
475
|
}
|
|
476
476
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
if (!Utils.isHTMLElement(zoomviewContainer)) {
|
|
480
|
-
callback(new TypeError('Peaks.init(): The containers options must be valid HTML elements'));
|
|
477
|
+
if (!Utils.isHTMLElement(instance.options.container)) {
|
|
478
|
+
callback(new TypeError('Peaks.init(): The container must be a valid HTML element'));
|
|
481
479
|
return;
|
|
482
480
|
}
|
|
483
481
|
|
|
484
|
-
if (
|
|
482
|
+
if (instance.options.container && instance.options.container.clientWidth <= 0) {
|
|
485
483
|
callback(new TypeError('Peaks.init(): Please ensure that the container is visible and has non-zero width'));
|
|
486
484
|
return;
|
|
487
485
|
}
|
|
488
486
|
|
|
489
487
|
instance.player = new Player(instance);
|
|
490
|
-
instance.
|
|
491
|
-
instance.
|
|
488
|
+
instance.segmentHandler = new SegmentHandler(instance);
|
|
489
|
+
instance.sourceHandler = new SourceHandler(instance);
|
|
490
|
+
instance.lineHandler = new LineHandler(instance);
|
|
492
491
|
|
|
493
492
|
// Setup the UI components
|
|
494
|
-
instance.view = new
|
|
495
|
-
|
|
493
|
+
instance.view = new View(
|
|
494
|
+
instance.options.container,
|
|
496
495
|
instance
|
|
497
496
|
);
|
|
498
497
|
|
|
@@ -502,10 +501,6 @@ define([
|
|
|
502
501
|
|
|
503
502
|
instance._addWindowResizeHandler();
|
|
504
503
|
|
|
505
|
-
if (instance.options.sources) {
|
|
506
|
-
instance.sources.add(instance.options.sources);
|
|
507
|
-
}
|
|
508
|
-
|
|
509
504
|
document.fonts.ready.then(function() {
|
|
510
505
|
setTimeout(function() {
|
|
511
506
|
instance.emit('peaks.ready');
|
|
@@ -646,17 +641,34 @@ define([
|
|
|
646
641
|
*/
|
|
647
642
|
|
|
648
643
|
Peaks.prototype.addSource = function(source) {
|
|
649
|
-
this.
|
|
644
|
+
this.sourceHandler.add(source);
|
|
650
645
|
};
|
|
651
646
|
|
|
652
647
|
/**
|
|
653
648
|
* Destroy a source from the {@link Peaks} instance.
|
|
654
649
|
*
|
|
655
650
|
* @param {String} sourceId
|
|
651
|
+
* @param {Boolean} [notify=false] If true, emits a
|
|
652
|
+
* <code>source.destroyed</code> event with the destroyed {@link Source}
|
|
653
|
+
* object.
|
|
656
654
|
*/
|
|
657
655
|
|
|
658
656
|
Peaks.prototype.destroySource = function(sourceId, notify) {
|
|
659
|
-
this.
|
|
657
|
+
const sources = this.sourceHandler.destroyById(sourceId);
|
|
658
|
+
|
|
659
|
+
if (notify && sources.length > 0) {
|
|
660
|
+
this.emit('source.destroyed', sources[0]);
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Cut a source on the cutting time.
|
|
666
|
+
*
|
|
667
|
+
* @param {Object} sourceToCut The source to cut.
|
|
668
|
+
* @param {Number} cuttingTime The time in seconds where to cut the source.
|
|
669
|
+
*/
|
|
670
|
+
Peaks.prototype.cutSource = function(sourceToCut, cuttingTime) {
|
|
671
|
+
this.sourceHandler.cutSource(sourceToCut, cuttingTime);
|
|
660
672
|
};
|
|
661
673
|
|
|
662
674
|
/**
|
|
@@ -666,7 +678,7 @@ define([
|
|
|
666
678
|
*/
|
|
667
679
|
|
|
668
680
|
Peaks.prototype.showSource = function(sourceId) {
|
|
669
|
-
this.
|
|
681
|
+
this.sourceHandler.showById(sourceId);
|
|
670
682
|
};
|
|
671
683
|
|
|
672
684
|
/**
|
|
@@ -676,11 +688,47 @@ define([
|
|
|
676
688
|
*/
|
|
677
689
|
|
|
678
690
|
Peaks.prototype.hideSource = function(sourceId) {
|
|
679
|
-
this.
|
|
691
|
+
this.sourceHandler.hideById(sourceId);
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Add a new line to the {@link Peaks} instance.
|
|
696
|
+
*
|
|
697
|
+
* @param {LineOptions} lineOptions
|
|
698
|
+
*/
|
|
699
|
+
Peaks.prototype.addLine = function(lineOptions, notify) {
|
|
700
|
+
const lines = this.lineHandler.add(lineOptions);
|
|
701
|
+
|
|
702
|
+
if (notify && lines.length > 0) {
|
|
703
|
+
this.emit('line.added', lines[0]);
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
|
|
707
|
+
/**
|
|
708
|
+
* Destroy a line from the {@link Peaks} instance.
|
|
709
|
+
*
|
|
710
|
+
* @param {String} lineId
|
|
711
|
+
*/
|
|
712
|
+
Peaks.prototype.destroyLine = function(lineId, notify) {
|
|
713
|
+
const lines = this.lineHandler.removeById(lineId);
|
|
714
|
+
|
|
715
|
+
if (notify && lines.length > 0) {
|
|
716
|
+
this.emit('line.destroyed', lines[0]);
|
|
717
|
+
}
|
|
680
718
|
};
|
|
681
719
|
|
|
682
|
-
|
|
683
|
-
|
|
720
|
+
/**
|
|
721
|
+
* Move a line to a new position.
|
|
722
|
+
*
|
|
723
|
+
* @param {String} lineId The ID of the line to move.
|
|
724
|
+
* @param {Number} position The new position.
|
|
725
|
+
*/
|
|
726
|
+
Peaks.prototype.moveLine = function(lineId, position) {
|
|
727
|
+
this.lineHandler.moveById(lineId, position);
|
|
728
|
+
};
|
|
729
|
+
|
|
730
|
+
Peaks.prototype.showSegments = function(segmentsGroupId, lineId) {
|
|
731
|
+
this.segmentHandler.addSegmentsToLine(segmentsGroupId, lineId);
|
|
684
732
|
};
|
|
685
733
|
|
|
686
734
|
/**
|
|
@@ -690,15 +738,15 @@ define([
|
|
|
690
738
|
*/
|
|
691
739
|
|
|
692
740
|
Peaks.prototype.destroySegment = function(segmentId) {
|
|
693
|
-
this.
|
|
741
|
+
this.segmentHandler.removeById(segmentId);
|
|
694
742
|
};
|
|
695
743
|
|
|
696
744
|
Peaks.prototype.setDefaultMode = function() {
|
|
697
|
-
this.emit('
|
|
745
|
+
this.emit('handler.view.defaultmode');
|
|
698
746
|
};
|
|
699
747
|
|
|
700
748
|
Peaks.prototype.setCutMode = function() {
|
|
701
|
-
this.emit('
|
|
749
|
+
this.emit('handler.view.cutmode');
|
|
702
750
|
};
|
|
703
751
|
|
|
704
752
|
Peaks.prototype.setIndicatorType = function(linePosition, type) {
|
|
@@ -724,13 +772,11 @@ define([
|
|
|
724
772
|
};
|
|
725
773
|
|
|
726
774
|
Peaks.prototype.overrideInteractions = function(bool, areInteractionsAllowed) {
|
|
727
|
-
|
|
728
|
-
.overrideInteractions(bool, areInteractionsAllowed);
|
|
775
|
+
this.emit('main.overrideInteractions', bool, areInteractionsAllowed);
|
|
729
776
|
};
|
|
730
777
|
|
|
731
778
|
Peaks.prototype.allowInteractions = function(forSources, forSegments) {
|
|
732
|
-
|
|
733
|
-
.allowInteractions(forSources, forSegments);
|
|
779
|
+
this.emit('main.allowInteractions', forSources, forSegments);
|
|
734
780
|
};
|
|
735
781
|
|
|
736
782
|
Peaks.prototype.getSelectedElements = function() {
|
|
@@ -771,13 +817,6 @@ define([
|
|
|
771
817
|
window.removeEventListener('resize', this._onResize);
|
|
772
818
|
};
|
|
773
819
|
|
|
774
|
-
Peaks.prototype.setLineHeight = function(newLineHeight) {
|
|
775
|
-
var oldHeight = this.options.lineHeight;
|
|
776
|
-
|
|
777
|
-
this.options.lineHeight = newLineHeight;
|
|
778
|
-
this.emit('options.set.line_height', oldHeight);
|
|
779
|
-
};
|
|
780
|
-
|
|
781
820
|
Peaks.prototype.zoomIn = function() {
|
|
782
821
|
this.view.setZoom(
|
|
783
822
|
this.view.getTimeToPixelsScale() + Math.floor(this.view.getTimeToPixelsScale() / 10) + 1
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
*
|
|
4
|
+
* Defines the {@link Line} class.
|
|
5
|
+
*
|
|
6
|
+
* @module line
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
define([
|
|
10
|
+
'../utils'
|
|
11
|
+
], function(Utils) {
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
function validateLine(options, context) {
|
|
15
|
+
if (!Utils.isInteger(options.position) || options.position < 0) {
|
|
16
|
+
throw new TypeError('peaks.lines.' + context + ': position must be a non-negative integer');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (Utils.isNullOrUndefined(options.indicatorType)) {
|
|
20
|
+
options.indicatorType = 'default';
|
|
21
|
+
}
|
|
22
|
+
else if (!Utils.isValidIndicatorType(options.indicatorType)) {
|
|
23
|
+
throw new TypeError('peaks.lines.' + context + ': indicatorType must be a valid indicator type');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (Utils.isNullOrUndefined(options.indicatorText)) {
|
|
27
|
+
options.indicatorText = '';
|
|
28
|
+
}
|
|
29
|
+
else if (!Utils.isString(options.indicatorText)) {
|
|
30
|
+
throw new TypeError('peaks.lines.' + context + ': indicatorText must be a string');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A line is a horizontal line that can be placed on the timeline.
|
|
36
|
+
* It can contain sources or segments.
|
|
37
|
+
*
|
|
38
|
+
* @class
|
|
39
|
+
* @alias Segment
|
|
40
|
+
* @param {Peaks} peaks The parent {@link Peaks} object.
|
|
41
|
+
* @param {String} id A unique identifier for the line.
|
|
42
|
+
* @param {Number} position Position of the line on the timeline.
|
|
43
|
+
* @param {String} indicatorType Type of the line indicator.
|
|
44
|
+
* @param {String} indicatorText Text to display above the line indicator.
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
function Line(peaks, id, position, indicatorType, indicatorText) {
|
|
48
|
+
var opts = {
|
|
49
|
+
position: position,
|
|
50
|
+
indicatorType: indicatorType,
|
|
51
|
+
indicatorText: indicatorText
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
validateLine(opts, 'add()');
|
|
55
|
+
|
|
56
|
+
this._peaks = peaks;
|
|
57
|
+
this._id = id;
|
|
58
|
+
this._position = opts.position;
|
|
59
|
+
this._indicatorType = opts.indicatorType;
|
|
60
|
+
this._indicatorText = opts.indicatorText;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
Object.defineProperties(Line.prototype, {
|
|
64
|
+
id: {
|
|
65
|
+
enumerable: true,
|
|
66
|
+
get: function() {
|
|
67
|
+
return this._id;
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
position: {
|
|
71
|
+
enumerable: true,
|
|
72
|
+
get: function() {
|
|
73
|
+
return this._position;
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
set: function(pos) {
|
|
77
|
+
if (!Utils.isInteger(pos) || pos < 0) {
|
|
78
|
+
throw new TypeError('peaks.lines.setPosition(): position must be a non-negative integer');
|
|
79
|
+
}
|
|
80
|
+
this._position = pos;
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
indicatorType: {
|
|
84
|
+
enumerable: true,
|
|
85
|
+
get: function() {
|
|
86
|
+
return this._indicatorType;
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
indicatorText: {
|
|
90
|
+
enumerable: true,
|
|
91
|
+
get: function() {
|
|
92
|
+
return this._indicatorText;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
Line.prototype.update = function(options) {
|
|
98
|
+
var opts = {
|
|
99
|
+
position: this.position,
|
|
100
|
+
indicatorType: this.indicatorType,
|
|
101
|
+
indicatorText: this.indicatorText
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
Utils.extend(opts, options);
|
|
105
|
+
|
|
106
|
+
validateLine(this._peaks, opts, 'update()');
|
|
107
|
+
|
|
108
|
+
this._startTime = opts.startTime;
|
|
109
|
+
this._endTime = opts.endTime;
|
|
110
|
+
this._duration = opts.duration;
|
|
111
|
+
this._labelText = opts.labelText;
|
|
112
|
+
this._color = opts.color;
|
|
113
|
+
this._textColor = opts.textColor;
|
|
114
|
+
this._handleTextColor = opts.handleTextColor;
|
|
115
|
+
this._hoverColor = opts.hoverColor;
|
|
116
|
+
this._warningColor = opts.warningColor;
|
|
117
|
+
this._opacity = opts.opacity;
|
|
118
|
+
this._borderColor = opts.borderColor;
|
|
119
|
+
this._borderWidth = opts.borderWidth;
|
|
120
|
+
this._borderRadius = opts.borderRadius;
|
|
121
|
+
this._editable = opts.editable;
|
|
122
|
+
this._allowDeletion = opts.allowDeletion;
|
|
123
|
+
this._line = opts.line;
|
|
124
|
+
this._indicators = opts.indicators;
|
|
125
|
+
|
|
126
|
+
this._peaks.emit('model.line.update', this);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Returns a serializable object containing only the properties defined with Object.defineProperties.
|
|
131
|
+
* This includes all enumerable properties that can be safely serialized.
|
|
132
|
+
*
|
|
133
|
+
* @returns {Object} A plain object containing the serializable properties of the line.
|
|
134
|
+
*/
|
|
135
|
+
Line.prototype.toSerializable = function() {
|
|
136
|
+
var serializable = {};
|
|
137
|
+
|
|
138
|
+
// Add all the enumerable properties from the prototype
|
|
139
|
+
var proto = Object.getPrototypeOf(this);
|
|
140
|
+
var descriptors = Object.getOwnPropertyDescriptors(proto);
|
|
141
|
+
|
|
142
|
+
for (var prop in descriptors) {
|
|
143
|
+
if (Object.prototype.hasOwnProperty.call(descriptors, prop)) {
|
|
144
|
+
var descriptor = descriptors[prop];
|
|
145
|
+
|
|
146
|
+
if (descriptor.enumerable && descriptor.get && typeof descriptor.get === 'function') {
|
|
147
|
+
serializable[prop] = this[prop];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return serializable;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
return Line;
|
|
156
|
+
});
|