Skip to content

Commit

Permalink
skeleton: add base ID option
Browse files Browse the repository at this point in the history
This allows users to specify a base ID to replace the usual
org.eclipse.tracecompass.incubator prefix. For example, this could be
used by a company called "ACME" to create plugins for their own
features. They would then use the "com.acme" base ID.

To test this:

1. cd ./skeleton
2. ./create_new_feature.py Defaults --dir ../tracetypes --copyright Acme
3. ./create_new_feature.py Acmes --dir ../tracetypes --copyright Acme \
    --base-id com.acme

Grepping for "org.eclipse.tracecompass.incubator" proves the absence of
it, since "com.acme" was used instead in the generated "Acmes" plugin
files. Only the annotation-equipped classpath files kept it, which is
expected.

As for the "Defaults" case above, which does not use the '--base-id'
option, regenerating an existing plugin gives the same result it would
have given before, as expected.

Loading the resulting new projects in Eclipse builds successfully, same
for the maven build from clean.

Change-Id: If8528e5f0282074565856509538e046a6bf7f8af
Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
Reviewed-on: https://git.eclipse.org/r/c/tracecompass.incubator/org.eclipse.tracecompass.incubator/+/194973
Tested-by: Marco Miller <marco.miller@ericsson.com>
Reviewed-by: Marco Miller <marco.miller@ericsson.com>
  • Loading branch information
christophebedard authored and marco-miller committed Aug 26, 2022
1 parent aa182d8 commit 0e44636
Show file tree
Hide file tree
Showing 21 changed files with 57 additions and 52 deletions.
29 changes: 17 additions & 12 deletions skeleton/create_new_feature.py
Expand Up @@ -22,14 +22,17 @@
parser.add_argument('--no-help', dest='noHelp', action='store_const', const=True, default=False, help='Whether to add an help plugin for this feature')
parser.add_argument('--year', default=time.strftime("%Y"), help='The current year (defaults to current year from system time)')
parser.add_argument('--copyright', default="École Polytechnique de Montréal", help='The organisation that has the copyright on the new files')
parser.add_argument('--base-id', default='org.eclipse.tracecompass.incubator', help='The base ID for the plugin (e.g. org.eclipse.tracecompass.incubator)')

args = parser.parse_args()
baseIdPlaceholder = "{%baseId}"
idPlaceholder = "{%skeleton}"
namePlaceholder = "{%skeletonName}"
yearPlaceholder = "{%year}"
copyrightPlaceholder = "{%copyright}"
year = args.year
copyright = args.copyright
baseId = args.base_id

baseDir = os.path.dirname(os.path.realpath(__file__))

