nativescript 9.1.0-alpha.1 → 9.1.0-alpha.11
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/commands/prepare.js +5 -0
- package/lib/common/definitions/mobile.d.ts +15 -10
- package/lib/common/mobile/android/android-emulator-services.js +11 -3
- package/lib/common/mobile/emulator-helper.js +1 -0
- package/lib/common/mobile/ios/device/ios-device-file-system.js +29 -1
- package/lib/controllers/prepare-controller.js +53 -11
- package/lib/controllers/run-controller.js +200 -13
- package/lib/data/prepare-data.js +4 -0
- package/lib/declarations.d.ts +38 -42
- package/lib/definitions/ios.d.ts +29 -14
- package/lib/definitions/project.d.ts +16 -0
- package/lib/options.js +1 -0
- package/lib/services/android-plugin-build-service.js +20 -12
- package/lib/services/bundler/bundler-compiler-service.js +160 -2
- package/lib/services/ios/spm-service.js +170 -10
- package/lib/services/ios/xcodebuild-args-service.js +26 -0
- package/lib/services/ios/xcodebuild-command-service.js +19 -3
- package/lib/services/ios-project-service.js +79 -14
- package/lib/services/livesync/ios-livesync-service.js +113 -2
- package/lib/services/plugins-service.js +12 -4
- package/lib/services/project-data-service.js +14 -11
- package/node_modules/debug/LICENSE +20 -0
- package/node_modules/debug/README.md +481 -0
- package/node_modules/debug/package.json +64 -0
- package/node_modules/debug/src/browser.js +272 -0
- package/node_modules/debug/src/common.js +292 -0
- package/node_modules/debug/src/index.js +10 -0
- package/node_modules/debug/src/node.js +263 -0
- package/node_modules/ms/index.js +162 -0
- package/node_modules/ms/license.md +21 -0
- package/node_modules/ms/package.json +38 -0
- package/node_modules/ms/readme.md +59 -0
- package/node_modules/universal-analytics/.travis.yml +11 -0
- package/node_modules/universal-analytics/AcceptableParams.md +757 -0
- package/node_modules/universal-analytics/HISTORY.md +170 -0
- package/node_modules/universal-analytics/Makefile +5 -0
- package/node_modules/universal-analytics/README.md +651 -0
- package/node_modules/universal-analytics/index.js +2 -0
- package/node_modules/universal-analytics/lib/config.js +171 -0
- package/node_modules/universal-analytics/lib/index.js +563 -0
- package/node_modules/universal-analytics/lib/request.js +73 -0
- package/node_modules/universal-analytics/lib/utils.js +29 -0
- package/node_modules/universal-analytics/package.json +33 -0
- package/node_modules/universal-analytics/test/_enqueue.js +144 -0
- package/node_modules/universal-analytics/test/event.js +346 -0
- package/node_modules/universal-analytics/test/exception.js +233 -0
- package/node_modules/universal-analytics/test/index.js +141 -0
- package/node_modules/universal-analytics/test/item.js +550 -0
- package/node_modules/universal-analytics/test/middleware.js +119 -0
- package/node_modules/universal-analytics/test/mocha.opts +3 -0
- package/node_modules/universal-analytics/test/pageview.js +286 -0
- package/node_modules/universal-analytics/test/send.js +232 -0
- package/node_modules/universal-analytics/test/set.js +68 -0
- package/node_modules/universal-analytics/test/timing.js +363 -0
- package/node_modules/universal-analytics/test/transaction.js +371 -0
- package/node_modules/uuid/LICENSE.md +9 -0
- package/node_modules/uuid/README.md +510 -0
- package/node_modules/uuid/dist/cjs/index.d.ts +15 -0
- package/node_modules/uuid/dist/cjs/index.js +31 -0
- package/node_modules/uuid/dist/cjs/max.d.ts +2 -0
- package/node_modules/uuid/dist/cjs/max.js +3 -0
- package/node_modules/uuid/dist/cjs/md5.d.ts +4 -0
- package/node_modules/uuid/dist/cjs/md5.js +13 -0
- package/node_modules/uuid/dist/cjs/native.d.ts +6 -0
- package/node_modules/uuid/dist/cjs/native.js +4 -0
- package/node_modules/uuid/dist/cjs/nil.d.ts +2 -0
- package/node_modules/uuid/dist/cjs/nil.js +3 -0
- package/node_modules/uuid/dist/cjs/package.json +1 -0
- package/node_modules/uuid/dist/cjs/parse.d.ts +2 -0
- package/node_modules/uuid/dist/cjs/parse.js +11 -0
- package/node_modules/uuid/dist/cjs/regex.d.ts +2 -0
- package/node_modules/uuid/dist/cjs/regex.js +3 -0
- package/node_modules/uuid/dist/cjs/rng.d.ts +1 -0
- package/node_modules/uuid/dist/cjs/rng.js +13 -0
- package/node_modules/uuid/dist/cjs/sha1.d.ts +4 -0
- package/node_modules/uuid/dist/cjs/sha1.js +13 -0
- package/node_modules/uuid/dist/cjs/stringify.d.ts +3 -0
- package/node_modules/uuid/dist/cjs/stringify.js +39 -0
- package/node_modules/uuid/dist/cjs/types.d.ts +21 -0
- package/node_modules/uuid/dist/cjs/types.js +2 -0
- package/node_modules/uuid/dist/cjs/uuid-bin.d.ts +1 -0
- package/node_modules/uuid/dist/cjs/uuid-bin.js +72 -0
- package/node_modules/uuid/dist/cjs/v1.d.ts +11 -0
- package/node_modules/uuid/dist/cjs/v1.js +87 -0
- package/node_modules/uuid/dist/cjs/v1ToV6.d.ts +2 -0
- package/node_modules/uuid/dist/cjs/v1ToV6.js +13 -0
- package/node_modules/uuid/dist/cjs/v3.d.ts +9 -0
- package/node_modules/uuid/dist/cjs/v3.js +14 -0
- package/node_modules/uuid/dist/cjs/v35.d.ts +7 -0
- package/node_modules/uuid/dist/cjs/v35.js +41 -0
- package/node_modules/uuid/dist/cjs/v4.d.ts +4 -0
- package/node_modules/uuid/dist/cjs/v4.js +29 -0
- package/node_modules/uuid/dist/cjs/v5.d.ts +9 -0
- package/node_modules/uuid/dist/cjs/v5.js +14 -0
- package/node_modules/uuid/dist/cjs/v6.d.ts +4 -0
- package/node_modules/uuid/dist/cjs/v6.js +19 -0
- package/node_modules/uuid/dist/cjs/v6ToV1.d.ts +2 -0
- package/node_modules/uuid/dist/cjs/v6ToV1.js +13 -0
- package/node_modules/uuid/dist/cjs/v7.d.ts +9 -0
- package/node_modules/uuid/dist/cjs/v7.js +69 -0
- package/node_modules/uuid/dist/cjs/validate.d.ts +2 -0
- package/node_modules/uuid/dist/cjs/validate.js +7 -0
- package/node_modules/uuid/dist/cjs/version.d.ts +2 -0
- package/node_modules/uuid/dist/cjs/version.js +10 -0
- package/node_modules/uuid/dist/cjs-browser/index.d.ts +15 -0
- package/node_modules/uuid/dist/cjs-browser/index.js +31 -0
- package/node_modules/uuid/dist/cjs-browser/max.d.ts +2 -0
- package/node_modules/uuid/dist/cjs-browser/max.js +3 -0
- package/node_modules/uuid/dist/cjs-browser/md5.d.ts +2 -0
- package/node_modules/uuid/dist/cjs-browser/md5.js +137 -0
- package/node_modules/uuid/dist/cjs-browser/native.d.ts +4 -0
- package/node_modules/uuid/dist/cjs-browser/native.js +4 -0
- package/node_modules/uuid/dist/cjs-browser/nil.d.ts +2 -0
- package/node_modules/uuid/dist/cjs-browser/nil.js +3 -0
- package/node_modules/uuid/dist/cjs-browser/package.json +1 -0
- package/node_modules/uuid/dist/cjs-browser/parse.d.ts +2 -0
- package/node_modules/uuid/dist/cjs-browser/parse.js +11 -0
- package/node_modules/uuid/dist/cjs-browser/regex.d.ts +2 -0
- package/node_modules/uuid/dist/cjs-browser/regex.js +3 -0
- package/node_modules/uuid/dist/cjs-browser/rng.d.ts +1 -0
- package/node_modules/uuid/dist/cjs-browser/rng.js +14 -0
- package/node_modules/uuid/dist/cjs-browser/sha1.d.ts +2 -0
- package/node_modules/uuid/dist/cjs-browser/sha1.js +72 -0
- package/node_modules/uuid/dist/cjs-browser/stringify.d.ts +3 -0
- package/node_modules/uuid/dist/cjs-browser/stringify.js +39 -0
- package/node_modules/uuid/dist/cjs-browser/types.d.ts +21 -0
- package/node_modules/uuid/dist/cjs-browser/types.js +2 -0
- package/node_modules/uuid/dist/cjs-browser/uuid-bin.d.ts +1 -0
- package/node_modules/uuid/dist/cjs-browser/uuid-bin.js +72 -0
- package/node_modules/uuid/dist/cjs-browser/v1.d.ts +11 -0
- package/node_modules/uuid/dist/cjs-browser/v1.js +87 -0
- package/node_modules/uuid/dist/cjs-browser/v1ToV6.d.ts +2 -0
- package/node_modules/uuid/dist/cjs-browser/v1ToV6.js +13 -0
- package/node_modules/uuid/dist/cjs-browser/v3.d.ts +9 -0
- package/node_modules/uuid/dist/cjs-browser/v3.js +14 -0
- package/node_modules/uuid/dist/cjs-browser/v35.d.ts +7 -0
- package/node_modules/uuid/dist/cjs-browser/v35.js +41 -0
- package/node_modules/uuid/dist/cjs-browser/v4.d.ts +4 -0
- package/node_modules/uuid/dist/cjs-browser/v4.js +29 -0
- package/node_modules/uuid/dist/cjs-browser/v5.d.ts +9 -0
- package/node_modules/uuid/dist/cjs-browser/v5.js +14 -0
- package/node_modules/uuid/dist/cjs-browser/v6.d.ts +4 -0
- package/node_modules/uuid/dist/cjs-browser/v6.js +19 -0
- package/node_modules/uuid/dist/cjs-browser/v6ToV1.d.ts +2 -0
- package/node_modules/uuid/dist/cjs-browser/v6ToV1.js +13 -0
- package/node_modules/uuid/dist/cjs-browser/v7.d.ts +9 -0
- package/node_modules/uuid/dist/cjs-browser/v7.js +69 -0
- package/node_modules/uuid/dist/cjs-browser/validate.d.ts +2 -0
- package/node_modules/uuid/dist/cjs-browser/validate.js +7 -0
- package/node_modules/uuid/dist/cjs-browser/version.d.ts +2 -0
- package/node_modules/uuid/dist/cjs-browser/version.js +10 -0
- package/node_modules/uuid/dist/esm/bin/uuid +2 -0
- package/node_modules/uuid/dist/esm/index.d.ts +15 -0
- package/node_modules/uuid/dist/esm/index.js +14 -0
- package/node_modules/uuid/dist/esm/max.d.ts +2 -0
- package/node_modules/uuid/dist/esm/max.js +1 -0
- package/node_modules/uuid/dist/esm/md5.d.ts +4 -0
- package/node_modules/uuid/dist/esm/md5.js +11 -0
- package/node_modules/uuid/dist/esm/native.d.ts +6 -0
- package/node_modules/uuid/dist/esm/native.js +2 -0
- package/node_modules/uuid/dist/esm/nil.d.ts +2 -0
- package/node_modules/uuid/dist/esm/nil.js +1 -0
- package/node_modules/uuid/dist/esm/parse.d.ts +2 -0
- package/node_modules/uuid/dist/esm/parse.js +9 -0
- package/node_modules/uuid/dist/esm/regex.d.ts +2 -0
- package/node_modules/uuid/dist/esm/regex.js +1 -0
- package/node_modules/uuid/dist/esm/rng.d.ts +1 -0
- package/node_modules/uuid/dist/esm/rng.js +10 -0
- package/node_modules/uuid/dist/esm/sha1.d.ts +4 -0
- package/node_modules/uuid/dist/esm/sha1.js +11 -0
- package/node_modules/uuid/dist/esm/stringify.d.ts +3 -0
- package/node_modules/uuid/dist/esm/stringify.js +35 -0
- package/node_modules/uuid/dist/esm/types.d.ts +21 -0
- package/node_modules/uuid/dist/esm/types.js +1 -0
- package/node_modules/uuid/dist/esm/uuid-bin.d.ts +1 -0
- package/node_modules/uuid/dist/esm/uuid-bin.js +70 -0
- package/node_modules/uuid/dist/esm/v1.d.ts +11 -0
- package/node_modules/uuid/dist/esm/v1.js +83 -0
- package/node_modules/uuid/dist/esm/v1ToV6.d.ts +2 -0
- package/node_modules/uuid/dist/esm/v1ToV6.js +10 -0
- package/node_modules/uuid/dist/esm/v3.d.ts +9 -0
- package/node_modules/uuid/dist/esm/v3.js +9 -0
- package/node_modules/uuid/dist/esm/v35.d.ts +7 -0
- package/node_modules/uuid/dist/esm/v35.js +36 -0
- package/node_modules/uuid/dist/esm/v4.d.ts +4 -0
- package/node_modules/uuid/dist/esm/v4.js +27 -0
- package/node_modules/uuid/dist/esm/v5.d.ts +9 -0
- package/node_modules/uuid/dist/esm/v5.js +9 -0
- package/node_modules/uuid/dist/esm/v6.d.ts +4 -0
- package/node_modules/uuid/dist/esm/v6.js +17 -0
- package/node_modules/uuid/dist/esm/v6ToV1.d.ts +2 -0
- package/node_modules/uuid/dist/esm/v6ToV1.js +10 -0
- package/node_modules/uuid/dist/esm/v7.d.ts +9 -0
- package/node_modules/uuid/dist/esm/v7.js +65 -0
- package/node_modules/uuid/dist/esm/validate.d.ts +2 -0
- package/node_modules/uuid/dist/esm/validate.js +5 -0
- package/node_modules/uuid/dist/esm/version.d.ts +2 -0
- package/node_modules/uuid/dist/esm/version.js +8 -0
- package/node_modules/uuid/dist/esm-browser/index.d.ts +15 -0
- package/node_modules/uuid/dist/esm-browser/index.js +14 -0
- package/node_modules/uuid/dist/esm-browser/max.d.ts +2 -0
- package/node_modules/uuid/dist/esm-browser/max.js +1 -0
- package/node_modules/uuid/dist/esm-browser/md5.d.ts +2 -0
- package/node_modules/uuid/dist/esm-browser/md5.js +135 -0
- package/node_modules/uuid/dist/esm-browser/native.d.ts +4 -0
- package/node_modules/uuid/dist/esm-browser/native.js +2 -0
- package/node_modules/uuid/dist/esm-browser/nil.d.ts +2 -0
- package/node_modules/uuid/dist/esm-browser/nil.js +1 -0
- package/node_modules/uuid/dist/esm-browser/parse.d.ts +2 -0
- package/node_modules/uuid/dist/esm-browser/parse.js +9 -0
- package/node_modules/uuid/dist/esm-browser/regex.d.ts +2 -0
- package/node_modules/uuid/dist/esm-browser/regex.js +1 -0
- package/node_modules/uuid/dist/esm-browser/rng.d.ts +1 -0
- package/node_modules/uuid/dist/esm-browser/rng.js +11 -0
- package/node_modules/uuid/dist/esm-browser/sha1.d.ts +2 -0
- package/node_modules/uuid/dist/esm-browser/sha1.js +70 -0
- package/node_modules/uuid/dist/esm-browser/stringify.d.ts +3 -0
- package/node_modules/uuid/dist/esm-browser/stringify.js +35 -0
- package/node_modules/uuid/dist/esm-browser/types.d.ts +21 -0
- package/node_modules/uuid/dist/esm-browser/types.js +1 -0
- package/node_modules/uuid/dist/esm-browser/uuid-bin.d.ts +1 -0
- package/node_modules/uuid/dist/esm-browser/uuid-bin.js +70 -0
- package/node_modules/uuid/dist/esm-browser/v1.d.ts +11 -0
- package/node_modules/uuid/dist/esm-browser/v1.js +83 -0
- package/node_modules/uuid/dist/esm-browser/v1ToV6.d.ts +2 -0
- package/node_modules/uuid/dist/esm-browser/v1ToV6.js +10 -0
- package/node_modules/uuid/dist/esm-browser/v3.d.ts +9 -0
- package/node_modules/uuid/dist/esm-browser/v3.js +9 -0
- package/node_modules/uuid/dist/esm-browser/v35.d.ts +7 -0
- package/node_modules/uuid/dist/esm-browser/v35.js +36 -0
- package/node_modules/uuid/dist/esm-browser/v4.d.ts +4 -0
- package/node_modules/uuid/dist/esm-browser/v4.js +27 -0
- package/node_modules/uuid/dist/esm-browser/v5.d.ts +9 -0
- package/node_modules/uuid/dist/esm-browser/v5.js +9 -0
- package/node_modules/uuid/dist/esm-browser/v6.d.ts +4 -0
- package/node_modules/uuid/dist/esm-browser/v6.js +17 -0
- package/node_modules/uuid/dist/esm-browser/v6ToV1.d.ts +2 -0
- package/node_modules/uuid/dist/esm-browser/v6ToV1.js +10 -0
- package/node_modules/uuid/dist/esm-browser/v7.d.ts +9 -0
- package/node_modules/uuid/dist/esm-browser/v7.js +65 -0
- package/node_modules/uuid/dist/esm-browser/validate.d.ts +2 -0
- package/node_modules/uuid/dist/esm-browser/validate.js +5 -0
- package/node_modules/uuid/dist/esm-browser/version.d.ts +2 -0
- package/node_modules/uuid/dist/esm-browser/version.js +8 -0
- package/node_modules/uuid/package.json +132 -0
- package/package.json +8 -4
|
@@ -243,6 +243,10 @@ class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase
|
|
|
243
243
|
}
|
|
244
244
|
async buildProject(projectRoot, projectData, buildData) {
|
|
245
245
|
const platformData = this.getPlatformData(projectData);
|
|
246
|
+
// On a first build, the runtime (and any other Swift packages) download
|
|
247
|
+
// here. Pre-resolve under a clear spinner so the subsequent
|
|
248
|
+
// "Xcode build..." step doesn't appear to hang while that happens.
|
|
249
|
+
await this.$spmService.ensureSPMDependenciesResolved(platformData, projectData);
|
|
246
250
|
const handler = (data) => {
|
|
247
251
|
this.emit(constants.BUILD_OUTPUT_EVENT_NAME, data);
|
|
248
252
|
};
|
|
@@ -265,8 +269,7 @@ class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase
|
|
|
265
269
|
return Promise.resolve();
|
|
266
270
|
}
|
|
267
271
|
async isDynamicFramework(frameworkPath) {
|
|
268
|
-
const isDynamicFrameworkBundle = async (
|
|
269
|
-
const frameworkBinaryPath = path.join(bundlePath, frameworkName);
|
|
272
|
+
const isDynamicFrameworkBundle = async (frameworkBinaryPath) => {
|
|
270
273
|
const fileResult = (await this.$childProcess.spawnFromEvent("file", [frameworkBinaryPath], "close")).stdout;
|
|
271
274
|
const isDynamicallyLinked = _.includes(fileResult, "dynamically linked");
|
|
272
275
|
return isDynamicallyLinked;
|
|
@@ -278,7 +281,11 @@ class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase
|
|
|
278
281
|
const singlePlatformFramework = path.join(frameworkPath, library.LibraryIdentifier, library.LibraryPath);
|
|
279
282
|
if (this.$fs.exists(singlePlatformFramework)) {
|
|
280
283
|
const frameworkName = path.basename(singlePlatformFramework, path.extname(singlePlatformFramework));
|
|
281
|
-
|
|
284
|
+
let frameworkBinaryPath = path.join(singlePlatformFramework, frameworkName);
|
|
285
|
+
if (library.BinaryPath) {
|
|
286
|
+
frameworkBinaryPath = path.join(frameworkPath, library.LibraryIdentifier, library.BinaryPath);
|
|
287
|
+
}
|
|
288
|
+
isDynamic = await isDynamicFrameworkBundle(frameworkBinaryPath);
|
|
282
289
|
break;
|
|
283
290
|
}
|
|
284
291
|
}
|
|
@@ -286,7 +293,7 @@ class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase
|
|
|
286
293
|
}
|
|
287
294
|
else {
|
|
288
295
|
const frameworkName = path.basename(frameworkPath, path.extname(frameworkPath));
|
|
289
|
-
return await isDynamicFrameworkBundle(frameworkPath, frameworkName);
|
|
296
|
+
return await isDynamicFrameworkBundle(path.join(frameworkPath, frameworkName));
|
|
290
297
|
}
|
|
291
298
|
}
|
|
292
299
|
/**
|
|
@@ -353,7 +360,18 @@ class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase
|
|
|
353
360
|
project.addFramework(relativeStaticLibPath);
|
|
354
361
|
const relativeHeaderSearchPath = path.join(this.getLibSubpathRelativeToProjectPath(headersSubpath, projectData));
|
|
355
362
|
project.addToHeaderSearchPaths({ relativePath: relativeHeaderSearchPath });
|
|
356
|
-
|
|
363
|
+
// Write the generated modulemap into a CLI-managed folder under the
|
|
364
|
+
// platform root (never into node_modules). The modulemap references the
|
|
365
|
+
// plugin's headers in-place via relative paths, so nothing is copied.
|
|
366
|
+
const modulemapDir = path.join(this.getPlatformData(projectData).projectRoot, IOSProjectService.GENERATED_PLUGINS_DIR_NAME, libraryName);
|
|
367
|
+
const hasModulemap = this.generateModulemap(headersSubpath, libraryName, modulemapDir);
|
|
368
|
+
if (hasModulemap) {
|
|
369
|
+
// Put the modulemap dir on the header search path so clang discovers
|
|
370
|
+
// the module there instead of inside node_modules.
|
|
371
|
+
project.addToHeaderSearchPaths({
|
|
372
|
+
relativePath: this.getLibSubpathRelativeToProjectPath(modulemapDir, projectData),
|
|
373
|
+
});
|
|
374
|
+
}
|
|
357
375
|
this.savePbxProj(project, projectData);
|
|
358
376
|
}
|
|
359
377
|
async prepareProject(projectData, prepareData) {
|
|
@@ -623,6 +641,27 @@ class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase
|
|
|
623
641
|
await this.prepareFrameworks(pluginPlatformsFolderPath, pluginData, projectData);
|
|
624
642
|
await this.prepareStaticLibs(pluginPlatformsFolderPath, pluginData, projectData);
|
|
625
643
|
}
|
|
644
|
+
shouldRepreparePlugin(pluginData, projectData) {
|
|
645
|
+
const pluginPlatformsFolderPath = pluginData.pluginPlatformsFolderPath(IOSProjectService.IOS_PLATFORM_NAME);
|
|
646
|
+
for (const fileName of this.getAllLibsForPluginWithFileExtension(pluginData, ".a")) {
|
|
647
|
+
const staticLibPath = path.join(pluginPlatformsFolderPath, fileName);
|
|
648
|
+
const libraryName = path.basename(staticLibPath, ".a");
|
|
649
|
+
const headersSubpath = path.join(path.dirname(staticLibPath), "include", libraryName);
|
|
650
|
+
if (!this.$fs.exists(headersSubpath)) {
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
653
|
+
const headerFiles = this.$fs
|
|
654
|
+
.readDirectory(headersSubpath)
|
|
655
|
+
.filter((f) => path.extname(f) === ".h" &&
|
|
656
|
+
this.$fs.getFsStats(path.join(headersSubpath, f)).isFile());
|
|
657
|
+
if (headerFiles.length > 0 &&
|
|
658
|
+
!this.$fs.exists(path.join(headersSubpath, "module.modulemap"))) {
|
|
659
|
+
this.$logger.trace(`Plugin ${pluginData.name}: modulemap missing at ${headersSubpath}, will re-prepare`);
|
|
660
|
+
return true;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return false;
|
|
664
|
+
}
|
|
626
665
|
async removePluginNativeCode(pluginData, projectData) {
|
|
627
666
|
const pluginPlatformsFolderPath = pluginData.pluginPlatformsFolderPath(IOSProjectService.IOS_PLATFORM_NAME);
|
|
628
667
|
this.removeNativeSourceCode(pluginPlatformsFolderPath, pluginData, projectData);
|
|
@@ -881,23 +920,46 @@ class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase
|
|
|
881
920
|
project.removeFromHeaderSearchPaths({
|
|
882
921
|
relativePath: relativeHeaderSearchPath,
|
|
883
922
|
});
|
|
923
|
+
// Remove the generated modulemap dir search path (see addStaticLibrary)
|
|
924
|
+
const modulemapDir = path.join(this.getPlatformData(projectData).projectRoot, IOSProjectService.GENERATED_PLUGINS_DIR_NAME, path.basename(staticLibPath, ".a"));
|
|
925
|
+
project.removeFromHeaderSearchPaths({
|
|
926
|
+
relativePath: this.getLibSubpathRelativeToProjectPath(modulemapDir, projectData),
|
|
927
|
+
});
|
|
884
928
|
});
|
|
885
929
|
this.savePbxProj(project, projectData);
|
|
886
930
|
}
|
|
887
|
-
generateModulemap(headersFolderPath, libraryName) {
|
|
931
|
+
generateModulemap(headersFolderPath, libraryName, modulemapDir) {
|
|
932
|
+
const modulemapPath = path.join(modulemapDir, "module.modulemap");
|
|
933
|
+
// A plugin may ship a `.a` without an `include/{lib}` headers folder. In
|
|
934
|
+
// that case there's nothing to expose as a module - clean up any stale
|
|
935
|
+
// modulemap and bail out instead of letting readDirectory throw.
|
|
936
|
+
if (!this.$fs.exists(headersFolderPath)) {
|
|
937
|
+
if (this.$fs.exists(modulemapPath)) {
|
|
938
|
+
this.$fs.deleteFile(modulemapPath);
|
|
939
|
+
}
|
|
940
|
+
return false;
|
|
941
|
+
}
|
|
888
942
|
const headersFilter = (fileName, containingFolderPath) => path.extname(fileName) === ".h" &&
|
|
889
943
|
this.$fs.getFsStats(path.join(containingFolderPath, fileName)).isFile();
|
|
890
944
|
const headersFolderContents = this.$fs.readDirectory(headersFolderPath);
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
.
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
return;
|
|
945
|
+
const headerFiles = headersFolderContents.filter((item) => headersFilter(item, headersFolderPath));
|
|
946
|
+
if (!headerFiles.length) {
|
|
947
|
+
if (this.$fs.exists(modulemapPath)) {
|
|
948
|
+
this.$fs.deleteFile(modulemapPath);
|
|
949
|
+
}
|
|
950
|
+
return false;
|
|
897
951
|
}
|
|
898
|
-
|
|
952
|
+
// Reference the plugin's headers (still in node_modules) relative to the
|
|
953
|
+
// generated modulemap's location, so we don't copy headers or write into
|
|
954
|
+
// node_modules.
|
|
955
|
+
const headers = _.map(headerFiles, (value) => {
|
|
956
|
+
const relativeHeaderPath = path.relative(modulemapDir, path.join(headersFolderPath, value));
|
|
957
|
+
return `header "${relativeHeaderPath}"`;
|
|
958
|
+
});
|
|
899
959
|
const modulemap = `module ${libraryName} { explicit module ${libraryName} { ${headers.join(" ")} } }`;
|
|
900
|
-
this.$fs.
|
|
960
|
+
this.$fs.ensureDirectoryExists(modulemapDir);
|
|
961
|
+
this.$fs.writeFile(modulemapPath, modulemap);
|
|
962
|
+
return true;
|
|
901
963
|
}
|
|
902
964
|
async mergeProjectXcconfigFiles(projectData) {
|
|
903
965
|
const platformData = this.getPlatformData(projectData);
|
|
@@ -971,6 +1033,9 @@ class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase
|
|
|
971
1033
|
exports.IOSProjectService = IOSProjectService;
|
|
972
1034
|
IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER = "__PROJECT_NAME__";
|
|
973
1035
|
IOSProjectService.IOS_PLATFORM_NAME = "ios";
|
|
1036
|
+
// CLI-managed folder under the platform root where we write generated
|
|
1037
|
+
// artifacts (e.g. plugin modulemaps) so we never write into node_modules
|
|
1038
|
+
IOSProjectService.GENERATED_PLUGINS_DIR_NAME = ".plugins";
|
|
974
1039
|
__decorate([
|
|
975
1040
|
(0, helpers_2.hook)("buildIOS")
|
|
976
1041
|
], IOSProjectService.prototype, "buildProject", null);
|
|
@@ -11,6 +11,7 @@ const path = require("path");
|
|
|
11
11
|
const ios_device_livesync_service_1 = require("./ios-device-livesync-service");
|
|
12
12
|
const platform_livesync_service_base_1 = require("./platform-livesync-service-base");
|
|
13
13
|
const constants_1 = require("../../constants");
|
|
14
|
+
const constants_2 = require("../../common/constants");
|
|
14
15
|
const decorators_1 = require("../../common/decorators");
|
|
15
16
|
const yok_1 = require("../../common/yok");
|
|
16
17
|
class IOSLiveSyncService extends platform_livesync_service_base_1.PlatformLiveSyncServiceBase {
|
|
@@ -40,14 +41,124 @@ class IOSLiveSyncService extends platform_livesync_service_base_1.PlatformLiveSy
|
|
|
40
41
|
await this.$fs.zipFiles(tempZip, filesToTransfer, (res) => {
|
|
41
42
|
return path.join(constants_1.APP_FOLDER_NAME, path.relative(projectFilesPath, res));
|
|
42
43
|
});
|
|
43
|
-
await
|
|
44
|
+
const deviceProjectRootPath = await deviceAppData.getDeviceProjectRootPath();
|
|
45
|
+
const transferSyncZip = () => device.fileSystem.transferFiles(deviceAppData, [
|
|
44
46
|
{
|
|
45
47
|
getLocalPath: () => tempZip,
|
|
46
48
|
getDevicePath: () => deviceAppData.deviceSyncZipPath,
|
|
47
49
|
getRelativeToProjectBasePath: () => "../sync.zip",
|
|
48
|
-
deviceProjectRootPath
|
|
50
|
+
deviceProjectRootPath,
|
|
49
51
|
},
|
|
50
52
|
]);
|
|
53
|
+
// ── Fail-closed delivery verification ──────────────────────────
|
|
54
|
+
//
|
|
55
|
+
// The AFC transfer has been observed to fail without surfacing an
|
|
56
|
+
// error, leaving the app to boot the stale JavaScript baked into
|
|
57
|
+
// the installed .app payload with no indication anywhere that the
|
|
58
|
+
// sync was lost. After the transfer we therefore confirm the zip
|
|
59
|
+
// is actually present in the app sandbox; one retry covers
|
|
60
|
+
// transient AFC hiccups, and an unconfirmed delivery fails the
|
|
61
|
+
// sync loudly instead of printing "Successfully synced" over
|
|
62
|
+
// stale code (the run-controller surfaces the error; --clean
|
|
63
|
+
// reinstalls the full package).
|
|
64
|
+
//
|
|
65
|
+
// Presence alone is NOT sufficient evidence: a previous run that
|
|
66
|
+
// transferred the zip but aborted before the app restarted leaves
|
|
67
|
+
// a LEFTOVER sync.zip behind (the runtime only consumes it at
|
|
68
|
+
// boot), which would satisfy the check even when THIS upload
|
|
69
|
+
// failed. So any pre-existing zip is deleted up front — after
|
|
70
|
+
// that, post-transfer presence can only be produced by this run's
|
|
71
|
+
// upload.
|
|
72
|
+
//
|
|
73
|
+
// NOTE: deviceProjectRootPath is `.../LiveSync/app` (the extracted
|
|
74
|
+
// app folder); the zip is uploaded one level up, at the LiveSync
|
|
75
|
+
// root — the listing targets THAT directory.
|
|
76
|
+
//
|
|
77
|
+
// Escape hatch: NS_SKIP_IOS_SYNC_VERIFICATION=1 disables the
|
|
78
|
+
// whole verification for exotic setups where directory listing
|
|
79
|
+
// misbehaves but uploads are known-good.
|
|
80
|
+
const syncZipDevicePath = deviceAppData.deviceSyncZipPath;
|
|
81
|
+
const verificationSupported = !!device.fileSystem.getDirectoryEntries &&
|
|
82
|
+
process.env.NS_SKIP_IOS_SYNC_VERIFICATION !== "1";
|
|
83
|
+
const listLiveSyncRoot = () => device.fileSystem.getDirectoryEntries(constants_2.LiveSyncPaths.IOS_DEVICE_PROJECT_ROOT_PATH, deviceAppData.appIdentifier);
|
|
84
|
+
// Entry shape: ios-device-lib's native `read_dir` recursively joins
|
|
85
|
+
// `<requested dir>/<entry>` and returns FULL paths rooted at the
|
|
86
|
+
// requested directory (verified against IOSDeviceLib.cpp and live
|
|
87
|
+
// device output), so the canonical match is exact equality with
|
|
88
|
+
// `Library/Application Support/LiveSync/sync.zip`. The bare
|
|
89
|
+
// `"sync.zip"` equality is defensive cover for listing
|
|
90
|
+
// implementations that return root-relative names. Deliberately NO
|
|
91
|
+
// suffix matching — `endsWith("/sync.zip")` would false-positively
|
|
92
|
+
// accept a nested app asset like `.../LiveSync/app/sync.zip`.
|
|
93
|
+
const containsSyncZip = (entries) => entries.some((entry) => entry === syncZipDevicePath || entry === "sync.zip");
|
|
94
|
+
// "delivered" / "missing" are definitive listings; "unknown" means
|
|
95
|
+
// the listing itself could not be read (after one retry).
|
|
96
|
+
const checkDelivery = async () => {
|
|
97
|
+
let entries = await listLiveSyncRoot();
|
|
98
|
+
if (entries === null) {
|
|
99
|
+
entries = await listLiveSyncRoot();
|
|
100
|
+
}
|
|
101
|
+
if (entries === null) {
|
|
102
|
+
return "unknown";
|
|
103
|
+
}
|
|
104
|
+
return containsSyncZip(entries) ? "delivered" : "missing";
|
|
105
|
+
};
|
|
106
|
+
let preListingAvailable = false;
|
|
107
|
+
let leftoverZipPresent = false;
|
|
108
|
+
if (verificationSupported) {
|
|
109
|
+
// Clear any leftover zip so the post-transfer check attributes
|
|
110
|
+
// presence to this run. Best-effort: AFC "file not found" is
|
|
111
|
+
// tolerated inside deleteFile.
|
|
112
|
+
await device.fileSystem.deleteFile(syncZipDevicePath, deviceAppData.appIdentifier);
|
|
113
|
+
const preEntries = await listLiveSyncRoot();
|
|
114
|
+
preListingAvailable = Array.isArray(preEntries);
|
|
115
|
+
leftoverZipPresent = preListingAvailable && containsSyncZip(preEntries);
|
|
116
|
+
}
|
|
117
|
+
await transferSyncZip();
|
|
118
|
+
if (verificationSupported) {
|
|
119
|
+
if (leftoverZipPresent) {
|
|
120
|
+
// The pre-transfer delete did not take effect, so presence
|
|
121
|
+
// can no longer be attributed to this run. Most likely the
|
|
122
|
+
// upload succeeded too, but say so explicitly rather than
|
|
123
|
+
// claim verification.
|
|
124
|
+
this.$logger.warn("A leftover sync.zip from a previous run could not be removed — delivery verification for this sync is inconclusive. " +
|
|
125
|
+
"If the app runs stale code, re-run the command or use a clean rebuild (--clean).");
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
let state = await checkDelivery();
|
|
129
|
+
if (state === "missing") {
|
|
130
|
+
this.$logger.warn("sync.zip was not found on the device after transfer — retrying once...");
|
|
131
|
+
await transferSyncZip();
|
|
132
|
+
state = await checkDelivery();
|
|
133
|
+
if (state === "delivered") {
|
|
134
|
+
this.$logger.info("sync.zip delivered on retry.");
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (state === "missing") {
|
|
138
|
+
throw new Error(`Unable to deliver the application payload (sync.zip) to device ${device.deviceInfo.identifier}. ` +
|
|
139
|
+
`The app would run stale JavaScript without it. ` +
|
|
140
|
+
`Re-run the command, or use a clean rebuild (--clean) to reinstall the full application package.`);
|
|
141
|
+
}
|
|
142
|
+
if (state === "unknown") {
|
|
143
|
+
if (preListingAvailable) {
|
|
144
|
+
// The listing worked moments before the upload and
|
|
145
|
+
// broke right after it — the AFC session is
|
|
146
|
+
// misbehaving at exactly the point where the upload
|
|
147
|
+
// itself is suspect. Fail closed.
|
|
148
|
+
throw new Error(`Unable to confirm delivery of the application payload (sync.zip) to device ${device.deviceInfo.identifier}: ` +
|
|
149
|
+
`the device directory listing failed right after the transfer. ` +
|
|
150
|
+
`Re-run the command, or use a clean rebuild (--clean) to reinstall the full application package. ` +
|
|
151
|
+
`(Set NS_SKIP_IOS_SYNC_VERIFICATION=1 to bypass delivery verification.)`);
|
|
152
|
+
}
|
|
153
|
+
// Listing was unavailable both before and after the
|
|
154
|
+
// transfer — verification is unsupported for this
|
|
155
|
+
// device/session. This is the single fail-open path,
|
|
156
|
+
// and it is loud rather than silent.
|
|
157
|
+
this.$logger.warn("Could not verify sync.zip delivery (device directory listing unavailable). " +
|
|
158
|
+
"If the transfer failed, the app will run stale JavaScript — re-run the command or use a clean rebuild (--clean).");
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
51
162
|
await deviceAppData.device.applicationManager.setTransferredAppFiles(filesToTransfer);
|
|
52
163
|
return {
|
|
53
164
|
deviceAppData,
|
|
@@ -107,6 +107,7 @@ class PluginsService {
|
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
async preparePluginNativeCode({ pluginData, platform, projectData, }) {
|
|
110
|
+
var _a, _b, _c;
|
|
110
111
|
const platformData = this.$platformsDataService.getPlatformData(platform, projectData);
|
|
111
112
|
const pluginPlatformsFolderPath = pluginData.pluginPlatformsFolderPath(platform);
|
|
112
113
|
if (this.$fs.exists(pluginPlatformsFolderPath)) {
|
|
@@ -114,8 +115,10 @@ class PluginsService {
|
|
|
114
115
|
const allPluginsNativeHashes = this.getAllPluginsNativeHashes(pathToPluginsBuildFile);
|
|
115
116
|
const oldPluginNativeHashes = allPluginsNativeHashes[pluginData.name];
|
|
116
117
|
const currentPluginNativeHashes = await this.getPluginNativeHashes(pluginPlatformsFolderPath);
|
|
117
|
-
|
|
118
|
-
this.$filesHashService.hasChangesInShasums(oldPluginNativeHashes, currentPluginNativeHashes)
|
|
118
|
+
const needsReprepare = !oldPluginNativeHashes ||
|
|
119
|
+
this.$filesHashService.hasChangesInShasums(oldPluginNativeHashes, currentPluginNativeHashes) ||
|
|
120
|
+
((_c = (_b = (_a = platformData.platformProjectService).shouldRepreparePlugin) === null || _b === void 0 ? void 0 : _b.call(_a, pluginData, projectData)) !== null && _c !== void 0 ? _c : false);
|
|
121
|
+
if (needsReprepare) {
|
|
119
122
|
await platformData.platformProjectService.preparePluginNativeCode(pluginData, projectData);
|
|
120
123
|
const updatedPluginNativeHashes = await this.getPluginNativeHashes(pluginPlatformsFolderPath);
|
|
121
124
|
this.setPluginNativeHashes({
|
|
@@ -366,7 +369,12 @@ This framework comes from ${dependencyName} plugin, which is installed multiple
|
|
|
366
369
|
getNodeModuleData(module, projectDir) {
|
|
367
370
|
// module can be modulePath or moduleName
|
|
368
371
|
if (!this.$fs.exists(module) || path.basename(module) !== "package.json") {
|
|
369
|
-
|
|
372
|
+
const resolvedPath = this.getPackageJsonFilePathForModule(module, projectDir);
|
|
373
|
+
if (!resolvedPath) {
|
|
374
|
+
this.$logger.warn(`Could not find module ${color_1.color.yellow(module)}. It may have been removed or is not installed. Skipping.`);
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
module = resolvedPath;
|
|
370
378
|
}
|
|
371
379
|
const data = this.$fs.readJson(module);
|
|
372
380
|
return {
|
|
@@ -384,7 +392,7 @@ This framework comes from ${dependencyName} plugin, which is installed multiple
|
|
|
384
392
|
async getAllInstalledModules(projectData) {
|
|
385
393
|
await this.ensure(projectData);
|
|
386
394
|
const nodeModules = this.getDependencies(projectData.projectDir);
|
|
387
|
-
return _.map(nodeModules, (nodeModuleName) => this.getNodeModuleData(nodeModuleName, projectData.projectDir));
|
|
395
|
+
return _.map(nodeModules, (nodeModuleName) => this.getNodeModuleData(nodeModuleName, projectData.projectDir)).filter(Boolean);
|
|
388
396
|
}
|
|
389
397
|
async executeNpmCommand(npmCommandName, npmCommandArguments, projectData) {
|
|
390
398
|
if (npmCommandName === PluginsService.INSTALL_COMMAND_NAME) {
|
|
@@ -18,10 +18,11 @@ const yok_1 = require("../common/yok");
|
|
|
18
18
|
const semver = require("semver");
|
|
19
19
|
const package_path_helper_1 = require("../helpers/package-path-helper");
|
|
20
20
|
class ProjectDataService {
|
|
21
|
-
constructor($fs, $staticConfig, $logger, $devicePlatformsConstants, $androidResourcesMigrationService, $injector) {
|
|
21
|
+
constructor($fs, $staticConfig, $logger, $projectData, $devicePlatformsConstants, $androidResourcesMigrationService, $injector) {
|
|
22
22
|
this.$fs = $fs;
|
|
23
23
|
this.$staticConfig = $staticConfig;
|
|
24
24
|
this.$logger = $logger;
|
|
25
|
+
this.$projectData = $projectData;
|
|
25
26
|
this.$devicePlatformsConstants = $devicePlatformsConstants;
|
|
26
27
|
this.$androidResourcesMigrationService = $androidResourcesMigrationService;
|
|
27
28
|
this.$injector = $injector;
|
|
@@ -373,20 +374,20 @@ class ProjectDataService {
|
|
|
373
374
|
return this.getInstalledRuntimePackage(projectDir, platform);
|
|
374
375
|
}
|
|
375
376
|
getInstalledRuntimePackage(projectDir, platform) {
|
|
377
|
+
var _a, _b, _c, _d;
|
|
376
378
|
const runtimePackage = this.$pluginsService
|
|
377
379
|
.getDependenciesFromPackageJson(projectDir)
|
|
378
380
|
.devDependencies.find((d) => {
|
|
381
|
+
var _a, _b, _c, _d;
|
|
379
382
|
if (platform === "ios" /* constants.PlatformTypes.ios */) {
|
|
380
|
-
|
|
381
|
-
constants.SCOPED_IOS_RUNTIME_NAME
|
|
382
|
-
|
|
383
|
-
].includes(d.name);
|
|
383
|
+
const packageName = ((_b = (_a = this.$projectData.nsConfig) === null || _a === void 0 ? void 0 : _a.ios) === null || _b === void 0 ? void 0 : _b.runtimePackageName) ||
|
|
384
|
+
constants.SCOPED_IOS_RUNTIME_NAME;
|
|
385
|
+
return [packageName, constants.TNS_IOS_RUNTIME_NAME].includes(d.name);
|
|
384
386
|
}
|
|
385
387
|
else if (platform === "android" /* constants.PlatformTypes.android */) {
|
|
386
|
-
|
|
387
|
-
constants.SCOPED_ANDROID_RUNTIME_NAME
|
|
388
|
-
|
|
389
|
-
].includes(d.name);
|
|
388
|
+
const packageName = ((_d = (_c = this.$projectData.nsConfig) === null || _c === void 0 ? void 0 : _c.android) === null || _d === void 0 ? void 0 : _d.runtimePackageName) ||
|
|
389
|
+
constants.SCOPED_ANDROID_RUNTIME_NAME;
|
|
390
|
+
return [packageName, constants.TNS_ANDROID_RUNTIME_NAME].includes(d.name);
|
|
390
391
|
}
|
|
391
392
|
else if (platform === "visionos" /* constants.PlatformTypes.visionos */) {
|
|
392
393
|
return d.name === constants.SCOPED_VISIONOS_RUNTIME_NAME;
|
|
@@ -424,13 +425,15 @@ class ProjectDataService {
|
|
|
424
425
|
this.$logger.trace("Could not find an installed runtime, falling back to default runtimes");
|
|
425
426
|
if (platform === "ios" /* constants.PlatformTypes.ios */) {
|
|
426
427
|
return {
|
|
427
|
-
name:
|
|
428
|
+
name: ((_b = (_a = this.$projectData.nsConfig) === null || _a === void 0 ? void 0 : _a.ios) === null || _b === void 0 ? void 0 : _b.runtimePackageName) ||
|
|
429
|
+
constants.SCOPED_IOS_RUNTIME_NAME,
|
|
428
430
|
version: null,
|
|
429
431
|
};
|
|
430
432
|
}
|
|
431
433
|
else if (platform === "android" /* constants.PlatformTypes.android */) {
|
|
432
434
|
return {
|
|
433
|
-
name:
|
|
435
|
+
name: ((_d = (_c = this.$projectData.nsConfig) === null || _c === void 0 ? void 0 : _c.android) === null || _d === void 0 ? void 0 : _d.runtimePackageName) ||
|
|
436
|
+
constants.SCOPED_ANDROID_RUNTIME_NAME,
|
|
434
437
|
version: null,
|
|
435
438
|
};
|
|
436
439
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
(The MIT License)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014-2017 TJ Holowaychuk <tj@vision-media.ca>
|
|
4
|
+
Copyright (c) 2018-2021 Josh Junon
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
|
7
|
+
and associated documentation files (the 'Software'), to deal in the Software without restriction,
|
|
8
|
+
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
9
|
+
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
10
|
+
subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
13
|
+
portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
16
|
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
17
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
18
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
19
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
20
|
+
|