This is an automated email from the ASF dual-hosted git repository. jin pushed a commit to branch fix-npm in repository https://gitbox.apache.org/repos/asf/incubator-hugegraph-toolchain.git
commit 75ea527a95af3a9bd2e1c6bbc9d8539455bf0c0d Author: imbajin <[email protected]> AuthorDate: Thu Dec 14 17:22:44 2023 +0800 fix: build error with npm not exist & tiny improve --- README.md | 15 ++++--- hugegraph-hubble/Dockerfile | 7 ++-- hugegraph-hubble/README.md | 7 ++-- hugegraph-hubble/hubble-dist/pom.xml | 2 + .../org/apache/hugegraph/structure/JsonGraph.java | 2 +- .../java/org/apache/hugegraph/util/ToolUtil.java | 2 +- .../hugegraph/test/functional/AuthBackupTest.java | 34 ++++++--------- .../hugegraph/test/functional/AuthRestoreTest.java | 46 ++++++++------------ .../hugegraph/test/functional/CommandTest.java | 33 +++++---------- .../org/apache/hugegraph/test/util/FileUtil.java | 49 ++++++++++------------ pom.xml | 6 +-- 11 files changed, 85 insertions(+), 118 deletions(-) diff --git a/README.md b/README.md index 71e8f1d8..8b04b749 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ [](https://github.com/apache/hugegraph-toolchain/actions/workflows/tools-ci.yml) [](https://mvnrepository.com/artifact/org.apache.hugegraph/hugegraph-client) -`hugegraph-toolchain` is the integration project of a series of utilities for [HugeGraph](https://github.com/apache/hugegraph), it includes 4 main modules. +`hugegraph-toolchain` is the integration project contains a series of utilities for [HugeGraph](https://github.com/apache/hugegraph), +it includes 5+ main modules. ## Modules @@ -15,28 +16,30 @@ - [hugegraph-hubble](./hugegraph-hubble): Online HugeGraph management and analysis dashboard (Include: data loading, schema management, graph traverser and display). - [hugegraph-tools](./hugegraph-tools): Command line tool for deploying, managing and backing-up/restoring graphs from HugeGraph. - [hugegraph-client](./hugegraph-client): A Java-written client for HugeGraph, providing `RESTful` APIs for accessing graph vertex/edge/schema/gremlin/variables and traversals etc. +- [hugegraph-client-go](./hugegraph-client-go): A Go-written client for HugeGraph, providing `RESTful` APIs for accessing graph vertex/edge/schema/gremlin/variables and traversals etc. (WIP) ## Usage -- [hugegraph-loader](./hugegraph-loader): We can use `docker run -itd --name loader hugegraph/loader` to quickly start [loader](https://hub.docker.com/r/hugegraph/loader) or we can follow [this](./hugegraph-loader/README.md#212-docker-compose) to use docker-compose to start `loader` with `server`. And we can find more details in the [doc](https://hugegraph.apache.org/docs/quickstart/hugegraph-loader/). -- [hugegraph-hubble](./hugegraph-hubble): We can use `docker run -itd --name=hubble -p 8088:8088 hugegraph/hubble` to quickly start [hubble](https://hub.docker.com/r/hugegraph/hubble) or we can follow [this](hugegraph-hubble/README.md#quick-start) to use docker-compose to start `hubble` with `server`. And we can find more details in the [doc](https://hugegraph.apache.org/docs/quickstart/hugegraph-hubble/). -- [hugegraph-client](./hugegraph-client): We can follow the [doc](https://hugegraph.apache.org/docs/quickstart/hugegraph-client/) to learn how to quick start with `client`. +- [hugegraph-loader](./hugegraph-loader): We can use `docker run -itd --name loader hugegraph/loader` to quickly start [loader,](https://hub.docker.com/r/hugegraph/loader) or we can follow [this](./hugegraph-loader/README.md#212-docker-compose) to use docker-compose to start `loader` with `server`. And we can find more details in the [doc](https://hugegraph.apache.org/docs/quickstart/hugegraph-loader/). +- [hugegraph-hubble](./hugegraph-hubble): We can use `docker run -itd --name=hubble -p 8088:8088 hugegraph/hubble` to quickly start [hubble,](https://hub.docker.com/r/hugegraph/hubble) or we can follow [this](hugegraph-hubble/README.md#quick-start) to use docker-compose to start `hubble` with `server`. And we can find more details in the [doc](https://hugegraph.apache.org/docs/quickstart/hugegraph-hubble/). +- [hugegraph-client](./hugegraph-client): We can follow the [doc](https://hugegraph.apache.org/docs/quickstart/hugegraph-client/) to learn how to quickly start with `client`. ## Maven Dependencies You could use import the dependencies in `maven` like this: ```xml + <!-- Note: use the latest release version in maven repo, here is just an example --> <dependency> <groupId>org.apache.hugegraph</groupId> <artifactId>hugegraph-client</artifactId> - <version>1.0.0</version> + <version>1.2.0</version> </dependency> <dependency> <groupId>org.apache.hugegraph</groupId> <artifactId>hugegraph-loader</artifactId> - <version>1.0.0</version> + <version>1.2.0</version> </dependency> ``` diff --git a/hugegraph-hubble/Dockerfile b/hugegraph-hubble/Dockerfile index ef513c65..1f43147c 100644 --- a/hugegraph-hubble/Dockerfile +++ b/hugegraph-hubble/Dockerfile @@ -25,10 +25,9 @@ WORKDIR /pkg RUN set -x \ && apt-get -q update \ - && apt-get install curl gnupg -yq \ - && curl -sL https://deb.nodesource.com/setup_16.x | bash \ - && apt-get install -y nodejs \ - && apt-get clean + && apt-get install curl -yq \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* RUN set -x \ && mvn install $MAVEN_ARGS -pl hugegraph-client,hugegraph-loader -am -Dmaven.javadoc.skip=true -DskipTests -ntp \ diff --git a/hugegraph-hubble/README.md b/hugegraph-hubble/README.md index 6de7f686..5faf67ed 100644 --- a/hugegraph-hubble/README.md +++ b/hugegraph-hubble/README.md @@ -4,14 +4,15 @@ [](https://github.com/apache/incubator-hugegraph-toolchain/actions/workflows/hubble-ci.yml) [](https://github.com/apache/incubator-hugegraph-toolchain/actions/workflows/codeql-analysis.yml) -hugegraph-hubble is a graph management and analysis platform that provides features: graph data load, schema management, graph relationship analysis and graphical display. +hugegraph-hubble is a graph management and analysis platform that provides features: +graph data load, schema management, graph relationship analysis, and graphical display. ## Features - Graph connection management, supporting to easily switch graph to operate - Graph data load, supporting to load large amounts of data from files into hugegraph-server - Schema management, supporting to easily perform schema manipulation and display -- Graph analysis and graphical display, supporting to build query via the gremlin or algorithms with a little effort then will get cool graphical results +- Graph analysis and graphical display, supporting to build a query via the gremlin or algorithms with a little effort then will get cool graphical results ## Quick Start @@ -29,7 +30,7 @@ We can quickly start `hubble` in two ways: #environment: # - PRELOAD=true ports: - - 18080:8080 + - 8080:8080 hubble: image: hugegraph/hubble diff --git a/hugegraph-hubble/hubble-dist/pom.xml b/hugegraph-hubble/hubble-dist/pom.xml index 93b06905..6b4e51eb 100644 --- a/hugegraph-hubble/hubble-dist/pom.xml +++ b/hugegraph-hubble/hubble-dist/pom.xml @@ -82,9 +82,11 @@ <id>install node and yarn</id> <goals> <goal>install-node-and-yarn</goal> + <goal>install-node-and-npm</goal> </goals> <configuration> <nodeVersion>v16.16.0</nodeVersion> + <npmVersion>8.19.1</npmVersion> <yarnVersion>v1.22.15</yarnVersion> </configuration> </execution> diff --git a/hugegraph-tools/src/main/java/org/apache/hugegraph/structure/JsonGraph.java b/hugegraph-tools/src/main/java/org/apache/hugegraph/structure/JsonGraph.java index 8e83d9aa..bf66f79b 100644 --- a/hugegraph-tools/src/main/java/org/apache/hugegraph/structure/JsonGraph.java +++ b/hugegraph-tools/src/main/java/org/apache/hugegraph/structure/JsonGraph.java @@ -32,7 +32,7 @@ public class JsonGraph { private static final int INIT_VERTEX_CAPACITY = 1_000_000; - private Map<String, Map<Object, JsonVertex>> tables; + private final Map<String, Map<Object, JsonVertex>> tables; public JsonGraph() { this.tables = new ConcurrentHashMap<>(); diff --git a/hugegraph-tools/src/main/java/org/apache/hugegraph/util/ToolUtil.java b/hugegraph-tools/src/main/java/org/apache/hugegraph/util/ToolUtil.java index d97f8a4b..e39cf72b 100644 --- a/hugegraph-tools/src/main/java/org/apache/hugegraph/util/ToolUtil.java +++ b/hugegraph-tools/src/main/java/org/apache/hugegraph/util/ToolUtil.java @@ -62,7 +62,7 @@ public final class ToolUtil { } public static String commandsCategory(JCommander jCommander) { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append("================================================"); sb.append("\n"); sb.append("Warning : must provide one sub-command"); diff --git a/hugegraph-tools/src/test/java/org/apache/hugegraph/test/functional/AuthBackupTest.java b/hugegraph-tools/src/test/java/org/apache/hugegraph/test/functional/AuthBackupTest.java index 675dc50c..d69711b1 100644 --- a/hugegraph-tools/src/test/java/org/apache/hugegraph/test/functional/AuthBackupTest.java +++ b/hugegraph-tools/src/test/java/org/apache/hugegraph/test/functional/AuthBackupTest.java @@ -34,53 +34,43 @@ public class AuthBackupTest extends AuthTest { @Test public void testAuthBackup() { - String[] args = new String[]{ - "--throw-mode", "true", - "--user", USER_NAME, - "--password", USER_PASSWORD, - "auth-backup" + String[] args = new String[]{"--throw-mode", "true", "--user", USER_NAME, + "--password", USER_PASSWORD, "auth-backup" }; HugeGraphCommand.main(args); Assert.assertTrue(FileUtil.checkFileExists(DEFAULT_URL)); List<String> fileNames = FileUtil.subdirectories(DEFAULT_URL); - Assert.assertTrue(fileNames.size() == 5); + Assert.assertEquals(5, fileNames.size()); } @Test public void testAuthBackupByTypes() { - String[] args = new String[]{ - "--throw-mode", "true", - "--user", USER_NAME, - "--password", USER_PASSWORD, - "auth-backup", - "--types", "user,group" + String[] args = new String[]{"--throw-mode", "true", "--user", USER_NAME, + "--password", USER_PASSWORD, "auth-backup", + "--types", "user,group" }; HugeGraphCommand.main(args); Assert.assertTrue(FileUtil.checkFileExists(DEFAULT_URL)); List<String> fileNames = FileUtil.subdirectories(DEFAULT_URL); - Assert.assertTrue(fileNames.size() == 2); + Assert.assertEquals(2, fileNames.size()); } @Test public void testAuthBackupWithWrongType() { - String[] args = new String[]{ - "--throw-mode", "true", - "--user", USER_NAME, - "--password", USER_PASSWORD, - "auth-backup", - "--types", "user,group,test" + String[] args = new String[]{"--throw-mode", "true", "--user", USER_NAME, + "--password", USER_PASSWORD, "auth-backup", + "--types", "user,group,test" }; Assert.assertThrows(IllegalArgumentException.class, () -> { HugeGraphCommand.main(args); }, e -> { Assert.assertContains("valid value is 'all' or combination of " + - "[user,group,target,belong,access]", - e.getMessage()); + "[user,group,target,belong,access]", e.getMessage()); }); } @@ -99,6 +89,6 @@ public class AuthBackupTest extends AuthTest { Assert.assertTrue(FileUtil.checkFileExists(directory)); List<String> fileNames = FileUtil.subdirectories(directory); - Assert.assertTrue(fileNames.size() == 5); + Assert.assertEquals(5, fileNames.size()); } } diff --git a/hugegraph-tools/src/test/java/org/apache/hugegraph/test/functional/AuthRestoreTest.java b/hugegraph-tools/src/test/java/org/apache/hugegraph/test/functional/AuthRestoreTest.java index 734138d1..365d98f5 100644 --- a/hugegraph-tools/src/test/java/org/apache/hugegraph/test/functional/AuthRestoreTest.java +++ b/hugegraph-tools/src/test/java/org/apache/hugegraph/test/functional/AuthRestoreTest.java @@ -58,14 +58,10 @@ public class AuthRestoreTest extends AuthTest { this.loadData(HugeType.BELONG, "auth_belongs.txt"); this.loadData(HugeType.ACCESS, "auth_accesses.txt"); - String[] args = new String[]{ - "--throw-mode", "true", - "--user", USER_NAME, - "--password", USER_PASSWORD, - "auth-restore", - "--directory", DEFAULT_URL, - "--init-password", "123456", - "--strategy", "ignore" + String[] args = new String[]{"--throw-mode", "true", "--user", USER_NAME, + "--password", USER_PASSWORD, "auth-restore", + "--directory", DEFAULT_URL, "--init-password", "123456", + "--strategy", "ignore" }; HugeGraphCommand.main(args); @@ -82,7 +78,7 @@ public class AuthRestoreTest extends AuthTest { List<Group> groups = this.client.auth().listGroups(); Map<String, Group> groupMap = Maps.newHashMap(); for (Group group : groups) { - groupMap.put(group.name(), group); + groupMap.put(group.name(), group); } Assert.assertTrue(groupMap.containsKey("test_group6")); idList.add(groupMap.get("test_group6").id().toString()); @@ -90,7 +86,7 @@ public class AuthRestoreTest extends AuthTest { List<Target> targets = this.client.auth().listTargets(); Map<String, Target> targetMap = Maps.newHashMap(); for (Target target : targets) { - targetMap.put(target.name(), target); + targetMap.put(target.name(), target); } Assert.assertTrue(targetMap.containsKey("test_target1")); idList.add(targetMap.get("test_target1").id().toString()); @@ -139,7 +135,7 @@ public class AuthRestoreTest extends AuthTest { List<User> userList = this.client.auth().listUsers(); Map<String, User> userMap = Maps.newHashMap(); for (User user1 : userList) { - userMap.put(user1.name(), user1); + userMap.put(user1.name(), user1); } Assert.assertTrue(userMap.containsKey("test_user1")); @@ -160,8 +156,7 @@ public class AuthRestoreTest extends AuthTest { HugeGraphCommand.main(args); }, e -> { String msg = e.getMessage(); - Assert.assertTrue(msg.endsWith("The following option is " + - "required: [--init-password]")); + Assert.assertTrue(msg.endsWith("The following option is required: [--init-password]")); }); } @@ -182,8 +177,7 @@ public class AuthRestoreTest extends AuthTest { Assert.assertThrows(IllegalStateException.class, () -> { HugeGraphCommand.main(args); }, e -> { - Assert.assertContains("Restore conflict with STOP strategy", - e.getMessage()); + Assert.assertContains("Restore conflict with STOP strategy", e.getMessage()); }); } @@ -206,7 +200,7 @@ public class AuthRestoreTest extends AuthTest { List<User> userList = this.client.auth().listUsers(); Map<String, User> userMap = Maps.newHashMap(); for (User user1 : userList) { - userMap.put(user1.name(), user1); + userMap.put(user1.name(), user1); } Assert.assertTrue(userMap.containsKey("admin")); @@ -230,8 +224,7 @@ public class AuthRestoreTest extends AuthTest { Assert.assertThrows(IllegalStateException.class, () -> { HugeGraphCommand.main(args); }, e -> { - Assert.assertContains("The directory does not exist", - e.getMessage()); + Assert.assertContains("The directory does not exist", e.getMessage()); }); } @@ -244,7 +237,7 @@ public class AuthRestoreTest extends AuthTest { "--user", USER_NAME, "--password", USER_PASSWORD, "auth-restore", - "--types", "user,test", + "--types", "user, test", "--strategy", "stop", "--init-password", "123456", "--directory", filePath @@ -254,8 +247,7 @@ public class AuthRestoreTest extends AuthTest { HugeGraphCommand.main(args); }, e -> { Assert.assertContains("valid value is 'all' or combination of " + - "[user,group,target,belong,access]", - e.getMessage()); + "[user,group,target,belong,access]", e.getMessage()); }); } @@ -278,8 +270,7 @@ public class AuthRestoreTest extends AuthTest { HugeGraphCommand.main(args); }, e -> { Assert.assertContains("if type contains 'belong' then " + - "'user' and 'group' are required.", - e.getMessage()); + "'user' and 'group' are required.", e.getMessage()); }); } @@ -302,8 +293,7 @@ public class AuthRestoreTest extends AuthTest { HugeGraphCommand.main(args); }, e -> { Assert.assertContains("if type contains 'access' then " + - "'group' and 'target' are required.", - e.getMessage()); + "'group' and 'target' are required.", e.getMessage()); }); } @@ -326,8 +316,7 @@ public class AuthRestoreTest extends AuthTest { HugeGraphCommand.main(args); }, e -> { Assert.assertContains("Invalid --strategy 'test', valid " + - "value is 'stop' or 'ignore", - e.getMessage()); + "value is 'stop' or 'ignore", e.getMessage()); }); } @@ -335,8 +324,7 @@ public class AuthRestoreTest extends AuthTest { String restoreDataPath = DEFAULT_URL + hugeType.string(); String testRestoreDataPath = DEFAULT_TEST_URL + dataFilePath; - List<String> list = FileUtil.readTestRestoreData(FileUtil.configPath( - testRestoreDataPath)); + List<String> list = FileUtil.readTestRestoreData(FileUtil.configPath(testRestoreDataPath)); FileUtil.writeTestRestoreData(restoreDataPath, list); } } diff --git a/hugegraph-tools/src/test/java/org/apache/hugegraph/test/functional/CommandTest.java b/hugegraph-tools/src/test/java/org/apache/hugegraph/test/functional/CommandTest.java index 73d0ba90..b73ba2a1 100644 --- a/hugegraph-tools/src/test/java/org/apache/hugegraph/test/functional/CommandTest.java +++ b/hugegraph-tools/src/test/java/org/apache/hugegraph/test/functional/CommandTest.java @@ -26,21 +26,16 @@ public class CommandTest extends AuthTest { @Test public void testHelpCommand() { - String[] args = new String[]{ - "--throw-mode", "true", - "--user", USER_NAME, - "--password", USER_PASSWORD, - "help" + String[] args = new String[]{"--throw-mode", "true", "--user", USER_NAME, + "--password", USER_PASSWORD, "help" }; Assert.assertThrows(ExitException.class, () -> { HugeGraphCommand.main(args); }, e -> { ExitException exception = (ExitException) e; - Assert.assertContains("Command : hugegragh help", - exception.getMessage()); - Assert.assertContains("Usage: hugegraph [options] [command]", - exception.details()); + Assert.assertContains("Command : hugegragh help", exception.getMessage()); + Assert.assertContains("Usage: hugegraph [options] [command]", exception.details()); }); } @@ -57,10 +52,8 @@ public class CommandTest extends AuthTest { HugeGraphCommand.main(args); }, e -> { ExitException exception = (ExitException) e; - Assert.assertContains("Command : hugegragh help auth-backup", - exception.getMessage()); - Assert.assertContains("Usage: auth-backup [options]", - exception.details()); + Assert.assertContains("Command : hugegragh help auth-backup", exception.getMessage()); + Assert.assertContains("Usage: auth-backup [options]", exception.details()); }); } @@ -78,11 +71,9 @@ public class CommandTest extends AuthTest { HugeGraphCommand.main(args); }, e -> { ExitException exception = (ExitException) e; - Assert.assertContains(String.format( - "Unexpected help sub-command %s", - badCommand), exception.getMessage()); - Assert.assertContains("Here are some sub-command ", - exception.details()); + Assert.assertContains(String.format("Unexpected help sub-command %s", + badCommand), exception.getMessage()); + Assert.assertContains("Here are some sub-command ", exception.details()); }); } @@ -98,10 +89,8 @@ public class CommandTest extends AuthTest { HugeGraphCommand.main(args); }, e -> { ExitException exception = (ExitException) e; - Assert.assertContains("No sub-command found", - exception.getMessage()); - Assert.assertContains("Warning : must provide one sub-command", - exception.details()); + Assert.assertContains("No sub-command found", exception.getMessage()); + Assert.assertContains("Warning : must provide one sub-command", exception.details()); }); } } diff --git a/hugegraph-tools/src/test/java/org/apache/hugegraph/test/util/FileUtil.java b/hugegraph-tools/src/test/java/org/apache/hugegraph/test/util/FileUtil.java index 6d4a34db..d2741293 100644 --- a/hugegraph-tools/src/test/java/org/apache/hugegraph/test/util/FileUtil.java +++ b/hugegraph-tools/src/test/java/org/apache/hugegraph/test/util/FileUtil.java @@ -20,11 +20,11 @@ package org.apache.hugegraph.test.util; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; @@ -45,10 +45,7 @@ public class FileUtil { public static boolean checkFileExists(String filePath) { File file = new File(filePath); - if (file.exists()) { - return true; - } - return false; + return file.exists(); } public static List<String> subdirectories(String filePath) { @@ -58,9 +55,9 @@ public class FileUtil { } String[] files = file.list(); List<String> list = Lists.newArrayList(); - for (int i = 0; i < files.length; i++) { - File fileDir = new File(file, files[i]); - list.add(fileDir.getName()); + for (String s : files) { + File fileDir = new File(file, s); + list.add(fileDir.getName()); } return list; @@ -70,8 +67,8 @@ public class FileUtil { File file = new File(filePath); if (file.exists()) { String[] files = file.list(); - for (int i = 0; i < files.length; i++) { - File fileDir = new File(file, files[i]); + for (String s : files) { + File fileDir = new File(file, s); fileDir.delete(); } } @@ -81,16 +78,15 @@ public class FileUtil { long count = 0L; try (FileOutputStream os = new FileOutputStream(filePath); ByteArrayOutputStream baos = new ByteArrayOutputStream(LBUF_SIZE)) { - StringBuilder builder = new StringBuilder(LBUF_SIZE); - for (Object e : list) { - count++; - builder.append(e).append("\n"); - } - baos.write(builder.toString().getBytes(API.CHARSET)); - os.write(baos.toByteArray()); + StringBuilder builder = new StringBuilder(LBUF_SIZE); + for (Object e : list) { + count++; + builder.append(e).append("\n"); + } + baos.write(builder.toString().getBytes(API.CHARSET)); + os.write(baos.toByteArray()); } catch (IOException e) { - throw new ToolsException("Failed write file path is %s", - e, filePath); + throw new ToolsException("Failed write file path is %s", e, filePath); } return count; @@ -98,16 +94,15 @@ public class FileUtil { public static List<String> readTestRestoreData(String filePath) { List<String> results = Lists.newArrayList(); - try (InputStream is = new FileInputStream(filePath); + try (InputStream is = Files.newInputStream(Paths.get(filePath)); InputStreamReader isr = new InputStreamReader(is, API.CHARSET)) { - BufferedReader reader = new BufferedReader(isr); - String line; - while ((line = reader.readLine()) != null) { - results.add(line); - } + BufferedReader reader = new BufferedReader(isr); + String line; + while ((line = reader.readLine()) != null) { + results.add(line); + } } catch (IOException e) { - throw new ToolsException("Failed read file path is %s", - e, filePath); + throw new ToolsException("Failed read file path is %s", e, filePath); } return results; diff --git a/pom.xml b/pom.xml index daa21e32..0d90acb3 100644 --- a/pom.xml +++ b/pom.xml @@ -28,8 +28,8 @@ <name>${project.artifactId}</name> <url>https://github.com/apache/incubator-hugegraph-toolchain</url> <description> - hugegraph-toolchain is the integration project of a series of utilities for HugeGraph, - it includes 4 main modules (loader/hubble/tools/client) + hugegraph-toolchain is the integration project contains a series of utilities for HugeGraph, + it includes 5+ main modules (loader/hubble/tools/clients/data connector) </description> <parent> @@ -48,7 +48,7 @@ <developers> <developer> - <id>Apache Hugegraph(Incubating)</id> + <id>Apache HugeGraph(Incubating)</id> <email>[email protected]</email> <url>https://hugegraph.apache.org/</url> </developer>
