From e9523db4191fca66ea3ae48e3d008726b9586800 Mon Sep 17 00:00:00 2001
From: RIHTARSIC Joze <joze.rihtarsic@ext.ec.europa.eu>
Date: Wed, 10 Apr 2024 17:54:27 +0200
Subject: [PATCH] [EDELIVERY-12755] implement DNS lookup tools

---
 changelog.txt                                 |   1 +
 smp-angular/package-lock.json                 | 662 +++++++++---------
 smp-angular/package.json                      |  12 +-
 smp-angular/src/app/app.module.ts             |   8 +
 smp-angular/src/app/app.routes.ts             |   2 +
 .../access-token-ro.model.ts                  |   6 -
 .../src/app/common/enums/dns-type.enum.ts     |   4 +
 .../error/http-error-handler.service.ts       |   2 -
 smp-angular/src/app/common/global-lookups.ts  |   9 +-
 .../model/dns-query-request-ro.model.ts       |   6 +
 .../app/common/model/dns-query-ro.model.ts    |   9 +
 .../app/common/model/dns-record-ro.model.ts   |   8 +
 .../src/app/common/model/group-ro.model.ts    |   2 -
 smp-angular/src/app/smp.constants.ts          |  12 +-
 .../admin-properties/property-result.model.ts |   8 -
 .../dns-query-panel.component.css             |  19 +
 .../dns-query-panel.component.html            |  24 +
 .../dns-query-panel.component.ts              |  25 +
 .../tools/dns-tools/dns-tools.component.html  |  45 ++
 .../tools/dns-tools/dns-tools.component.ts    |  44 ++
 .../app/tools/dns-tools/dns-tools.service.ts  |  26 +
 .../smp/config/enums/SMPPropertyEnum.java     |   3 +
 .../smp/data/ui/CredentialResetRO.java        |   2 +-
 .../ec/edelivery/smp/data/ui/DNSQueryRO.java  |  93 +++
 .../smp/data/ui/DNSQueryRequestRO.java        |  80 +++
 .../ec/edelivery/smp/data/ui/DNSRecord.java   |  96 +++
 .../edelivery/smp/exceptions/ErrorCode.java   |   1 -
 .../services/ui/UIDynamicDiscoveryTools.java  | 173 +++++
 .../ui/UIDynamicDiscoveryToolsTest.java       |  97 +++
 .../edelivery/smp/ui/ResourceConstants.java   |  78 ++-
 .../smp/ui/external/DNSToolsController.java   |  43 ++
 .../smp/ui/external/UserController.java       |  10 +-
 32 files changed, 1197 insertions(+), 413 deletions(-)
 delete mode 100644 smp-angular/src/app/common/dialogs/credential-dialog/access-token-ro.model.ts
 create mode 100644 smp-angular/src/app/common/enums/dns-type.enum.ts
 create mode 100644 smp-angular/src/app/common/model/dns-query-request-ro.model.ts
 create mode 100644 smp-angular/src/app/common/model/dns-query-ro.model.ts
 create mode 100644 smp-angular/src/app/common/model/dns-record-ro.model.ts
 delete mode 100644 smp-angular/src/app/system-settings/admin-properties/property-result.model.ts
 create mode 100644 smp-angular/src/app/tools/dns-tools/dns-query-panel/dns-query-panel.component.css
 create mode 100644 smp-angular/src/app/tools/dns-tools/dns-query-panel/dns-query-panel.component.html
 create mode 100644 smp-angular/src/app/tools/dns-tools/dns-query-panel/dns-query-panel.component.ts
 create mode 100644 smp-angular/src/app/tools/dns-tools/dns-tools.component.html
 create mode 100644 smp-angular/src/app/tools/dns-tools/dns-tools.component.ts
 create mode 100644 smp-angular/src/app/tools/dns-tools/dns-tools.service.ts
 create mode 100644 smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DNSQueryRO.java
 create mode 100644 smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DNSQueryRequestRO.java
 create mode 100644 smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DNSRecord.java
 create mode 100644 smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDynamicDiscoveryTools.java
 create mode 100644 smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIDynamicDiscoveryToolsTest.java
 create mode 100644 smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/DNSToolsController.java

diff --git a/changelog.txt b/changelog.txt
index 1c1279605..9bc0b97eb 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -7,6 +7,7 @@ eDelivery SMP 5.1
     smp.sso.cas.registration.enabled: Enable/Disable automatic user registration from CAS at first login.
     smp.sso.cas.registration.confirmation.mandatory: Enable/Disable user confirmation after registration from CAS at first login.
     smp.sso.cas.registration.mapping: The CAS property mapping to user data. Ex: 'EMAIL:${email}|FULL_NAME:${firstName} ${lastName}'
+    bdmsl.integration.dns.zone: The DNS zone/top domain of the SML server. The DNS zone is used to generate DNS queries.
 
 eDelivery SMP 5.0
 - removed: bdmsl.participant.multidomain.enabled
diff --git a/smp-angular/package-lock.json b/smp-angular/package-lock.json
index dc520c052..c8ecc1b57 100644
--- a/smp-angular/package-lock.json
+++ b/smp-angular/package-lock.json
@@ -12,21 +12,21 @@
         "@angular-material-components/datetime-picker": "^16.0.1",
         "@angular-material-components/moment-adapter": "^16.0.1",
         "@angular/animations": "^16.2.12",
-        "@angular/cdk": "^16.2.12",
+        "@angular/cdk": "^16.2.14",
         "@angular/common": "^16.2.12",
         "@angular/compiler": "^16.2.12",
         "@angular/core": "^16.2.12",
         "@angular/flex-layout": "^15.0.0-beta.42",
         "@angular/forms": "^16.2.12",
         "@angular/material": "^16.2.12",
-        "@angular/material-moment-adapter": "^16.2.12",
+        "@angular/material-moment-adapter": "^16.2.14",
         "@angular/platform-browser": "^16.2.12",
         "@angular/platform-browser-dynamic": "^16.2.12",
         "@angular/platform-server": "^16.2.12",
         "@angular/router": "^16.2.12",
-        "@codemirror/language": "^6.10.0",
-        "@codemirror/language-data": "^6.3.1",
-        "@codemirror/merge": "^6.5.0",
+        "@codemirror/language": "^6.10.1",
+        "@codemirror/language-data": "^6.5.0",
+        "@codemirror/merge": "^6.6.1",
         "@codemirror/theme-one-dark": "^6.1.2",
         "@swimlane/ngx-datatable": "^20.1.0",
         "codemirror": "^6.0.1",
@@ -34,7 +34,7 @@
         "rxjs": "^7.8.1",
         "ts-helpers": "^1.1.2",
         "tslib": "^2.6.2",
-        "zone.js": "^0.13.0"
+        "zone.js": "^0.13.3"
       },
       "devDependencies": {
         "@angular-devkit/build-angular": "^16.2.10",
@@ -87,15 +87,15 @@
       }
     },
     "node_modules/@angular-devkit/build-angular": {
-      "version": "16.2.11",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.11.tgz",
-      "integrity": "sha512-yNzUiAeg1WHMsFG9IBg4S/7dsMcEAMYQ1I360ib80c0T/IwRb8pHhOokrl5Mu8zfNqZ/dxH4ItKY1uIMDmuMGQ==",
+      "version": "16.2.13",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.13.tgz",
+      "integrity": "sha512-2G8gnBpBKcu+/jJH5DJZyMgn2RwDFPgiNSkcLKFg5DdqVFVT3CCoZAobfpAEMndrysfMmoUPGuAmsgCfdczQjg==",
       "dev": true,
       "dependencies": {
         "@ampproject/remapping": "2.2.1",
-        "@angular-devkit/architect": "0.1602.11",
-        "@angular-devkit/build-webpack": "0.1602.11",
-        "@angular-devkit/core": "16.2.11",
+        "@angular-devkit/architect": "0.1602.13",
+        "@angular-devkit/build-webpack": "0.1602.13",
+        "@angular-devkit/core": "16.2.13",
         "@babel/core": "7.22.9",
         "@babel/generator": "7.22.9",
         "@babel/helper-annotate-as-pure": "7.22.5",
@@ -107,7 +107,7 @@
         "@babel/runtime": "7.22.6",
         "@babel/template": "7.22.5",
         "@discoveryjs/json-ext": "0.5.7",
-        "@ngtools/webpack": "16.2.11",
+        "@ngtools/webpack": "16.2.13",
         "@vitejs/plugin-basic-ssl": "1.0.1",
         "ansi-colors": "4.1.3",
         "autoprefixer": "10.4.14",
@@ -150,9 +150,9 @@
         "text-table": "0.2.0",
         "tree-kill": "1.2.2",
         "tslib": "2.6.1",
-        "vite": "4.5.1",
+        "vite": "4.5.2",
         "webpack": "5.88.2",
-        "webpack-dev-middleware": "6.1.1",
+        "webpack-dev-middleware": "6.1.2",
         "webpack-dev-server": "4.15.1",
         "webpack-merge": "5.9.0",
         "webpack-subresource-integrity": "5.1.0"
@@ -209,12 +209,12 @@
       }
     },
     "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/architect": {
-      "version": "0.1602.11",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.11.tgz",
-      "integrity": "sha512-qC1tPL/82gxqCS1z9pTpLn5NQH6uqbV6UNjbkFEQpTwEyWEK6VLChAJsybHHfbpssPS2HWf31VoUzX7RqDjoQQ==",
+      "version": "0.1602.13",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.13.tgz",
+      "integrity": "sha512-ejrOYoXgbhDYjdaW4B2SyWeb6AqR8vqqzMyvCq2JX7fo08IhLnVu1fcl0fwr161l37TuzgPNWrHSciOzzmZDkw==",
       "dev": true,
       "dependencies": {
-        "@angular-devkit/core": "16.2.11",
+        "@angular-devkit/core": "16.2.13",
         "rxjs": "7.8.1"
       },
       "engines": {
@@ -224,9 +224,9 @@
       }
     },
     "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": {
-      "version": "16.2.11",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.11.tgz",
-      "integrity": "sha512-u3cEQHqhSMWyAFIaPdRukCJwEUJt7Fy3C02gTlTeCB4F/OnftVFIm2e5vmCqMo9rgbfdvjWj9V+7wWiCpMrzAQ==",
+      "version": "16.2.13",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.13.tgz",
+      "integrity": "sha512-6jTlYOIeYsOF/Vw/hBNusjoCmKJBByoyGS1Fu2Yav8ltxYK04aDtI73l9JJB/5Cpzhc4YELrMqBMH7in5Vowaw==",
       "dev": true,
       "dependencies": {
         "ajv": "8.12.0",
@@ -451,12 +451,12 @@
       }
     },
     "node_modules/@angular-devkit/build-webpack": {
-      "version": "0.1602.11",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.11.tgz",
-      "integrity": "sha512-2Au6xRMxNugFkXP0LS1TwNE5gAfGW4g6yxC9P5j5p3kdGDnAVaZRTOKB9dg73i3uXtJHUMciYOThV0b78XRxwA==",
+      "version": "0.1602.13",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.13.tgz",
+      "integrity": "sha512-H7CqnC0kvWR0Q45ZXsCO3M9lGd4dOajEmkCVmq7vVptU3nJRbCqJ0ZScj9bH5YSlcdO0jPbOdcTELWyEZ3BMFQ==",
       "dev": true,
       "dependencies": {
-        "@angular-devkit/architect": "0.1602.11",
+        "@angular-devkit/architect": "0.1602.13",
         "rxjs": "7.8.1"
       },
       "engines": {
@@ -470,12 +470,12 @@
       }
     },
     "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/architect": {
-      "version": "0.1602.11",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.11.tgz",
-      "integrity": "sha512-qC1tPL/82gxqCS1z9pTpLn5NQH6uqbV6UNjbkFEQpTwEyWEK6VLChAJsybHHfbpssPS2HWf31VoUzX7RqDjoQQ==",
+      "version": "0.1602.13",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.13.tgz",
+      "integrity": "sha512-ejrOYoXgbhDYjdaW4B2SyWeb6AqR8vqqzMyvCq2JX7fo08IhLnVu1fcl0fwr161l37TuzgPNWrHSciOzzmZDkw==",
       "dev": true,
       "dependencies": {
-        "@angular-devkit/core": "16.2.11",
+        "@angular-devkit/core": "16.2.13",
         "rxjs": "7.8.1"
       },
       "engines": {
@@ -485,9 +485,9 @@
       }
     },
     "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/core": {
-      "version": "16.2.11",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.11.tgz",
-      "integrity": "sha512-u3cEQHqhSMWyAFIaPdRukCJwEUJt7Fy3C02gTlTeCB4F/OnftVFIm2e5vmCqMo9rgbfdvjWj9V+7wWiCpMrzAQ==",
+      "version": "16.2.13",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.13.tgz",
+      "integrity": "sha512-6jTlYOIeYsOF/Vw/hBNusjoCmKJBByoyGS1Fu2Yav8ltxYK04aDtI73l9JJB/5Cpzhc4YELrMqBMH7in5Vowaw==",
       "dev": true,
       "dependencies": {
         "ajv": "8.12.0",
@@ -600,9 +600,9 @@
       }
     },
     "node_modules/@angular/cdk": {
-      "version": "16.2.12",
-      "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-16.2.12.tgz",
-      "integrity": "sha512-wT8/265zm2WKY0BDaRoYbrAT4kadrmejTRLjuimQIEUKnw4vBsJMWCwQkpFo3s6zr6eznGqYVAFb8KKPVLKGBg==",
+      "version": "16.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-16.2.14.tgz",
+      "integrity": "sha512-n6PrGdiVeSTEmM/HEiwIyg6YQUUymZrb5afaNLGFRM5YL0Y8OBqd+XhCjb0OfD/AfgCUtedVEPwNqrfW8KzgGw==",
       "dependencies": {
         "tslib": "^2.3.0"
       },
@@ -760,9 +760,9 @@
       }
     },
     "node_modules/@angular/material": {
-      "version": "16.2.12",
-      "resolved": "https://registry.npmjs.org/@angular/material/-/material-16.2.12.tgz",
-      "integrity": "sha512-k1DGRfP1mMmhg/nLJjZBOPzX3SyAjgbRBY2KauKOV8OFCXJGoMn/oLgMBh+qB1WugzIna/31dBV8ruHD3Uvp2w==",
+      "version": "16.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/material/-/material-16.2.14.tgz",
+      "integrity": "sha512-zQIxUb23elPfiIvddqkIDYqQhAHa9ZwMblfbv+ug8bxr4D0Dw360jIarxCgMjAcLj7Ccl3GBqZMUnVeM6cjthw==",
       "dependencies": {
         "@material/animation": "15.0.0-canary.bc9ae6c9c.0",
         "@material/auto-init": "15.0.0-canary.bc9ae6c9c.0",
@@ -815,7 +815,7 @@
       },
       "peerDependencies": {
         "@angular/animations": "^16.0.0 || ^17.0.0",
-        "@angular/cdk": "16.2.12",
+        "@angular/cdk": "16.2.14",
         "@angular/common": "^16.0.0 || ^17.0.0",
         "@angular/core": "^16.0.0 || ^17.0.0",
         "@angular/forms": "^16.0.0 || ^17.0.0",
@@ -824,15 +824,15 @@
       }
     },
     "node_modules/@angular/material-moment-adapter": {
-      "version": "16.2.12",
-      "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-16.2.12.tgz",
-      "integrity": "sha512-Is6tv6CF5ts/wNVELtIOje233P8JzVR15/NH6vL1fcoXOOPmhJVyGbAB+U6WaVLPJw31xufP7nKry+G3+ECyow==",
+      "version": "16.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-16.2.14.tgz",
+      "integrity": "sha512-LagTDXEq8XOVLy8CVswCbmq7v9bb84+VikEEN09tz831U/7PHjDZ3xRgpKtv7hXrh8cTZOg3UPQw5tZk0hwh3Q==",
       "dependencies": {
         "tslib": "^2.3.0"
       },
       "peerDependencies": {
         "@angular/core": "^16.0.0 || ^17.0.0",
-        "@angular/material": "16.2.12",
+        "@angular/material": "16.2.14",
         "moment": "^2.18.1"
       }
     },
@@ -2789,17 +2789,6 @@
         "@lezer/common": "^1.0.0"
       }
     },
