@dynatrace/cordova-plugin
Advanced tools
Comparing version 1.275.1 to 2.277.1
@@ -575,3 +575,3 @@ { | ||
{ | ||
"filePath": "\/opt\/jenkins\/workspace\/eAgent_ios-agent_release_8.275.x\/adk\/DynatraceUEM\/Dynatrace\/SwiftUIExtensions.swift", | ||
"filePath": "\/opt\/jenkins\/workspace\/eAgent_ios-agent_release_8.277.x\/adk\/DynatraceUEM\/Dynatrace\/SwiftUIExtensions.swift", | ||
"kind": "BooleanLiteral", | ||
@@ -578,0 +578,0 @@ "offset": 1277, |
@@ -575,3 +575,3 @@ { | ||
{ | ||
"filePath": "\/opt\/jenkins\/workspace\/eAgent_ios-agent_release_8.275.x\/adk\/DynatraceUEM\/Dynatrace\/SwiftUIExtensions.swift", | ||
"filePath": "\/opt\/jenkins\/workspace\/eAgent_ios-agent_release_8.277.x\/adk\/DynatraceUEM\/Dynatrace\/SwiftUIExtensions.swift", | ||
"kind": "BooleanLiteral", | ||
@@ -578,0 +578,0 @@ "offset": 1277, |
@@ -575,3 +575,3 @@ { | ||
{ | ||
"filePath": "\/opt\/jenkins\/workspace\/eAgent_ios-agent_release_8.275.x\/adk\/DynatraceUEM\/Dynatrace\/SwiftUIExtensions.swift", | ||
"filePath": "\/opt\/jenkins\/workspace\/eAgent_ios-agent_release_8.277.x\/adk\/DynatraceUEM\/Dynatrace\/SwiftUIExtensions.swift", | ||
"kind": "BooleanLiteral", | ||
@@ -578,0 +578,0 @@ "offset": 1277, |
{ | ||
"name": "@dynatrace/cordova-plugin", | ||
"version": "1.275.1", | ||
"version": "2.277.1", | ||
"description": "This plugin gives you the ability to use the Dynatrace instrumentation in your hybrid application (Cordova, Ionic, ..). It uses the Mobile Agent, the JavaScript Agent. The Mobile Agent will give you all device specific values containing lifecycle information and the Javascript Agent will allow you to manually instrument your JavaScript/TypeScript code out of the box (Typescript definitions included). The JavaScript Agent will cover the network calls and will automatically detect them.", | ||
"cordova": { | ||
"id": "dynatrace-cordova-plugin", | ||
"id": "@dynatrace/cordova-plugin", | ||
"platforms": [ | ||
@@ -40,4 +40,3 @@ "ios", | ||
"dependencies": { | ||
"axios": "^1.5.0", | ||
"cordova-common": "^5.0.0", | ||
"axios": "^1.5.1", | ||
"jsdom": "^22.1.0", | ||
@@ -61,3 +60,3 @@ "plist": "^3.1.0" | ||
"eslint-plugin-unicorn": "^41.0.1", | ||
"cordova": "^11.0.0", | ||
"cordova": "^12.0.0", | ||
"jest": "^29.2.2", | ||
@@ -64,0 +63,0 @@ "mock-fs": "^5.2.0", |
@@ -7,6 +7,12 @@ [![N|Solid](https://assets.dynatrace.com/content/dam/dynatrace/misc/dynatrace_web.png)](https://dynatrace.com) | ||
## Versioning | ||
## Upgrading major versions | ||
The `dynatrace-cordova-plugin` is the old version of this plugin. Consider it deprecated. Only use `@dyntrace/cordova-plugin` from now on, if you want to have the newest version. If you are upgrading from the old version have a look at our [migration](#migration-from-old-plugin) guide which is explaining what has changed. The versioning changed as well, the old 7.2.x was based on the versions of the Mobile Agents used. Now the plugin has its own versioning. The version of the used Mobile Agent can be seen [here](#agent-versions). | ||
If you are upgrading from version 1.xxx.x of the plugin to the new major version 2.xxx.x, please follow the instructions below: | ||
* Uninstall the version 1.xxx.x of the plugin from the root directory of your project: | ||
* `cordova plugin remove dynatrace-cordova-plugin` | ||
* Install the latest version of the plugin: | ||
* `cordova plugin add @dynatrace/cordova-plugin@latest --save` | ||
For information as to why this is necessary, read more [here](#migration-from-major-version-1-to-2). | ||
## Requirements | ||
@@ -23,2 +29,3 @@ | ||
* Node: >= 16.x | ||
* Cordova: 10+ | ||
@@ -29,4 +36,4 @@ ## Agent Versions | ||
* Android Agent: 8.273.1.1003 | ||
* iOS Agent: 8.275.1.1006 | ||
* Android Agent: 8.277.1.1003 | ||
* iOS Agent: 8.277.1.1004 | ||
@@ -72,3 +79,3 @@ ## Quick Setup | ||
* [Custom arguments for instrumentation script](#custom-arguments-for-instrumentation-script) | ||
* [Migration from old plugin](#migration-from-old-plugin) | ||
* [Migration from major version 1 to 2](#migration-from-major-version-1-to-2) | ||
* [Updating to Gradle 6](#updating-to-gradle-6) | ||
@@ -697,10 +704,21 @@ * [MavenCentral in top level gradle file](#mavencentral-in-top-level-gradle-file) | ||
## Migration from major version 1 to 2 | ||
## Migration from old plugin | ||
The id has now changed for the plugin from `dynatrace-cordova-plugin` to `@dyntrace/cordova-plugin`. Because of this, there can be some issues with the upgrading of the plugin from major version `1.xxx.x` to `2.xxx.x`. You will likely see the following error if you are just trying to install the newest version of the plugin: | ||
The differences to the old `dynatrace-cordova-plugin` are very small. There are three differences: | ||
``` | ||
Error during processing of action! Attempting to revert... | ||
Failed to install '@dynatrace/cordova-plugin': CordovaError: Uh oh! | ||
"/path/DynatraceCordovaPlugin.java" already exists! | ||
at copyNewFile (/projectPath/node_modules/cordova-android/lib/pluginHandlers.js:231:45) | ||
at install (/projectPath/node_modules/cordova-android/lib/pluginHandlers.js:34:17) | ||
at ActionStack.process (/projectPath/node_modules/cordova-common/src/ActionStack.js:55:25) | ||
at PluginManager.doOperation (/projectPath/node_modules/cordova-common/src/PluginManager.js:111:24) | ||
at PluginManager.addPlugin (/projectPath/node_modules/cordova-common/src/PluginManager.js:141:21) | ||
at /Users/nicholas.mcwherter/projectPath/node_modules/cordova-android/lib/Api.js:155:78 | ||
Uh oh! | ||
"/projectPath/platforms/android/app/src/main/java/com/dynatrace/cordova/plugin/DynatraceCordovaPlugin.java" already exists! | ||
``` | ||
* The Android instrumentation is now executed via gradle. This makes the build way faster and more stable. The new plugin is now automatically modifying your gradle files. | ||
* The plugin raised the requirements for Gradle to version 6. This can easily be [upgraded](#updating-to-gradle-6) in your project by changing one line. | ||
* The format of the configuration changed from `dynatrace.config` to `dynatrace.config.js`. The new format can be downloaded via WebUI. If you had some custom settings in Android take a look in the detailed [documentation](#official-documentation). The format of iOS basically stayed the same. | ||
It will be necessary to follow the steps mentioned [here](#upgrading-major-versions) to resolve this issue. | ||
@@ -830,2 +848,7 @@ ## Updating to Gradle 6 | ||
2.277.1 | ||
* Updated requirements for Cordova 10+ | ||
* Changed plugin id to @dynatrace/cordova-plugin and removed old workarounds used for plugin migration | ||
* Updated Android (8.277.1.1003) & iOS Agent (8.277.1.1004) | ||
1.275.1 | ||
@@ -832,0 +855,0 @@ * Updated iOS Agent (8.275.1.1006) |
@@ -11,2 +11,3 @@ "use strict"; | ||
var GRADLE_BUILDSCRIPT_IDENTIFIER = 'buildscript'; | ||
var OLD_DYNATRACE_PLUGIN = 'dynatrace-cordova-plugin'; | ||
var getGradleApplyDynatraceScript = function () { return "apply from: \"".concat((0, PathHelper_1.getDynatraceGradleFile)().split(path_1.sep).join("".concat(path_1.sep + path_1.sep)), "\""); }; | ||
@@ -58,3 +59,8 @@ exports.getGradleApplyDynatraceScript = getGradleApplyDynatraceScript; | ||
else { | ||
if (gradlePluginFileIndex === -1) { | ||
var oldPluginValue = gradleFileContentLines[gradlePluginFileIndex]; | ||
var oldDynatraceValue = gradleFileContentLines[gradleDynatraceFileIndex]; | ||
if (gradlePluginFileIndex === -1 || (oldPluginValue !== undefined && oldPluginValue.includes(OLD_DYNATRACE_PLUGIN))) { | ||
if (oldPluginValue !== undefined && oldPluginValue.includes(OLD_DYNATRACE_PLUGIN)) { | ||
gradleFileContentLines.splice(gradlePluginFileIndex, 1); | ||
} | ||
var gradleFileCordovaIndex = -1; | ||
@@ -73,3 +79,6 @@ for (var i = 0; i < gradleFileContentLines.length; i++) { | ||
} | ||
if (gradleDynatraceFileIndex === -1) { | ||
if (gradleDynatraceFileIndex === -1 || (oldDynatraceValue !== undefined && oldDynatraceValue.includes(OLD_DYNATRACE_PLUGIN))) { | ||
if (oldDynatraceValue !== undefined && oldDynatraceValue.includes(OLD_DYNATRACE_PLUGIN)) { | ||
gradleFileContentLines.splice(gradleDynatraceFileIndex, 1); | ||
} | ||
gradleFileContentLines.splice(gradleFileContentLines.length, 0, (0, exports.getGradleApplyDynatraceScript)()); | ||
@@ -76,0 +85,0 @@ modified = true; |
@@ -39,3 +39,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isOptOut = exports.parsedNpmConfig = exports.parsedCapPackageJson = exports.parsedPluginPackageJson = exports.parsedApplicationPackageJson = exports.removeScriptHookAndDeps = exports.addScriptHook = exports.isCapVersionThreeOneOrHigher = exports.modifyConfigXmlUninstall = exports.modifyConfigXmlInstall = exports.removePListModification = exports.removeGradleModification = exports.modifyPackageJson = exports.modifyPackageJsonCap = exports.CAP_HOOK = exports.IONIC_HOOK = void 0; | ||
exports.isOptOut = exports.parsedNpmConfig = exports.parsedCapPackageJson = exports.parsedPluginPackageJson = exports.parsedApplicationPackageJson = exports.removeScriptHookAndDeps = exports.addScriptHook = exports.isCapVersionThreeOneOrHigher = exports.removePListModification = exports.removeGradleModification = exports.modifyPackageJsonCap = exports.CAP_HOOK = exports.IONIC_HOOK = void 0; | ||
var path_1 = require("path"); | ||
@@ -49,7 +49,5 @@ var fs_1 = require("fs"); | ||
var child_process_1 = require("child_process"); | ||
var ConfigParser = require('cordova-common').ConfigParser; | ||
exports.IONIC_HOOK = 'ionic:capacitor:build:before'; | ||
exports.CAP_HOOK = 'capacitor:sync:after'; | ||
var DYNATRACE_PLUGIN = '@dynatrace/cordova-plugin'; | ||
var OLD_DYNATRACE_PLUGIN = 'dynatrace-cordova-plugin'; | ||
var NPM_CONFIG_OPT_OUT = 'dynatrace-not-adding-scripts'; | ||
@@ -112,38 +110,2 @@ var modifyPackageJsonCap = function (install, isOptOut, path) { return __awaiter(void 0, void 0, void 0, function () { | ||
exports.modifyPackageJsonCap = modifyPackageJsonCap; | ||
var modifyPackageJson = function (install) { return __awaiter(void 0, void 0, void 0, function () { | ||
var packageJsonParsed, e_2; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
_a.trys.push([0, 3, , 4]); | ||
return [4, (0, exports.parsedApplicationPackageJson)()]; | ||
case 1: | ||
packageJsonParsed = _a.sent(); | ||
if (install) { | ||
if (packageJsonParsed.scripts === undefined) { | ||
packageJsonParsed.scripts = {}; | ||
} | ||
packageJsonParsed.cordova.plugins[DYNATRACE_PLUGIN] = {}; | ||
delete packageJsonParsed.cordova.plugins[OLD_DYNATRACE_PLUGIN]; | ||
} | ||
else { | ||
if (packageJsonParsed.cordova !== undefined && packageJsonParsed.cordova.plugins !== undefined) { | ||
delete packageJsonParsed.cordova.plugins[DYNATRACE_PLUGIN]; | ||
delete packageJsonParsed.cordova.plugins[OLD_DYNATRACE_PLUGIN]; | ||
} | ||
packageJsonParsed = (0, exports.removeScriptHookAndDeps)(packageJsonParsed); | ||
} | ||
return [4, (0, FileHelper_1.writeTextToFile)((0, PathHelper_1.getApplicationPackage)(), JSON.stringify(packageJsonParsed, null, '\t'))]; | ||
case 2: | ||
_a.sent(); | ||
return [3, 4]; | ||
case 3: | ||
e_2 = _a.sent(); | ||
Logger_1.Logger.getInstance().logWarning('Cannot find package.json!'); | ||
return [3, 4]; | ||
case 4: return [2]; | ||
} | ||
}); | ||
}); }; | ||
exports.modifyPackageJson = modifyPackageJson; | ||
var removeGradleModification = function () { return __awaiter(void 0, void 0, void 0, function () { | ||
@@ -176,3 +138,3 @@ var path; | ||
var removePListModification = function () { return __awaiter(void 0, void 0, void 0, function () { | ||
var isCapacitor, e_3, e_4; | ||
var isCapacitor, e_2, e_3; | ||
return __generator(this, function (_a) { | ||
@@ -200,3 +162,3 @@ switch (_a.label) { | ||
case 6: | ||
e_3 = _a.sent(); | ||
e_2 = _a.sent(); | ||
Logger_1.Logger.getInstance().logError("Removal of PList modification didn't work!"); | ||
@@ -206,3 +168,3 @@ return [3, 7]; | ||
case 8: | ||
e_4 = _a.sent(); | ||
e_3 = _a.sent(); | ||
return [3, 9]; | ||
@@ -214,33 +176,2 @@ case 9: return [2]; | ||
exports.removePListModification = removePListModification; | ||
var modifyConfigXmlInstall = function () { | ||
try { | ||
var ConfigParser_1 = require('cordova-common').ConfigParser; | ||
var cfg = new ConfigParser_1((0, path_1.join)((0, PathHelper_1.getApplicationPath)(), 'config.xml')); | ||
var plugin = cfg.getPlugin('dynatrace-cordova-plugin'); | ||
if (plugin === undefined) { | ||
return; | ||
} | ||
var pluginWithAt = cfg.getPlugin(DYNATRACE_PLUGIN); | ||
if (pluginWithAt === undefined) { | ||
cfg.addPlugin({ name: DYNATRACE_PLUGIN, spec: plugin.spec }); | ||
} | ||
cfg.removePlugin(OLD_DYNATRACE_PLUGIN); | ||
cfg.write(); | ||
} | ||
catch (e) { | ||
Logger_1.Logger.getInstance().logWarning('Config.xml is not available - Cannot modify Dynatrace dependency'); | ||
} | ||
}; | ||
exports.modifyConfigXmlInstall = modifyConfigXmlInstall; | ||
var modifyConfigXmlUninstall = function () { | ||
try { | ||
var cfg = new ConfigParser((0, path_1.join)((0, PathHelper_1.getApplicationPath)(), 'config.xml')); | ||
cfg.removePlugin(DYNATRACE_PLUGIN); | ||
cfg.write(); | ||
} | ||
catch (e) { | ||
Logger_1.Logger.getInstance().logWarning('Config.xml is not available - Cannot modify Dynatrace dependency'); | ||
} | ||
}; | ||
exports.modifyConfigXmlUninstall = modifyConfigXmlUninstall; | ||
var isCapVersionThreeOneOrHigher = function (packageJson) { | ||
@@ -275,3 +206,3 @@ var version = packageJson.version; | ||
var parsedPackageJson = function (path) { return __awaiter(void 0, void 0, void 0, function () { | ||
var _a, _b, e_5; | ||
var _a, _b, e_4; | ||
return __generator(this, function (_c) { | ||
@@ -285,4 +216,4 @@ switch (_c.label) { | ||
case 2: | ||
e_5 = _c.sent(); | ||
Logger_1.Logger.getInstance().logWarning('Error in parsedPackageJson => \n' + e_5 + '\nUnable to find package.json!'); | ||
e_4 = _c.sent(); | ||
Logger_1.Logger.getInstance().logWarning('Error in parsedPackageJson => \n' + e_4 + '\nUnable to find package.json!'); | ||
return [3, 3]; | ||
@@ -289,0 +220,0 @@ case 3: return [2]; |
@@ -34,3 +34,3 @@ "use strict"; | ||
var getApplicationPath = function () { | ||
return isCapacitorApp() ? (0, path_1.join)(getPluginPath(), '..', '..', '..') : isNpxCommand() ? (0, path_1.join)(getPluginPath(), '..') : (0, path_1.join)(getPluginPath(), '..', '..'); | ||
return isNpxCommand() ? (0, path_1.join)(getPluginPath(), '..') : (0, path_1.join)(getPluginPath(), '..', '..', '..'); | ||
}; | ||
@@ -134,2 +134,2 @@ exports.getApplicationPath = getApplicationPath; | ||
exports.isCapacitorApp = isCapacitorApp; | ||
var isNpxCommand = function () { return (0, fs_1.existsSync)((0, path_1.join)(__dirname, '..', '..', '..', '..', '..', 'package.json')); }; | ||
var isNpxCommand = function () { return (0, fs_1.existsSync)((0, path_1.join)(__dirname, '..', '..', '..', '..', '..', 'package.json')) && __dirname.includes('node_modules'); }; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var ConfigurationUtil_1 = require("./config/ConfigurationUtil"); | ||
var InstallHelper_1 = require("./helpers/InstallHelper"); | ||
module.exports = function (context) { return new Promise(function (resolve) { | ||
(0, InstallHelper_1.modifyPackageJson)(true).then(function () { | ||
(0, InstallHelper_1.modifyConfigXmlInstall)(); | ||
(0, ConfigurationUtil_1.checkConfiguration)().then(function () { | ||
resolve(''); | ||
}); | ||
(0, ConfigurationUtil_1.checkConfiguration)().then(function () { | ||
resolve(''); | ||
}); | ||
}); }; |
@@ -5,15 +5,7 @@ "use strict"; | ||
module.exports = function (context) { | ||
if (context !== undefined && context.opts !== undefined && context.opts.plugins !== undefined) { | ||
var plugins = context.opts.plugins; | ||
if (plugins.includes('@dynatrace/cordova-plugin')) { | ||
var index = plugins.indexOf('@dynatrace/cordova-plugin'); | ||
plugins[index] = 'dynatrace-cordova-plugin'; | ||
return new Promise(function (resolve) { | ||
(0, InstallHelper_1.modifyPackageJson)(false).then(function () { return (0, InstallHelper_1.removeGradleModification)(); }).then(function () { return (0, InstallHelper_1.removePListModification)(); }).then(function () { | ||
(0, InstallHelper_1.modifyConfigXmlUninstall)(); | ||
resolve(''); | ||
}); | ||
}); | ||
} | ||
} | ||
return new Promise(function (resolve) { | ||
(0, InstallHelper_1.removeGradleModification)().then(function () { return (0, InstallHelper_1.removePListModification)(); }).then(function () { | ||
resolve(''); | ||
}); | ||
}); | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 14 instances in 1 package
25284122
3
967
2
6313
- Removedcordova-common@^5.0.0
- Removed@netflix/nerror@1.1.3(transitive)
- Removed@nodelib/fs.scandir@2.1.5(transitive)
- Removed@nodelib/fs.stat@2.0.5(transitive)
- Removed@nodelib/fs.walk@1.2.8(transitive)
- Removedansi@0.3.1(transitive)
- Removedassert-plus@1.0.0(transitive)
- Removedbalanced-match@1.0.2(transitive)
- Removedbig-integer@1.6.52(transitive)
- Removedbplist-parser@0.3.2(transitive)
- Removedbrace-expansion@1.1.11(transitive)
- Removedbraces@3.0.3(transitive)
- Removedconcat-map@0.0.1(transitive)
- Removedcordova-common@5.0.0(transitive)
- Removedcross-spawn@7.0.5(transitive)
- Removeddedent@0.7.0(transitive)
- Removedelementtree@0.1.7(transitive)
- Removedendent@2.1.0(transitive)
- Removedextsprintf@1.4.1(transitive)
- Removedfast-glob@3.3.2(transitive)
- Removedfast-json-parse@1.0.3(transitive)
- Removedfastq@1.17.1(transitive)
- Removedfill-range@7.1.1(transitive)
- Removedfs-extra@11.2.0(transitive)
- Removedfs.realpath@1.0.0(transitive)
- Removedglob@7.2.3(transitive)
- Removedglob-parent@5.1.2(transitive)
- Removedgraceful-fs@4.2.11(transitive)
- Removedinflight@1.0.6(transitive)
- Removedinherits@2.0.4(transitive)
- Removedis-extglob@2.1.1(transitive)
- Removedis-glob@4.0.3(transitive)
- Removedis-number@7.0.0(transitive)
- Removedisexe@2.0.0(transitive)
- Removedjsonfile@6.1.0(transitive)
- Removedlodash@4.17.21(transitive)
- Removedlodash.assign@4.2.0(transitive)
- Removedlodash.isdate@4.0.1(transitive)
- Removedlodash.isobject@3.0.2(transitive)
- Removedlodash.zip@4.2.0(transitive)
- Removedmerge2@1.4.1(transitive)
- Removedmicromatch@4.0.8(transitive)
- Removedminimatch@3.1.2(transitive)
- Removedobjectorarray@1.0.5(transitive)
- Removedonce@1.4.0(transitive)
- Removedp-finally@1.0.0(transitive)
- Removedp-try@2.2.0(transitive)
- Removedpath-is-absolute@1.0.1(transitive)
- Removedpath-key@3.1.1(transitive)
- Removedpicomatch@2.3.1(transitive)
- Removedpify@4.0.1(transitive)
- Removedq@1.5.1(transitive)
- Removedqueue-microtask@1.2.3(transitive)
- Removedread-chunk@3.2.0(transitive)
- Removedreusify@1.0.4(transitive)
- Removedrun-parallel@1.2.0(transitive)
- Removedsax@1.1.4(transitive)
- Removedshebang-command@2.0.0(transitive)
- Removedshebang-regex@3.0.0(transitive)
- Removedstrip-bom@4.0.0(transitive)
- Removedto-regex-range@5.0.1(transitive)
- Removeduniversalify@2.0.1(transitive)
- Removedwhich@2.0.2(transitive)
- Removedwith-open-file@0.1.7(transitive)
- Removedwrappy@1.0.2(transitive)
Updatedaxios@^1.5.1