Expand All @@ -44,8 +47,8 @@
"""

pomModulePlaceholder = "<!-- insert modules here -->"
pomModuleStr = """<module>org.eclipse.tracecompass.incubator.{%skeleton}{%suffix}</module>
"""
pomModuleStr = """<module>{%baseId}.{%skeleton}{%suffix}</module>
""".replace(baseIdPlaceholder, baseId)

def copyAndUpdate(srcDir, destDir, name, id):
shutil.copytree(srcDir, destDir)
Expand All @@ -57,6 +60,7 @@ def copyAndUpdate(srcDir, destDir, name, id):
try:
with open(fpath, encoding = "utf-8") as f:
s = f.read()
s = s.replace(baseIdPlaceholder, baseId)
s = s.replace(idPlaceholder, id)
s = s.replace(namePlaceholder, name)
s = s.replace(yearPlaceholder, year)
Expand All @@ -67,13 +71,13 @@ def copyAndUpdate(srcDir, destDir, name, id):
print("Problem opening file. That may be normal if the file is not a text file")

def moveActivator(moveTo, suffix, id):
os.makedirs(moveTo + '.' + suffix + '/src/org/eclipse/tracecompass/incubator/internal/' + id.replace('.', '/') + '/' + suffix)
shutil.move(moveTo + '.' + suffix + '/src/Activator.java', moveTo + '.' + suffix + '/src/org/eclipse/tracecompass/incubator/internal/' + id.replace('.', '/') + '/' + suffix)
shutil.move(moveTo + '.' + suffix + '/src/package-info.java', moveTo + '.' + suffix + '/src/org/eclipse/tracecompass/incubator/internal/' + id.replace('.', '/') + '/' + suffix)
os.makedirs(moveTo + '.' + suffix + '/src/' + baseId.replace('.', '/') + '/internal/' + id.replace('.', '/') + '/' + suffix)
shutil.move(moveTo + '.' + suffix + '/src/Activator.java', moveTo + '.' + suffix + '/src/' + baseId.replace('.', '/') + '/internal/' + id.replace('.', '/') + '/' + suffix)
shutil.move(moveTo + '.' + suffix + '/src/package-info.java', moveTo + '.' + suffix + '/src/' + baseId.replace('.', '/') + '/internal/' + id.replace('.', '/') + '/' + suffix)

def moveActivatorTest(moveTo, suffix, id):
os.makedirs(moveTo + '.' + suffix + '/src/org/eclipse/tracecompass/incubator/' + id.replace('.', '/') + '/' + suffix.replace('.', '/'))
shutil.move(moveTo + '.' + suffix + '/src/ActivatorTest.java', moveTo + '.' + suffix + '/src/org/eclipse/tracecompass/incubator/' + id.replace('.', '/') + '/' + suffix.replace('.', '/'))
os.makedirs(moveTo + '.' + suffix + '/src/' + baseId.replace('.', '/') + '/' + id.replace('.', '/') + '/' + suffix.replace('.', '/'))
shutil.move(moveTo + '.' + suffix + '/src/ActivatorTest.java', moveTo + '.' + suffix + '/src/' + baseId.replace('.', '/') + '/' + id.replace('.', '/') + '/' + suffix.replace('.', '/'))

def updatePom(baseDir, destDir, id, moduleStr):
# Does a pom.xml exists in the destination directory?
Expand All @@ -83,6 +87,7 @@ def updatePom(baseDir, destDir, id, moduleStr):

with open(destPom, encoding = "utf-8") as f:
s = f.read();
s = s.replace(baseIdPlaceholder, baseId)
s = s.replace("{%dir}", destDir)
s = s.replace(pomModulePlaceholder, moduleStr + pomModulePlaceholder)
s = s.replace(yearPlaceholder, year)
Expand All @@ -97,13 +102,13 @@ def copyDirs(fullname, dir, noUi, noHelp):

id = fullname.lower().replace(' ', '.')
pomModule = ""
moveTo = dir + '/org.eclipse.tracecompass.incubator.' + id
moveTo = dir + '/' + baseId + '.' + id
print('Copying skeleton directories to ' + moveTo + '[.*]')
copyAndUpdate(baseDir + '/skeleton.feature', moveTo, fullname, id)
pomModule = pomModuleStr.replace(idPlaceholder, id).replace("{%suffix}", "")
copyAndUpdate(baseDir + '/skeleton.core', moveTo + '.core', fullname, id)
moveActivator(moveTo, "core", id)
pluginStr = featurePluginStr.replace("{%plugin}", "org.eclipse.tracecompass.incubator." + id + ".core")
pluginStr = featurePluginStr.replace("{%plugin}", baseId + '.' + id + ".core")
pomModule += pomModuleStr.replace(idPlaceholder, id).replace("{%suffix}", ".core")

copyAndUpdate(baseDir + '/skeleton.core.tests', moveTo + '.core.tests', fullname, id)
Expand All @@ -113,14 +118,14 @@ def copyDirs(fullname, dir, noUi, noHelp):
if not(noUi):
copyAndUpdate(baseDir + '/skeleton.ui', moveTo + '.ui', fullname, id)
moveActivator(moveTo, "ui", id)
pluginStr = pluginStr + featurePluginStr.replace("{%plugin}", "org.eclipse.tracecompass.incubator." + id + ".ui")
pluginStr = pluginStr + featurePluginStr.replace("{%plugin}", baseId + '.' + id + ".ui")
pomModule += pomModuleStr.replace(idPlaceholder, id).replace("{%suffix}", ".ui")
copyAndUpdate(baseDir + '/skeleton.ui.swtbot.tests', moveTo + '.ui.swtbot.tests', fullname, id)
os.makedirs(moveTo + '.ui.swtbot.tests/src')

if not(noHelp):
copyAndUpdate(baseDir + '/skeleton.doc.user', baseDir + '/../doc/org.eclipse.tracecompass.incubator.' + id + '.doc.user', fullname, id)
pluginStr = pluginStr + featurePluginStr.replace("{%plugin}", "org.eclipse.tracecompass.incubator." + id + ".doc.user")
copyAndUpdate(baseDir + '/skeleton.doc.user', baseDir + '/../doc/' + baseId + '.' + id + '.doc.user', fullname, id)
pluginStr = pluginStr + featurePluginStr.replace("{%plugin}", baseId + '.' + id + ".doc.user")
# Update the pom.xml
updatePom(baseDir, baseDir + '/../doc', id, pomModuleStr.replace(idPlaceholder, id).replace("{%suffix}", ".doc.user"))

Expand Down
2 changes: 1 addition & 1 deletion skeleton/pom.xml
Expand Up @@ -21,7 +21,7 @@
<version>0.2.0-SNAPSHOT</version>
</parent>

<artifactId>org.eclipse.tracecompass.incubator.{%dir}-parent</artifactId>
<artifactId>{%baseId}.{%dir}-parent</artifactId>
<packaging>pom</packaging>

<name>Trace Compass Incubator {%dir} Parent</name>
Expand Down
2 changes: 1 addition & 1 deletion skeleton/skeleton.core.tests/.project.skel
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.eclipse.tracecompass.incubator.{%skeleton}.core.tests</name>
<name>{%baseId}.{%skeleton}.core.tests</name>
<comment></comment>
<projects>
</projects>
Expand Down
8 changes: 4 additions & 4 deletions skeleton/skeleton.core.tests/META-INF/MANIFEST.MF
Expand Up @@ -2,15 +2,15 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-Vendor: %Bundle-Vendor
Bundle-SymbolicName: org.eclipse.tracecompass.incubator.{%skeleton}.core.tests
Bundle-SymbolicName: {%baseId}.{%skeleton}.core.tests
Bundle-Version: 0.1.0.qualifier
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.eclipse.core.runtime,
org.eclipse.core.resources,
org.eclipse.tracecompass.common.core,
org.eclipse.tracecompass.incubator.{%skeleton}.core,
{%baseId}.{%skeleton}.core,
org.junit,
org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional
Export-Package: org.eclipse.tracecompass.incubator.{%skeleton}.core.tests
Automatic-Module-Name: org.eclipse.tracecompass.incubator.{%skeleton}.core.tests
Export-Package: {%baseId}.{%skeleton}.core.tests
Automatic-Module-Name: {%baseId}.{%skeleton}.core.tests
8 changes: 4 additions & 4 deletions skeleton/skeleton.core.tests/src/ActivatorTest.java
Expand Up @@ -9,7 +9,7 @@
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/

package org.eclipse.tracecompass.incubator.{%skeleton}.core.tests;
package {%baseId}.{%skeleton}.core.tests;

import static org.junit.Assert.assertEquals;

Expand All @@ -21,7 +21,7 @@
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.tracecompass.common.core.TraceCompassActivator;
import org.eclipse.tracecompass.incubator.internal.{%skeleton}.core.Activator;
import {%baseId}.internal.{%skeleton}.core.Activator;
import org.junit.Test;
import org.osgi.framework.BundleContext;

Expand All @@ -39,7 +39,7 @@ public class ActivatorTest extends Plugin {
/**
* The plug-in ID
*/
public static final String PLUGIN_ID = "org.eclipse.tracecompass.incubator.{%skeleton}.core.tests"; //$NON-NLS-1$
public static final String PLUGIN_ID = "{%baseId}.{%skeleton}.core.tests"; //$NON-NLS-1$

/**
* The shared instance
Expand Down Expand Up @@ -91,7 +91,7 @@ public void stop(BundleContext context) throws Exception {
@Test
public void testActivator() {
TraceCompassActivator instance = Activator.getInstance();
assertEquals("org.eclipse.tracecompass.incubator.{%skeleton}.core", instance.getPluginId());
assertEquals("{%baseId}.{%skeleton}.core", instance.getPluginId());
}

/**
Expand Down
2 changes: 1 addition & 1 deletion skeleton/skeleton.core/.project.skel
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.eclipse.tracecompass.incubator.{%skeleton}.core</name>
<name>{%baseId}.{%skeleton}.core</name>
<comment></comment>
<projects>
</projects>
Expand Down
8 changes: 4 additions & 4 deletions skeleton/skeleton.core/META-INF/MANIFEST.MF
Expand Up @@ -2,15 +2,15 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-Vendor: %Bundle-Vendor
Bundle-SymbolicName: org.eclipse.tracecompass.incubator.{%skeleton}.core;singleton:=true
Bundle-SymbolicName: {%baseId}.{%skeleton}.core;singleton:=true
Bundle-Version: 0.1.0.qualifier
Bundle-Localization: plugin
Bundle-Activator: org.eclipse.tracecompass.incubator.internal.{%skeleton}.core.Activator
Bundle-Activator: {%baseId}.internal.{%skeleton}.core.Activator
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.eclipse.core.runtime,
org.eclipse.core.resources,
org.eclipse.tracecompass.common.core,
org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional
Export-Package: org.eclipse.tracecompass.incubator.internal.{%skeleton}.core;x-friends:="org.eclipse.tracecompass.incubator.{%skeleton}.core.tests"
Automatic-Module-Name: org.eclipse.tracecompass.incubator.{%skeleton}.core
Export-Package: {%baseId}.internal.{%skeleton}.core;x-friends:="{%baseId}.{%skeleton}.core.tests"
Automatic-Module-Name: {%baseId}.{%skeleton}.core
4 changes: 2 additions & 2 deletions skeleton/skeleton.core/src/Activator.java
Expand Up @@ -9,7 +9,7 @@
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/

package org.eclipse.tracecompass.incubator.internal.{%skeleton}.core;
package {%baseId}.internal.{%skeleton}.core;

import org.eclipse.tracecompass.common.core.TraceCompassActivator;

Expand All @@ -19,7 +19,7 @@
public class Activator extends TraceCompassActivator {

/** The plug-in ID */
public static final String PLUGIN_ID = "org.eclipse.tracecompass.incubator.{%skeleton}.core"; //$NON-NLS-1$
public static final String PLUGIN_ID = "{%baseId}.{%skeleton}.core"; //$NON-NLS-1$

/**
* The constructor
Expand Down
2 changes: 1 addition & 1 deletion skeleton/skeleton.core/src/package-info.java
Expand Up @@ -10,4 +10,4 @@
*******************************************************************************/

@org.eclipse.jdt.annotation.NonNullByDefault
package org.eclipse.tracecompass.incubator.internal.{%skeleton}.core;
package {%baseId}.internal.{%skeleton}.core;
2 changes: 1 addition & 1 deletion skeleton/skeleton.doc.user/.project.skel
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.eclipse.tracecompass.incubator.{%skeleton}.doc.user</name>
<name>{%baseId}.{%skeleton}.doc.user</name>
<comment></comment>
<projects>
</projects>
Expand Down
4 changes: 2 additions & 2 deletions skeleton/skeleton.doc.user/META-INF/MANIFEST.MF
Expand Up @@ -4,6 +4,6 @@ Bundle-Name: %Bundle-Name
Bundle-Vendor: %Bundle-Vendor
Bundle-Version: 0.2.0.qualifier
Bundle-Localization: plugin
Bundle-SymbolicName: org.eclipse.tracecompass.incubator.{%skeleton}.doc.user;singleton:=true
Bundle-SymbolicName: {%baseId}.{%skeleton}.doc.user;singleton:=true
Require-Bundle: org.eclipse.help
Automatic-Module-Name: org.eclipse.tracecompass.incubator.{%skeleton}.doc.user
Automatic-Module-Name: {%baseId}.{%skeleton}.doc.user
2 changes: 1 addition & 1 deletion skeleton/skeleton.doc.user/build.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="org.eclipse.tracecompass.incubator.{%skeleton}.doc.user" default="build" basedir=".">
<project name="{%baseId}.{%skeleton}.doc.user" default="build" basedir=".">
<description>
Generate Eclipse help content for the {%skeletonName} User Guide
</description>
Expand Down
8 changes: 4 additions & 4 deletions skeleton/skeleton.doc.user/pom.xml
Expand Up @@ -19,7 +19,7 @@
<version>0.2.0-SNAPSHOT</version>
</parent>

<artifactId>org.eclipse.tracecompass.incubator.{%skeleton}.doc.user</artifactId>
<artifactId>{%baseId}.{%skeleton}.doc.user</artifactId>
<packaging>eclipse-plugin</packaging>

<name>Trace Compass Incubator {%skeletonName} User Guide</name>
Expand Down Expand Up @@ -102,14 +102,14 @@
</goals>
<configuration>
<target>
<mkdir dir="${docDestination}/org.eclipse.tracecompass.incubator.{%skeleton}.doc.user" />
<mkdir dir="${docDestination}/{%baseId}.{%skeleton}.doc.user" />
<delete includeemptydirs="false">
<fileset
dir="${docDestination}/org.eclipse.tracecompass.incubator.{%skeleton}.doc.user">
dir="${docDestination}/{%baseId}.{%skeleton}.doc.user">
<include name="**" />
</fileset>
</delete>
<copy includeemptydirs="false" todir="${docDestination}/org.eclipse.tracecompass.incubator.{%skeleton}.doc.user">
<copy includeemptydirs="false" todir="${docDestination}/{%baseId}.{%skeleton}.doc.user">
<fileset dir="doc" includes="*.html,images/**"/>
</copy>
</target>
Expand Down
2 changes: 1 addition & 1 deletion skeleton/skeleton.feature/.project.skel
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.eclipse.tracecompass.incubator.{%skeleton}</name>
<name>{%baseId}.{%skeleton}</name>
<comment></comment>
<projects>
</projects>
Expand Down
2 changes: 1 addition & 1 deletion skeleton/skeleton.feature/feature.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<feature
id="org.eclipse.tracecompass.incubator.{%skeleton}"
id="{%baseId}.{%skeleton}"
label="%featureName"
version="0.2.0.qualifier"
provider-name="%featureProvider"
Expand Down
2 changes: 1 addition & 1 deletion skeleton/skeleton.ui.swtbot.tests/.project.skel
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.eclipse.tracecompass.incubator.{%skeleton}.ui.swtbot.tests</name>
<name>{%baseId}.{%skeleton}.ui.swtbot.tests</name>
<comment></comment>
<projects>
</projects>
Expand Down
4 changes: 2 additions & 2 deletions skeleton/skeleton.ui.swtbot.tests/META-INF/MANIFEST.MF
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-Vendor: %Bundle-Vendor
Bundle-SymbolicName: org.eclipse.tracecompass.incubator.{%skeleton}.ui.swtbot.tests;singleton:=true
Bundle-SymbolicName: {%baseId}.{%skeleton}.ui.swtbot.tests;singleton:=true
Bundle-Version: 0.1.0.qualifier
Bundle-Localization: plugin
Bundle-ActivationPolicy: lazy
Expand All @@ -16,4 +16,4 @@ Require-Bundle: org.eclipse.core.resources,
org.eclipse.ui.views,
org.junit,
org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional
Automatic-Module-Name: org.eclipse.tracecompass.incubator.{%skeleton}.ui.swtbot.tests
Automatic-Module-Name: {%baseId}.{%skeleton}.ui.swtbot.tests
2 changes: 1 addition & 1 deletion skeleton/skeleton.ui/.project.skel
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.eclipse.tracecompass.incubator.{%skeleton}.ui</name>
<name>{%baseId}.{%skeleton}.ui</name>
<comment></comment>
<projects>
</projects>
Expand Down
10 changes: 5 additions & 5 deletions skeleton/skeleton.ui/META-INF/MANIFEST.MF
Expand Up @@ -2,16 +2,16 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-Vendor: %Bundle-Vendor
Bundle-SymbolicName: org.eclipse.tracecompass.incubator.{%skeleton}.ui;singleton:=true
Bundle-SymbolicName: {%baseId}.{%skeleton}.ui;singleton:=true
Bundle-Version: 0.1.0.qualifier
Bundle-Localization: plugin
Bundle-Activator: org.eclipse.tracecompass.incubator.internal.{%skeleton}.ui.Activator
Bundle-Activator: {%baseId}.internal.{%skeleton}.ui.Activator
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.tracecompass.common.core,
org.eclipse.tracecompass.incubator.{%skeleton}.core,
{%baseId}.{%skeleton}.core,
org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional
Export-Package: org.eclipse.tracecompass.incubator.internal.{%skeleton}.ui;x-internal:=true
Automatic-Module-Name: org.eclipse.tracecompass.incubator.{%skeleton}.ui
Export-Package: {%baseId}.internal.{%skeleton}.ui;x-internal:=true
Automatic-Module-Name: {%baseId}.{%skeleton}.ui
4 changes: 2 additions & 2 deletions skeleton/skeleton.ui/src/Activator.java
Expand Up @@ -9,7 +9,7 @@
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/

package org.eclipse.tracecompass.incubator.internal.{%skeleton}.ui;
package {%baseId}.internal.{%skeleton}.ui;

import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ui.plugin.AbstractUIPlugin;
Expand All @@ -21,7 +21,7 @@
public class Activator extends AbstractUIPlugin {

/** The plugin ID */
public static final String PLUGIN_ID = "org.eclipse.tracecompass.incubator.{%skeleton}.ui"; //$NON-NLS-1$
public static final String PLUGIN_ID = "{%baseId}.{%skeleton}.ui"; //$NON-NLS-1$

// The shared instance
private static @Nullable Activator plugin;
Expand Down
2 changes: 1 addition & 1 deletion skeleton/skeleton.ui/src/package-info.java
Expand Up @@ -10,4 +10,4 @@
*******************************************************************************/

@org.eclipse.jdt.annotation.NonNullByDefault
package org.eclipse.tracecompass.incubator.internal.{%skeleton}.ui;
package {%baseId}.internal.{%skeleton}.ui;

0 comments on commit 0e44636

Please sign in to comment.