-    "node_modules/@codemirror/commands": {
-      "version": "6.3.3",
-      "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.3.3.tgz",
-      "integrity": "sha512-dO4hcF0fGT9tu1Pj1D2PvGvxjeGkbC6RGcZw6Qs74TH+Ed1gw98jmUgd2axWvIZEqTeTuFrg1lEB1KV6cK9h1A==",
-      "dependencies": {
-        "@codemirror/language": "^6.0.0",
-        "@codemirror/state": "^6.4.0",
-        "@codemirror/view": "^6.0.0",
-        "@lezer/common": "^1.1.0"
-      }
-    },
     "node_modules/@codemirror/lang-angular": {
       "version": "0.1.3",
       "resolved": "https://registry.npmjs.org/@codemirror/lang-angular/-/lang-angular-0.1.3.tgz",
@@ -2834,6 +2823,18 @@
         "@lezer/css": "^1.0.0"
       }
     },
+    "node_modules/@codemirror/lang-go": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-go/-/lang-go-6.0.0.tgz",
+      "integrity": "sha512-mMT4YeYdKGjnffDBOhr1ur1glee4oV/rfMe28vzazNHZkSt7vSiuHiBcgr3L/79Cl2RIjFdpQ1XMD0/T8Rx64g==",
+      "dependencies": {
+        "@codemirror/autocomplete": "^6.0.0",
+        "@codemirror/language": "^6.6.0",
+        "@codemirror/state": "^6.0.0",
+        "@lezer/common": "^1.0.0",
+        "@lezer/go": "^1.0.0"
+      }
+    },
     "node_modules/@codemirror/lang-html": {
       "version": "6.4.7",
       "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.7.tgz",
@@ -2894,6 +2895,21 @@
         "@lezer/lr": "^1.0.0"
       }
     },
+    "node_modules/@codemirror/lang-liquid": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-liquid/-/lang-liquid-6.2.1.tgz",
+      "integrity": "sha512-J1Mratcm6JLNEiX+U2OlCDTysGuwbHD76XwuL5o5bo9soJtSbz2g6RU3vGHFyS5DC8rgVmFSzi7i6oBftm7tnA==",
+      "dependencies": {
+        "@codemirror/autocomplete": "^6.0.0",
+        "@codemirror/lang-html": "^6.0.0",
+        "@codemirror/language": "^6.0.0",
+        "@codemirror/state": "^6.0.0",
+        "@codemirror/view": "^6.0.0",
+        "@lezer/common": "^1.0.0",
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.3.1"
+      }
+    },
     "node_modules/@codemirror/lang-markdown": {
       "version": "6.2.4",
       "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.2.4.tgz",
@@ -3000,10 +3016,23 @@
         "@lezer/xml": "^1.0.0"
       }
     },
+    "node_modules/@codemirror/lang-yaml": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-yaml/-/lang-yaml-6.1.0.tgz",
+      "integrity": "sha512-QQEEOWjHplNScULb0NCMVUcp+TPTpg42vmTcH62UMLVBkvAEFuVkhqH11f50m/pnai7qUfSLv6ZJoPv76Ky3QA==",
+      "dependencies": {
+        "@codemirror/autocomplete": "^6.0.0",
+        "@codemirror/language": "^6.0.0",
+        "@codemirror/state": "^6.0.0",
+        "@lezer/common": "^1.2.0",
+        "@lezer/highlight": "^1.2.0",
+        "@lezer/yaml": "^1.0.0"
+      }
+    },
     "node_modules/@codemirror/language": {
-      "version": "6.10.0",
-      "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.0.tgz",
-      "integrity": "sha512-2vaNn9aPGCRFKWcHPFksctzJ8yS5p7YoaT+jHpc0UGKzNuAIx4qy6R5wiqbP+heEEdyaABA582mNqSHzSoYdmg==",
+      "version": "6.10.1",
+      "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.1.tgz",
+      "integrity": "sha512-5GrXzrhq6k+gL5fjkAwt90nYDmjlzTIJV8THnxNFtNKWotMIlzzN+CpqxqwXOECnUdOndmSeWntVrVcv5axWRQ==",
       "dependencies": {
         "@codemirror/state": "^6.0.0",
         "@codemirror/view": "^6.23.0",
@@ -3014,18 +3043,20 @@
       }
     },
     "node_modules/@codemirror/language-data": {
-      "version": "6.3.1",
-      "resolved": "https://registry.npmjs.org/@codemirror/language-data/-/language-data-6.3.1.tgz",
-      "integrity": "sha512-p6jhJmvhGe1TG1EGNhwH7nFWWFSTJ8NDKnB2fVx5g3t+PpO0+63R7GJNxjS0TmmH3cdMxZbzejsik+rlEh1EyQ==",
+      "version": "6.5.0",
+      "resolved": "https://registry.npmjs.org/@codemirror/language-data/-/language-data-6.5.0.tgz",
+      "integrity": "sha512-+F2PyUJtTfGO/3X0fgwZwyyCQ35GZycQSI/731tHifhFMaKYTM8Ic45uK1jrcg086pDy573CL2DWvHJlSkFGzQ==",
       "dependencies": {
         "@codemirror/lang-angular": "^0.1.0",
         "@codemirror/lang-cpp": "^6.0.0",
         "@codemirror/lang-css": "^6.0.0",
+        "@codemirror/lang-go": "^6.0.0",
         "@codemirror/lang-html": "^6.0.0",
         "@codemirror/lang-java": "^6.0.0",
         "@codemirror/lang-javascript": "^6.0.0",
         "@codemirror/lang-json": "^6.0.0",
         "@codemirror/lang-less": "^6.0.0",
+        "@codemirror/lang-liquid": "^6.0.0",
         "@codemirror/lang-markdown": "^6.0.0",
         "@codemirror/lang-php": "^6.0.0",
         "@codemirror/lang-python": "^6.0.0",
@@ -3035,6 +3066,7 @@
         "@codemirror/lang-vue": "^0.1.1",
         "@codemirror/lang-wast": "^6.0.0",
         "@codemirror/lang-xml": "^6.0.0",
+        "@codemirror/lang-yaml": "^6.0.0",
         "@codemirror/language": "^6.0.0",
         "@codemirror/legacy-modes": "^6.1.0"
       }
@@ -3058,9 +3090,9 @@
       }
     },
     "node_modules/@codemirror/merge": {
-      "version": "6.5.0",
-      "resolved": "https://registry.npmjs.org/@codemirror/merge/-/merge-6.5.0.tgz",
-      "integrity": "sha512-Am88bwcZFrVM84M7x+Njq3X1TSNXqEdOjp7iFI+45KDG+zJUA1gTkJxzGtrTKBKK7gL1Q0/tihpGQBlZOZCO/w==",
+      "version": "6.6.1",
+      "resolved": "https://registry.npmjs.org/@codemirror/merge/-/merge-6.6.1.tgz",
+      "integrity": "sha512-7wuc0R8+CSMlGZzEpxphQVkoBYb4D+M/MeB7/8g1ZrmLuP1wxhyOy7xWftmCzjKlVuRAUaKgBoA3LHS42H8eKA==",
       "dependencies": {
         "@codemirror/language": "^6.0.0",
         "@codemirror/state": "^6.0.0",
@@ -3069,16 +3101,6 @@
         "style-mod": "^4.1.0"
       }
     },
-    "node_modules/@codemirror/search": {
-      "version": "6.5.5",
-      "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.5.tgz",
-      "integrity": "sha512-PIEN3Ke1buPod2EHbJsoQwlbpkz30qGZKcnmH1eihq9+bPQx8gelauUwLYaY4vBOuBAuEhmpDLii4rj/uO0yMA==",
-      "dependencies": {
-        "@codemirror/state": "^6.0.0",
-        "@codemirror/view": "^6.0.0",
-        "crelt": "^1.0.5"
-      }
-    },
     "node_modules/@codemirror/state": {
       "version": "6.4.0",
       "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.0.tgz",
@@ -3817,9 +3839,9 @@
       }
     },
     "node_modules/@leichtgewicht/ip-codec": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
-      "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz",
+      "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==",
       "dev": true
     },
     "node_modules/@lezer/common": {
@@ -3847,6 +3869,16 @@
         "@lezer/lr": "^1.0.0"
       }
     },
+    "node_modules/@lezer/go": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@lezer/go/-/go-1.0.0.tgz",
+      "integrity": "sha512-co9JfT3QqX1YkrMmourYw2Z8meGC50Ko4d54QEcQbEYpvdUvN4yb0NBZdn/9ertgvjsySxHsKzH3lbm3vqJ4Jw==",
+      "dependencies": {
+        "@lezer/common": "^1.2.0",
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.0.0"
+      }
+    },
     "node_modules/@lezer/highlight": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.0.tgz",
@@ -3896,9 +3928,9 @@
       }
     },
     "node_modules/@lezer/lr": {
-      "version": "1.3.14",
-      "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.14.tgz",
-      "integrity": "sha512-z5mY4LStlA3yL7aHT/rqgG614cfcvklS+8oFRFBYrs4YaWLJyKKM4+nN6KopToX0o9Hj6zmH6M5kinOYuy06ug==",
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.0.tgz",
+      "integrity": "sha512-Wst46p51km8gH0ZUmeNrtpRYmdlRHUpN1DQd3GFAyKANi8WVz8c2jHYTf1CVScFaCjQw1iO3ZZdqGDxQPRErTg==",
       "dependencies": {
         "@lezer/common": "^1.0.0"
       }
@@ -3962,6 +3994,16 @@
         "@lezer/lr": "^1.0.0"
       }
     },
+    "node_modules/@lezer/yaml": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@lezer/yaml/-/yaml-1.0.2.tgz",
+      "integrity": "sha512-XCkwuxe+eumJ28nA9e1S6XKsXz9W7V/AG+WBiWOtiIuUpKcZ/bHuvN8bLxSDREIcybSRpEd/jvphh4vgm6Ed2g==",
+      "dependencies": {
+        "@lezer/common": "^1.2.0",
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.4.0"
+      }
+    },
     "node_modules/@material/animation": {
       "version": "15.0.0-canary.bc9ae6c9c.0",
       "resolved": "https://registry.npmjs.org/@material/animation/-/animation-15.0.0-canary.bc9ae6c9c.0.tgz",
@@ -4715,9 +4757,9 @@
       }
     },
     "node_modules/@ngtools/webpack": {
-      "version": "16.2.11",
-      "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.11.tgz",
-      "integrity": "sha512-4ndXJ4s94ZsryVGSDk/waIDrUqXqdGWftoOEn81Zu+nkL9ncI/G1fNUlSJ5OqeKmMLxMFouoy+BuJfvT+gEgnQ==",
+      "version": "16.2.13",
+      "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.13.tgz",
+      "integrity": "sha512-P5OiVp9MeMwVxihtC9NB4mx1Zlbup2DLMAWYAl8/kcFdRrRW+1YDQn93tlFToQDHGpPxkqW7cnFUPnA+QwQMYA==",
       "dev": true,
       "engines": {
         "node": "^16.14.0 || >=18.10.0",
@@ -5374,9 +5416,9 @@
       }
     },
     "node_modules/@types/express-serve-static-core": {
-      "version": "4.17.41",
-      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz",
-      "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==",
+      "version": "4.19.0",
+      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz",
+      "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==",
       "dev": true,
       "dependencies": {
         "@types/node": "*",
@@ -5464,9 +5506,9 @@
       "peer": true
     },
     "node_modules/@types/qs": {
-      "version": "6.9.11",
-      "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz",
-      "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==",
+      "version": "6.9.14",
+      "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz",
+      "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==",
       "dev": true
     },
     "node_modules/@types/range-parser": {
@@ -5515,14 +5557,14 @@
       }
     },
     "node_modules/@types/serve-static": {
-      "version": "1.15.5",
-      "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz",
-      "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==",
+      "version": "1.15.7",
+      "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz",
+      "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==",
       "dev": true,
       "dependencies": {
         "@types/http-errors": "*",
-        "@types/mime": "*",
-        "@types/node": "*"
+        "@types/node": "*",
+        "@types/send": "*"
       }
     },
     "node_modules/@types/sockjs": {
@@ -6915,18 +6957,10 @@
       }
     },
     "node_modules/codemirror": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
-      "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
-      "dependencies": {
-        "@codemirror/autocomplete": "^6.0.0",
-        "@codemirror/commands": "^6.0.0",
-        "@codemirror/language": "^6.0.0",
-        "@codemirror/lint": "^6.0.0",
-        "@codemirror/search": "^6.0.0",
-        "@codemirror/state": "^6.0.0",
-        "@codemirror/view": "^6.0.0"
-      }
+      "version": "6.65.7",
+      "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.65.7.tgz",
+      "integrity": "sha512-HcfnUFJwI2FvH73YWVbbMh7ObWxZiHIycEhv9ZEXy6e8ZKDjtZKbbYFUtsLN46HFXPvU5V2Uvc2d55Z//oFW5A==",
+      "deprecated": "This is an accidentally mis-tagged instance of 5.65.7"
     },
     "node_modules/color-convert": {
       "version": "1.9.3",
@@ -8637,17 +8671,17 @@
       "dev": true
     },
     "node_modules/express": {
-      "version": "4.18.2",
-      "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
-      "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
+      "version": "4.19.2",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
+      "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
       "dev": true,
       "dependencies": {
         "accepts": "~1.3.8",
         "array-flatten": "1.1.1",
-        "body-parser": "1.20.1",
+        "body-parser": "1.20.2",
         "content-disposition": "0.5.4",
         "content-type": "~1.0.4",
-        "cookie": "0.5.0",
+        "cookie": "0.6.0",
         "cookie-signature": "1.0.6",
         "debug": "2.6.9",
         "depd": "2.0.0",
@@ -8678,34 +8712,10 @@
         "node": ">= 0.10.0"
       }
     },
-    "node_modules/express/node_modules/body-parser": {
-      "version": "1.20.1",
-      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
-      "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
-      "dev": true,
-      "dependencies": {
-        "bytes": "3.1.2",
-        "content-type": "~1.0.4",
-        "debug": "2.6.9",
-        "depd": "2.0.0",
-        "destroy": "1.2.0",
-        "http-errors": "2.0.0",
-        "iconv-lite": "0.4.24",
-        "on-finished": "2.4.1",
-        "qs": "6.11.0",
-        "raw-body": "2.5.1",
-        "type-is": "~1.6.18",
-        "unpipe": "1.0.0"
-      },
-      "engines": {
-        "node": ">= 0.8",
-        "npm": "1.2.8000 || >= 1.4.16"
-      }
-    },
     "node_modules/express/node_modules/cookie": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
-      "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
+      "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
       "dev": true,
       "engines": {
         "node": ">= 0.6"
@@ -8744,21 +8754,6 @@
       "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
       "dev": true
     },
-    "node_modules/express/node_modules/raw-body": {
-      "version": "2.5.1",
-      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
-      "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
-      "dev": true,
-      "dependencies": {
-        "bytes": "3.1.2",
-        "http-errors": "2.0.0",
-        "iconv-lite": "0.4.24",
-        "unpipe": "1.0.0"
-      },
-      "engines": {
-        "node": ">= 0.8"
-      }
-    },
     "node_modules/express/node_modules/statuses": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
