@marmooo/midy 0.3.8 → 0.4.0
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/esm/midy-GM1.d.ts +6 -24
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +98 -51
- package/esm/midy-GM2.d.ts +6 -29
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +107 -60
- package/esm/midy-GMLite.d.ts +6 -24
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +100 -53
- package/esm/midy.d.ts +6 -30
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +107 -60
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +6 -24
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +98 -51
- package/script/midy-GM2.d.ts +6 -29
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +107 -60
- package/script/midy-GMLite.d.ts +6 -24
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +100 -53
- package/script/midy.d.ts +6 -30
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +107 -60
package/script/midy-GMLite.js
CHANGED
|
@@ -4,7 +4,19 @@ exports.MidyGMLite = void 0;
|
|
|
4
4
|
const midi_file_1 = require("midi-file");
|
|
5
5
|
const soundfont_parser_1 = require("@marmooo/soundfont-parser");
|
|
6
6
|
class Note {
|
|
7
|
-
constructor(noteNumber, velocity, startTime
|
|
7
|
+
constructor(noteNumber, velocity, startTime) {
|
|
8
|
+
Object.defineProperty(this, "voice", {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
configurable: true,
|
|
11
|
+
writable: true,
|
|
12
|
+
value: void 0
|
|
13
|
+
});
|
|
14
|
+
Object.defineProperty(this, "voiceParams", {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
configurable: true,
|
|
17
|
+
writable: true,
|
|
18
|
+
value: void 0
|
|
19
|
+
});
|
|
8
20
|
Object.defineProperty(this, "index", {
|
|
9
21
|
enumerable: true,
|
|
10
22
|
configurable: true,
|
|
@@ -17,6 +29,12 @@ class Note {
|
|
|
17
29
|
writable: true,
|
|
18
30
|
value: false
|
|
19
31
|
});
|
|
32
|
+
Object.defineProperty(this, "pending", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
writable: true,
|
|
36
|
+
value: true
|
|
37
|
+
});
|
|
20
38
|
Object.defineProperty(this, "bufferSource", {
|
|
21
39
|
enumerable: true,
|
|
22
40
|
configurable: true,
|
|
@@ -62,8 +80,6 @@ class Note {
|
|
|
62
80
|
this.noteNumber = noteNumber;
|
|
63
81
|
this.velocity = velocity;
|
|
64
82
|
this.startTime = startTime;
|
|
65
|
-
this.voice = voice;
|
|
66
|
-
this.voiceParams = voiceParams;
|
|
67
83
|
}
|
|
68
84
|
}
|
|
69
85
|
const drumExclusiveClasses = new Uint8Array(128);
|
|
@@ -230,6 +246,12 @@ class MidyGMLite {
|
|
|
230
246
|
writable: true,
|
|
231
247
|
value: new Map()
|
|
232
248
|
});
|
|
249
|
+
Object.defineProperty(this, "realtimeVoiceCache", {
|
|
250
|
+
enumerable: true,
|
|
251
|
+
configurable: true,
|
|
252
|
+
writable: true,
|
|
253
|
+
value: new Map()
|
|
254
|
+
});
|
|
233
255
|
Object.defineProperty(this, "isPlaying", {
|
|
234
256
|
enumerable: true,
|
|
235
257
|
configurable: true,
|
|
@@ -468,10 +490,10 @@ class MidyGMLite {
|
|
|
468
490
|
const startTime = event.startTime + schedulingOffset;
|
|
469
491
|
switch (event.type) {
|
|
470
492
|
case "noteOn":
|
|
471
|
-
await this.
|
|
493
|
+
await this.noteOn(event.channel, event.noteNumber, event.velocity, startTime);
|
|
472
494
|
break;
|
|
473
495
|
case "noteOff": {
|
|
474
|
-
const notePromise = this.
|
|
496
|
+
const notePromise = this.noteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
|
|
475
497
|
if (notePromise)
|
|
476
498
|
this.notePromises.push(notePromise);
|
|
477
499
|
break;
|
|
@@ -504,6 +526,7 @@ class MidyGMLite {
|
|
|
504
526
|
this.exclusiveClassNotes.fill(undefined);
|
|
505
527
|
this.drumExclusiveClassNotes.fill(undefined);
|
|
506
528
|
this.voiceCache.clear();
|
|
529
|
+
this.realtimeVoiceCache.clear();
|
|
507
530
|
for (let i = 0; i < this.channels.length; i++) {
|
|
508
531
|
this.channels[i].scheduledNotes = [];
|
|
509
532
|
this.resetChannelStates(i);
|
|
@@ -541,7 +564,6 @@ class MidyGMLite {
|
|
|
541
564
|
this.notePromises = [];
|
|
542
565
|
while (queueIndex < this.timeline.length) {
|
|
543
566
|
const now = this.audioContext.currentTime;
|
|
544
|
-
queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
|
|
545
567
|
if (this.isPausing) {
|
|
546
568
|
await this.stopNotes(0, true, now);
|
|
547
569
|
await this.audioContext.suspend();
|
|
@@ -563,6 +585,7 @@ class MidyGMLite {
|
|
|
563
585
|
this.isSeeking = false;
|
|
564
586
|
continue;
|
|
565
587
|
}
|
|
588
|
+
queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
|
|
566
589
|
const waitTime = now + this.noteCheckInterval;
|
|
567
590
|
await this.scheduleTask(() => { }, waitTime);
|
|
568
591
|
}
|
|
@@ -640,7 +663,7 @@ class MidyGMLite {
|
|
|
640
663
|
const channel = this.channels[channelNumber];
|
|
641
664
|
const promises = [];
|
|
642
665
|
this.processActiveNotes(channel, scheduleTime, (note) => {
|
|
643
|
-
const promise = this.
|
|
666
|
+
const promise = this.noteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
|
|
644
667
|
this.notePromises.push(promise);
|
|
645
668
|
promises.push(promise);
|
|
646
669
|
});
|
|
@@ -650,7 +673,7 @@ class MidyGMLite {
|
|
|
650
673
|
const channel = this.channels[channelNumber];
|
|
651
674
|
const promises = [];
|
|
652
675
|
this.processScheduledNotes(channel, (note) => {
|
|
653
|
-
const promise = this.
|
|
676
|
+
const promise = this.noteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
|
|
654
677
|
this.notePromises.push(promise);
|
|
655
678
|
promises.push(promise);
|
|
656
679
|
});
|
|
@@ -683,7 +706,7 @@ class MidyGMLite {
|
|
|
683
706
|
if (!this.isPlaying || this.isPaused)
|
|
684
707
|
return;
|
|
685
708
|
const now = this.audioContext.currentTime;
|
|
686
|
-
this.resumeTime
|
|
709
|
+
this.resumeTime = now - this.startTime - this.startDelay;
|
|
687
710
|
this.isPausing = true;
|
|
688
711
|
await this.playPromise;
|
|
689
712
|
this.isPausing = false;
|
|
@@ -709,11 +732,13 @@ class MidyGMLite {
|
|
|
709
732
|
if (totalTime < event.startTime)
|
|
710
733
|
totalTime = event.startTime;
|
|
711
734
|
}
|
|
712
|
-
return totalTime;
|
|
735
|
+
return totalTime + this.startDelay;
|
|
713
736
|
}
|
|
714
737
|
currentTime() {
|
|
738
|
+
if (!this.isPlaying)
|
|
739
|
+
return this.resumeTime;
|
|
715
740
|
const now = this.audioContext.currentTime;
|
|
716
|
-
return
|
|
741
|
+
return now + this.resumeTime - this.startTime;
|
|
717
742
|
}
|
|
718
743
|
processScheduledNotes(channel, callback) {
|
|
719
744
|
const scheduledNotes = channel.scheduledNotes;
|
|
@@ -850,31 +875,42 @@ class MidyGMLite {
|
|
|
850
875
|
note.modulationLFO.connect(note.volumeDepth);
|
|
851
876
|
note.volumeDepth.connect(note.volumeEnvelopeNode.gain);
|
|
852
877
|
}
|
|
853
|
-
async getAudioBuffer(channel, noteNumber, velocity, voiceParams) {
|
|
878
|
+
async getAudioBuffer(channel, noteNumber, velocity, voiceParams, realtime) {
|
|
854
879
|
const audioBufferId = this.getVoiceId(channel, noteNumber, velocity);
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
this.voiceCache.delete(audioBufferId);
|
|
860
|
-
}
|
|
861
|
-
return cache.audioBuffer;
|
|
862
|
-
}
|
|
863
|
-
else {
|
|
864
|
-
const maxCount = this.voiceCounter.get(audioBufferId) ?? 0;
|
|
880
|
+
if (realtime) {
|
|
881
|
+
const cachedAudioBuffer = this.realtimeVoiceCache.get(audioBufferId);
|
|
882
|
+
if (cachedAudioBuffer)
|
|
883
|
+
return cachedAudioBuffer;
|
|
865
884
|
const audioBuffer = await this.createAudioBuffer(voiceParams);
|
|
866
|
-
|
|
867
|
-
this.voiceCache.set(audioBufferId, cache);
|
|
885
|
+
this.realtimeVoiceCache.set(audioBufferId, audioBuffer);
|
|
868
886
|
return audioBuffer;
|
|
869
887
|
}
|
|
888
|
+
else {
|
|
889
|
+
const cache = this.voiceCache.get(audioBufferId);
|
|
890
|
+
if (cache) {
|
|
891
|
+
cache.counter += 1;
|
|
892
|
+
if (cache.maxCount <= cache.counter) {
|
|
893
|
+
this.voiceCache.delete(audioBufferId);
|
|
894
|
+
}
|
|
895
|
+
return cache.audioBuffer;
|
|
896
|
+
}
|
|
897
|
+
else {
|
|
898
|
+
const maxCount = this.voiceCounter.get(audioBufferId) ?? 0;
|
|
899
|
+
const audioBuffer = await this.createAudioBuffer(voiceParams);
|
|
900
|
+
const cache = { audioBuffer, maxCount, counter: 1 };
|
|
901
|
+
this.voiceCache.set(audioBufferId, cache);
|
|
902
|
+
return audioBuffer;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
870
905
|
}
|
|
871
|
-
async
|
|
906
|
+
async setNoteAudioNode(channel, note, realtime) {
|
|
872
907
|
const now = this.audioContext.currentTime;
|
|
908
|
+
const { noteNumber, velocity, startTime } = note;
|
|
873
909
|
const state = channel.state;
|
|
874
910
|
const controllerState = this.getControllerState(channel, noteNumber, velocity);
|
|
875
|
-
const voiceParams = voice.getAllParams(controllerState);
|
|
876
|
-
|
|
877
|
-
const audioBuffer = await this.getAudioBuffer(channel, noteNumber, velocity, voiceParams);
|
|
911
|
+
const voiceParams = note.voice.getAllParams(controllerState);
|
|
912
|
+
note.voiceParams = voiceParams;
|
|
913
|
+
const audioBuffer = await this.getAudioBuffer(channel, noteNumber, velocity, voiceParams, realtime);
|
|
878
914
|
note.bufferSource = this.createBufferSource(channel, voiceParams, audioBuffer);
|
|
879
915
|
note.volumeEnvelopeNode = new GainNode(this.audioContext);
|
|
880
916
|
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
@@ -901,7 +937,7 @@ class MidyGMLite {
|
|
|
901
937
|
if (prev) {
|
|
902
938
|
const [prevNote, prevChannelNumber] = prev;
|
|
903
939
|
if (prevNote && !prevNote.ending) {
|
|
904
|
-
this.
|
|
940
|
+
this.noteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
|
|
905
941
|
startTime, true);
|
|
906
942
|
}
|
|
907
943
|
}
|
|
@@ -917,13 +953,31 @@ class MidyGMLite {
|
|
|
917
953
|
const index = drumExclusiveClass * this.channels.length + channelNumber;
|
|
918
954
|
const prevNote = this.drumExclusiveClassNotes[index];
|
|
919
955
|
if (prevNote && !prevNote.ending) {
|
|
920
|
-
this.
|
|
956
|
+
this.noteOff(channelNumber, prevNote.noteNumber, 0, // velocity,
|
|
921
957
|
startTime, true);
|
|
922
958
|
}
|
|
923
959
|
this.drumExclusiveClassNotes[index] = note;
|
|
924
960
|
}
|
|
925
|
-
|
|
961
|
+
setNoteRouting(channelNumber, note, startTime) {
|
|
962
|
+
const channel = this.channels[channelNumber];
|
|
963
|
+
const volumeEnvelopeNode = note.volumeEnvelopeNode;
|
|
964
|
+
volumeEnvelopeNode.connect(channel.gainL);
|
|
965
|
+
volumeEnvelopeNode.connect(channel.gainR);
|
|
966
|
+
if (0.5 <= channel.state.sustainPedal) {
|
|
967
|
+
channel.sustainNotes.push(note);
|
|
968
|
+
}
|
|
969
|
+
this.handleExclusiveClass(note, channelNumber, startTime);
|
|
970
|
+
this.handleDrumExclusiveClass(note, channelNumber, startTime);
|
|
971
|
+
}
|
|
972
|
+
async noteOn(channelNumber, noteNumber, velocity, startTime) {
|
|
926
973
|
const channel = this.channels[channelNumber];
|
|
974
|
+
const realtime = startTime === undefined;
|
|
975
|
+
if (realtime)
|
|
976
|
+
startTime = this.audioContext.currentTime;
|
|
977
|
+
const note = new Note(noteNumber, velocity, startTime);
|
|
978
|
+
const scheduledNotes = channel.scheduledNotes;
|
|
979
|
+
note.index = scheduledNotes.length;
|
|
980
|
+
scheduledNotes.push(note);
|
|
927
981
|
const programNumber = channel.programNumber;
|
|
928
982
|
const bankTable = this.soundFontTable[programNumber];
|
|
929
983
|
if (!bankTable)
|
|
@@ -933,24 +987,16 @@ class MidyGMLite {
|
|
|
933
987
|
if (soundFontIndex === undefined)
|
|
934
988
|
return;
|
|
935
989
|
const soundFont = this.soundFonts[soundFontIndex];
|
|
936
|
-
|
|
937
|
-
if (!voice)
|
|
990
|
+
note.voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
|
|
991
|
+
if (!note.voice)
|
|
938
992
|
return;
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
note.
|
|
942
|
-
|
|
943
|
-
|
|
993
|
+
await this.setNoteAudioNode(channel, note, realtime);
|
|
994
|
+
this.setNoteRouting(channelNumber, note, startTime);
|
|
995
|
+
note.pending = false;
|
|
996
|
+
const off = note.offEvent;
|
|
997
|
+
if (off) {
|
|
998
|
+
this.noteOff(channelNumber, noteNumber, off.velocity, off.startTime);
|
|
944
999
|
}
|
|
945
|
-
this.handleExclusiveClass(note, channelNumber, startTime);
|
|
946
|
-
this.handleDrumExclusiveClass(note, channelNumber, startTime);
|
|
947
|
-
const scheduledNotes = channel.scheduledNotes;
|
|
948
|
-
note.index = scheduledNotes.length;
|
|
949
|
-
scheduledNotes.push(note);
|
|
950
|
-
}
|
|
951
|
-
noteOn(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
952
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
953
|
-
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime, undefined);
|
|
954
1000
|
}
|
|
955
1001
|
disconnectNote(note) {
|
|
956
1002
|
note.bufferSource.disconnect();
|
|
@@ -963,6 +1009,7 @@ class MidyGMLite {
|
|
|
963
1009
|
}
|
|
964
1010
|
}
|
|
965
1011
|
releaseNote(channel, note, endTime) {
|
|
1012
|
+
endTime ??= this.audioContext.currentTime;
|
|
966
1013
|
const volRelease = endTime + note.voiceParams.volRelease;
|
|
967
1014
|
const modRelease = endTime + note.voiceParams.modRelease;
|
|
968
1015
|
const stopTime = Math.min(volRelease, modRelease);
|
|
@@ -983,7 +1030,7 @@ class MidyGMLite {
|
|
|
983
1030
|
}, stopTime);
|
|
984
1031
|
});
|
|
985
1032
|
}
|
|
986
|
-
|
|
1033
|
+
noteOff(channelNumber, noteNumber, velocity, endTime, force) {
|
|
987
1034
|
const channel = this.channels[channelNumber];
|
|
988
1035
|
if (!force) {
|
|
989
1036
|
if (channel.isDrum)
|
|
@@ -995,6 +1042,10 @@ class MidyGMLite {
|
|
|
995
1042
|
if (index < 0)
|
|
996
1043
|
return;
|
|
997
1044
|
const note = channel.scheduledNotes[index];
|
|
1045
|
+
if (note.pending) {
|
|
1046
|
+
note.offEvent = { velocity, startTime: endTime };
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
998
1049
|
note.ending = true;
|
|
999
1050
|
this.setNoteIndex(channel, index);
|
|
1000
1051
|
this.releaseNote(channel, note, endTime);
|
|
@@ -1025,16 +1076,12 @@ class MidyGMLite {
|
|
|
1025
1076
|
}
|
|
1026
1077
|
return -1;
|
|
1027
1078
|
}
|
|
1028
|
-
noteOff(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
1029
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1030
|
-
return this.scheduleNoteOff(channelNumber, noteNumber, velocity, scheduleTime, false);
|
|
1031
|
-
}
|
|
1032
1079
|
releaseSustainPedal(channelNumber, halfVelocity, scheduleTime) {
|
|
1033
1080
|
const velocity = halfVelocity * 2;
|
|
1034
1081
|
const channel = this.channels[channelNumber];
|
|
1035
1082
|
const promises = [];
|
|
1036
1083
|
for (let i = 0; i < channel.sustainNotes.length; i++) {
|
|
1037
|
-
const promise = this.
|
|
1084
|
+
const promise = this.noteOff(channelNumber, channel.sustainNotes[i].noteNumber, velocity, scheduleTime);
|
|
1038
1085
|
promises.push(promise);
|
|
1039
1086
|
}
|
|
1040
1087
|
channel.sustainNotes = [];
|
package/script/midy.d.ts
CHANGED
|
@@ -44,6 +44,7 @@ export class Midy {
|
|
|
44
44
|
soundFontTable: never[][];
|
|
45
45
|
voiceCounter: Map<any, any>;
|
|
46
46
|
voiceCache: Map<any, any>;
|
|
47
|
+
realtimeVoiceCache: Map<any, any>;
|
|
47
48
|
isPlaying: boolean;
|
|
48
49
|
isPausing: boolean;
|
|
49
50
|
isPaused: boolean;
|
|
@@ -173,18 +174,17 @@ export class Midy {
|
|
|
173
174
|
setFilterEnvelope(channel: any, note: any, scheduleTime: any): void;
|
|
174
175
|
startModulation(channel: any, note: any, scheduleTime: any): void;
|
|
175
176
|
startVibrato(channel: any, note: any, scheduleTime: any): void;
|
|
176
|
-
getAudioBuffer(channel: any, noteNumber: any, velocity: any, voiceParams: any): Promise<any>;
|
|
177
|
-
|
|
177
|
+
getAudioBuffer(channel: any, noteNumber: any, velocity: any, voiceParams: any, realtime: any): Promise<any>;
|
|
178
|
+
setNoteAudioNode(channel: any, note: any, realtime: any): Promise<any>;
|
|
178
179
|
handleExclusiveClass(note: any, channelNumber: any, startTime: any): void;
|
|
179
180
|
handleDrumExclusiveClass(note: any, channelNumber: any, startTime: any): void;
|
|
180
|
-
|
|
181
|
-
noteOn(channelNumber: any, noteNumber: any, velocity: any,
|
|
181
|
+
setNoteRouting(channelNumber: any, note: any, startTime: any): void;
|
|
182
|
+
noteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
182
183
|
disconnectNote(note: any): void;
|
|
183
184
|
releaseNote(channel: any, note: any, endTime: any): Promise<any>;
|
|
184
|
-
|
|
185
|
+
noteOff(channelNumber: any, noteNumber: any, velocity: any, endTime: any, force: any): void;
|
|
185
186
|
setNoteIndex(channel: any, index: any): void;
|
|
186
187
|
findNoteOffIndex(channel: any, noteNumber: any): any;
|
|
187
|
-
noteOff(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): void;
|
|
188
188
|
releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
|
|
189
189
|
releaseSostenutoPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
|
|
190
190
|
createMessageHandlers(): any[];
|
|
@@ -326,28 +326,4 @@ export class Midy {
|
|
|
326
326
|
handleSysEx(data: any, scheduleTime: any): void;
|
|
327
327
|
scheduleTask(callback: any, scheduleTime: any): Promise<any>;
|
|
328
328
|
}
|
|
329
|
-
declare class Note {
|
|
330
|
-
constructor(noteNumber: any, velocity: any, startTime: any, voice: any, voiceParams: any);
|
|
331
|
-
index: number;
|
|
332
|
-
ending: boolean;
|
|
333
|
-
bufferSource: any;
|
|
334
|
-
filterNode: any;
|
|
335
|
-
filterDepth: any;
|
|
336
|
-
volumeEnvelopeNode: any;
|
|
337
|
-
volumeDepth: any;
|
|
338
|
-
modulationLFO: any;
|
|
339
|
-
modulationDepth: any;
|
|
340
|
-
vibratoLFO: any;
|
|
341
|
-
vibratoDepth: any;
|
|
342
|
-
reverbSend: any;
|
|
343
|
-
chorusSend: any;
|
|
344
|
-
portamentoNoteNumber: number;
|
|
345
|
-
pressure: number;
|
|
346
|
-
noteNumber: any;
|
|
347
|
-
velocity: any;
|
|
348
|
-
startTime: any;
|
|
349
|
-
voice: any;
|
|
350
|
-
voiceParams: any;
|
|
351
|
-
}
|
|
352
|
-
export {};
|
|
353
329
|
//# sourceMappingURL=midy.d.ts.map
|
package/script/midy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}
|