react-native-update-cli 2.8.0 → 2.8.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/lib/bundle.js +6 -385
- package/lib/diff.js +387 -0
- package/lib/index.js +3 -0
- package/lib/utils/app-info-parser/utils.js +0 -1
- package/lib/utils/app-info-parser/zip.js +12 -14
- package/lib/utils/latest-version/index.js +5 -4
- package/lib/utils/zip-entries.js +129 -0
- package/package.json +2 -2
- package/src/bundle.ts +1 -483
- package/src/diff.ts +405 -0
- package/src/index.ts +3 -0
- package/src/utils/app-info-parser/utils.ts +0 -4
- package/src/utils/app-info-parser/zip.ts +9 -19
- package/src/utils/latest-version/index.ts +2 -1
- package/src/utils/zip-entries.ts +96 -0
package/lib/bundle.js
CHANGED
|
@@ -2,33 +2,19 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", {
|
|
3
3
|
value: true
|
|
4
4
|
});
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
get: all[name]
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
_export(exports, {
|
|
12
|
-
bundleCommands: function() {
|
|
5
|
+
Object.defineProperty(exports, "bundleCommands", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
13
8
|
return bundleCommands;
|
|
14
|
-
},
|
|
15
|
-
enumZipEntries: function() {
|
|
16
|
-
return enumZipEntries;
|
|
17
|
-
},
|
|
18
|
-
readEntry: function() {
|
|
19
|
-
return readEntry;
|
|
20
9
|
}
|
|
21
10
|
});
|
|
22
11
|
const _child_process = require("child_process");
|
|
23
12
|
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
|
|
24
13
|
const _compareversions = require("compare-versions");
|
|
25
14
|
const _fsextra = /*#__PURE__*/ _interop_require_wildcard(require("fs-extra"));
|
|
26
|
-
const _yauzl = require("yauzl");
|
|
27
15
|
const _yazl = require("yazl");
|
|
28
16
|
const _app = require("./app");
|
|
29
17
|
const _utils = require("./utils");
|
|
30
|
-
const _os = /*#__PURE__*/ _interop_require_default(require("os"));
|
|
31
|
-
const _globaldirs = require("global-dirs");
|
|
32
18
|
const _addgitignore = require("./utils/add-gitignore");
|
|
33
19
|
const _checklockfile = require("./utils/check-lockfile");
|
|
34
20
|
const _constants = require("./utils/constants");
|
|
@@ -81,31 +67,8 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
81
67
|
}
|
|
82
68
|
return newObj;
|
|
83
69
|
}
|
|
84
|
-
var _loadDiffModule;
|
|
85
70
|
const g2js = require('gradle-to-js/lib/parser');
|
|
86
71
|
const properties = require('properties');
|
|
87
|
-
const loadDiffModule = (pkgName)=>{
|
|
88
|
-
const resolvePaths = [
|
|
89
|
-
process.cwd(),
|
|
90
|
-
_globaldirs.npm.packages,
|
|
91
|
-
_globaldirs.yarn.packages
|
|
92
|
-
];
|
|
93
|
-
try {
|
|
94
|
-
const resolved = require.resolve(pkgName, {
|
|
95
|
-
paths: resolvePaths
|
|
96
|
-
});
|
|
97
|
-
const mod = require(resolved);
|
|
98
|
-
if (mod == null ? void 0 : mod.diff) {
|
|
99
|
-
return mod.diff;
|
|
100
|
-
}
|
|
101
|
-
} catch (e) {}
|
|
102
|
-
return undefined;
|
|
103
|
-
};
|
|
104
|
-
let hdiff;
|
|
105
|
-
hdiff = (_loadDiffModule = loadDiffModule('node-hdiffpatch')) == null ? void 0 : _loadDiffModule.diff;
|
|
106
|
-
let bsdiff;
|
|
107
|
-
let diff;
|
|
108
|
-
bsdiff = loadDiffModule('node-bsdiff');
|
|
109
72
|
async function runReactNativeBundleCommand({ bundleName, dev, entryFile, outputFolder, platform, sourcemapOutput, config, forceHermes, cli }) {
|
|
110
73
|
let gradleConfig = {};
|
|
111
74
|
if (platform === 'android') {
|
|
@@ -290,9 +253,9 @@ async function runReactNativeBundleCommand({ bundleName, dev, entryFile, outputF
|
|
|
290
253
|
});
|
|
291
254
|
}
|
|
292
255
|
function getHermesOSBin() {
|
|
293
|
-
if (
|
|
294
|
-
if (
|
|
295
|
-
if (
|
|
256
|
+
if (os.platform() === 'win32') return 'win64-bin';
|
|
257
|
+
if (os.platform() === 'darwin') return 'osx-bin';
|
|
258
|
+
if (os.platform() === 'linux') return 'linux64-bin';
|
|
296
259
|
}
|
|
297
260
|
async function checkGradleConfig() {
|
|
298
261
|
let enableHermes = false;
|
|
@@ -484,286 +447,6 @@ async function pack(dir, output) {
|
|
|
484
447
|
file: output
|
|
485
448
|
}));
|
|
486
449
|
}
|
|
487
|
-
function readEntry(entry, zipFile) {
|
|
488
|
-
const buffers = [];
|
|
489
|
-
return new Promise((resolve, reject)=>{
|
|
490
|
-
zipFile.openReadStream(entry, (err, stream)=>{
|
|
491
|
-
stream.on('data', (chunk)=>{
|
|
492
|
-
buffers.push(chunk);
|
|
493
|
-
});
|
|
494
|
-
stream.on('end', ()=>{
|
|
495
|
-
resolve(Buffer.concat(buffers));
|
|
496
|
-
});
|
|
497
|
-
stream.on('error', (err)=>{
|
|
498
|
-
reject(err);
|
|
499
|
-
});
|
|
500
|
-
});
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
function basename(fn) {
|
|
504
|
-
const m = /^(.+\/)[^\/]+\/?$/.exec(fn);
|
|
505
|
-
return m == null ? void 0 : m[1];
|
|
506
|
-
}
|
|
507
|
-
async function diffFromPPK(origin, next, output) {
|
|
508
|
-
_fsextra.ensureDirSync(_path.default.dirname(output));
|
|
509
|
-
const originEntries = {};
|
|
510
|
-
const originMap = {};
|
|
511
|
-
let originSource;
|
|
512
|
-
await enumZipEntries(origin, (entry, zipFile)=>{
|
|
513
|
-
originEntries[entry.fileName] = entry;
|
|
514
|
-
if (!/\/$/.test(entry.fileName)) {
|
|
515
|
-
// isFile
|
|
516
|
-
originMap[entry.crc32] = entry.fileName;
|
|
517
|
-
if ((0, _constants.isPPKBundleFileName)(entry.fileName)) {
|
|
518
|
-
// This is source.
|
|
519
|
-
return readEntry(entry, zipFile).then((v)=>originSource = v);
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
});
|
|
523
|
-
if (!originSource) {
|
|
524
|
-
throw new Error((0, _i18n.t)('bundleFileNotFound'));
|
|
525
|
-
}
|
|
526
|
-
const copies = {};
|
|
527
|
-
const zipfile = new _yazl.ZipFile();
|
|
528
|
-
const writePromise = new Promise((resolve, reject)=>{
|
|
529
|
-
zipfile.outputStream.on('error', (err)=>{
|
|
530
|
-
throw err;
|
|
531
|
-
});
|
|
532
|
-
zipfile.outputStream.pipe(_fsextra.createWriteStream(output)).on('close', ()=>{
|
|
533
|
-
resolve(void 0);
|
|
534
|
-
});
|
|
535
|
-
});
|
|
536
|
-
const addedEntry = {};
|
|
537
|
-
function addEntry(fn) {
|
|
538
|
-
//console.log(fn);
|
|
539
|
-
if (!fn || addedEntry[fn]) {
|
|
540
|
-
return;
|
|
541
|
-
}
|
|
542
|
-
const base = basename(fn);
|
|
543
|
-
if (base) {
|
|
544
|
-
addEntry(base);
|
|
545
|
-
}
|
|
546
|
-
zipfile.addEmptyDirectory(fn);
|
|
547
|
-
}
|
|
548
|
-
const newEntries = {};
|
|
549
|
-
await enumZipEntries(next, (entry, nextZipfile)=>{
|
|
550
|
-
newEntries[entry.fileName] = entry;
|
|
551
|
-
if (/\/$/.test(entry.fileName)) {
|
|
552
|
-
// Directory
|
|
553
|
-
if (!originEntries[entry.fileName]) {
|
|
554
|
-
addEntry(entry.fileName);
|
|
555
|
-
}
|
|
556
|
-
} else if ((0, _constants.isPPKBundleFileName)(entry.fileName)) {
|
|
557
|
-
//console.log('Found bundle');
|
|
558
|
-
return readEntry(entry, nextZipfile).then((newSource)=>{
|
|
559
|
-
//console.log('Begin diff');
|
|
560
|
-
zipfile.addBuffer(diff(originSource, newSource), `${entry.fileName}.patch`);
|
|
561
|
-
//console.log('End diff');
|
|
562
|
-
});
|
|
563
|
-
} else {
|
|
564
|
-
// If same file.
|
|
565
|
-
const originEntry = originEntries[entry.fileName];
|
|
566
|
-
if (originEntry && originEntry.crc32 === entry.crc32) {
|
|
567
|
-
// ignore
|
|
568
|
-
return;
|
|
569
|
-
}
|
|
570
|
-
// If moved from other place
|
|
571
|
-
if (originMap[entry.crc32]) {
|
|
572
|
-
const base = basename(entry.fileName);
|
|
573
|
-
if (!originEntries[base]) {
|
|
574
|
-
addEntry(base);
|
|
575
|
-
}
|
|
576
|
-
copies[entry.fileName] = originMap[entry.crc32];
|
|
577
|
-
return;
|
|
578
|
-
}
|
|
579
|
-
// New file.
|
|
580
|
-
addEntry(basename(entry.fileName));
|
|
581
|
-
return new Promise((resolve, reject)=>{
|
|
582
|
-
nextZipfile.openReadStream(entry, (err, readStream)=>{
|
|
583
|
-
if (err) {
|
|
584
|
-
return reject(err);
|
|
585
|
-
}
|
|
586
|
-
zipfile.addReadStream(readStream, entry.fileName);
|
|
587
|
-
readStream.on('end', ()=>{
|
|
588
|
-
//console.log('add finished');
|
|
589
|
-
resolve(void 0);
|
|
590
|
-
});
|
|
591
|
-
});
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
});
|
|
595
|
-
const deletes = {};
|
|
596
|
-
for(const k in originEntries){
|
|
597
|
-
if (!newEntries[k]) {
|
|
598
|
-
console.log((0, _i18n.t)('deleteFile', {
|
|
599
|
-
file: k
|
|
600
|
-
}));
|
|
601
|
-
deletes[k] = 1;
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
//console.log({copies, deletes});
|
|
605
|
-
zipfile.addBuffer(Buffer.from(JSON.stringify({
|
|
606
|
-
copies,
|
|
607
|
-
deletes
|
|
608
|
-
})), '__diff.json');
|
|
609
|
-
zipfile.end();
|
|
610
|
-
await writePromise;
|
|
611
|
-
}
|
|
612
|
-
async function diffFromPackage(origin, next, output, originBundleName, transformPackagePath = (v)=>v) {
|
|
613
|
-
_fsextra.ensureDirSync(_path.default.dirname(output));
|
|
614
|
-
const originEntries = {};
|
|
615
|
-
const originMap = {};
|
|
616
|
-
let originSource;
|
|
617
|
-
await enumZipEntries(origin, (entry, zipFile)=>{
|
|
618
|
-
if (!/\/$/.test(entry.fileName)) {
|
|
619
|
-
const fn = transformPackagePath(entry.fileName);
|
|
620
|
-
if (!fn) {
|
|
621
|
-
return;
|
|
622
|
-
}
|
|
623
|
-
//console.log(fn);
|
|
624
|
-
// isFile
|
|
625
|
-
originEntries[fn] = entry.crc32;
|
|
626
|
-
originMap[entry.crc32] = fn;
|
|
627
|
-
if (fn === originBundleName) {
|
|
628
|
-
// This is source.
|
|
629
|
-
return readEntry(entry, zipFile).then((v)=>originSource = v);
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
});
|
|
633
|
-
if (!originSource) {
|
|
634
|
-
throw new Error((0, _i18n.t)('bundleFileNotFound'));
|
|
635
|
-
}
|
|
636
|
-
const copies = {};
|
|
637
|
-
const zipfile = new _yazl.ZipFile();
|
|
638
|
-
const writePromise = new Promise((resolve, reject)=>{
|
|
639
|
-
zipfile.outputStream.on('error', (err)=>{
|
|
640
|
-
throw err;
|
|
641
|
-
});
|
|
642
|
-
zipfile.outputStream.pipe(_fsextra.createWriteStream(output)).on('close', ()=>{
|
|
643
|
-
resolve(void 0);
|
|
644
|
-
});
|
|
645
|
-
});
|
|
646
|
-
await enumZipEntries(next, (entry, nextZipfile)=>{
|
|
647
|
-
if (/\/$/.test(entry.fileName)) {
|
|
648
|
-
// Directory
|
|
649
|
-
zipfile.addEmptyDirectory(entry.fileName);
|
|
650
|
-
} else if ((0, _constants.isPPKBundleFileName)(entry.fileName)) {
|
|
651
|
-
//console.log('Found bundle');
|
|
652
|
-
return readEntry(entry, nextZipfile).then((newSource)=>{
|
|
653
|
-
//console.log('Begin diff');
|
|
654
|
-
zipfile.addBuffer(diff(originSource, newSource), `${entry.fileName}.patch`);
|
|
655
|
-
//console.log('End diff');
|
|
656
|
-
});
|
|
657
|
-
} else {
|
|
658
|
-
// If same file.
|
|
659
|
-
if (originEntries[entry.fileName] === entry.crc32) {
|
|
660
|
-
copies[entry.fileName] = '';
|
|
661
|
-
return;
|
|
662
|
-
}
|
|
663
|
-
// If moved from other place
|
|
664
|
-
if (originMap[entry.crc32]) {
|
|
665
|
-
copies[entry.fileName] = originMap[entry.crc32];
|
|
666
|
-
return;
|
|
667
|
-
}
|
|
668
|
-
return new Promise((resolve, reject)=>{
|
|
669
|
-
nextZipfile.openReadStream(entry, (err, readStream)=>{
|
|
670
|
-
if (err) {
|
|
671
|
-
return reject(err);
|
|
672
|
-
}
|
|
673
|
-
zipfile.addReadStream(readStream, entry.fileName);
|
|
674
|
-
readStream.on('end', ()=>{
|
|
675
|
-
//console.log('add finished');
|
|
676
|
-
resolve(void 0);
|
|
677
|
-
});
|
|
678
|
-
});
|
|
679
|
-
});
|
|
680
|
-
}
|
|
681
|
-
});
|
|
682
|
-
zipfile.addBuffer(Buffer.from(JSON.stringify({
|
|
683
|
-
copies
|
|
684
|
-
})), '__diff.json');
|
|
685
|
-
zipfile.end();
|
|
686
|
-
await writePromise;
|
|
687
|
-
}
|
|
688
|
-
async function enumZipEntries(zipFn, callback, nestedPath = '') {
|
|
689
|
-
return new Promise((resolve, reject)=>{
|
|
690
|
-
(0, _yauzl.open)(zipFn, {
|
|
691
|
-
lazyEntries: true
|
|
692
|
-
}, async (err, zipfile)=>{
|
|
693
|
-
if (err) {
|
|
694
|
-
return reject(err);
|
|
695
|
-
}
|
|
696
|
-
zipfile.on('end', resolve);
|
|
697
|
-
zipfile.on('error', reject);
|
|
698
|
-
zipfile.on('entry', async (entry)=>{
|
|
699
|
-
const fullPath = nestedPath + entry.fileName;
|
|
700
|
-
try {
|
|
701
|
-
if (!entry.fileName.endsWith('/') && entry.fileName.toLowerCase().endsWith('.hap')) {
|
|
702
|
-
const tempDir = _path.default.join(_os.default.tmpdir(), `nested_zip_${Date.now()}`);
|
|
703
|
-
await _fsextra.ensureDir(tempDir);
|
|
704
|
-
const tempZipPath = _path.default.join(tempDir, 'temp.zip');
|
|
705
|
-
await new Promise((res, rej)=>{
|
|
706
|
-
zipfile.openReadStream(entry, async (err, readStream)=>{
|
|
707
|
-
if (err) return rej(err);
|
|
708
|
-
const writeStream = _fsextra.createWriteStream(tempZipPath);
|
|
709
|
-
readStream.pipe(writeStream);
|
|
710
|
-
writeStream.on('finish', ()=>res(void 0));
|
|
711
|
-
writeStream.on('error', rej);
|
|
712
|
-
});
|
|
713
|
-
});
|
|
714
|
-
await enumZipEntries(tempZipPath, callback, `${fullPath}/`);
|
|
715
|
-
await _fsextra.remove(tempDir);
|
|
716
|
-
}
|
|
717
|
-
const result = callback(entry, zipfile, fullPath);
|
|
718
|
-
if (result && typeof result.then === 'function') {
|
|
719
|
-
await result;
|
|
720
|
-
}
|
|
721
|
-
} catch (error) {
|
|
722
|
-
console.error((0, _i18n.t)('processingError', {
|
|
723
|
-
error
|
|
724
|
-
}));
|
|
725
|
-
}
|
|
726
|
-
zipfile.readEntry();
|
|
727
|
-
});
|
|
728
|
-
zipfile.readEntry();
|
|
729
|
-
});
|
|
730
|
-
});
|
|
731
|
-
}
|
|
732
|
-
function diffArgsCheck(args, options, diffFn) {
|
|
733
|
-
const [origin, next] = args;
|
|
734
|
-
if (!origin || !next) {
|
|
735
|
-
console.error((0, _i18n.t)('usageDiff', {
|
|
736
|
-
command: diffFn
|
|
737
|
-
}));
|
|
738
|
-
process.exit(1);
|
|
739
|
-
}
|
|
740
|
-
if (diffFn.startsWith('hdiff')) {
|
|
741
|
-
if (!hdiff) {
|
|
742
|
-
console.error((0, _i18n.t)('nodeHdiffpatchRequired', {
|
|
743
|
-
scriptName: _constants.scriptName
|
|
744
|
-
}));
|
|
745
|
-
process.exit(1);
|
|
746
|
-
}
|
|
747
|
-
diff = hdiff;
|
|
748
|
-
} else {
|
|
749
|
-
if (!bsdiff) {
|
|
750
|
-
console.error((0, _i18n.t)('nodeBsdiffRequired', {
|
|
751
|
-
scriptName: _constants.scriptName
|
|
752
|
-
}));
|
|
753
|
-
process.exit(1);
|
|
754
|
-
}
|
|
755
|
-
diff = bsdiff;
|
|
756
|
-
}
|
|
757
|
-
const { output } = (0, _utils.translateOptions)({
|
|
758
|
-
...options,
|
|
759
|
-
tempDir: _constants.tempDir
|
|
760
|
-
});
|
|
761
|
-
return {
|
|
762
|
-
origin,
|
|
763
|
-
next,
|
|
764
|
-
realOutput: output.replace(/\$\{time\}/g, `${Date.now()}`)
|
|
765
|
-
};
|
|
766
|
-
}
|
|
767
450
|
const bundleCommands = {
|
|
768
451
|
bundle: async ({ options })=>{
|
|
769
452
|
const platform = await (0, _app.getPlatform)(options.platform);
|
|
@@ -838,67 +521,5 @@ const bundleCommands = {
|
|
|
838
521
|
}
|
|
839
522
|
}
|
|
840
523
|
}
|
|
841
|
-
},
|
|
842
|
-
async diff ({ args, options }) {
|
|
843
|
-
const { origin, next, realOutput } = diffArgsCheck(args, options, 'diff');
|
|
844
|
-
await diffFromPPK(origin, next, realOutput);
|
|
845
|
-
console.log((0, _i18n.t)('diffPackageGenerated', {
|
|
846
|
-
output: realOutput
|
|
847
|
-
}));
|
|
848
|
-
},
|
|
849
|
-
async hdiff ({ args, options }) {
|
|
850
|
-
const { origin, next, realOutput } = diffArgsCheck(args, options, 'hdiff');
|
|
851
|
-
await diffFromPPK(origin, next, realOutput);
|
|
852
|
-
console.log((0, _i18n.t)('diffPackageGenerated', {
|
|
853
|
-
output: realOutput
|
|
854
|
-
}));
|
|
855
|
-
},
|
|
856
|
-
async diffFromApk ({ args, options }) {
|
|
857
|
-
const { origin, next, realOutput } = diffArgsCheck(args, options, 'diffFromApk');
|
|
858
|
-
await diffFromPackage(origin, next, realOutput, 'assets/index.android.bundle');
|
|
859
|
-
console.log((0, _i18n.t)('diffPackageGenerated', {
|
|
860
|
-
output: realOutput
|
|
861
|
-
}));
|
|
862
|
-
},
|
|
863
|
-
async hdiffFromApk ({ args, options }) {
|
|
864
|
-
const { origin, next, realOutput } = diffArgsCheck(args, options, 'hdiffFromApk');
|
|
865
|
-
await diffFromPackage(origin, next, realOutput, 'assets/index.android.bundle');
|
|
866
|
-
console.log((0, _i18n.t)('diffPackageGenerated', {
|
|
867
|
-
output: realOutput
|
|
868
|
-
}));
|
|
869
|
-
},
|
|
870
|
-
async diffFromApp ({ args, options }) {
|
|
871
|
-
const { origin, next, realOutput } = diffArgsCheck(args, options, 'diffFromApp');
|
|
872
|
-
await diffFromPackage(origin, next, realOutput, 'resources/rawfile/bundle.harmony.js');
|
|
873
|
-
console.log((0, _i18n.t)('diffPackageGenerated', {
|
|
874
|
-
output: realOutput
|
|
875
|
-
}));
|
|
876
|
-
},
|
|
877
|
-
async hdiffFromApp ({ args, options }) {
|
|
878
|
-
const { origin, next, realOutput } = diffArgsCheck(args, options, 'hdiffFromApp');
|
|
879
|
-
await diffFromPackage(origin, next, realOutput, 'resources/rawfile/bundle.harmony.js');
|
|
880
|
-
console.log((0, _i18n.t)('diffPackageGenerated', {
|
|
881
|
-
output: realOutput
|
|
882
|
-
}));
|
|
883
|
-
},
|
|
884
|
-
async diffFromIpa ({ args, options }) {
|
|
885
|
-
const { origin, next, realOutput } = diffArgsCheck(args, options, 'diffFromIpa');
|
|
886
|
-
await diffFromPackage(origin, next, realOutput, 'main.jsbundle', (v)=>{
|
|
887
|
-
const m = /^Payload\/[^/]+\/(.+)$/.exec(v);
|
|
888
|
-
return m == null ? void 0 : m[1];
|
|
889
|
-
});
|
|
890
|
-
console.log((0, _i18n.t)('diffPackageGenerated', {
|
|
891
|
-
output: realOutput
|
|
892
|
-
}));
|
|
893
|
-
},
|
|
894
|
-
async hdiffFromIpa ({ args, options }) {
|
|
895
|
-
const { origin, next, realOutput } = diffArgsCheck(args, options, 'hdiffFromIpa');
|
|
896
|
-
await diffFromPackage(origin, next, realOutput, 'main.jsbundle', (v)=>{
|
|
897
|
-
const m = /^Payload\/[^/]+\/(.+)$/.exec(v);
|
|
898
|
-
return m == null ? void 0 : m[1];
|
|
899
|
-
});
|
|
900
|
-
console.log((0, _i18n.t)('diffPackageGenerated', {
|
|
901
|
-
output: realOutput
|
|
902
|
-
}));
|
|
903
524
|
}
|
|
904
525
|
};
|