@@ -8992,9 +8987,9 @@
       "dev": true
     },
     "node_modules/follow-redirects": {
-      "version": "1.15.5",
-      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
-      "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
+      "version": "1.15.6",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
+      "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
       "dev": true,
       "funding": [
         {
@@ -9667,9 +9662,9 @@
       }
     },
     "node_modules/html-entities": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz",
-      "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==",
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz",
+      "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==",
       "dev": true,
       "funding": [
         {
@@ -10140,9 +10135,9 @@
       }
     },
     "node_modules/ip": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
-      "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz",
+      "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==",
       "dev": true
     },
     "node_modules/ipaddr.js": {
@@ -16894,9 +16889,9 @@
       }
     },
     "node_modules/tar": {
-      "version": "6.2.0",
-      "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz",
-      "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==",
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
+      "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
       "dev": true,
       "dependencies": {
         "chownr": "^2.0.0",
@@ -17696,9 +17691,9 @@
       }
     },
     "node_modules/vite": {
-      "version": "4.5.1",
-      "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.1.tgz",
-      "integrity": "sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA==",
+      "version": "4.5.2",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz",
+      "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==",
       "dev": true,
       "dependencies": {
         "esbuild": "^0.18.10",
@@ -18037,9 +18032,9 @@
       }
     },
     "node_modules/webpack-dev-middleware": {
-      "version": "6.1.1",
-      "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.1.tgz",
-      "integrity": "sha512-y51HrHaFeeWir0YO4f0g+9GwZawuigzcAdRNon6jErXy/SqV/+O6eaVAzDqE6t3e3NpGeR5CS+cCDaTC+V3yEQ==",
+      "version": "6.1.2",
+      "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.2.tgz",
+      "integrity": "sha512-Wu+EHmX326YPYUpQLKmKbTyZZJIB8/n6R09pTmB03kJmnMsVPTo9COzHZFr01txwaCAuZvfBJE4ZCHRcKs5JaQ==",
       "dev": true,
       "dependencies": {
         "colorette": "^2.0.10",
@@ -18124,9 +18119,9 @@
       }
     },
     "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": {
-      "version": "5.3.3",
-      "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz",
-      "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==",
+      "version": "5.3.4",
+      "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz",
+      "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==",
       "dev": true,
       "dependencies": {
         "colorette": "^2.0.10",
@@ -18654,15 +18649,15 @@
       }
     },
     "@angular-devkit/build-angular": {
-      "version": "16.2.11",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.11.tgz",
-      "integrity": "sha512-yNzUiAeg1WHMsFG9IBg4S/7dsMcEAMYQ1I360ib80c0T/IwRb8pHhOokrl5Mu8zfNqZ/dxH4ItKY1uIMDmuMGQ==",
+      "version": "16.2.13",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.13.tgz",
+      "integrity": "sha512-2G8gnBpBKcu+/jJH5DJZyMgn2RwDFPgiNSkcLKFg5DdqVFVT3CCoZAobfpAEMndrysfMmoUPGuAmsgCfdczQjg==",
       "dev": true,
       "requires": {
         "@ampproject/remapping": "2.2.1",
-        "@angular-devkit/architect": "0.1602.11",
-        "@angular-devkit/build-webpack": "0.1602.11",
-        "@angular-devkit/core": "16.2.11",
+        "@angular-devkit/architect": "0.1602.13",
+        "@angular-devkit/build-webpack": "0.1602.13",
+        "@angular-devkit/core": "16.2.13",
         "@babel/core": "7.22.9",
         "@babel/generator": "7.22.9",
         "@babel/helper-annotate-as-pure": "7.22.5",
@@ -18674,7 +18669,7 @@
         "@babel/runtime": "7.22.6",
         "@babel/template": "7.22.5",
         "@discoveryjs/json-ext": "0.5.7",
-        "@ngtools/webpack": "16.2.11",
+        "@ngtools/webpack": "16.2.13",
         "@vitejs/plugin-basic-ssl": "1.0.1",
         "ansi-colors": "4.1.3",
         "autoprefixer": "10.4.14",
@@ -18718,28 +18713,28 @@
         "text-table": "0.2.0",
         "tree-kill": "1.2.2",
         "tslib": "2.6.1",
-        "vite": "4.5.1",
+        "vite": "4.5.2",
         "webpack": "5.88.2",
-        "webpack-dev-middleware": "6.1.1",
+        "webpack-dev-middleware": "6.1.2",
         "webpack-dev-server": "4.15.1",
         "webpack-merge": "5.9.0",
         "webpack-subresource-integrity": "5.1.0"
       },
       "dependencies": {
         "@angular-devkit/architect": {
-          "version": "0.1602.11",
-          "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.11.tgz",
-          "integrity": "sha512-qC1tPL/82gxqCS1z9pTpLn5NQH6uqbV6UNjbkFEQpTwEyWEK6VLChAJsybHHfbpssPS2HWf31VoUzX7RqDjoQQ==",
+          "version": "0.1602.13",
+          "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.13.tgz",
+          "integrity": "sha512-ejrOYoXgbhDYjdaW4B2SyWeb6AqR8vqqzMyvCq2JX7fo08IhLnVu1fcl0fwr161l37TuzgPNWrHSciOzzmZDkw==",
           "dev": true,
           "requires": {
-            "@angular-devkit/core": "16.2.11",
+            "@angular-devkit/core": "16.2.13",
             "rxjs": "7.8.1"
           }
         },
         "@angular-devkit/core": {
-          "version": "16.2.11",
-          "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.11.tgz",
-          "integrity": "sha512-u3cEQHqhSMWyAFIaPdRukCJwEUJt7Fy3C02gTlTeCB4F/OnftVFIm2e5vmCqMo9rgbfdvjWj9V+7wWiCpMrzAQ==",
+          "version": "16.2.13",
+          "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.13.tgz",
+          "integrity": "sha512-6jTlYOIeYsOF/Vw/hBNusjoCmKJBByoyGS1Fu2Yav8ltxYK04aDtI73l9JJB/5Cpzhc4YELrMqBMH7in5Vowaw==",
           "dev": true,
           "requires": {
             "ajv": "8.12.0",
@@ -18885,29 +18880,29 @@
       }
     },
     "@angular-devkit/build-webpack": {
-      "version": "0.1602.11",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.11.tgz",
-      "integrity": "sha512-2Au6xRMxNugFkXP0LS1TwNE5gAfGW4g6yxC9P5j5p3kdGDnAVaZRTOKB9dg73i3uXtJHUMciYOThV0b78XRxwA==",
+      "version": "0.1602.13",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.13.tgz",
+      "integrity": "sha512-H7CqnC0kvWR0Q45ZXsCO3M9lGd4dOajEmkCVmq7vVptU3nJRbCqJ0ZScj9bH5YSlcdO0jPbOdcTELWyEZ3BMFQ==",
       "dev": true,
       "requires": {
-        "@angular-devkit/architect": "0.1602.11",
+        "@angular-devkit/architect": "0.1602.13",
         "rxjs": "7.8.1"
       },
       "dependencies": {
         "@angular-devkit/architect": {
-          "version": "0.1602.11",
-          "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.11.tgz",
-          "integrity": "sha512-qC1tPL/82gxqCS1z9pTpLn5NQH6uqbV6UNjbkFEQpTwEyWEK6VLChAJsybHHfbpssPS2HWf31VoUzX7RqDjoQQ==",
+          "version": "0.1602.13",
+          "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.13.tgz",
+          "integrity": "sha512-ejrOYoXgbhDYjdaW4B2SyWeb6AqR8vqqzMyvCq2JX7fo08IhLnVu1fcl0fwr161l37TuzgPNWrHSciOzzmZDkw==",
           "dev": true,
           "requires": {
-            "@angular-devkit/core": "16.2.11",
+            "@angular-devkit/core": "16.2.13",
             "rxjs": "7.8.1"
           }
         },
         "@angular-devkit/core": {
-          "version": "16.2.11",
-          "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.11.tgz",
-          "integrity": "sha512-u3cEQHqhSMWyAFIaPdRukCJwEUJt7Fy3C02gTlTeCB4F/OnftVFIm2e5vmCqMo9rgbfdvjWj9V+7wWiCpMrzAQ==",
+          "version": "16.2.13",
+          "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.13.tgz",
+          "integrity": "sha512-6jTlYOIeYsOF/Vw/hBNusjoCmKJBByoyGS1Fu2Yav8ltxYK04aDtI73l9JJB/5Cpzhc4YELrMqBMH7in5Vowaw==",
           "dev": true,
           "requires": {
             "ajv": "8.12.0",
@@ -18972,9 +18967,9 @@
       }
     },
     "@angular/cdk": {
-      "version": "16.2.12",
-      "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-16.2.12.tgz",
-      "integrity": "sha512-wT8/265zm2WKY0BDaRoYbrAT4kadrmejTRLjuimQIEUKnw4vBsJMWCwQkpFo3s6zr6eznGqYVAFb8KKPVLKGBg==",
+      "version": "16.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-16.2.14.tgz",
+      "integrity": "sha512-n6PrGdiVeSTEmM/HEiwIyg6YQUUymZrb5afaNLGFRM5YL0Y8OBqd+XhCjb0OfD/AfgCUtedVEPwNqrfW8KzgGw==",
       "requires": {
         "parse5": "^7.1.2",
         "tslib": "^2.3.0"
@@ -19063,9 +19058,9 @@
       }
     },
     "@angular/material": {
-      "version": "16.2.12",
-      "resolved": "https://registry.npmjs.org/@angular/material/-/material-16.2.12.tgz",
-      "integrity": "sha512-k1DGRfP1mMmhg/nLJjZBOPzX3SyAjgbRBY2KauKOV8OFCXJGoMn/oLgMBh+qB1WugzIna/31dBV8ruHD3Uvp2w==",
+      "version": "16.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/material/-/material-16.2.14.tgz",
+      "integrity": "sha512-zQIxUb23elPfiIvddqkIDYqQhAHa9ZwMblfbv+ug8bxr4D0Dw360jIarxCgMjAcLj7Ccl3GBqZMUnVeM6cjthw==",
       "requires": {
         "@material/animation": "15.0.0-canary.bc9ae6c9c.0",
         "@material/auto-init": "15.0.0-canary.bc9ae6c9c.0",
@@ -19118,9 +19113,9 @@
       }
     },
     "@angular/material-moment-adapter": {
-      "version": "16.2.12",
-      "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-16.2.12.tgz",
-      "integrity": "sha512-Is6tv6CF5ts/wNVELtIOje233P8JzVR15/NH6vL1fcoXOOPmhJVyGbAB+U6WaVLPJw31xufP7nKry+G3+ECyow==",
+      "version": "16.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-16.2.14.tgz",
+      "integrity": "sha512-LagTDXEq8XOVLy8CVswCbmq7v9bb84+VikEEN09tz831U/7PHjDZ3xRgpKtv7hXrh8cTZOg3UPQw5tZk0hwh3Q==",
       "requires": {
         "tslib": "^2.3.0"
       }
@@ -20484,17 +20479,6 @@
         "@lezer/common": "^1.0.0"
       }
     },
-    "@codemirror/commands": {
-      "version": "6.3.3",
-      "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.3.3.tgz",
-      "integrity": "sha512-dO4hcF0fGT9tu1Pj1D2PvGvxjeGkbC6RGcZw6Qs74TH+Ed1gw98jmUgd2axWvIZEqTeTuFrg1lEB1KV6cK9h1A==",
-      "requires": {
-        "@codemirror/language": "^6.0.0",
-        "@codemirror/state": "^6.4.0",
-        "@codemirror/view": "^6.0.0",
-        "@lezer/common": "^1.1.0"
-      }
-    },
     "@codemirror/lang-angular": {
       "version": "0.1.3",
       "resolved": "https://registry.npmjs.org/@codemirror/lang-angular/-/lang-angular-0.1.3.tgz",
@@ -20529,6 +20513,18 @@
         "@lezer/css": "^1.0.0"
       }
     },
+    "@codemirror/lang-go": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-go/-/lang-go-6.0.0.tgz",
+      "integrity": "sha512-mMT4YeYdKGjnffDBOhr1ur1glee4oV/rfMe28vzazNHZkSt7vSiuHiBcgr3L/79Cl2RIjFdpQ1XMD0/T8Rx64g==",
+      "requires": {
+        "@codemirror/autocomplete": "^6.0.0",
+        "@codemirror/language": "^6.6.0",
+        "@codemirror/state": "^6.0.0",
+        "@lezer/common": "^1.0.0",
+        "@lezer/go": "^1.0.0"
+      }
+    },
     "@codemirror/lang-html": {
       "version": "6.4.7",
       "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.7.tgz",
@@ -20589,6 +20585,21 @@
         "@lezer/lr": "^1.0.0"
       }
     },
+    "@codemirror/lang-liquid": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-liquid/-/lang-liquid-6.2.1.tgz",
+      "integrity": "sha512-J1Mratcm6JLNEiX+U2OlCDTysGuwbHD76XwuL5o5bo9soJtSbz2g6RU3vGHFyS5DC8rgVmFSzi7i6oBftm7tnA==",
+      "requires": {
+        "@codemirror/autocomplete": "^6.0.0",
+        "@codemirror/lang-html": "^6.0.0",
+        "@codemirror/language": "^6.0.0",
+        "@codemirror/state": "^6.0.0",
+        "@codemirror/view": "^6.0.0",
+        "@lezer/common": "^1.0.0",
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.3.1"
+      }
+    },
     "@codemirror/lang-markdown": {
       "version": "6.2.4",
       "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.2.4.tgz",
@@ -20695,10 +20706,23 @@
         "@lezer/xml": "^1.0.0"
       }
     },
+    "@codemirror/lang-yaml": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-yaml/-/lang-yaml-6.1.0.tgz",
+      "integrity": "sha512-QQEEOWjHplNScULb0NCMVUcp+TPTpg42vmTcH62UMLVBkvAEFuVkhqH11f50m/pnai7qUfSLv6ZJoPv76Ky3QA==",
+      "requires": {
+        "@codemirror/autocomplete": "^6.0.0",
+        "@codemirror/language": "^6.0.0",
+        "@codemirror/state": "^6.0.0",
+        "@lezer/common": "^1.2.0",
+        "@lezer/highlight": "^1.2.0",
+        "@lezer/yaml": "^1.0.0"
+      }
+    },
     "@codemirror/language": {
-      "version": "6.10.0",
-      "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.0.tgz",
-      "integrity": "sha512-2vaNn9aPGCRFKWcHPFksctzJ8yS5p7YoaT+jHpc0UGKzNuAIx4qy6R5wiqbP+heEEdyaABA582mNqSHzSoYdmg==",
+      "version": "6.10.1",
+      "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.1.tgz",
+      "integrity": "sha512-5GrXzrhq6k+gL5fjkAwt90nYDmjlzTIJV8THnxNFtNKWotMIlzzN+CpqxqwXOECnUdOndmSeWntVrVcv5axWRQ==",
       "requires": {
         "@codemirror/state": "^6.0.0",
         "@codemirror/view": "^6.23.0",
@@ -20709,18 +20733,20 @@
       }
     },
     "@codemirror/language-data": {
-      "version": "6.3.1",
-      "resolved": "https://registry.npmjs.org/@codemirror/language-data/-/language-data-6.3.1.tgz",
-      "integrity": "sha512-p6jhJmvhGe1TG1EGNhwH7nFWWFSTJ8NDKnB2fVx5g3t+PpO0+63R7GJNxjS0TmmH3cdMxZbzejsik+rlEh1EyQ==",
+      "version": "6.5.0",
+      "resolved": "https://registry.npmjs.org/@codemirror/language-data/-/language-data-6.5.0.tgz",
+      "integrity": "sha512-+F2PyUJtTfGO/3X0fgwZwyyCQ35GZycQSI/731tHifhFMaKYTM8Ic45uK1jrcg086pDy573CL2DWvHJlSkFGzQ==",
       "requires": {
         "@codemirror/lang-angular": "^0.1.0",
         "@codemirror/lang-cpp": "^6.0.0",
         "@codemirror/lang-css": "^6.0.0",
+        "@codemirror/lang-go": "^6.0.0",
         "@codemirror/lang-html": "^6.0.0",
         "@codemirror/lang-java": "^6.0.0",
         "@codemirror/lang-javascript": "^6.0.0",
         "@codemirror/lang-json": "^6.0.0",
         "@codemirror/lang-less": "^6.0.0",
+        "@codemirror/lang-liquid": "^6.0.0",
         "@codemirror/lang-markdown": "^6.0.0",
         "@codemirror/lang-php": "^6.0.0",
         "@codemirror/lang-python": "^6.0.0",
@@ -20730,6 +20756,7 @@
         "@codemirror/lang-vue": "^0.1.1",
         "@codemirror/lang-wast": "^6.0.0",
         "@codemirror/lang-xml": "^6.0.0",
+        "@codemirror/lang-yaml": "^6.0.0",
         "@codemirror/language": "^6.0.0",
         "@codemirror/legacy-modes": "^6.1.0"
       }
@@ -20753,9 +20780,9 @@
       }
     },
     "@codemirror/merge": {
-      "version": "6.5.0",
-      "resolved": "https://registry.npmjs.org/@codemirror/merge/-/merge-6.5.0.tgz",
-      "integrity": "sha512-Am88bwcZFrVM84M7x+Njq3X1TSNXqEdOjp7iFI+45KDG+zJUA1gTkJxzGtrTKBKK7gL1Q0/tihpGQBlZOZCO/w==",
+      "version": "6.6.1",
+      "resolved": "https://registry.npmjs.org/@codemirror/merge/-/merge-6.6.1.tgz",
+      "integrity": "sha512-7wuc0R8+CSMlGZzEpxphQVkoBYb4D+M/MeB7/8g1ZrmLuP1wxhyOy7xWftmCzjKlVuRAUaKgBoA3LHS42H8eKA==",
       "requires": {
         "@codemirror/language": "^6.0.0",
         "@codemirror/state": "^6.0.0",
@@ -20764,16 +20791,6 @@
         "style-mod": "^4.1.0"
       }
     },
-    "@codemirror/search": {
-      "version": "6.5.5",
-      "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.5.tgz",
-      "integrity": "sha512-PIEN3Ke1buPod2EHbJsoQwlbpkz30qGZKcnmH1eihq9+bPQx8gelauUwLYaY4vBOuBAuEhmpDLii4rj/uO0yMA==",
-      "requires": {
-        "@codemirror/state": "^6.0.0",
-        "@codemirror/view": "^6.0.0",
-        "crelt": "^1.0.5"
-      }
-    },
     "@codemirror/state": {
       "version": "6.4.0",
       "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.0.tgz",
@@ -21217,9 +21234,9 @@
       }
     },
     "@leichtgewicht/ip-codec": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
-      "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz",
+      "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==",
       "dev": true
     },
     "@lezer/common": {
@@ -21247,6 +21264,16 @@
         "@lezer/lr": "^1.0.0"
       }
     },
+    "@lezer/go": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@lezer/go/-/go-1.0.0.tgz",
+      "integrity": "sha512-co9JfT3QqX1YkrMmourYw2Z8meGC50Ko4d54QEcQbEYpvdUvN4yb0NBZdn/9ertgvjsySxHsKzH3lbm3vqJ4Jw==",
+      "requires": {
+        "@lezer/common": "^1.2.0",
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.0.0"
+      }
+    },
     "@lezer/highlight": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.0.tgz",
@@ -21296,9 +21323,9 @@
       }
     },
     "@lezer/lr": {
-      "version": "1.3.14",
-      "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.14.tgz",
-      "integrity": "sha512-z5mY4LStlA3yL7aHT/rqgG614cfcvklS+8oFRFBYrs4YaWLJyKKM4+nN6KopToX0o9Hj6zmH6M5kinOYuy06ug==",
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.0.tgz",
+      "integrity": "sha512-Wst46p51km8gH0ZUmeNrtpRYmdlRHUpN1DQd3GFAyKANi8WVz8c2jHYTf1CVScFaCjQw1iO3ZZdqGDxQPRErTg==",
       "requires": {
         "@lezer/common": "^1.0.0"
       }
@@ -21362,6 +21389,16 @@
         "@lezer/lr": "^1.0.0"
       }
     },
+    "@lezer/yaml": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@lezer/yaml/-/yaml-1.0.2.tgz",
+      "integrity": "sha512-XCkwuxe+eumJ28nA9e1S6XKsXz9W7V/AG+WBiWOtiIuUpKcZ/bHuvN8bLxSDREIcybSRpEd/jvphh4vgm6Ed2g==",
+      "requires": {
+        "@lezer/common": "^1.2.0",
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.4.0"
+      }
+    },
     "@material/animation": {
       "version": "15.0.0-canary.bc9ae6c9c.0",
       "resolved": "https://registry.npmjs.org/@material/animation/-/animation-15.0.0-canary.bc9ae6c9c.0.tgz",
@@ -22115,9 +22152,9 @@
       }
     },
     "@ngtools/webpack": {
-      "version": "16.2.11",
-      "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.11.tgz",
-      "integrity": "sha512-4ndXJ4s94ZsryVGSDk/waIDrUqXqdGWftoOEn81Zu+nkL9ncI/G1fNUlSJ5OqeKmMLxMFouoy+BuJfvT+gEgnQ==",
+      "version": "16.2.13",
+      "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.13.tgz",
+      "integrity": "sha512-P5OiVp9MeMwVxihtC9NB4mx1Zlbup2DLMAWYAl8/kcFdRrRW+1YDQn93tlFToQDHGpPxkqW7cnFUPnA+QwQMYA==",
       "dev": true,
       "requires": {}
     },
@@ -22617,9 +22654,9 @@
       }
     },
     "@types/express-serve-static-core": {
-      "version": "4.17.41",
-      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz",
-      "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==",
+      "version": "4.19.0",
+      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz",
+      "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==",
       "dev": true,
       "requires": {
         "@types/node": "*",
@@ -22707,9 +22744,9 @@
       "peer": true
     },
     "@types/qs": {
-      "version": "6.9.11",
-      "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz",
-      "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==",
+      "version": "6.9.14",
+      "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz",
+      "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==",
       "dev": true
     },
     "@types/range-parser": {
@@ -22758,14 +22795,14 @@
       }
     },
     "@types/serve-static": {
-      "version": "1.15.5",
-      "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz",
-      "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==",
+      "version": "1.15.7",
+      "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz",
+      "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==",
       "dev": true,
       "requires": {
         "@types/http-errors": "*",
-        "@types/mime": "*",
-        "@types/node": "*"
+        "@types/node": "*",
+        "@types/send": "*"
       }
     },
     "@types/sockjs": {
@@ -23832,18 +23869,9 @@
       }
     },
     "codemirror": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
-      "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
-      "requires": {
-        "@codemirror/autocomplete": "^6.0.0",
-        "@codemirror/commands": "^6.0.0",
-        "@codemirror/language": "^6.0.0",
-        "@codemirror/lint": "^6.0.0",
-        "@codemirror/search": "^6.0.0",
-        "@codemirror/state": "^6.0.0",
-        "@codemirror/view": "^6.0.0"
-      }
+      "version": "6.65.7",
+      "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.65.7.tgz",
+      "integrity": "sha512-HcfnUFJwI2FvH73YWVbbMh7ObWxZiHIycEhv9ZEXy6e8ZKDjtZKbbYFUtsLN46HFXPvU5V2Uvc2d55Z//oFW5A=="
     },
     "color-convert": {
       "version": "1.9.3",
@@ -25161,17 +25189,17 @@
       "dev": true
     },
     "express": {
-      "version": "4.18.2",
-      "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
-      "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
+      "version": "4.19.2",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
+      "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
       "dev": true,
       "requires": {
         "accepts": "~1.3.8",
         "array-flatten": "1.1.1",
-        "body-parser": "1.20.1",
+        "body-parser": "1.20.2",
         "content-disposition": "0.5.4",
         "content-type": "~1.0.4",
-        "cookie": "0.5.0",
+        "cookie": "0.6.0",
         "cookie-signature": "1.0.6",
         "debug": "2.6.9",
         "depd": "2.0.0",
@@ -25199,30 +25227,10 @@
         "vary": "~1.1.2"
       },
       "dependencies": {
-        "body-parser": {
-          "version": "1.20.1",
-          "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
-          "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
-          "dev": true,
-          "requires": {
-            "bytes": "3.1.2",
-            "content-type": "~1.0.4",
-            "debug": "2.6.9",
-            "depd": "2.0.0",
-            "destroy": "1.2.0",
-            "http-errors": "2.0.0",
-            "iconv-lite": "0.4.24",
-            "on-finished": "2.4.1",
-            "qs": "6.11.0",
-            "raw-body": "2.5.1",
-            "type-is": "~1.6.18",
-            "unpipe": "1.0.0"
-          }
-        },
         "cookie": {
-          "version": "0.5.0",
-          "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
-          "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+          "version": "0.6.0",
+          "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
+          "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
           "dev": true
         },
         "debug": {
@@ -25255,18 +25263,6 @@
           "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
           "dev": true
         },
-        "raw-body": {
-          "version": "2.5.1",
-          "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
-          "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
-          "dev": true,
-          "requires": {
-            "bytes": "3.1.2",
-            "http-errors": "2.0.0",
-            "iconv-lite": "0.4.24",
-            "unpipe": "1.0.0"
-          }
-        },
         "statuses": {
           "version": "2.0.1",
           "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
@@ -25459,9 +25455,9 @@
       "dev": true
     },
     "follow-redirects": {
-      "version": "1.15.5",
-      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
-      "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
+      "version": "1.15.6",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
+      "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
       "dev": true
     },
     "foreground-child": {
@@ -25977,9 +25973,9 @@
       }
     },
     "html-entities": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz",
-      "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==",
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz",
+      "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==",
       "dev": true
     },
     "htmlparser2": {
@@ -26326,9 +26322,9 @@
       }
     },
     "ip": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
-      "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz",
+      "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==",
       "dev": true
     },
     "ipaddr.js": {
@@ -31441,9 +31437,9 @@
       "dev": true
     },
     "tar": {
-      "version": "6.2.0",
-      "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz",
-      "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==",
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
+      "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
       "dev": true,
       "requires": {
         "chownr": "^2.0.0",
@@ -32031,9 +32027,9 @@
       }
     },
     "vite": {
-      "version": "4.5.1",
-      "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.1.tgz",
-      "integrity": "sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA==",
+      "version": "4.5.2",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz",
+      "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==",
       "dev": true,
       "requires": {
         "esbuild": "^0.18.10",
@@ -32327,9 +32323,9 @@
       }
     },
     "webpack-dev-middleware": {
-      "version": "6.1.1",
-      "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.1.tgz",
-      "integrity": "sha512-y51HrHaFeeWir0YO4f0g+9GwZawuigzcAdRNon6jErXy/SqV/+O6eaVAzDqE6t3e3NpGeR5CS+cCDaTC+V3yEQ==",
+      "version": "6.1.2",
+      "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.2.tgz",
+      "integrity": "sha512-Wu+EHmX326YPYUpQLKmKbTyZZJIB8/n6R09pTmB03kJmnMsVPTo9COzHZFr01txwaCAuZvfBJE4ZCHRcKs5JaQ==",
       "dev": true,
       "requires": {
         "colorette": "^2.0.10",
@@ -32378,9 +32374,9 @@
       },
       "dependencies": {
         "webpack-dev-middleware": {
-          "version": "5.3.3",
-          "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz",
-          "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==",
+          "version": "5.3.4",
+          "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz",
+          "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==",
           "dev": true,
           "requires": {
             "colorette": "^2.0.10",
diff --git a/smp-angular/package.json b/smp-angular/package.json
index 169ef3444..2b10e914c 100644
--- a/smp-angular/package.json
+++ b/smp-angular/package.json
@@ -16,13 +16,13 @@
   "private": true,
   "dependencies": {
     "@angular/animations": "^16.2.12",
-    "@angular/cdk": "^16.2.12",
+    "@angular/cdk": "^16.2.14",
     "@angular/common": "^16.2.12",
     "@angular/compiler": "^16.2.12",
     "@angular/core": "^16.2.12",
     "@angular/forms": "^16.2.12",
     "@angular/material": "^16.2.12",
-    "@angular/material-moment-adapter": "^16.2.12",
+    "@angular/material-moment-adapter": "^16.2.14",
     "@angular/platform-browser": "^16.2.12",
     "@angular/platform-browser-dynamic": "^16.2.12",
     "@angular/platform-server": "^16.2.12",
@@ -32,15 +32,15 @@
     "@angular-material-components/datetime-picker": "^16.0.1",
     "@angular-material-components/moment-adapter": "^16.0.1",
     "codemirror": "^6.0.1",
-    "@codemirror/language": "^6.10.0",
-    "@codemirror/language-data": "^6.3.1",
+    "@codemirror/language": "^6.10.1",
+    "@codemirror/language-data": "^6.5.0",
     "@codemirror/theme-one-dark": "^6.1.2",
-    "@codemirror/merge": "^6.5.0",
+    "@codemirror/merge": "^6.6.1",
     "file-saver": "^2.0.5",
     "rxjs": "^7.8.1",
     "ts-helpers": "^1.1.2",
     "tslib": "^2.6.2",
-    "zone.js": "^0.13.0"
+    "zone.js": "^0.13.3"
   },
   "devDependencies": {
     "@angular-devkit/build-angular": "^16.2.10",
diff --git a/smp-angular/src/app/app.module.ts b/smp-angular/src/app/app.module.ts
index 3a62f776b..ad34702c5 100644
--- a/smp-angular/src/app/app.module.ts
+++ b/smp-angular/src/app/app.module.ts
@@ -142,6 +142,11 @@ import {
 import {UserAlertsComponent} from "./user-settings/user-alerts/user-alerts.component";
 import {SmpEditorComponent} from "./common/components/smp-editor/smp-editor.component";
 import {ResetCredentialComponent} from "./security/reset-credential/reset-credential.component";
+import {DnsToolsComponent} from "./tools/dns-tools/dns-tools.component";
+import {DnsToolsService} from "./tools/dns-tools/dns-tools.service";
+import {
+  DnsQueryPanelComponent
+} from "./tools/dns-tools/dns-query-panel/dns-query-panel.component";
 
 
 @NgModule({
@@ -171,6 +176,8 @@ import {ResetCredentialComponent} from "./security/reset-credential/reset-creden
     DatePipe,
     DefaultPasswordDialogComponent,
     DialogComponent,
+    DnsToolsComponent,
+    DnsQueryPanelComponent,
     DocumentWizardDialogComponent,
     DomainGroupComponent,
     DomainPanelComponent,
@@ -276,6 +283,7 @@ import {ResetCredentialComponent} from "./security/reset-credential/reset-creden
     AuthorizedGuard,
     CertificateService,
     DatePipe,
+    DnsToolsService,
     DomainService,
     MembershipService,
     DownloadService,
diff --git a/smp-angular/src/app/app.routes.ts b/smp-angular/src/app/app.routes.ts
index 904ef7326..792415e13 100644
--- a/smp-angular/src/app/app.routes.ts
+++ b/smp-angular/src/app/app.routes.ts
@@ -22,12 +22,14 @@ import {activateChildResourceGuard} from "./guards/activate-child-document.guard
 import {UserAlertsComponent} from "./user-settings/user-alerts/user-alerts.component";
 import {AdminAlertsComponent} from "./system-settings/admin-alerts/admin-alerts.component";
 import {ResetCredentialComponent} from "./security/reset-credential/reset-credential.component";
+import {DnsToolsComponent} from "./tools/dns-tools/dns-tools.component";
 
 
 const appRoutes: Routes = [
 
   {path: '', component: ResourceSearchComponent},
   {path: 'search', redirectTo: ''},
+  {path: 'public/dns-tools', component: DnsToolsComponent},
   {path: 'login', component: LoginComponent},
   {path: 'reset-credential/:resetToken', component: ResetCredentialComponent},
   {
diff --git a/smp-angular/src/app/common/dialogs/credential-dialog/access-token-ro.model.ts b/smp-angular/src/app/common/dialogs/credential-dialog/access-token-ro.model.ts
deleted file mode 100644
index 0dd11abcb..000000000
--- a/smp-angular/src/app/common/dialogs/credential-dialog/access-token-ro.model.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export interface AccessTokenRo {
-  identifier: string;
-  value: string;
-  generatedOn?: Date;
-  expireOn?: Date;
-}
diff --git a/smp-angular/src/app/common/enums/dns-type.enum.ts b/smp-angular/src/app/common/enums/dns-type.enum.ts
new file mode 100644
index 000000000..7c17b9bf6
--- /dev/null
+++ b/smp-angular/src/app/common/enums/dns-type.enum.ts
@@ -0,0 +1,4 @@
+export enum DnsTypeEnum {
+  CNAME,
+  NAPTR
+}
diff --git a/smp-angular/src/app/common/error/http-error-handler.service.ts b/smp-angular/src/app/common/error/http-error-handler.service.ts
index d2848ac39..d93cf8a14 100644
--- a/smp-angular/src/app/common/error/http-error-handler.service.ts
+++ b/smp-angular/src/app/common/error/http-error-handler.service.ts
@@ -1,6 +1,4 @@
 import {Injectable} from '@angular/core';
-import {Router, NavigationStart, NavigationEnd} from '@angular/router';
-import {Observable, Subject} from 'rxjs';
 import {HttpErrorResponse} from "@angular/common/http";
 import {NavigationService} from "../../window/sidenav/navigation-model.service";
 import {AlertMessageService} from "../alert-message/alert-message.service";
diff --git a/smp-angular/src/app/common/global-lookups.ts b/smp-angular/src/app/common/global-lookups.ts
index 96ad181ce..fc8f8e5e8 100644
--- a/smp-angular/src/app/common/global-lookups.ts
+++ b/smp-angular/src/app/common/global-lookups.ts
@@ -12,6 +12,7 @@ import {SmpConfig} from "../app-config/smp-config.model";
 import {SecurityEventService} from "../security/security-event.service";
 import {DateAdapter} from "@angular/material/core";
 import {NgxMatDateAdapter} from "@angular-material-components/datetime-picker";
+import {DomainRo} from "./model/domain-ro.model";
 
 /**
  * Purpose of object is to fetch lookups as domains and users
@@ -22,10 +23,8 @@ export class GlobalLookups {
 
   domainObserver: Observable<SearchTableResult>
   userObserver: Observable<SearchTableResult>
-  cachedDomainList: Array<any> = [];
+  cachedDomainList: Array<DomainRo> = [];
   cachedServiceGroupOwnerList: Array<any> = [];
-  cachedCertificateList: Array<any> = [];
-  cachedCertificateAliasList: Array<string> = [];
   cachedApplicationInfo: SmpInfo;
   cachedApplicationConfig?: SmpConfig;
 
@@ -161,8 +160,4 @@ export class GlobalLookups {
     this.cachedApplicationConfig = null;
     this.cachedDomainList = [];
   }
-
-
-
-
 }
diff --git a/smp-angular/src/app/common/model/dns-query-request-ro.model.ts b/smp-angular/src/app/common/model/dns-query-request-ro.model.ts
new file mode 100644
index 000000000..2307ba9ba
--- /dev/null
+++ b/smp-angular/src/app/common/model/dns-query-request-ro.model.ts
@@ -0,0 +1,6 @@
+export interface DnsQueryRequestRo {
+  identifierValue:string;
+  identifierScheme?:string;
+  domainCode?:string;
+  topDnsDomain?:string;
+}
diff --git a/smp-angular/src/app/common/model/dns-query-ro.model.ts b/smp-angular/src/app/common/model/dns-query-ro.model.ts
new file mode 100644
index 000000000..d5d7bff7c
--- /dev/null
+++ b/smp-angular/src/app/common/model/dns-query-ro.model.ts
@@ -0,0 +1,9 @@
+import {DnsTypeEnum} from "../enums/dns-type.enum";
+import {DnsRecordRo} from "./dns-record-ro.model";
+
+export interface DnsQueryRo {
+  dnsQuery:string
+  dnsType:DnsTypeEnum
+  dnsEntries?:DnsRecordRo[]
+  error?:string[]
+}
diff --git a/smp-angular/src/app/common/model/dns-record-ro.model.ts b/smp-angular/src/app/common/model/dns-record-ro.model.ts
new file mode 100644
index 000000000..5f705c71b
--- /dev/null
+++ b/smp-angular/src/app/common/model/dns-record-ro.model.ts
@@ -0,0 +1,8 @@
+import {DnsTypeEnum} from "../enums/dns-type.enum";
+
+export interface DnsRecordRo {
+  dnsType:DnsTypeEnum;
+  rawRecordResult?:string;
+  naptrService?:string;
+  value?:string;
+}
diff --git a/smp-angular/src/app/common/model/group-ro.model.ts b/smp-angular/src/app/common/model/group-ro.model.ts
index d17f87292..df46b2632 100644
--- a/smp-angular/src/app/common/model/group-ro.model.ts
+++ b/smp-angular/src/app/common/model/group-ro.model.ts
@@ -1,7 +1,5 @@
 
-import {MembershipRoleEnum} from "../enums/membership-role.enum";
 import {SearchTableEntity} from "../search-table/search-table-entity.model";
-import {MemberTypeEnum} from "../enums/member-type.enum";
 import {VisibilityEnum} from "../enums/visibility.enum";
 
 export interface GroupRo extends SearchTableEntity {
diff --git a/smp-angular/src/app/smp.constants.ts b/smp-angular/src/app/smp.constants.ts
index 23e75fb4b..05cf40aea 100644
--- a/smp-angular/src/app/smp.constants.ts
+++ b/smp-angular/src/app/smp.constants.ts
@@ -1,7 +1,7 @@
 export class SmpConstants {
 
-  public static EXPANDED_MENU_WIDTH: string = "180px"
-  public static COLLAPSED_MENU_WIDTH: string = "50px"
+  public static readonly EXPANDED_MENU_WIDTH: string = "180px"
+  public static readonly COLLAPSED_MENU_WIDTH: string = "50px"
   public static readonly NULL_VALUE: string = "-----------"
   public static readonly DATE_TIME_FORMAT = 'dd/MM/yyyy HH:mm:ss z';
   public static readonly DATE_FORMAT = 'dd/MM/yyyy';
@@ -18,6 +18,7 @@ export class SmpConstants {
   public static readonly PATH_ACTION_SEARCH = 'search';
   public static readonly PATH_ACTION_UPDATE_RESOURCE_TYPES = 'update-resource-types';
   public static readonly PATH_ACTION_UPDATE_SML_INTEGRATION = 'update-sml-integration-data';
+  public static readonly PATH_ACTION_GENERATE_DNS_QUERY : string = 'generate-dns-query';
   /* URL variables */
   public static readonly PATH_PARAM_ENC_USER_ID = '{user-id}';
   public static readonly PATH_PARAM_ENC_DOMAIN_ID = '{domain-id}';
@@ -36,6 +37,7 @@ export class SmpConstants {
   public static readonly PATH_RESOURCE_TYPE_DOMAIN = 'domain';
   public static readonly PATH_RESOURCE_TYPE_MEMBER = 'member';
   public static readonly PATH_RESOURCE_TYPE_GROUP = 'group';
+  public static readonly PATH_DNS_TOOLS = 'dns-tools';
 
   public static readonly PATH_RESOURCE_TYPE_RESOURCE_DEF = 'res-def';
 
@@ -49,9 +51,9 @@ export class SmpConstants {
   // public endpoints
   public static readonly REST_PUBLIC = 'public/rest/';
   public static readonly REST_INTERNAL = 'internal/rest/';
-
   public static readonly REST_EDIT = 'edit/rest/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/';
 
+
   public static readonly REST_EDIT_RESOURCE_SHORT = SmpConstants.REST_EDIT + SmpConstants.PATH_RESOURCE_TYPE_RESOURCE + '/' +  SmpConstants.PATH_PARAM_ENC_RESOURCE_ID;
 
   public static readonly REST_EDIT_DOCUMENT = SmpConstants.REST_EDIT_RESOURCE_SHORT + '/' +  SmpConstants.PATH_RESOURCE_TYPE_DOCUMENT ;
@@ -70,8 +72,10 @@ export class SmpConstants {
 
   /* Public services */
   public static readonly REST_PUBLIC_SEARCH_RESOURCE = SmpConstants.REST_PUBLIC + SmpConstants.PATH_ACTION_SEARCH;
-
   public static readonly REST_PUBLIC_DOMAIN = SmpConstants.REST_PUBLIC + SmpConstants.PATH_RESOURCE_TYPE_DOMAIN;
+  public static readonly REST_PUBLIC_DNS_TOOLS = SmpConstants.REST_PUBLIC  + SmpConstants.PATH_DNS_TOOLS;
+  public static readonly REST_PUBLIC_DNS_TOOLS_GEN_QUERY: string = SmpConstants.REST_PUBLIC_DNS_TOOLS + '/' + SmpConstants.PATH_ACTION_GENERATE_DNS_QUERY;
+
   /* Public edit services */
   public static readonly REST_EDIT_DOMAIN = SmpConstants.REST_EDIT + SmpConstants.PATH_RESOURCE_TYPE_DOMAIN;
   public static readonly REST_EDIT_DOMAIN_MANAGE = SmpConstants.REST_EDIT_DOMAIN + '/' + SmpConstants.PATH_PARAM_ENC_DOMAIN_ID;
diff --git a/smp-angular/src/app/system-settings/admin-properties/property-result.model.ts b/smp-angular/src/app/system-settings/admin-properties/property-result.model.ts
deleted file mode 100644
index 79d464ce9..000000000
--- a/smp-angular/src/app/system-settings/admin-properties/property-result.model.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import {PropertyRo} from './property-ro.model';
-
-export interface PropertyResult {
-  serviceEntities: Array<PropertyRo>;
-  pageSize: number;
-  count: number;
-  filter: any;
-}
diff --git a/smp-angular/src/app/tools/dns-tools/dns-query-panel/dns-query-panel.component.css b/smp-angular/src/app/tools/dns-tools/dns-query-panel/dns-query-panel.component.css
new file mode 100644
index 000000000..e33164497
--- /dev/null
+++ b/smp-angular/src/app/tools/dns-tools/dns-query-panel/dns-query-panel.component.css
@@ -0,0 +1,19 @@
+.dns-query-panel {
+  display: flex;
+  flex-direction: column;
+  width: 100%;
+  padding-right: 10px;
+  font-size: 0.8rem;
+}
+
+.dns-query-panel fieldset {
+  border: 1px solid #ccc;
+  border-radius: 5px;
+  padding: 10px;
+  margin-bottom: 10px;
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  /* adjustment */
+  position: relative;
+}
diff --git a/smp-angular/src/app/tools/dns-tools/dns-query-panel/dns-query-panel.component.html b/smp-angular/src/app/tools/dns-tools/dns-query-panel/dns-query-panel.component.html
new file mode 100644
index 000000000..b24daf624
--- /dev/null
+++ b/smp-angular/src/app/tools/dns-tools/dns-query-panel/dns-query-panel.component.html
@@ -0,0 +1,24 @@
+<div class="dns-query-panel">
+  <fieldset>
+    <legend>{{ dnsQeury?.dnsType }}</legend>
+    <smp-warning-panel *ngIf="dnsQueryNotResolved;" class="smp-warning-panel"
+                       [padding]="false"
+                       icon="error"
+                       label="DNS query not resolved">
+    </smp-warning-panel>
+    <b>DNS domain</b>
+    <pre style="font-size: 0.8em">{{ dnsQeury?.dnsQuery }}</pre>
+    <div *ngIf="!dnsQueryNotResolved;">
+      <mat-icon style="position: relative; left: 30%;">arrow_downward</mat-icon>
+      <div style="font-weight:bold;">Resolved DNS entries</div>
+      <div *ngFor="let dnsRecord of dnsQeury.dnsEntries; let i = index">
+        <mat-icon *ngIf="i!==0" style="position: relative; left: 30%">
+          arrow_downward
+        </mat-icon>
+        <pre
+          style="font-size: 0.8em"
+        >{{ dnsRecord.rawRecordResult }}</pre>
+      </div>
+    </div>
+  </fieldset>
+</div>
diff --git a/smp-angular/src/app/tools/dns-tools/dns-query-panel/dns-query-panel.component.ts b/smp-angular/src/app/tools/dns-tools/dns-query-panel/dns-query-panel.component.ts
new file mode 100644
index 000000000..0ec93e05d
--- /dev/null
+++ b/smp-angular/src/app/tools/dns-tools/dns-query-panel/dns-query-panel.component.ts
@@ -0,0 +1,25 @@
+import {Component, Input} from "@angular/core";
+import {DnsQueryRo} from "../../../common/model/dns-query-ro.model";
+
+/**
+ * This is a generic dns query panel component for previewing dns results
+ */
+@Component({
+  selector: 'dns-query-panel',
+  templateUrl: './dns-query-panel.component.html',
+  styleUrls: ['./dns-query-panel.component.css']
+})
+export class DnsQueryPanelComponent {
+
+
+  @Input() dnsQeury: DnsQueryRo = null;
+
+  constructor() {
+  }
+
+  get dnsQueryNotResolved(): boolean {
+    return this.dnsQeury
+      && (this.dnsQeury?.dnsEntries === null
+        || this.dnsQeury?.dnsEntries.length === 0);
+  }
+}
diff --git a/smp-angular/src/app/tools/dns-tools/dns-tools.component.html b/smp-angular/src/app/tools/dns-tools/dns-tools.component.html
new file mode 100644
index 000000000..5b49ca492
--- /dev/null
+++ b/smp-angular/src/app/tools/dns-tools/dns-tools.component.html
@@ -0,0 +1,45 @@
+<div id="dns-tool-panel">
+  <form [formGroup]="dnsToolsForm">
+    <data-panel title="DNS lookup"
+                [showTitle]="true"
+                text="Enter the DNS data to create DNS query"
+
+                [labelColumnContent]="dnsLookupData"
+    >
+      <dns-query-panel *ngFor="let dnsquery of result"
+                       [dnsQeury]="dnsquery"
+      />
+    </data-panel>
+    <ng-template #dnsLookupData>
+      <div class="panel">
+        <mat-form-field class="smp-data-panel-field">
+          <mat-label>Resource Identifier</mat-label>
+          <input matInput name="ResourceIdentifier"
+                 formControlName="resourceIdentifier"
+                 id="resource-identifier-id">
+        </mat-form-field>
+        <mat-form-field class="smp-data-panel-field">
+          <mat-label>Resource scheme</mat-label>
+          <input matInput name="ResourceScheme"
+                 formControlName="resourceScheme"
+                 id="resource-scheme-id">
+        </mat-form-field>
+        <mat-form-field class="smp-data-panel-field">
+          <mat-label>Top domain</mat-label>
+          <input matInput name="DNS top Domain"
+                 formControlName=dnsTopDomain
+                 id="dns-top-domain-id">
+        </mat-form-field>
+
+        <button mat-raised-button color="primary" id="btn-generate_id"
+                [disabled]="dnsToolsForm.invalid"
+                [style]="'width:250px'"
+                (click)="generateLookupQuery()"
+        >
+          <mat-icon>input</mat-icon>
+          <span>Generate lookup query</span>
+        </button>
+      </div>
+    </ng-template>
+  </form>
+</div>
diff --git a/smp-angular/src/app/tools/dns-tools/dns-tools.component.ts b/smp-angular/src/app/tools/dns-tools/dns-tools.component.ts
new file mode 100644
index 000000000..913690e3c
--- /dev/null
+++ b/smp-angular/src/app/tools/dns-tools/dns-tools.component.ts
@@ -0,0 +1,44 @@
+import {Component} from "@angular/core";
+import {DnsToolsService} from "./dns-tools.service";
+import {DnsQueryRo} from "../../common/model/dns-query-ro.model";
+import {FormBuilder, FormGroup, Validators} from "@angular/forms";
+import {GlobalLookups} from "../../common/global-lookups";
+
+@Component({
+  templateUrl: './dns-tools.component.html',
+})
+export class DnsToolsComponent {
+
+  displayedColumns: string[] = ['dnsqueryColumn'];
+  dnsToolsForm: FormGroup;
+  private _result: DnsQueryRo[];
+
+  constructor(private dnsToolsService: DnsToolsService,
+              private lookups: GlobalLookups,
+              private formBuilder: FormBuilder) {
+
+    this.dnsToolsForm = formBuilder.group({
+      // common values
+      'resourceIdentifier': ['', Validators.required],
+      'resourceScheme': [''],
+      'dnsTopDomain': [''],
+    });
+  }
+
+
+
+  get result(): DnsQueryRo[] {
+    return this._result;
+  }
+
+  generateLookupQuery() {
+    console.log('submit');
+    this.dnsToolsService.executeDnsLookup(
+      this.dnsToolsForm.get('dnsTopDomain').value,
+      this.dnsToolsForm.get('resourceIdentifier').value,
+      this.dnsToolsForm.get('resourceScheme').value
+    ).subscribe((res: DnsQueryRo[]) => {
+      this._result = res;
+    })
+  }
+}
diff --git a/smp-angular/src/app/tools/dns-tools/dns-tools.service.ts b/smp-angular/src/app/tools/dns-tools/dns-tools.service.ts
new file mode 100644
index 000000000..906d4c80b
--- /dev/null
+++ b/smp-angular/src/app/tools/dns-tools/dns-tools.service.ts
@@ -0,0 +1,26 @@
+import {Injectable} from "@angular/core";
+import {HttpClient, HttpHeaders} from "@angular/common/http";
+import {SmpConstants} from "../../smp.constants";
+import {DnsQueryRo} from "../../common/model/dns-query-ro.model";
+import {Observable} from "rxjs";
+import {DnsQueryRequestRo} from "../../common/model/dns-query-request-ro.model";
+
+@Injectable()
+export class DnsToolsService {
+
+  constructor(private http: HttpClient) {
+  }
+
+  executeDnsLookup(topDNSDomain:string, value: string, scheme: string): Observable<DnsQueryRo[]> {
+    console.log('getHashValues: val: ' + value + ' scheme:' + scheme);
+
+    let resource: DnsQueryRequestRo =  {
+      identifierValue: value,
+      identifierScheme: scheme,
+      topDnsDomain: topDNSDomain,
+    };
+    let headers: HttpHeaders = new HttpHeaders({'Content-Type': 'application/json'});
+    return this.http.post<DnsQueryRo[]>(SmpConstants.REST_PUBLIC_DNS_TOOLS_GEN_QUERY,
+      resource, {headers});
+  }
+}
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/enums/SMPPropertyEnum.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/enums/SMPPropertyEnum.java
index 5b084de70..af1755c91 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/enums/SMPPropertyEnum.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/enums/SMPPropertyEnum.java
@@ -100,6 +100,9 @@ public enum SMPPropertyEnum {
             OPTIONAL, NOT_ENCRYPTED, NO_RESTART_NEEDED, STRING),
     SML_CUSTOM_NAPTR_SERVICE_PARAMS("bdmsl.integration.naptr_service.map", "edelivery-oasis-cppa-3.0-cpp:meta:cppa3", "naptr service for resource type as key:value properties separated with '|'. Ex edelivery-oasis-cppa3-extension:meta:cppa3  ",
             OPTIONAL, NOT_ENCRYPTED, NO_RESTART_NEEDED, MAP_STRING),
+    SML_DNS_ZONE("bdmsl.integration.dns.zone", "acc.edelivery.tech.ec.europa.eu", "DBS top domain or DNS zone. Data is used for DNS lookup of SMP domain",
+            OPTIONAL, NOT_ENCRYPTED, NO_RESTART_NEEDED, MAP_STRING),
+
     // keystore truststore
     KEYSTORE_PASSWORD("smp.keystore.password", "", "Encrypted keystore (and keys) password ",
             OPTIONAL, ENCRYPTED, NO_RESTART_NEEDED, STRING),
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CredentialResetRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CredentialResetRO.java
index 6d85e8a40..e07bdada1 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CredentialResetRO.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CredentialResetRO.java
@@ -30,7 +30,7 @@ import java.util.StringJoiner;
  */
 public class CredentialResetRO extends BaseRO {
 
-    private static final long serialVersionUID = 9008583888835630030L;
+    private static final long serialVersionUID = 9008583888835630031L;
 
     String credentialName;
     String credentialValue;
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DNSQueryRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DNSQueryRO.java
new file mode 100644
index 000000000..953e9cd69
--- /dev/null
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DNSQueryRO.java
@@ -0,0 +1,93 @@
+/*-
+ * #START_LICENSE#
+ * smp-server-library
+ * %%
+ * Copyright (C) 2017 - 2023 European Commission | eDelivery | DomiSMP
+ * %%
+ * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent
+ * versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ *
+ * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and limitations under the Licence.
+ * #END_LICENSE#
+ */
+package eu.europa.ec.edelivery.smp.data.ui;
+
+import eu.europa.ec.dynamicdiscovery.enums.DNSLookupType;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringJoiner;
+
+/**
+ * DNS query request object with DNS type and query string
+ *
+ * @since 5.1
+ */
+public class DNSQueryRO implements Serializable {
+
+    private static final long serialVersionUID = 9008583888835630032L;
+
+    private String dnsQuery;
+    private DNSLookupType dnsType;
+    private List<DNSRecord> dnsRecordEntries = new ArrayList<>();
+    private List<String> dnsErrors = new ArrayList<>();
+
+    public DNSQueryRO() {
+    }
+
+    public DNSQueryRO(String dnsQuery, DNSLookupType dnsType) {
+        this.dnsQuery = dnsQuery;
+        this.dnsType = dnsType;
+    }
+
+    public String getDnsQuery() {
+        return dnsQuery;
+    }
+
+    public void setDnsQuery(String dnsQuery) {
+        this.dnsQuery = dnsQuery;
+    }
+
+    public DNSLookupType getDnsType() {
+        return dnsType;
+    }
+
+    public void setDnsType(DNSLookupType dnsType) {
+        this.dnsType = dnsType;
+    }
+
+    public void addDnsRecordEntry(DNSRecord dnsRecord) {
+        dnsRecordEntries.add(dnsRecord);
+    }
+
+    public void addDnsRecordEntry(String domain, DNSLookupType type, String rawResult, String value) {
+        dnsRecordEntries.add(new DNSRecord(domain, type, rawResult, value));
+    }
+
+    public List<DNSRecord> getDnsEntries() {
+        return dnsRecordEntries;
+    }
+
+    public void addDnsError(String dnsError) {
+        dnsErrors.add(dnsError);
+    }
+
+    public List<String> getDnsErrors() {
+        return dnsErrors;
+    }
+
+    @Override
+    public String toString() {
+        return new StringJoiner(", ", DNSQueryRO.class.getSimpleName() + "[", "]")
+                .add("dnsQuery='" + dnsQuery + "'")
+                .add("dnsType=" + dnsType)
+                .toString();
+    }
+}
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DNSQueryRequestRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DNSQueryRequestRO.java
new file mode 100644
index 000000000..3c700695f
--- /dev/null
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DNSQueryRequestRO.java
@@ -0,0 +1,80 @@
+/*-
+ * #START_LICENSE#
+ * smp-server-library
+ * %%
+ * Copyright (C) 2017 - 2023 European Commission | eDelivery | DomiSMP
+ * %%
+ * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent
+ * versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ *
+ * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and limitations under the Licence.
+ * #END_LICENSE#
+ */
+package eu.europa.ec.edelivery.smp.data.ui;
+
+import java.io.Serializable;
+import java.util.StringJoiner;
+
+/**
+ * DNS query request object with DNS type and query string
+ *
+ * @since 5.1
+ */
+public class DNSQueryRequestRO implements Serializable {
+
+    private static final long serialVersionUID = 9008583888835630034L;
+
+    String identifierValue;
+    String identifierScheme;
+    String domainCode;
+    String topDnsDomain;
+
+    public String getIdentifierValue() {
+        return identifierValue;
+    }
+
+    public void setIdentifierValue(String identifierValue) {
+        this.identifierValue = identifierValue;
+    }
+
+    public String getIdentifierScheme() {
+        return identifierScheme;
+    }
+
+    public void setIdentifierScheme(String identifierScheme) {
+        this.identifierScheme = identifierScheme;
+    }
+
+    public String getDomainCode() {
+        return domainCode;
+    }
+
+    public void setDomainCode(String domainCode) {
+        this.domainCode = domainCode;
+    }
+
+    public String getTopDnsDomain() {
+        return topDnsDomain;
+    }
+
+    public void setTopDnsDomain(String topDnsDomain) {
+        this.topDnsDomain = topDnsDomain;
+    }
+
+    @Override
+    public String toString() {
+        return new StringJoiner(", ", DNSQueryRequestRO.class.getSimpleName() + "[", "]")
+                .add("identifierValue='" + identifierValue + "'")
+                .add("identifierScheme='" + identifierScheme + "'")
+                .add("domainCode='" + domainCode + "'")
+                .add("topDnsDomain='" + topDnsDomain + "'")
+                .toString();
+    }
+}
+
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DNSRecord.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DNSRecord.java
new file mode 100644
index 000000000..ab0abc1bb
--- /dev/null
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DNSRecord.java
@@ -0,0 +1,96 @@
+/*-
+ * #START_LICENSE#
+ * smp-server-library
+ * %%
+ * Copyright (C) 2017 - 2023 European Commission | eDelivery | DomiSMP
+ * %%
+ * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent
+ * versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ *
+ * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and limitations under the Licence.
+ * #END_LICENSE#
+ */
+package eu.europa.ec.edelivery.smp.data.ui;
+
+import eu.europa.ec.dynamicdiscovery.enums.DNSLookupType;
+
+import java.io.Serializable;
+import java.util.StringJoiner;
+
+/**
+ * DNS Record  with DNS type, raw  result string
+ *
+ * @since 5.1
+ */
+public class DNSRecord implements Serializable {
+
+    private static final long serialVersionUID = 9008583888835630033L;
+
+    DNSLookupType dnsType;
+    String dnsDomain;
+    String rawRecordResult;
+    String naptrService;
+    String value;
+
+    public DNSRecord() {
+    }
+
+    public DNSRecord(String dnsDomain, DNSLookupType dnsType, String rawRecordResult, String value) {
+        this(dnsDomain, dnsType, rawRecordResult, null, value);
+    }
+
+    public DNSRecord(String dnsDomain, DNSLookupType dnsType, String rawRecordResult, String naptrService, String value) {
+        this.dnsDomain = dnsDomain;
+        this.dnsType = dnsType;
+        this.rawRecordResult = rawRecordResult;
+        this.naptrService = naptrService;
+        this.value = value;
+    }
+
+    public String getNaptrService() {
+        return naptrService;
+    }
+
+    public void setNaptrService(String naptrService) {
+        this.naptrService = naptrService;
+    }
+
+    public DNSLookupType getDnsType() {
+        return dnsType;
+    }
+
+    public void setDnsType(DNSLookupType dnsType) {
+        this.dnsType = dnsType;
+    }
+
+    public String getRawRecordResult() {
+        return rawRecordResult;
+    }
+
+    public void setRawRecordResult(String rawRecordResult) {
+        this.rawRecordResult = rawRecordResult;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    @Override
+    public String toString() {
+        return new StringJoiner(", ", DNSRecord.class.getSimpleName() + "[", "]")
+                .add("dnsType=" + dnsType)
+                .add("rawRecordResult='" + rawRecordResult + "'")
+                .add("value='" + value + "'")
+                .toString();
+    }
+}
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorCode.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorCode.java
index 6efe2bb61..c6befd06b 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorCode.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorCode.java
@@ -76,7 +76,6 @@ public enum ErrorCode {
 
     // SML integration
     SML_INTEGRATION_EXCEPTION (500,"SMP:150",ErrorBusinessCode.TECHNICAL,"SML integration error! Error: %s "),
-    //
     XML_SIGNING_EXCEPTION (500,"SMP:500",ErrorBusinessCode.TECHNICAL,"Error occurred while signing response!"),
     JAXB_INITIALIZATION (500,"SMP:511",ErrorBusinessCode.TECHNICAL, "Could not create Unmarshaller for class [%s]!"),
     XML_PARSE_EXCEPTION (500,"SMP:512",ErrorBusinessCode.TECHNICAL, "Error occurred while parsing input stream for [%s].  Error: %s!"),
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDynamicDiscoveryTools.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDynamicDiscoveryTools.java
new file mode 100644
index 000000000..571deb8dd
--- /dev/null
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDynamicDiscoveryTools.java
@@ -0,0 +1,173 @@
+package eu.europa.ec.edelivery.smp.services.ui;
+
+import eu.europa.ec.dynamicdiscovery.core.locator.dns.IDNSLookup;
+import eu.europa.ec.dynamicdiscovery.core.locator.dns.impl.DefaultDNSLookup;
+import eu.europa.ec.dynamicdiscovery.core.locator.impl.DefaultBDXRLocator;
+import eu.europa.ec.dynamicdiscovery.enums.DNSLookupType;
+import eu.europa.ec.dynamicdiscovery.exception.TechnicalException;
+import eu.europa.ec.dynamicdiscovery.model.identifiers.SMPParticipantIdentifier;
+import eu.europa.ec.edelivery.smp.data.ui.DNSQueryRO;
+import eu.europa.ec.edelivery.smp.data.ui.DNSQueryRequestRO;
+import eu.europa.ec.edelivery.smp.data.ui.ResourceRO;
+import eu.europa.ec.edelivery.smp.exceptions.ErrorCode;
+import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException;
+import eu.europa.ec.edelivery.smp.logging.SMPLogger;
+import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
+import eu.europa.ec.edelivery.smp.services.spi.SmpIdentifierService;
+import eu.europa.ec.smp.spi.api.model.ResourceIdentifier;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.springframework.stereotype.Service;
+import org.xbill.DNS.CNAMERecord;
+import org.xbill.DNS.NAPTRRecord;
+import org.xbill.DNS.Record;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class provide dynamic discovery tools for UI.
+ *
+ * @author Joze Rihtarsic
+ * @since 5.0
+ */
+
+@Service
+public class UIDynamicDiscoveryTools {
+    private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UIDynamicDiscoveryTools.class);
+
+    private final SmpIdentifierService smpIdentifierService;
+
+    public UIDynamicDiscoveryTools(SmpIdentifierService smpIdentifierService) {
+        this.smpIdentifierService = smpIdentifierService;
+    }
+
+    /**
+     * Metod return DNS queries for given domain and resource identifier
+     *
+     * @return list of DNS queries
+     */
+    public List<DNSQueryRO> createDnsQueries(DNSQueryRequestRO dnsQueryRequest) {
+
+        String domainPrivate = StringUtils.trimToEmpty(dnsQueryRequest.getTopDnsDomain());
+        ResourceIdentifier identifier = smpIdentifierService.normalizeResourceIdentifier(dnsQueryRequest.getIdentifierValue(),
+                dnsQueryRequest.getIdentifierScheme());
+
+        SMPParticipantIdentifier participantIdentifier
+                = new SMPParticipantIdentifier(identifier.getValue(), identifier.getScheme());
+
+        // configure ddc client
+        DefaultDNSLookup testDNSLookup = new DefaultDNSLookup.Builder()
+                .build();
+        DefaultBDXRLocator bdxrLocator = new DefaultBDXRLocator.Builder()
+                .addTopDnsDomain(domainPrivate)
+                .dnsLookup(testDNSLookup).build();
+
+        List<DNSQueryRO> dnsLookupTypes = new ArrayList<>();
+        DNSQueryRO cnameResult = createDnsQuery(domainPrivate, participantIdentifier, bdxrLocator, DNSLookupType.CNAME);
+        DNSQueryRO naptrResult = createDnsQuery(domainPrivate, participantIdentifier, bdxrLocator, DNSLookupType.NAPTR);
+
+        dnsLookupTypes.add(cnameResult);
+        dnsLookupTypes.add(naptrResult);
+
+        return dnsLookupTypes;
+    }
+
+    /**
+     * Method creates CNAME DNS query and if domain is not empty it tries to resolve it.
+     * Method returns list of all resolved domains
+     *
+     * @param domain             the top dns domain/dns zone
+     * @param resourceIdentifier the resource identifier
+     * @param bdxrLocator        the bdxr locator
+     * @return the DNS query RO object
+     */
+    private DNSQueryRO createDnsQuery(String domain, SMPParticipantIdentifier resourceIdentifier,
+                                      DefaultBDXRLocator bdxrLocator,
+                                      DNSLookupType dnsLookupType) {
+
+        String dnsQuery ;
+        switch (dnsLookupType) {
+            case CNAME:
+                dnsQuery = bdxrLocator.buildCNameDNSQuery(resourceIdentifier, domain);
+                break;
+            case NAPTR:
+                dnsQuery = bdxrLocator.buildNaptrDNSQuery(resourceIdentifier, domain);
+                break;
+            default:
+                throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DNS Lookup", "Unknown DNS lookup type: " + dnsLookupType);
+        }
+
+        DNSQueryRO dnsQueryRO = new DNSQueryRO(dnsQuery,
+                dnsLookupType);
+
+        if (StringUtils.isNotBlank(domain)) {
+            switch (dnsLookupType) {
+                case CNAME:
+                    resolveCNameQuery(dnsQueryRO, resourceIdentifier, bdxrLocator);
+                    break;
+                case NAPTR:
+                    resolveNaptrQuery(dnsQueryRO, resourceIdentifier, bdxrLocator);
+                    break;
+            }
+        }
+        return dnsQueryRO;
+    }
+
+    /**
+     * Method resolve CNAME query and add results to DNS query object or add error message.
+     * Method is resolving all CNAMES in chain.
+     * @param dnsQuery the DNS query object to add results or errors
+     * @param resourceIdentifier the resource identifier for the query. Used for logging.
+     * @param bdxrLocator the bdxr locator tool to resolve DNS queries
+     */
+    public void resolveCNameQuery(DNSQueryRO dnsQuery, SMPParticipantIdentifier resourceIdentifier, DefaultBDXRLocator bdxrLocator){
+        IDNSLookup testDNSLookup = bdxrLocator.getDnsLookup();
+        try {
+            List<Record> result = testDNSLookup.getAllRecordsForType(resourceIdentifier, dnsQuery.getDnsQuery(), DNSLookupType.CNAME);
+            // cname is always expected only one
+            while (true) {
+                if (result != null && !result.isEmpty() && result.get(0).getType() == 5) {
+                    CNAMERecord record = (CNAMERecord) result.get(0);
+                    dnsQuery.addDnsRecordEntry(
+                            record.getName().toString(),
+                            DNSLookupType.CNAME,
+                            record.toString(),
+                            record.getTarget().toString());
+                    // follow resolution until CNAMe exists
+                    result = testDNSLookup.getAllRecordsForType(resourceIdentifier, record.getTarget().toString(), DNSLookupType.CNAME);
+                } else {
+                    break;
+                }
+            }
+        } catch (TechnicalException e) {
+            LOG.warn("Error during DNS lookup for CNAME record: [{}]", ExceptionUtils.getRootCauseMessage(e));
+            dnsQuery.addDnsError(ExceptionUtils.getRootCauseMessage(e));
+        }
+    }
+
+
+    /**
+     * Method resolve NAPTR query and add results to DNS query object or add error message
+     * @param dnsQuery the DNS query object to add results or errors
+     * @param resourceIdentifier the resource identifier for the query. Used for logging.
+     * @param bdxrLocator the bdxr locator tool to resolve DNS queries
+     */
+    public void resolveNaptrQuery(DNSQueryRO dnsQuery, SMPParticipantIdentifier resourceIdentifier, DefaultBDXRLocator bdxrLocator){
+        IDNSLookup testDNSLookup = bdxrLocator.getDnsLookup();
+        try {
+            List<Record> result = testDNSLookup.getAllRecordsForType(resourceIdentifier, dnsQuery.getDnsQuery(), DNSLookupType.NAPTR);
+            for (Record rec : result) {
+                NAPTRRecord record = (NAPTRRecord) rec;
+                dnsQuery.addDnsRecordEntry(
+                        record.getName().toString(),
+                        DNSLookupType.NAPTR,
+                        record.rdataToString(),
+                        record.getRegexp());
+            }
+        } catch (TechnicalException e) {
+            LOG.warn("Error during DNS lookup for NAPTR record: [{}]", e.getMessage());
+            dnsQuery.addDnsError(ExceptionUtils.getRootCauseMessage(e));
+        }
+    }
+}
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIDynamicDiscoveryToolsTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIDynamicDiscoveryToolsTest.java
new file mode 100644
index 000000000..bb40df580
--- /dev/null
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIDynamicDiscoveryToolsTest.java
@@ -0,0 +1,97 @@
+package eu.europa.ec.edelivery.smp.services.ui;
+
+import eu.europa.ec.edelivery.smp.data.ui.DNSQueryRO;
+import eu.europa.ec.edelivery.smp.data.ui.DNSQueryRequestRO;
+import eu.europa.ec.edelivery.smp.data.ui.ResourceRO;
+import eu.europa.ec.edelivery.smp.services.spi.SmpIdentifierService;
+import eu.europa.ec.smp.spi.PayloadValidatorSpi;
+import eu.europa.ec.smp.spi.api.model.ResourceIdentifier;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullAndEmptySource;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class UIDynamicDiscoveryToolsTest {
+
+    SmpIdentifierService mockIdentifierService = Mockito.mock(SmpIdentifierService.class);;
+    UIDynamicDiscoveryTools testInstance = new UIDynamicDiscoveryTools(mockIdentifierService);
+
+
+    /**
+     *  Test method tries to resolve DNS queries for given
+     *  participant identifier iso6523-actorid-upis::0007:001:oasis:eusend
+     *  on domain acc.edelivery.tech.ec.europa.eu.
+     *  For test to pass the data must be registered in the DNS server and build
+     *  server must have access to internet!
+     *
+     *  If the test fails, please check the eDelivery DNS server still contains
+     *  CNAME records
+     *  B-3c66f725f5d01a2de8c413d100da4bc9.iso6523-actorid-upis.test.acc.edelivery.tech.ec.europa.eu
+     *  NAPTR records
+     *  B3THMADDQQOBPZPE7CVM5PGD5UE4XHTPPGZZQRM4OH74P2HOSIBA.iso6523-actorid-upis.test.acc.edelivery.tech.ec.europa.eu
+     *  domain and resource identifier
+     *
+     */
+    @Test
+    void testGetDNSQuerySuccess() {
+        DNSQueryRequestRO request =createDNSQueryRequestRO("test.acc.edelivery.tech.ec.europa.eu");
+
+        Mockito.doReturn(new ResourceIdentifier(request.getIdentifierValue(), request.getIdentifierScheme()))
+                .when(mockIdentifierService).normalizeResourceIdentifier(Mockito.anyString(), Mockito.anyString());
+
+        List<DNSQueryRO> result = testInstance.createDnsQueries(request);
+
+        assertEquals( 2, result.size());
+        assertEquals( "B-3c66f725f5d01a2de8c413d100da4bc9.iso6523-actorid-upis.test.acc.edelivery.tech.ec.europa.eu", result.get(0).getDnsQuery());
+        assertNotEquals( 0, result.get(0).getDnsEntries().size());
+        assertEquals( "B3THMADDQQOBPZPE7CVM5PGD5UE4XHTPPGZZQRM4OH74P2HOSIBA.iso6523-actorid-upis.test.acc.edelivery.tech.ec.europa.eu", result.get(1).getDnsQuery());
+        assertNotEquals( 0, result.get(1).getDnsEntries().size());
+    }
+
+    @Test
+    void testGetDNSQueryDoesNotExists() {
+
+        DNSQueryRequestRO request =createDNSQueryRequestRO("domainNoExists.local");
+
+        Mockito.doReturn(new ResourceIdentifier(request.getIdentifierValue(), request.getIdentifierScheme()))
+                .when(mockIdentifierService).normalizeResourceIdentifier(Mockito.anyString(), Mockito.anyString());
+
+        List<DNSQueryRO> result = testInstance.createDnsQueries(request);
+
+        assertEquals( 2, result.size());
+        assertEquals( "B-3c66f725f5d01a2de8c413d100da4bc9.iso6523-actorid-upis.domainNoExists.local", result.get(0).getDnsQuery());
+        assertEquals( 0, result.get(0).getDnsEntries().size());
+        assertEquals( "B3THMADDQQOBPZPE7CVM5PGD5UE4XHTPPGZZQRM4OH74P2HOSIBA.iso6523-actorid-upis.domainNoExists.local", result.get(1).getDnsQuery());
+        assertEquals( 0, result.get(1).getDnsEntries().size());
+    }
+
+    @ParameterizedTest
+    @NullAndEmptySource
+    void testGetDNSQueryWithNullEmptyDomain(String domain) {
+        DNSQueryRequestRO request =createDNSQueryRequestRO(domain);
+
+        Mockito.doReturn(new ResourceIdentifier(request.getIdentifierValue(), request.getIdentifierScheme()))
+                .when(mockIdentifierService).normalizeResourceIdentifier(Mockito.anyString(), Mockito.anyString());
+
+        List<DNSQueryRO> result = testInstance.createDnsQueries(request);
+
+        assertEquals( 2, result.size());
+        assertEquals( "B-3c66f725f5d01a2de8c413d100da4bc9.iso6523-actorid-upis.", result.get(0).getDnsQuery());
+        assertEquals( 0, result.get(0).getDnsEntries().size());
+        assertEquals( "B3THMADDQQOBPZPE7CVM5PGD5UE4XHTPPGZZQRM4OH74P2HOSIBA.iso6523-actorid-upis.", result.get(1).getDnsQuery());
+        assertEquals( 0, result.get(1).getDnsEntries().size());
+    }
+
+    private DNSQueryRequestRO createDNSQueryRequestRO(String topDnsDomain) {
+        DNSQueryRequestRO dnsQueryRequestRO = new DNSQueryRequestRO();
+        dnsQueryRequestRO.setIdentifierScheme("iso6523-actorid-upis");
+        dnsQueryRequestRO.setIdentifierValue("0007:001:oasis:eusend");
+        dnsQueryRequestRO.setTopDnsDomain(topDnsDomain);
+        return dnsQueryRequestRO;
+    }
+}
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ResourceConstants.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ResourceConstants.java
index 69e900415..b946c238f 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ResourceConstants.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ResourceConstants.java
@@ -38,12 +38,14 @@ public class ResourceConstants {
     /**
      * Path resources
      */
+    private static final char URL_PATH_SEPARATOR = '/';
     public static final String PATH_RESOURCE_TYPE_DOMAIN = "domain";
     public static final String PATH_RESOURCE_TYPE_MEMBER = "member";
     public static final String PATH_RESOURCE_TYPE_GROUP = "group";
     public static final String PATH_RESOURCE_TYPE_RESOURCE = "resource";
     public static final String PATH_RESOURCE_TYPE_SUBRESOURCE = "subresource";
     public static final String PATH_RESOURCE_TYPE_DOCUMENT = "document";
+    public static final String PATH_RESOURCE_TYPE_PROPERTY = "property";
 
     public static final String PATH_RESOURCE_TYPE_RESOURCE_DEFINITION = "res-def";
     /**
@@ -71,7 +73,7 @@ public class ResourceConstants {
     public static final String PATH_ACTION_RESET_CREDENTIAL_REQUEST = "request-reset-credential";
     public static final String PATH_ACTION_RESET_CREDENTIAL = "reset-credential";
     public static final String PATH_ACTION_AUTHENTICATION = "authentication";
-
+    public static final String PATH_ACTION_GENERATE_DNS_QUERY = "generate-dns-query";
     public static final String PATH_ACTION_RETRIEVE = "retrieve";
     public static final String PATH_ACTION_SEARCH = "search";
     // --------------------------------------
@@ -80,60 +82,61 @@ public class ResourceConstants {
     public static final String CONTEXT_PATH_INTERNAL = "/ui/internal/rest/";
 
     public static final String CONTEXT_PATH_EDIT = "/ui/edit/rest/" + "{" + PATH_PARAM_ENC_USER_ID + "}";
-    public static final String CONTEXT_PATH_EDIT_DOMAIN = CONTEXT_PATH_EDIT + "/" + PATH_RESOURCE_TYPE_DOMAIN;
+    public static final String CONTEXT_PATH_EDIT_DOMAIN = CONTEXT_PATH_EDIT + URL_PATH_SEPARATOR + PATH_RESOURCE_TYPE_DOMAIN;
     public static final String SUB_CONTEXT_PATH_EDIT_DOMAIN_ADMIN = "{" + PATH_PARAM_ENC_DOMAIN_ID + "}";
-    public static final String SUB_CONTEXT_PATH_EDIT_DOMAIN_MEMBER = SUB_CONTEXT_PATH_EDIT_DOMAIN_ADMIN + "/" + PATH_RESOURCE_TYPE_MEMBER;
-    public static final String SUB_CONTEXT_PATH_EDIT_DOMAIN_MEMBER_PUT = SUB_CONTEXT_PATH_EDIT_DOMAIN_MEMBER + "/" + PATH_ACTION_PUT;
-    public static final String SUB_CONTEXT_PATH_EDIT_DOMAIN_MEMBER_DELETE = SUB_CONTEXT_PATH_EDIT_DOMAIN_MEMBER + "/"
-            + "{" + PATH_PARAM_ENC_MEMBER_ID + "}" + "/" +  PATH_ACTION_DELETE;
+    public static final String SUB_CONTEXT_PATH_EDIT_DOMAIN_MEMBER = SUB_CONTEXT_PATH_EDIT_DOMAIN_ADMIN + URL_PATH_SEPARATOR + PATH_RESOURCE_TYPE_MEMBER;
+    public static final String SUB_CONTEXT_PATH_EDIT_DOMAIN_MEMBER_PUT = SUB_CONTEXT_PATH_EDIT_DOMAIN_MEMBER + URL_PATH_SEPARATOR + PATH_ACTION_PUT;
+    public static final String SUB_CONTEXT_PATH_EDIT_DOMAIN_MEMBER_DELETE = SUB_CONTEXT_PATH_EDIT_DOMAIN_MEMBER + URL_PATH_SEPARATOR
+            + "{" + PATH_PARAM_ENC_MEMBER_ID + "}" + URL_PATH_SEPARATOR +  PATH_ACTION_DELETE;
 
     // domain edit data
-    public static final String SUB_CONTEXT_PATH_EDIT_DOMAIN_RESOURCE_DEF = SUB_CONTEXT_PATH_EDIT_DOMAIN_ADMIN + "/" + PATH_RESOURCE_TYPE_RESOURCE_DEFINITION;
+    public static final String SUB_CONTEXT_PATH_EDIT_DOMAIN_RESOURCE_DEF = SUB_CONTEXT_PATH_EDIT_DOMAIN_ADMIN + URL_PATH_SEPARATOR + PATH_RESOURCE_TYPE_RESOURCE_DEFINITION;
     // ------------------------------------------
     // group management
-    public static final String CONTEXT_PATH_EDIT_GROUP = CONTEXT_PATH_EDIT_DOMAIN + "/" +  SUB_CONTEXT_PATH_EDIT_DOMAIN_ADMIN
-            + "/"+ PATH_RESOURCE_TYPE_GROUP;
+    public static final String CONTEXT_PATH_EDIT_GROUP = CONTEXT_PATH_EDIT_DOMAIN + URL_PATH_SEPARATOR +  SUB_CONTEXT_PATH_EDIT_DOMAIN_ADMIN
+            + URL_PATH_SEPARATOR+ PATH_RESOURCE_TYPE_GROUP;
     public static final String SUB_CONTEXT_PATH_EDIT_GROUP_CREATE =  PATH_ACTION_CREATE;
-    public static final String SUB_CONTEXT_PATH_EDIT_GROUP_UPDATE =  "{" + PATH_PARAM_ENC_GROUP_ID + "}" + "/" +   PATH_ACTION_UPDATE;
-    public static final String SUB_CONTEXT_PATH_EDIT_GROUP_DELETE =  "{" + PATH_PARAM_ENC_GROUP_ID + "}" + "/" +  PATH_ACTION_DELETE;
-    public static final String SUB_CONTEXT_PATH_EDIT_GROUP_MEMBER =  "{" + PATH_PARAM_ENC_GROUP_ID + "}" + "/" +  PATH_RESOURCE_TYPE_MEMBER;
-    public static final String SUB_CONTEXT_PATH_EDIT_GROUP_MEMBER_PUT =  SUB_CONTEXT_PATH_EDIT_GROUP_MEMBER+ "/" +  PATH_ACTION_PUT;
-    public static final String SUB_CONTEXT_PATH_EDIT_GROUP_MEMBER_DELETE = SUB_CONTEXT_PATH_EDIT_GROUP_MEMBER + "/"
-            + "{" + PATH_PARAM_ENC_MEMBER_ID + "}" + "/" +  PATH_ACTION_DELETE;
-    public static final String CONTEXT_PATH_EDIT_RESOURCE = CONTEXT_PATH_EDIT_GROUP + "/" +  "{" + PATH_PARAM_ENC_GROUP_ID + "}"
-            + "/"+ PATH_RESOURCE_TYPE_RESOURCE;
+    public static final String SUB_CONTEXT_PATH_EDIT_GROUP_UPDATE =  "{" + PATH_PARAM_ENC_GROUP_ID + "}" + URL_PATH_SEPARATOR +   PATH_ACTION_UPDATE;
+    public static final String SUB_CONTEXT_PATH_EDIT_GROUP_DELETE =  "{" + PATH_PARAM_ENC_GROUP_ID + "}" + URL_PATH_SEPARATOR +  PATH_ACTION_DELETE;
+    public static final String SUB_CONTEXT_PATH_EDIT_GROUP_MEMBER =  "{" + PATH_PARAM_ENC_GROUP_ID + "}" + URL_PATH_SEPARATOR +  PATH_RESOURCE_TYPE_MEMBER;
+    public static final String SUB_CONTEXT_PATH_EDIT_GROUP_MEMBER_PUT =  SUB_CONTEXT_PATH_EDIT_GROUP_MEMBER+ URL_PATH_SEPARATOR +  PATH_ACTION_PUT;
+    public static final String SUB_CONTEXT_PATH_EDIT_GROUP_MEMBER_DELETE = SUB_CONTEXT_PATH_EDIT_GROUP_MEMBER + URL_PATH_SEPARATOR
+            + "{" + PATH_PARAM_ENC_MEMBER_ID + "}" + URL_PATH_SEPARATOR +  PATH_ACTION_DELETE;
+    public static final String CONTEXT_PATH_EDIT_RESOURCE = CONTEXT_PATH_EDIT_GROUP + URL_PATH_SEPARATOR +  "{" + PATH_PARAM_ENC_GROUP_ID + "}"
+            + URL_PATH_SEPARATOR+ PATH_RESOURCE_TYPE_RESOURCE;
     public static final String SUB_CONTEXT_PATH_EDIT_RESOURCE_CREATE =  PATH_ACTION_CREATE;
     public static final String SUB_CONTEXT_PATH_EDIT_RESOURCE_DELETE = "{" + PATH_PARAM_ENC_RESOURCE_ID + "}"
-            + "/"+ PATH_ACTION_DELETE;
+            + URL_PATH_SEPARATOR+ PATH_ACTION_DELETE;
     public static final String SUB_CONTEXT_PATH_EDIT_RESOURCE_UPDATE = "{" + PATH_PARAM_ENC_RESOURCE_ID + "}"
-            + "/"+ PATH_ACTION_UPDATE;
+            + URL_PATH_SEPARATOR+ PATH_ACTION_UPDATE;
 
-    public static final String SUB_CONTEXT_PATH_EDIT_RESOURCE_MEMBER =  "{" + PATH_PARAM_ENC_RESOURCE_ID + "}" + "/" +  PATH_RESOURCE_TYPE_MEMBER;
-    public static final String SUB_CONTEXT_PATH_EDIT_RESOURCE_MEMBER_PUT =  SUB_CONTEXT_PATH_EDIT_RESOURCE_MEMBER+ "/" +  PATH_ACTION_PUT;
-    public static final String SUB_CONTEXT_PATH_EDIT_RESOURCE_MEMBER_DELETE = SUB_CONTEXT_PATH_EDIT_RESOURCE_MEMBER + "/"
-            + "{" + PATH_PARAM_ENC_MEMBER_ID + "}" + "/" +  PATH_ACTION_DELETE;
+    public static final String SUB_CONTEXT_PATH_EDIT_RESOURCE_MEMBER =  "{" + PATH_PARAM_ENC_RESOURCE_ID + "}" + URL_PATH_SEPARATOR +  PATH_RESOURCE_TYPE_MEMBER;
+    public static final String SUB_CONTEXT_PATH_EDIT_RESOURCE_MEMBER_PUT =  SUB_CONTEXT_PATH_EDIT_RESOURCE_MEMBER+ URL_PATH_SEPARATOR +  PATH_ACTION_PUT;
+    public static final String SUB_CONTEXT_PATH_EDIT_RESOURCE_MEMBER_DELETE = SUB_CONTEXT_PATH_EDIT_RESOURCE_MEMBER + URL_PATH_SEPARATOR
+            + "{" + PATH_PARAM_ENC_MEMBER_ID + "}" + URL_PATH_SEPARATOR +  PATH_ACTION_DELETE;
 
 
-    public static final String CONTEXT_PATH_EDIT_RESOURCE_SHORT = CONTEXT_PATH_EDIT + "/" +PATH_RESOURCE_TYPE_RESOURCE +
-            "/" +  "{" + PATH_PARAM_ENC_RESOURCE_ID + "}";
+    public static final String CONTEXT_PATH_EDIT_RESOURCE_SHORT = CONTEXT_PATH_EDIT + URL_PATH_SEPARATOR +PATH_RESOURCE_TYPE_RESOURCE +
+            URL_PATH_SEPARATOR +  "{" + PATH_PARAM_ENC_RESOURCE_ID + "}";
 
-    public static final String CONTEXT_PATH_EDIT_SUBRESOURCE = CONTEXT_PATH_EDIT_RESOURCE_SHORT + "/" + PATH_RESOURCE_TYPE_SUBRESOURCE;
-    public static final String SUB_CONTEXT_PATH_EDIT_SUBRESOURCE_DELETE =  "{" + PATH_PARAM_ENC_SUBRESOURCE_ID + "}" + "/" +  PATH_ACTION_DELETE;
+    public static final String CONTEXT_PATH_EDIT_SUBRESOURCE = CONTEXT_PATH_EDIT_RESOURCE_SHORT + URL_PATH_SEPARATOR + PATH_RESOURCE_TYPE_SUBRESOURCE;
+    public static final String SUB_CONTEXT_PATH_EDIT_SUBRESOURCE_DELETE =  "{" + PATH_PARAM_ENC_SUBRESOURCE_ID + "}" + URL_PATH_SEPARATOR +  PATH_ACTION_DELETE;
 
-    public static final String CONTEXT_PATH_EDIT_DOCUMENT = CONTEXT_PATH_EDIT + "/" +PATH_RESOURCE_TYPE_RESOURCE +"/" + "{" + PATH_PARAM_ENC_RESOURCE_ID + "}";
+    public static final String CONTEXT_PATH_EDIT_DOCUMENT = CONTEXT_PATH_EDIT + URL_PATH_SEPARATOR +PATH_RESOURCE_TYPE_RESOURCE +URL_PATH_SEPARATOR + "{" + PATH_PARAM_ENC_RESOURCE_ID + "}";
     public static final String SUB_CONTEXT_PATH_EDIT_DOCUMENT_GET =  PATH_RESOURCE_TYPE_DOCUMENT;
-    public static final String SUB_CONTEXT_PATH_EDIT_DOCUMENT_VALIDATE =  SUB_CONTEXT_PATH_EDIT_DOCUMENT_GET +  "/" + PATH_ACTION_VALIDATE;
-    public static final String SUB_CONTEXT_PATH_EDIT_DOCUMENT_GENERATE =  SUB_CONTEXT_PATH_EDIT_DOCUMENT_GET +  "/" + PATH_ACTION_GENERATE;
+    public static final String SUB_CONTEXT_PATH_EDIT_DOCUMENT_VALIDATE =  SUB_CONTEXT_PATH_EDIT_DOCUMENT_GET +  URL_PATH_SEPARATOR + PATH_ACTION_VALIDATE;
+    public static final String SUB_CONTEXT_PATH_EDIT_DOCUMENT_GENERATE =  SUB_CONTEXT_PATH_EDIT_DOCUMENT_GET +  URL_PATH_SEPARATOR + PATH_ACTION_GENERATE;
 
-    public static final String SUB_CONTEXT_PATH_EDIT_DOCUMENT_GET_SUBRESOURCE = PATH_RESOURCE_TYPE_SUBRESOURCE +  "/" +  "{" + PATH_PARAM_ENC_SUBRESOURCE_ID + "}" +  "/" + PATH_RESOURCE_TYPE_DOCUMENT;
-    public static final String SUB_CONTEXT_PATH_EDIT_DOCUMENT_SUBRESOURCE_VALIDATE =  SUB_CONTEXT_PATH_EDIT_DOCUMENT_GET_SUBRESOURCE +  "/" + PATH_ACTION_VALIDATE;
-    public static final String SUB_CONTEXT_PATH_EDIT_DOCUMENT_SUBRESOURCE_GENERATE =  SUB_CONTEXT_PATH_EDIT_DOCUMENT_GET_SUBRESOURCE +  "/" + PATH_ACTION_GENERATE;
+    public static final String SUB_CONTEXT_PATH_EDIT_DOCUMENT_GET_SUBRESOURCE = PATH_RESOURCE_TYPE_SUBRESOURCE +  URL_PATH_SEPARATOR +  "{" + PATH_PARAM_ENC_SUBRESOURCE_ID + "}" +  URL_PATH_SEPARATOR + PATH_RESOURCE_TYPE_DOCUMENT;
+    public static final String SUB_CONTEXT_PATH_EDIT_DOCUMENT_SUBRESOURCE_VALIDATE =  SUB_CONTEXT_PATH_EDIT_DOCUMENT_GET_SUBRESOURCE +  URL_PATH_SEPARATOR + PATH_ACTION_VALIDATE;
+    public static final String SUB_CONTEXT_PATH_EDIT_DOCUMENT_SUBRESOURCE_GENERATE =  SUB_CONTEXT_PATH_EDIT_DOCUMENT_GET_SUBRESOURCE +  URL_PATH_SEPARATOR + PATH_ACTION_GENERATE;
     // public
-    public static final String CONTEXT_PATH_PUBLIC_SEARCH_PARTICIPANT = CONTEXT_PATH_PUBLIC + "search";
-    public static final String CONTEXT_PATH_PUBLIC_DOMAIN = CONTEXT_PATH_PUBLIC + "domain";
+    public static final String CONTEXT_PATH_PUBLIC_SEARCH_PARTICIPANT = CONTEXT_PATH_PUBLIC + PATH_ACTION_SEARCH;
+    public static final String CONTEXT_PATH_PUBLIC_DOMAIN = CONTEXT_PATH_PUBLIC + PATH_RESOURCE_TYPE_DOMAIN;
     public static final String CONTEXT_PATH_PUBLIC_APPLICATION = CONTEXT_PATH_PUBLIC + "application";
     public static final String CONTEXT_PATH_PUBLIC_USER = CONTEXT_PATH_PUBLIC + "user";
     public static final String CONTEXT_PATH_PUBLIC_TRUSTSTORE = CONTEXT_PATH_PUBLIC + "truststore";
+    public static final String CONTEXT_PATH_PUBLIC_DNS_TOOLS = CONTEXT_PATH_PUBLIC + "dns-tools";
 
     public static final String CONTEXT_PATH_PUBLIC_SECURITY = CONTEXT_PATH_PUBLIC + "security";
     public static final String CONTEXT_PATH_PUBLIC_SECURITY_AUTHENTICATION = CONTEXT_PATH_PUBLIC_SECURITY + "/authentication";
@@ -141,15 +144,14 @@ public class ResourceConstants {
 
     //internal
     public static final String CONTEXT_PATH_INTERNAL_ALERT = CONTEXT_PATH_INTERNAL + "alert";
-    public static final String CONTEXT_PATH_INTERNAL_DOMAIN = CONTEXT_PATH_INTERNAL + "domain";
-    public static final String CONTEXT_PATH_INTERNAL_PROPERTY = CONTEXT_PATH_INTERNAL + "property";
+    public static final String CONTEXT_PATH_INTERNAL_DOMAIN = CONTEXT_PATH_INTERNAL + PATH_RESOURCE_TYPE_DOMAIN;
+    public static final String CONTEXT_PATH_INTERNAL_PROPERTY = CONTEXT_PATH_INTERNAL + PATH_RESOURCE_TYPE_PROPERTY;
     public static final String CONTEXT_PATH_INTERNAL_APPLICATION = CONTEXT_PATH_INTERNAL + "application";
     public static final String CONTEXT_PATH_INTERNAL_USER = CONTEXT_PATH_INTERNAL + "user";
     public static final String CONTEXT_PATH_INTERNAL_EXTENSION = CONTEXT_PATH_INTERNAL + "extension";
     public static final String CONTEXT_PATH_INTERNAL_KEYSTORE = CONTEXT_PATH_INTERNAL + "keystore";
     public static final String CONTEXT_PATH_INTERNAL_TRUSTSTORE = CONTEXT_PATH_INTERNAL + "truststore";
 
-
     // --------------------------------------
     // parameters
     public static final String PARAM_PAGINATION_PAGE = "page";
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/DNSToolsController.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/DNSToolsController.java
new file mode 100644
index 000000000..889b31815
--- /dev/null
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/DNSToolsController.java
@@ -0,0 +1,43 @@
+package eu.europa.ec.edelivery.smp.ui.external;
+
+
+import eu.europa.ec.edelivery.smp.data.ui.DNSQueryRO;
+import eu.europa.ec.edelivery.smp.data.ui.DNSQueryRequestRO;
+import eu.europa.ec.edelivery.smp.logging.SMPLogger;
+import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
+import eu.europa.ec.edelivery.smp.services.ui.UIDynamicDiscoveryTools;
+import org.springframework.util.MimeTypeUtils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.CONTEXT_PATH_PUBLIC_DNS_TOOLS;
+import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.PATH_ACTION_GENERATE_DNS_QUERY;
+
+/**
+ * Controller for the DNS tools. The dns tools help users to test, debug and troubleshoot DNS issues.
+ *
+ * @since 5.1
+ */
+@RestController
+@RequestMapping(value = CONTEXT_PATH_PUBLIC_DNS_TOOLS)
+public class DNSToolsController {
+    private static final SMPLogger LOG = SMPLoggerFactory.getLogger(DNSToolsController.class);
+
+    UIDynamicDiscoveryTools uiDynamicDiscoveryTools;
+
+    public DNSToolsController(UIDynamicDiscoveryTools uiDynamicDiscoveryTools) {
+        this.uiDynamicDiscoveryTools = uiDynamicDiscoveryTools;
+    }
+
+    @PostMapping(path = PATH_ACTION_GENERATE_DNS_QUERY,
+            produces = {MimeTypeUtils.APPLICATION_JSON_VALUE},
+            consumes = {MimeTypeUtils.APPLICATION_JSON_VALUE})
+    public List<DNSQueryRO> getDnsQueryList(@RequestBody DNSQueryRequestRO resourceRO) {
+        LOG.debug("Received request to generate DNS queries: {}", resourceRO);
+        return uiDynamicDiscoveryTools.createDnsQueries(resourceRO);
+    }
+}
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/UserController.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/UserController.java
index 9213164a1..a6c0e81e7 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/UserController.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/UserController.java
@@ -196,7 +196,7 @@ public class UserController {
     public AccessTokenRO generateAccessTokenCredential(@PathVariable(PATH_PARAM_ENC_USER_ID) String encUserId,
                                                        @PathVariable("credential-id") String encAccessTokenId,
                                                        @RequestBody CredentialRO credentialRO) {
-        LOG.debug("Update User [{}] access token credential: [{}]", encUserId, encAccessTokenId);
+        LOG.debug("Generate User [{}] access token credential: [{}]", encUserId, encAccessTokenId);
         Long userId = decryptEntityId(encUserId);
         return uiUserService.createAccessTokenForUser(userId, credentialRO);
     }
@@ -231,7 +231,7 @@ public class UserController {
     public CredentialRO updateCertificateCredential(@PathVariable(PATH_PARAM_ENC_USER_ID) String encUserId,
                                                     @PathVariable("credential-id") String encCredentialId,
                                                     @RequestBody CredentialRO credentialRO) {
-        LOG.debug("Update User [{}] access token credential: [{}]", encUserId, encCredentialId);
+        LOG.debug("Update User [{}] certificate credential: [{}]", encUserId, encCredentialId);
         Long userId = decryptEntityId(encUserId);
         Long credentialId = decryptEntityId(encCredentialId);
         // delete user credential
@@ -249,7 +249,7 @@ public class UserController {
     @GetMapping(path = "/{user-id}/certificate-credential/{credential-id}")
     public CredentialRO getCertificateCredential(@PathVariable(PATH_PARAM_ENC_USER_ID) String encUserId,
                                                  @PathVariable("credential-id") String encCredentialId) {
-        LOG.debug("Update User [{}] access token credential: [{}]", encUserId, encCredentialId);
+        LOG.debug("get User [{}] certificate credential: [{}]", encUserId, encCredentialId);
         Long userId = decryptEntityId(encUserId);
         Long credentialId = decryptEntityId(encCredentialId);
         return uiUserService.getUserCertificateCredential(userId, credentialId);
@@ -260,7 +260,7 @@ public class UserController {
     public CredentialRO storeCertificateCredential(@PathVariable(PATH_PARAM_ENC_USER_ID) String encUserId,
                                                    @PathVariable("credential-id") String credentialId,
                                                    @RequestBody CredentialRO credentialRO) {
-        LOG.debug("Store credential for user [{}] certificate  credential: [{}]", encUserId, credentialId);
+        LOG.debug("Store credential for user [{}] certificate credential: [{}]", encUserId, credentialId);
         Long userId = decryptEntityId(encUserId);
         return uiUserService.storeCertificateCredentialForUser(userId, credentialRO);
     }
@@ -298,7 +298,7 @@ public class UserController {
     protected NavigationTreeNodeRO createPublicNavigationTreeNode() {
         NavigationTreeNodeRO node = new NavigationTreeNodeRO("search-tools", "Search", "search", "public");
         node.addChild(new NavigationTreeNodeRO("search-resources", "Resources", "find_in_page", "search-resource", "Search registered resources"));
-        //node.addChild(new NavigationTreeNodeRO("search-lookup", "DNS lookup", "dns", "dns-lookup" , "DNS lookup tools"));
+        node.addChild(new NavigationTreeNodeRO("dns-tools", "DNS tools", "dns", "dns-tools" , "DNS lookup tools"));
         return node;
     }
 
-- 
GitLab