diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000000..8893889f67
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,62 @@
+# Include any files or directories that you don't want to be copied to your
+# container here (e.g., local build artifacts, temporary files, etc.).
+#
+# For more help, visit the .dockerignore file reference guide at
+# https://docs.docker.com/go/build-context-dockerignore/
+
+**/.DS_Store
+**/.classpath
+**/.dockerignore
+**/.env
+**/.factorypath
+**/.git
+**/.gitignore
+**/.idea
+**/.project
+**/.sts4-cache
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/.next
+**/.cache
+**/*.dbmdl
+**/*.jfm
+**/charts
+**/docker-compose*
+**/compose.y*ml
+**/Dockerfile*
+**/secrets.dev.yaml
+**/values.dev.yaml
+**/vendor
+LICENSE
+README.md
+**/*.class
+**/*.iml
+**/*.ipr
+**/*.iws
+**/*.log
+**/.apt_generated
+**/.gradle
+**/.gradletasknamecache
+**/.nb-gradle
+**/.springBeans
+**/build
+**/dist
+**/gradle-app.setting
+**/nbbuild
+**/nbdist
+**/nbproject/private
+**/target
+*.ctxt
+.mtj.tmp
+.mvn/timing.properties
+buildNumber.properties
+dependency-reduced-pom.xml
+hs_err_pid*
+pom.xml.next
+pom.xml.releaseBackup
+pom.xml.tag
+pom.xml.versionsBackup
+release.properties
+replay_pid*
\ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000..dfdb8b771c
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+*.sh text eol=lf
diff --git a/.gitignore b/.gitignore
index 9dcfd64acf..b24f194ca2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,12 @@
hs_err_pid*
replay_pid*
+##############################
+## Javascript
+##############################
+node_modules/
+.env
+
##############################
## Maven
##############################
diff --git a/DEVELOPERS.md b/DEVELOPERS.md
new file mode 100644
index 0000000000..5899876971
--- /dev/null
+++ b/DEVELOPERS.md
@@ -0,0 +1,33 @@
+# For developers and contributors
+
+## "Easy Path" with docker
+
+```bash
+# Build using docker
+docker build -t oie-dev .
+# Start an ephemeral image
+# NOTE: All data will be deleted on stop due to --rm. Use a volume for "real" use.
+docker run --rm -p 8443:8443 oie-dev
+```
+
+Then use [Ballista](https://github.com/kayyagari/ballista) to connect to
+https://localhost:8443/ and login using admin admin.
+
+## Build Environment
+
+To build the solution, you must have a Java 1.8 JDK+FX and Apache Ant. This
+can be installed by [sdkman](https://sdkman.io/) by executing `sdkman env install`.
+
+## Build Process
+
+From the `server/` directory, run `ant -f mirth-build.xml -DdisableSigning=true`.
+
+If you are using Mirth Connect Administrator Launcher, you may need to omit
+`-DdisableSigning=true` to support JWS signatures. Launchers like
+[Ballista](https://github.com/kayyagari/ballista) do not require signing, and
+signing adds considerable time to the build process.
+
+## Run
+
+After build, run the server by invoking `server/mirth-server-launcher.jar`. An
+example of how to do this is listed in `docker/mirth-connect.sh`.
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000..77efc2e024
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,87 @@
+# syntax=docker/dockerfile:1.7-labs
+
+# Stages:
+# 1. Builder Stage: Compiles the application and resolves dependencies. Produces
+# JAR files that can be deployed.
+# 1a. Install dependencies
+# 1b. Build the application
+# 2. Runner Stage: Creates a lightweight image that runs the application using the JRE.
+
+FROM ubuntu:noble-20250415.1 AS builder
+WORKDIR /app
+# sdkman requires bash
+SHELL ["/bin/bash", "-c"]
+
+# Stage 1a: Install dependencies
+# Install necessary tools
+COPY .sdkmanrc .
+RUN apt-get update\
+ && apt-get install -y zip curl\
+ && curl -s "https://get.sdkman.io?ci=true" | bash \
+ && source "$HOME/.sdkman/bin/sdkman-init.sh" && sdk env install \
+ && rm -rf /var/lib/apt/lists/*
+
+# Stage 1b: Build the application
+# Copy the entire source tree (excluding .dockerignore files), and build
+COPY --exclude=docker . .
+WORKDIR /app/server
+RUN source "$HOME/.sdkman/bin/sdkman-init.sh" \
+ && ANT_OPTS="-Dfile.encoding=UTF8" ant -f mirth-build.xml -DdisableSigning=true
+
+# Stage 2b: JDK runtime container
+FROM eclipse-temurin:21.0.7_6-jdk-noble as jdk-run
+
+RUN groupadd mirth \
+ && usermod -l mirth ubuntu \
+ && adduser mirth mirth \
+ && mkdir -p /opt/connect/appdata \
+ && chown -R mirth:mirth /opt/connect
+
+WORKDIR /opt/connect
+COPY --chmod=0755 docker/entrypoint.sh docker/mirth-connect.sh ./
+COPY --chown=mirth:mirth --from=builder \
+ --exclude=cli-lib \
+ --exclude=mirth-cli-launcher.jar \
+ --exclude=mccommand \
+ --exclude=manager-lib \
+ --exclude=mirth-manager-launcher.jar \
+ --exclude=mcmanager \
+ /app/server/setup ./
+
+VOLUME /opt/connect/appdata
+VOLUME /opt/connect/custom-extensions
+EXPOSE 8443
+
+USER mirth
+ENTRYPOINT [ "/opt/connect/entrypoint.sh" ]
+CMD ["/opt/connect/mirth-connect.sh"]
+
+# Stage 2b: JRE runtime container
+FROM eclipse-temurin:21.0.7_6-jre-alpine as jre-run
+
+# Alpine does not include bash by default, so we install it
+RUN apk add --no-cache bash
+# useradd and groupadd are not available in Alpine
+RUN addgroup -S mirth \
+ && adduser -S -g mirth mirth \
+ && mkdir -p /opt/connect/appdata \
+ && chown -R mirth:mirth /opt/connect
+
+WORKDIR /opt/connect
+COPY --chmod=0755 docker/entrypoint.sh docker/mirth-connect.sh ./
+COPY --chown=mirth:mirth --from=builder \
+ --exclude=cli-lib \
+ --exclude=mirth-cli-launcher.jar \
+ --exclude=mccommand \
+ --exclude=manager-lib \
+ --exclude=mirth-manager-launcher.jar \
+ --exclude=mcmanager \
+ /app/server/setup ./
+
+VOLUME /opt/connect/appdata
+VOLUME /opt/connect/custom-extensions
+EXPOSE 8443
+
+USER mirth
+ENTRYPOINT [ "/opt/connect/entrypoint.sh" ]
+CMD ["/opt/connect/mirth-connect.sh"]
diff --git a/README.md b/README.md
index d5272e8c81..ce5e6f82c5 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,7 @@
---
## Table of Contents
+- [Quick-start](#quick-start)
- [Mission Statement](#mission-statement)
- [Overview](#overview)
- [Why Open Integration Engine?](#why-open-integration-engine)
@@ -19,6 +20,12 @@
- [Licensing](#licensing)
- [Acknowledgments](#acknowledgments)
+---
+## Quick-start
+
+Start an instance of OIE with `docker run -p 8443:8443 ghcr.io/mgaffigan/oie` and
+connect using [Ballista](https://github.com/kayyagari/ballista) to https://localhost:8443/ using login admin/admin.
+
---
## Mission Statement
diff --git a/connectservice/.dockerignore b/connectservice/.dockerignore
new file mode 100644
index 0000000000..a4bf05a8de
--- /dev/null
+++ b/connectservice/.dockerignore
@@ -0,0 +1,4 @@
+node_modules/
+docker-compose.yml
+test.http
+Readme.md
diff --git a/connectservice/Dockerfile b/connectservice/Dockerfile
new file mode 100644
index 0000000000..ba6a83fc20
--- /dev/null
+++ b/connectservice/Dockerfile
@@ -0,0 +1,11 @@
+FROM node:18
+WORKDIR /app
+
+COPY package*.json ./
+RUN npm install
+
+COPY . .
+
+EXPOSE 3000
+USER 1000
+CMD ["npm", "run", "start"]
diff --git a/connectservice/Readme.md b/connectservice/Readme.md
new file mode 100644
index 0000000000..367dbe529d
--- /dev/null
+++ b/connectservice/Readme.md
@@ -0,0 +1,21 @@
+# Connect Service
+
+Connect Service is a sample implementation of a web service which records usage
+of Mirth Server, and provides access to a notifications feed. The service implements
+the operations called by the client in `ConnectServiceUtil.java`.
+
+## Running and testing
+
+To start the example, run `docker-compose build` in this directory, followed by
+`docker-compose up -d`. You can use `http://localhost:3000` as `URL_CONNECT_SERVER`
+in `ConnectServiceUtil.java`, and see recorded data
+[in Kibana.](http://localhost:5601/app/management/data/index_management/indices/index_details?indexName=registration)
+
+## Not fit for production use as-is
+
+This example is purely for expository purposes only. Use as-is is not recommended.
+At a minimum, it would be neccesary to:
+
+- Use a reverse proxy to encrypt in-transit data
+- Secure communication between the connectservice and elasticsearch
+- Require authentication for elasticsearch and kibana
diff --git a/connectservice/docker-compose.yml b/connectservice/docker-compose.yml
new file mode 100644
index 0000000000..915d8c00c4
--- /dev/null
+++ b/connectservice/docker-compose.yml
@@ -0,0 +1,36 @@
+name: connectservice
+
+volumes:
+ connectservice_elastic_data: {}
+
+services:
+ elasticsearch:
+ image: docker.elastic.co/elasticsearch/elasticsearch:9.0.1
+ environment:
+ - discovery.type=single-node
+ # Don't do this in prod.
+ - xpack.security.enabled=false
+ ports:
+ - "9200:9200"
+ volumes:
+ - connectservice_elastic_data:/usr/share/elasticsearch/data
+
+ connectservice:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ environment:
+ - ELASTICSEARCH_URL=http://elasticsearch:9200
+ ports:
+ - "3000:3000"
+ depends_on:
+ - elasticsearch
+
+ kibana:
+ image: docker.elastic.co/kibana/kibana:9.0.1
+ ports:
+ - "5601:5601"
+ environment:
+ - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
+ depends_on:
+ - elasticsearch
diff --git a/connectservice/elastic.js b/connectservice/elastic.js
new file mode 100644
index 0000000000..9f63637beb
--- /dev/null
+++ b/connectservice/elastic.js
@@ -0,0 +1,13 @@
+import { Client } from '@elastic/elasticsearch';
+
+export const client = new Client({
+ node: process.env.ELASTICSEARCH_URL || 'http://localhost:9200',
+ auth: process.env.ELASTICSEARCH_USERNAME ? {
+ username: process.env.ELASTICSEARCH_USERNAME,
+ password: process.env.ELASTICSEARCH_PASSWORD || 'changeme',
+ } : undefined,
+ tls: {
+ rejectUnauthorized: process.env.ELASTICSEARCH_IGNORETLSERRORS && !!JSON.parse(process.env.ELASTICSEARCH_IGNORETLSERRORS),
+ },
+ requestTimeout: process.env.ELASTICSEARCH_TIMEOUT ? JSON.parse(process.env.ELASTICSEARCH_TIMEOUT) : 30000,
+});
diff --git a/connectservice/github.js b/connectservice/github.js
new file mode 100644
index 0000000000..6374bcc5bb
--- /dev/null
+++ b/connectservice/github.js
@@ -0,0 +1,31 @@
+const REPO_URL = process.env.NOTIFICATIONS_URL ?? 'https://api.github.com/repos/OpenIntegrationEngine/engine/releases?per_page=10';
+
+export async function getLatestReleases() {
+ const response = await fetch(REPO_URL, {
+ headers: {
+ 'Accept': 'application/vnd.github.html+json',
+ 'User-Agent': 'OIEConnectService',
+ },
+ });
+
+ if (!response.ok) {
+ throw new Error(`Failed to fetch latest release: ${response.statusText}`);
+ }
+
+ const releases = await response.json();
+ return releases.map(release => ({
+ id: release.id,
+ name: release.name,
+ body_html: release.body_html,
+ published_at: release.published_at,
+ }));
+}
+
+/*
+interface Release {
+ id: number;
+ name: string;
+ body_html: string;
+ published_at: string;
+}
+*/
diff --git a/connectservice/index.js b/connectservice/index.js
new file mode 100644
index 0000000000..ce9f1daea4
--- /dev/null
+++ b/connectservice/index.js
@@ -0,0 +1,50 @@
+import express from 'express';
+import * as yup from 'yup';
+import { postRegistration, postUsage, registrationBodySchema, usageBodySchema } from './usage.js';
+import { postNotifications, notificationBodySchema } from './notifications.js';
+
+const app = express();
+
+app.use(express.urlencoded({ extended: true }));
+
+app.post('/RegistrationServlet', [validateFormUrlEncoded, makeValidator(registrationBodySchema)], postRegistration);
+app.post('/UsageStatisticsServlet', [validateFormUrlEncoded, makeValidator(usageBodySchema)], postUsage);
+
+app.post('/NotificationServlet', [validateFormUrlEncoded, makeValidator(notificationBodySchema)], postNotifications);
+
+const port = process.env.PORT || 3000;
+app.listen(port, () =>
+ console.log(`connectservice available from http://localhost:${port}`),
+);
+
+function validateFormUrlEncoded(req, res, next) {
+ const contentType = req.headers['content-type'];
+ if (!contentType || !contentType.startsWith('application/x-www-form-urlencoded')) {
+ return res.status(415).send('Unsupported content-type');
+ }
+
+ next();
+}
+
+function makeValidator(schema) {
+ return async (req, res, next) => {
+ try {
+ // abortEarly: false collects all errors rather than stopping on the first
+ await schema.validate(req.body, { abortEarly: false });
+ next();
+ } catch (error) {
+ if (error instanceof yup.ValidationError) {
+ return res.status(400).json({
+ type: error.name,
+ message: error.message,
+ errors: error.inner.map(err => ({
+ path: err.path,
+ message: err.message,
+ type: err.type,
+ })),
+ });
+ }
+ next(error);
+ }
+ };
+}
diff --git a/connectservice/notifications.js b/connectservice/notifications.js
new file mode 100644
index 0000000000..e1c0deed95
--- /dev/null
+++ b/connectservice/notifications.js
@@ -0,0 +1,78 @@
+import * as yup from 'yup';
+import { getLatestReleases } from './github.js';
+
+export async function postNotifications(req, res) {
+ const notifications = await getLatestReleases();
+
+ if (req.body.op === 'getNotificationCount') {
+ return res.status(200).json(notifications.map(rel => rel.id));
+ } else if (req.body.op === 'getNotifications') {
+ return res.status(200).json(notifications.map(rel => ({
+ id: rel.id,
+ name: rel.name,
+ content: makeFullPageFromDiv(rel.body_html, rel.name),
+ date: rel.published_at,
+ })));
+ } else {
+ return res.status(400).json({
+ error: 'Invalid operation',
+ });
+ }
+}
+
+function makeFullPageFromDiv(div, name) {
+ name = htmlEncode(name);
+ return `
+
+ ${name}
+
+
+
+
+
+ ${name}
+
+ ${div}
+
+
+
+`;
+}
+
+function htmlEncode(text) {
+ return text
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''');
+}
+
+/*
+POST https://connect.mirthcorp.com/NotificationServlet HTTP/1.1
+Content-Type: application/x-www-form-urlencoded; charset=UTF-8
+User-Agent: Apache-HttpClient/4.5.13 (Java/21.0.7)
+Host: connect.mirthcorp.com
+Content-Length: 2116
+
+op=getNotificationCount&serverId=49885e13-4f2e-41a6-b66a-8e65f5492d9a&version=4.5.2&extensionVersions=url_encode_json
+*/
+export const notificationBodySchema = yup.object({
+ op: yup.string().oneOf(['getNotificationCount', 'getNotifications']).required(),
+ serverId: yup.string().required(),
+ version: yup.string().required(),
+ extensionVersions: yup.string().required(),
+}).required();
+
+/*
+extensionVersions is a JSON object with the version of each extension:
+{
+ "Server Log":"4.5.2",
+ "File Writer":"4.5.2",
+ ...
+}
+*/
diff --git a/connectservice/package-lock.json b/connectservice/package-lock.json
new file mode 100644
index 0000000000..b0c0b40d9c
--- /dev/null
+++ b/connectservice/package-lock.json
@@ -0,0 +1,1226 @@
+{
+ "name": "connectservice",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "connectservice",
+ "version": "1.0.0",
+ "license": "MPL-2.0",
+ "dependencies": {
+ "@elastic/elasticsearch": "^9.0.2",
+ "express": "^5.1.0",
+ "xml2js": "^0.6.2",
+ "yup": "^1.6.1"
+ }
+ },
+ "node_modules/@elastic/elasticsearch": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/@elastic/elasticsearch/-/elasticsearch-9.0.2.tgz",
+ "integrity": "sha512-uKA0PuPSND3OhHH9UFqnKZfxifAg/8mQW4VnrQ+sUtusTbPhGuErs5NeWCPyd/RLgruBWBmLSv1zzEv5GS+UnA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@elastic/transport": "^9.0.1",
+ "apache-arrow": "18.x - 19.x",
+ "tslib": "^2.4.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@elastic/transport": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/@elastic/transport/-/transport-9.0.1.tgz",
+ "integrity": "sha512-6jVZQzAe2iTRsZA6I/wkO2BjzJFD9BHTASo2YgGfbcoV95ey/8D/ABRhpgfg35LIDrmialIGJBizunSwxsRDLg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/api": "1.x",
+ "debug": "^4.4.0",
+ "hpagent": "^1.2.0",
+ "ms": "^2.1.3",
+ "secure-json-parse": "^3.0.2",
+ "tslib": "^2.8.1",
+ "undici": "^7.2.3"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@opentelemetry/api": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
+ "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/@swc/helpers": {
+ "version": "0.5.17",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz",
+ "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.8.0"
+ }
+ },
+ "node_modules/@types/command-line-args": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.2.3.tgz",
+ "integrity": "sha512-uv0aG6R0Y8WHZLTamZwtfsDLVRnOa+n+n5rEvFWL5Na5gZ8V2Teab/duDPFzIIIhs9qizDpcavCusCLJZu62Kw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/command-line-usage": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.4.tgz",
+ "integrity": "sha512-BwR5KP3Es/CSht0xqBcUXS3qCAUVXwpRKsV2+arxeb65atasuXG9LykC9Ab10Cw3s2raH92ZqOeILaQbsB2ACg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "20.17.57",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.57.tgz",
+ "integrity": "sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ==",
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.19.2"
+ }
+ },
+ "node_modules/accepts": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
+ "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "^3.0.0",
+ "negotiator": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/apache-arrow": {
+ "version": "19.0.1",
+ "resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-19.0.1.tgz",
+ "integrity": "sha512-APmMLzS4qbTivLrPdQXexGM4JRr+0g62QDaobzEvip/FdQIrv2qLy0mD5Qdmw4buydtVJgbFeKR8f59I6PPGDg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@swc/helpers": "^0.5.11",
+ "@types/command-line-args": "^5.2.3",
+ "@types/command-line-usage": "^5.0.4",
+ "@types/node": "^20.13.0",
+ "command-line-args": "^6.0.1",
+ "command-line-usage": "^7.0.1",
+ "flatbuffers": "^24.3.25",
+ "json-bignum": "^0.0.3",
+ "tslib": "^2.6.2"
+ },
+ "bin": {
+ "arrow2csv": "bin/arrow2csv.js"
+ }
+ },
+ "node_modules/array-back": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz",
+ "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.17"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
+ "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "^3.1.2",
+ "content-type": "^1.0.5",
+ "debug": "^4.4.0",
+ "http-errors": "^2.0.0",
+ "iconv-lite": "^0.6.3",
+ "on-finished": "^2.4.1",
+ "qs": "^6.14.0",
+ "raw-body": "^3.0.0",
+ "type-is": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chalk-template": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz",
+ "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==",
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.1.2"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk-template?sponsor=1"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "license": "MIT"
+ },
+ "node_modules/command-line-args": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-6.0.1.tgz",
+ "integrity": "sha512-Jr3eByUjqyK0qd8W0SGFW1nZwqCaNCtbXjRo2cRJC1OYxWl3MZ5t1US3jq+cO4sPavqgw4l9BMGX0CBe+trepg==",
+ "license": "MIT",
+ "dependencies": {
+ "array-back": "^6.2.2",
+ "find-replace": "^5.0.2",
+ "lodash.camelcase": "^4.3.0",
+ "typical": "^7.2.0"
+ },
+ "engines": {
+ "node": ">=12.20"
+ },
+ "peerDependencies": {
+ "@75lb/nature": "latest"
+ },
+ "peerDependenciesMeta": {
+ "@75lb/nature": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/command-line-usage": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.3.tgz",
+ "integrity": "sha512-PqMLy5+YGwhMh1wS04mVG44oqDsgyLRSKJBdOo1bnYhMKBW65gZF1dRp2OZRhiTjgUHljy99qkO7bsctLaw35Q==",
+ "license": "MIT",
+ "dependencies": {
+ "array-back": "^6.2.2",
+ "chalk-template": "^0.4.0",
+ "table-layout": "^4.1.0",
+ "typical": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
+ "node_modules/content-disposition": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
+ "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
+ "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.6.0"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "license": "MIT"
+ },
+ "node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "license": "MIT"
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
+ "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "^2.0.0",
+ "body-parser": "^2.2.0",
+ "content-disposition": "^1.0.0",
+ "content-type": "^1.0.5",
+ "cookie": "^0.7.1",
+ "cookie-signature": "^1.2.1",
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "finalhandler": "^2.1.0",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "merge-descriptors": "^2.0.0",
+ "mime-types": "^3.0.0",
+ "on-finished": "^2.4.1",
+ "once": "^1.4.0",
+ "parseurl": "^1.3.3",
+ "proxy-addr": "^2.0.7",
+ "qs": "^6.14.0",
+ "range-parser": "^1.2.1",
+ "router": "^2.2.0",
+ "send": "^1.1.0",
+ "serve-static": "^2.2.0",
+ "statuses": "^2.0.1",
+ "type-is": "^2.0.1",
+ "vary": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
+ "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "on-finished": "^2.4.1",
+ "parseurl": "^1.3.3",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/find-replace": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-5.0.2.tgz",
+ "integrity": "sha512-Y45BAiE3mz2QsrN2fb5QEtO4qb44NcS7en/0y9PEVsg351HsLeVclP8QPMH79Le9sH3rs5RSwJu99W0WPZO43Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "@75lb/nature": "latest"
+ },
+ "peerDependenciesMeta": {
+ "@75lb/nature": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/flatbuffers": {
+ "version": "24.12.23",
+ "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-24.12.23.tgz",
+ "integrity": "sha512-dLVCAISd5mhls514keQzmEG6QHmUUsNuWsb4tFafIUwvvgDjXhtfAYSKOzt5SWOy+qByV5pbsDZ+Vb7HUOBEdA==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+ "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/hpagent": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz",
+ "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-promise": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
+ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
+ "license": "MIT"
+ },
+ "node_modules/json-bignum": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/json-bignum/-/json-bignum-0.0.3.tgz",
+ "integrity": "sha512-2WHyXj3OfHSgNyuzDbSxI1w2jgw5gkWSWhS7Qg4bWXx1nLk3jnbwfUeS0PSba3IzpTUWdHxBieELUzXRjQB2zg==",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
+ "license": "MIT"
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
+ "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
+ "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/negotiator": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
+ "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz",
+ "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/property-expr": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz",
+ "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==",
+ "license": "MIT"
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "license": "MIT",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
+ "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.6.3",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/router": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
+ "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "depd": "^2.0.0",
+ "is-promise": "^4.0.0",
+ "parseurl": "^1.3.3",
+ "path-to-regexp": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
+ "node_modules/sax": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
+ "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
+ "license": "ISC"
+ },
+ "node_modules/secure-json-parse": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-3.0.2.tgz",
+ "integrity": "sha512-H6nS2o8bWfpFEV6U38sOSjS7bTbdgbCGU9wEM6W14P5H0QOsz94KCusifV44GpHDTu2nqZbuDNhTzu+mjDSw1w==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fastify"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fastify"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/send": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
+ "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.5",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "mime-types": "^3.0.1",
+ "ms": "^2.1.3",
+ "on-finished": "^2.4.1",
+ "range-parser": "^1.2.1",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/serve-static": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
+ "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "parseurl": "^1.3.3",
+ "send": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "license": "ISC"
+ },
+ "node_modules/side-channel": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/table-layout": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-4.1.1.tgz",
+ "integrity": "sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==",
+ "license": "MIT",
+ "dependencies": {
+ "array-back": "^6.2.2",
+ "wordwrapjs": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=12.17"
+ }
+ },
+ "node_modules/tiny-case": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
+ "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==",
+ "license": "MIT"
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/toposort": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
+ "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==",
+ "license": "MIT"
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
+ "node_modules/type-fest": {
+ "version": "2.19.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
+ "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
+ "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
+ "license": "MIT",
+ "dependencies": {
+ "content-type": "^1.0.5",
+ "media-typer": "^1.1.0",
+ "mime-types": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/typical": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/typical/-/typical-7.3.0.tgz",
+ "integrity": "sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.17"
+ }
+ },
+ "node_modules/undici": {
+ "version": "7.10.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.10.0.tgz",
+ "integrity": "sha512-u5otvFBOBZvmdjWLVW+5DAc9Nkq8f24g0O9oY7qw2JVIF1VocIFoyz9JFkuVOS2j41AufeO0xnlweJ2RLT8nGw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.18.1"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "6.19.8",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
+ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
+ "license": "MIT"
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/wordwrapjs": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.0.tgz",
+ "integrity": "sha512-JNjcULU2e4KJwUNv6CHgI46UvDGitb6dGryHajXTDiLgg1/RiGoPSDw4kZfYnwGtEXf2ZMeIewDQgFGzkCB2Sg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.17"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "license": "ISC"
+ },
+ "node_modules/xml2js": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
+ "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==",
+ "license": "MIT",
+ "dependencies": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~11.0.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/xmlbuilder": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/yup": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/yup/-/yup-1.6.1.tgz",
+ "integrity": "sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA==",
+ "license": "MIT",
+ "dependencies": {
+ "property-expr": "^2.0.5",
+ "tiny-case": "^1.0.3",
+ "toposort": "^2.0.2",
+ "type-fest": "^2.19.0"
+ }
+ }
+ }
+}
diff --git a/connectservice/package.json b/connectservice/package.json
new file mode 100644
index 0000000000..d7dafff773
--- /dev/null
+++ b/connectservice/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "connectservice",
+ "version": "1.0.0",
+ "description": "Example statistics and notification service",
+ "main": "index.js",
+ "type": "module",
+ "scripts": {
+ "start": "node index.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/OpenIntegrationEngine/engine.git"
+ },
+ "author": "",
+ "license": "MPL-2.0",
+ "bugs": {
+ "url": "https://github.com/OpenIntegrationEngine/engine/issues"
+ },
+ "homepage": "https://github.com/OpenIntegrationEngine/engine#readme",
+ "dependencies": {
+ "@elastic/elasticsearch": "^9.0.2",
+ "express": "^5.1.0",
+ "xml2js": "^0.6.2",
+ "yup": "^1.6.1"
+ }
+}
diff --git a/connectservice/test.http b/connectservice/test.http
new file mode 100644
index 0000000000..ffd6012b86
--- /dev/null
+++ b/connectservice/test.http
@@ -0,0 +1,43 @@
+---
+POST http://localhost:3000/NotificationServlet HTTP/1.1
+Content-Type: application/x-www-form-urlencoded; charset=UTF-8
+User-Agent: Apache-HttpClient/4.5.13 (Java/21.0.7)
+
+op=getNotificationCount&serverId=49885e13-4f2e-41a6-b66a-8e65f5492d9a&version=4.5.2&extensionVersions=%7B%22Server+Log%22%3A%224.5.2%22%2C%22File+Writer%22%3A%224.5.2%22%2C%22Delimited+Data+Type%22%3A%224.5.2%22%2C%22HTTP+Sender%22%3A%224.5.2%22%2C%22HTTP+Authentication+Settings%22%3A%224.5.2%22%2C%22Image+Viewer%22%3A%224.5.2%22%2C%22Data+Pruner%22%3A%224.5.2%22%2C%22Database+Writer%22%3A%224.5.2%22%2C%22TCP+Sender%22%3A%224.5.2%22%2C%22JavaScript+Filter+Rule%22%3A%224.5.2%22%2C%22Channel+Reader%22%3A%224.5.2%22%2C%22Mapper+Transformer+Step%22%3A%224.5.2%22%2C%22JMS+Listener%22%3A%224.5.2%22%2C%22Message+Builder+Transformer+Step%22%3A%224.5.2%22%2C%22DICOM+Sender%22%3A%224.5.2%22%2C%22External+Script+Transformer+Step%22%3A%224.5.2%22%2C%22External+Script+Filter+Step%22%3A%224.5.2%22%2C%22File+Reader%22%3A%224.5.2%22%2C%22HTTP+Listener%22%3A%224.5.2%22%2C%22DICOM+Listener%22%3A%224.5.2%22%2C%22TCP+Connector+Service+Plugin%22%3A%224.5.2%22%2C%22JavaScript+Reader%22%3A%224.5.2%22%2C%22JSON+Data+Type%22%3A%224.5.2%22%2C%22JavaScript+Writer%22%3A%224.5.2%22%2C%22Web+Service+Sender%22%3A%224.5.2%22%2C%22Text+Viewer%22%3A%224.5.2%22%2C%22XML+Data+Type%22%3A%224.5.2%22%2C%22HL7v2+Data+Type%22%3A%224.5.2%22%2C%22Raw+Data+Type%22%3A%224.5.2%22%2C%22DICOM+Data+Type%22%3A%224.5.2%22%2C%22Destination+Set+Filter+Step%22%3A%224.5.2%22%2C%22Document+Writer%22%3A%224.5.2%22%2C%22Web+Service+Listener%22%3A%224.5.2%22%2C%22HL7v3+Data+Type%22%3A%224.5.2%22%2C%22JavaScript+Transformer+Step%22%3A%224.5.2%22%2C%22Dashboard+Connector+Status+Monitor%22%3A%224.5.2%22%2C%22DICOM+Viewer%22%3A%224.5.2%22%2C%22Directory+Resource+Plugin%22%3A%224.5.2%22%2C%22SMTP+Sender%22%3A%224.5.2%22%2C%22NCPDP+Data+Type%22%3A%224.5.2%22%2C%22Transmission+Mode+-+MLLP%22%3A%224.5.2%22%2C%22Rule+Builder+Filter+Rule%22%3A%224.5.2%22%2C%22Channel+Writer%22%3A%224.5.2%22%2C%22TCP+Listener%22%3A%224.5.2%22%2C%22Database+Reader%22%3A%224.5.2%22%2C%22PDF+Viewer%22%3A%224.5.2%22%2C%22EDI+Data+Type%22%3A%224.5.2%22%2C%22Global+Map+Viewer%22%3A%224.5.2%22%2C%22XSLT+Transformer+Step%22%3A%224.5.2%22%2C%22JMS+Sender%22%3A%224.5.2%22%7D
+---
+POST https://connect.mirthcorp.com/NotificationServlet HTTP/1.1
+Content-Type: application/x-www-form-urlencoded; charset=UTF-8
+User-Agent: Apache-HttpClient/4.5.13 (Java/21.0.7)
+
+op=getNotifications&serverId=49885e13-4f2e-41a6-b66a-8e65f5492d9a&version=4.4.0&extensionVersions=%7B%22Server+Log%22%3A%224.5.2%22%2C%22File+Writer%22%3A%224.5.2%22%2C%22Delimited+Data+Type%22%3A%224.5.2%22%2C%22HTTP+Sender%22%3A%224.5.2%22%2C%22HTTP+Authentication+Settings%22%3A%224.5.2%22%2C%22Image+Viewer%22%3A%224.5.2%22%2C%22Data+Pruner%22%3A%224.5.2%22%2C%22Database+Writer%22%3A%224.5.2%22%2C%22TCP+Sender%22%3A%224.5.2%22%2C%22JavaScript+Filter+Rule%22%3A%224.5.2%22%2C%22Channel+Reader%22%3A%224.5.2%22%2C%22Mapper+Transformer+Step%22%3A%224.5.2%22%2C%22JMS+Listener%22%3A%224.5.2%22%2C%22Message+Builder+Transformer+Step%22%3A%224.5.2%22%2C%22DICOM+Sender%22%3A%224.5.2%22%2C%22External+Script+Transformer+Step%22%3A%224.5.2%22%2C%22External+Script+Filter+Step%22%3A%224.5.2%22%2C%22File+Reader%22%3A%224.5.2%22%2C%22HTTP+Listener%22%3A%224.5.2%22%2C%22DICOM+Listener%22%3A%224.5.2%22%2C%22TCP+Connector+Service+Plugin%22%3A%224.5.2%22%2C%22JavaScript+Reader%22%3A%224.5.2%22%2C%22JSON+Data+Type%22%3A%224.5.2%22%2C%22JavaScript+Writer%22%3A%224.5.2%22%2C%22Web+Service+Sender%22%3A%224.5.2%22%2C%22Text+Viewer%22%3A%224.5.2%22%2C%22XML+Data+Type%22%3A%224.5.2%22%2C%22HL7v2+Data+Type%22%3A%224.5.2%22%2C%22Raw+Data+Type%22%3A%224.5.2%22%2C%22DICOM+Data+Type%22%3A%224.5.2%22%2C%22Destination+Set+Filter+Step%22%3A%224.5.2%22%2C%22Document+Writer%22%3A%224.5.2%22%2C%22Web+Service+Listener%22%3A%224.5.2%22%2C%22HL7v3+Data+Type%22%3A%224.5.2%22%2C%22JavaScript+Transformer+Step%22%3A%224.5.2%22%2C%22Dashboard+Connector+Status+Monitor%22%3A%224.5.2%22%2C%22DICOM+Viewer%22%3A%224.5.2%22%2C%22Directory+Resource+Plugin%22%3A%224.5.2%22%2C%22SMTP+Sender%22%3A%224.5.2%22%2C%22NCPDP+Data+Type%22%3A%224.5.2%22%2C%22Transmission+Mode+-+MLLP%22%3A%224.5.2%22%2C%22Rule+Builder+Filter+Rule%22%3A%224.5.2%22%2C%22Channel+Writer%22%3A%224.5.2%22%2C%22TCP+Listener%22%3A%224.5.2%22%2C%22Database+Reader%22%3A%224.5.2%22%2C%22PDF+Viewer%22%3A%224.5.2%22%2C%22EDI+Data+Type%22%3A%224.5.2%22%2C%22Global+Map+Viewer%22%3A%224.5.2%22%2C%22XSLT+Transformer+Step%22%3A%224.5.2%22%2C%22JMS+Sender%22%3A%224.5.2%22%7D
+---
+POST http://localhost:3000/RegistrationServlet
+Content-Type: application/x-www-form-urlencoded; charset=UTF-8
+User-Agent: Apache-HttpClient/4.5.13 (Java/21.0.7)
+
+serverId=49885e13-4f2e-41a6-b66a-8e65f5492d9a&version=4.5.2&user=%3Cuser%3E%0A++%3Cid%3E1%3C%2Fid%3E%0A++%3Cusername%3Eadmin%3C%2Fusername%3E%0A++%3Cemail%3Eadmin%40local%3C%2Femail%3E%0A++%3CfirstName%3Eadmin%3C%2FfirstName%3E%0A++%3ClastName%3Eadmin%3C%2FlastName%3E%0A++%3Corganization%3Eadmin%3C%2Forganization%3E%0A++%3Cdescription%3Easdg%3C%2Fdescription%3E%0A++%3CphoneNumber%3E%2B1+219-707-6210%3C%2FphoneNumber%3E%0A++%3Cindustry%3EClinic%3C%2Findustry%3E%0A++%3ClastLogin%3E%0A++++%3Ctime%3E1748811423800%3C%2Ftime%3E%0A++++%3Ctimezone%3EEtc%2FUTC%3C%2Ftimezone%3E%0A++%3C%2FlastLogin%3E%0A++%3CstrikeCount%3E0%3C%2FstrikeCount%3E%0A++%3Ccountry%3EUnited+States%3C%2Fcountry%3E%0A++%3Crole%3EConsultant+-+Engineer%3C%2Frole%3E%0A++%3CuserConsent%3Etrue%3C%2FuserConsent%3E%0A%3C%2Fuser%3E
+---
+POST http://localhost:3000/UsageStatisticsServlet
+Content-Type: application/x-www-form-urlencoded; charset=UTF-8
+User-Agent: Apache-HttpClient/4.5.13 (Java/21.0.7)
+
+serverId=49885e13-4f2e-41a6-b66a-8e65f5492d9a&version=4.5.2&server=true&data=%7B%22mirthVersion%22%3A%224.5.2%22%2C%22serverId%22%3A%2249885e13-4f2e-41a6-b66a-8e65f5492d9a%22%2C%22databaseType%22%3A%22derby%22%2C%22serverSpecs%22%3A%7B%22availableProcessors%22%3A16%2C%22osVersion%22%3A%225.15.167.4-microsoft-standard-WSL2%22%2C%22javaVersion%22%3A%2221.0.7%22%2C%22osName%22%3A%22Linux%22%2C%22maxMemory%22%3A268435456%7D%2C%22clientSpecs%22%3A%7B%7D%2C%22globalScripts%22%3A%7B%22deployLines%22%3A3%2C%22preprocessorLines%22%3A3%2C%22undeployLines%22%3A4%2C%22postprocessorLines%22%3A5%7D%2C%22channels%22%3A%5B%5D%2C%22invalidChannels%22%3A0%2C%22codeTemplateLibraries%22%3A%5B%5D%2C%22alerts%22%3A%5B%5D%2C%22plugins%22%3A%5B%7B%22pluginPoint%22%3A%22Server+Log%22%7D%2C%7B%22pluginPoint%22%3A%22DELIMITED%22%7D%2C%7B%22pluginPoint%22%3A%22XML%22%7D%2C%7B%22pluginPoint%22%3A%22HTTP+Auth+Service+Plugin%22%7D%2C%7B%22pluginPoint%22%3A%22HL7V2%22%7D%2C%7B%22pluginPoint%22%3A%22Data+Pruner%22%7D%2C%7B%22pluginPoint%22%3A%22RAW%22%7D%2C%7B%22pluginPoint%22%3A%22DICOM%22%7D%2C%7B%22pluginPoint%22%3A%22HL7V3%22%7D%2C%7B%22pluginPoint%22%3A%22Dashboard+Connector+Status+Service%22%7D%2C%7B%22pluginPoint%22%3A%22Directory+Resource%22%7D%2C%7B%22pluginPoint%22%3A%22NCPDP%22%7D%2C%7B%22pluginPoint%22%3A%22MLLP%22%7D%2C%7B%22pluginPoint%22%3A%22TCP+Service+Plugin%22%7D%2C%7B%22pluginPoint%22%3A%22JSON%22%7D%2C%7B%22pluginPoint%22%3A%22EDI%2FX12%22%7D%2C%7B%22pluginPoint%22%3A%22Global+Maps%22%7D%5D%2C%22pluginMetaData%22%3A%5B%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.serverlog.ServerLogProvider%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.serverlog.ServerLogClient%22%2C%22weight%22%3A120%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Server+Log%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.textviewer.TextViewer%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Text+Viewer%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.delimited.DelimitedDataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.delimited.DelimitedDataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Delimited+Data+Type%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.xml.XMLDataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.xml.XMLDataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22XML+Data+Type%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.httpauth.HttpAuthServicePlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.httpauth.HttpAuthConnectorPropertiesPlugin%22%2C%22weight%22%3A-100%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22HTTP+Authentication+Settings%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.imageviewer.ImageViewer%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Image+Viewer%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.hl7v2.HL7v2DataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.hl7v2.HL7v2DataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22HL7v2+Data+Type%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datapruner.DataPrunerService%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datapruner.DataPrunerClient%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Data+Pruner%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.raw.RawDataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.raw.RawDataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Raw+Data+Type%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.dicom.DICOMDataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.dicom.DICOMDataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22DICOM+Data+Type%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.destinationsetfilter.DestinationSetFilterPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Destination+Set+Filter+Step%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.hl7v3.HL7V3DataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.hl7v3.HL7V3DataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22HL7v3+Data+Type%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.javascriptrule.JavaScriptRulePlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22JavaScript+Filter+Rule%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.mapper.MapperStepPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Mapper+Transformer+Step%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.javascriptstep.JavaScriptStepPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22JavaScript+Transformer+Step%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.messagebuilder.MessageBuilderPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Message+Builder+Transformer+Step%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.dashboardstatus.DashboardConnectorStatusMonitor%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.dashboardstatus.DashboardConnectorStatusColumn%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%2C%7B%22name%22%3A%22com.mirth.connect.plugins.dashboardstatus.DashboardConnectorStatusClient%22%2C%22weight%22%3A110%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Dashboard+Connector+Status+Monitor%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.dicomviewer.DICOMViewer%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22DICOM+Viewer%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.scriptfilestep.ExternalScriptStepPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22External+Script+Transformer+Step%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.directoryresource.DirectoryResourcePlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.directoryresource.DirectoryResourceClientPlugin%22%2C%22weight%22%3A110%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Directory+Resource+Plugin%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.scriptfilerule.ExternalScriptRulePlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22External+Script+Filter+Step%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.ncpdp.NCPDPDataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.ncpdp.NCPDPDataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22NCPDP+Data+Type%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.mllpmode.MLLPModeProvider%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.mllpmode.MLLPModePlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Transmission+Mode+-+MLLP%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.rulebuilder.RuleBuilderPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Rule+Builder+Filter+Rule%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.connectors.tcp.TcpServicePlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.connectors.tcp.TcpClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22TCP+Connector+Service+Plugin%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.json.JSONDataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.json.JSONDataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22JSON+Data+Type%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.pdfviewer.PDFViewer%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22PDF+Viewer%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.edi.EDIDataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.edi.EDIDataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22EDI+Data+Type%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.globalmapviewer.GlobalMapProvider%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.globalmapviewer.GlobalMapClient%22%2C%22weight%22%3A100%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Global+Map+Viewer%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.xsltstep.XsltStepPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22XSLT+Transformer+Step%22%7D%5D%2C%22connectorMetaData%22%3A%5B%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22smtp%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.smtp.SmtpDispatcher%22%2C%22name%22%3A%22SMTP+Sender%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.smtp.SmtpSender%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.smtp.SmtpDispatcherProperties%22%7D%2C%7B%22transformers%22%3Anull%2C%22protocol%22%3A%22file%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.file.FileDispatcher%22%2C%22name%22%3A%22File+Writer%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.file.FileWriter%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.file.FileDispatcherProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22http%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.http.HttpDispatcher%22%2C%22name%22%3A%22HTTP+Sender%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.http.HttpSender%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.http.HttpDispatcherProperties%22%7D%2C%7B%22transformers%22%3Anull%2C%22protocol%22%3A%22file%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.file.FileReceiver%22%2C%22name%22%3A%22File+Reader%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.file.FileReader%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.file.FileReceiverProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22http%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.http.HttpReceiver%22%2C%22name%22%3A%22HTTP+Listener%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.http.HttpListener%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.http.HttpReceiverProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22dicom%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.dimse.DICOMReceiver%22%2C%22name%22%3A%22DICOM+Listener%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.dimse.DICOMListener%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.dimse.DICOMReceiverProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22vm%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.vm.VmDispatcher%22%2C%22name%22%3A%22Channel+Writer%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.vm.ChannelWriter%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.vm.VmDispatcherProperties%22%7D%2C%7B%22transformers%22%3A%22ResultMapToXML%22%2C%22protocol%22%3A%22js%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.js.JavaScriptReceiver%22%2C%22name%22%3A%22JavaScript+Reader%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.js.JavaScriptReader%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.js.JavaScriptReceiverProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22tcp%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.tcp.TcpReceiver%22%2C%22name%22%3A%22TCP+Listener%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.tcp.TcpListener%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.tcp.TcpReceiverProperties%22%7D%2C%7B%22transformers%22%3Anull%2C%22protocol%22%3A%22jdbc%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.jdbc.DatabaseReceiver%22%2C%22name%22%3A%22Database+Reader%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.jdbc.DatabaseReader%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.jdbc.DatabaseReceiverProperties%22%7D%2C%7B%22transformers%22%3Anull%2C%22protocol%22%3A%22jdbc%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.jdbc.DatabaseDispatcher%22%2C%22name%22%3A%22Database+Writer%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.jdbc.DatabaseWriter%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.jdbc.DatabaseDispatcherProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22doc%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.doc.DocumentDispatcher%22%2C%22name%22%3A%22Document+Writer%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.doc.DocumentWriter%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.doc.DocumentDispatcherProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22ws%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.ws.WebServiceReceiver%22%2C%22name%22%3A%22Web+Service+Listener%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.ws.WebServiceListener%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.ws.WebServiceReceiverProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22tcp%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.tcp.TcpDispatcher%22%2C%22name%22%3A%22TCP+Sender%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.tcp.TcpSender%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.tcp.TcpDispatcherProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22js%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.js.JavaScriptDispatcher%22%2C%22name%22%3A%22JavaScript+Writer%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.js.JavaScriptWriter%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.js.JavaScriptDispatcherProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22vm%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.vm.VmReceiver%22%2C%22name%22%3A%22Channel+Reader%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.vm.ChannelReader%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.vm.VmReceiverProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22ws%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.ws.WebServiceDispatcher%22%2C%22name%22%3A%22Web+Service+Sender%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.ws.WebServiceSender%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.ws.WebServiceDispatcherProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22jms%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.jms.JmsDispatcher%22%2C%22name%22%3A%22JMS+Sender%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.jms.JmsSender%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.jms.JmsDispatcherProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22jms%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.jms.JmsReceiver%22%2C%22name%22%3A%22JMS+Listener%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.jms.JmsListener%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.jms.JmsReceiverProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22dicom%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.dimse.DICOMDispatcher%22%2C%22name%22%3A%22DICOM+Sender%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.dimse.DICOMSender%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.dimse.DICOMDispatcherProperties%22%7D%5D%2C%22serverSettings%22%3A%7B%22clearGlobalMap%22%3Atrue%2C%22smtpTimeout%22%3A%225000%22%2C%22smtpAuth%22%3Afalse%2C%22defaultMetaDataColumns%22%3A%5B%7B%22type%22%3A%22STRING%22%7D%2C%7B%22type%22%3A%22STRING%22%7D%5D%2C%22defaultAdministratorBackgroundColor%22%3A%7B%22red%22%3A158%2C%22green%22%3A177%2C%22blue%22%3A201%2C%22alpha%22%3A255%2C%22rgb%22%3A-6377015%2C%22colorSpace%22%3A%7B%22type%22%3A5%2C%22numComponents%22%3A3%2C%22profile%22%3A%7B%22matrix%22%3A%5B%5B0.43585205%2C0.3853302%2C0.14302063%5D%2C%5B0.22238159%2C0.717041%2C0.06059265%5D%2C%5B0.013916016%2C0.09713745%2C0.71383667%5D%5D%2C%22mediaWhitePoint%22%3A%5B0.95014954%2C1.0%2C1.0882568%5D%2C%22numComponents%22%3A3%2C%22colorSpaceType%22%3A5%2C%22profileClass%22%3A1%2C%22pcstype%22%3A0%2C%22majorVersion%22%3A2%2C%22minorVersion%22%3A48%2C%22data%22%3A%22AAAa3GxjbXMCMAAAbW50clJHQiBYWVogB9YADAAcABIABwAWYWNzcE1TRlQAAAAAbGNtcwAAAAAAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1sY21zAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALZG1uZAAAAQgAAABqZGVzYwAAAXQAAABoZG1kZAAAAdwAAABod3RwdAAAAkQAAAAUclhZWgAAAlgAAAAUYlhZWgAAAmwAAAAUZ1hZWgAAAoAAAAAUclRSQwAAApQAAAgMZ1RSQwAACqAAAAgMYlRSQwAAEqwAAAgMY2hybQAAGrgAAAAkZGVzYwAAAAAAAAAQKGxjbXMgaW50ZXJuYWwpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAOc1JHQiBidWlsdC1pbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkZXNjAAAAAAAAAA5zUkdCIGJ1aWx0LWluAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAADzPQABAAAAARaYWFlaIAAAAAAAAG%2BUAAA47gAAA5BYWVogAAAAAAAAJJ0AAA%2BDAAC2vlhZWiAAAAAAAABipQAAt5AAABjeY3VydgAAAAAAAAQAAAAABQAKAA8AFAAZAB4AIwAoAC0AMgA3ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACBAIYAiwCQAJUAmgCfAKQAqQCuALIAtwC8AMEAxgDLANAA1QDbAOAA5QDrAPAA9gD7AQEBBwENARMBGQEfASUBKwEyATgBPgFFAUwBUgFZAWABZwFuAXUBfAGDAYsBkgGaAaEBqQGxAbkBwQHJAdEB2QHhAekB8gH6AgMCDAIUAh0CJgIvAjgCQQJLAlQCXQJnAnECegKEAo4CmAKiAqwCtgLBAssC1QLgAusC9QMAAwsDFgMhAy0DOANDA08DWgNmA3IDfgOKA5YDogOuA7oDxwPTA%2BAD7AP5BAYEEwQgBC0EOwRIBFUEYwRxBH4EjASaBKgEtgTEBNME4QTwBP4FDQUcBSsFOgVJBVgFZwV3BYYFlgWmBbUFxQXVBeUF9gYGBhYGJwY3BkgGWQZqBnsGjAadBq8GwAbRBuMG9QcHBxkHKwc9B08HYQd0B4YHmQesB78H0gflB%2FgICwgfCDIIRghaCG4IggiWCKoIvgjSCOcI%2BwkQCSUJOglPCWQJeQmPCaQJugnPCeUJ%2BwoRCicKPQpUCmoKgQqYCq4KxQrcCvMLCwsiCzkLUQtpC4ALmAuwC8gL4Qv5DBIMKgxDDFwMdQyODKcMwAzZDPMNDQ0mDUANWg10DY4NqQ3DDd4N%2BA4TDi4OSQ5kDn8Omw62DtIO7g8JDyUPQQ9eD3oPlg%2BzD88P7BAJECYQQxBhEH4QmxC5ENcQ9RETETERTxFtEYwRqhHJEegSBxImEkUSZBKEEqMSwxLjEwMTIxNDE2MTgxOkE8UT5RQGFCcUSRRqFIsUrRTOFPAVEhU0FVYVeBWbFb0V4BYDFiYWSRZsFo8WshbWFvoXHRdBF2UXiReuF9IX9xgbGEAYZRiKGK8Y1Rj6GSAZRRlrGZEZtxndGgQaKhpRGncanhrFGuwbFBs7G2MbihuyG9ocAhwqHFIcexyjHMwc9R0eHUcdcB2ZHcMd7B4WHkAeah6UHr4e6R8THz4faR%2BUH78f6iAVIEEgbCCYIMQg8CEcIUghdSGhIc4h%2ByInIlUigiKvIt0jCiM4I2YjlCPCI%2FAkHyRNJHwkqyTaJQklOCVoJZclxyX3JicmVyaHJrcm6CcYJ0kneierJ9woDSg%2FKHEooijUKQYpOClrKZ0p0CoCKjUqaCqbKs8rAis2K2krnSvRLAUsOSxuLKIs1y0MLUEtdi2rLeEuFi5MLoIuty7uLyQvWi%2BRL8cv%2FjA1MGwwpDDbMRIxSjGCMbox8jIqMmMymzLUMw0zRjN%2FM7gz8TQrNGU0njTYNRM1TTWHNcI1%2FTY3NnI2rjbpNyQ3YDecN9c4FDhQOIw4yDkFOUI5fzm8Ofk6Njp0OrI67zstO2s7qjvoPCc8ZTykPOM9Ij1hPaE94D4gPmA%2BoD7gPyE%2FYT%2BiP%2BJAI0BkQKZA50EpQWpBrEHuQjBCckK1QvdDOkN9Q8BEA0RHRIpEzkUSRVVFmkXeRiJGZ0arRvBHNUd7R8BIBUhLSJFI10kdSWNJqUnwSjdKfUrESwxLU0uaS%2BJMKkxyTLpNAk1KTZNN3E4lTm5Ot08AT0lPk0%2FdUCdQcVC7UQZRUFGbUeZSMVJ8UsdTE1NfU6pT9lRCVI9U21UoVXVVwlYPVlxWqVb3V0RXklfgWC9YfVjLWRpZaVm4WgdaVlqmWvVbRVuVW%2BVcNVyGXNZdJ114XcleGl5sXr1fD19hX7NgBWBXYKpg%2FGFPYaJh9WJJYpxi8GNDY5dj62RAZJRk6WU9ZZJl52Y9ZpJm6Gc9Z5Nn6Wg%2FaJZo7GlDaZpp8WpIap9q92tPa6dr%2F2xXbK9tCG1gbbluEm5rbsRvHm94b9FwK3CGcOBxOnGVcfByS3KmcwFzXXO4dBR0cHTMdSh1hXXhdj52m3b4d1Z3s3gReG54zHkqeYl553pGeqV7BHtje8J8IXyBfOF9QX2hfgF%2BYn7CfyN%2FhH%2FlgEeAqIEKgWuBzYIwgpKC9INXg7qEHYSAhOOFR4Wrhg6GcobXhzuHn4gEiGmIzokziZmJ%2FopkisqLMIuWi%2FyMY4zKjTGNmI3%2FjmaOzo82j56QBpBukNaRP5GokhGSepLjk02TtpQglIqU9JVflcmWNJaflwqXdZfgmEyYuJkkmZCZ%2FJpomtWbQpuvnByciZz3nWSd0p5Anq6fHZ%2BLn%2FqgaaDYoUehtqImopajBqN2o%2BakVqTHpTilqaYapoum%2Fadup%2BCoUqjEqTepqaocqo%2BrAqt1q%2BmsXKzQrUStuK4trqGvFq%2BLsACwdbDqsWCx1rJLssKzOLOutCW0nLUTtYq2AbZ5tvC3aLfguFm40blKucK6O7q1uy67p7whvJu9Fb2Pvgq%2BhL7%2Fv3q%2F9cBwwOzBZ8Hjwl%2FC28NYw9TEUcTOxUvFyMZGxsPHQce%2FyD3IvMk6ybnKOMq3yzbLtsw1zLXNNc21zjbOts83z7jQOdC60TzRvtI%2F0sHTRNPG1EnUy9VO1dHWVdbY11zX4Nhk2OjZbNnx2nba%2B9uA3AXcit0Q3ZbeHN6i3ynfr%2BA24L3hROHM4lPi2%2BNj4%2Bvkc%2BT85YTmDeaW5x%2Fnqegy6LzpRunQ6lvq5etw6%2Fvshu0R7ZzuKO6070DvzPBY8OXxcvH%2F8ozzGfOn9DT0wvVQ9d72bfb794r4Gfio%2BTj5x%2FpX%2Buf7d%2FwH%2FJj9Kf26%2Fkv%2B3P9t%2F%2F9jdXJ2AAAAAAAABAAAAAAFAAoADwAUABkAHgAjACgALQAyADcAOwBAAEUASgBPAFQAWQBeAGMAaABtAHIAdwB8AIEAhgCLAJAAlQCaAJ8ApACpAK4AsgC3ALwAwQDGAMsA0ADVANsA4ADlAOsA8AD2APsBAQEHAQ0BEwEZAR8BJQErATIBOAE%2BAUUBTAFSAVkBYAFnAW4BdQF8AYMBiwGSAZoBoQGpAbEBuQHBAckB0QHZAeEB6QHyAfoCAwIMAhQCHQImAi8COAJBAksCVAJdAmcCcQJ6AoQCjgKYAqICrAK2AsECywLVAuAC6wL1AwADCwMWAyEDLQM4A0MDTwNaA2YDcgN%2BA4oDlgOiA64DugPHA9MD4APsA%2FkEBgQTBCAELQQ7BEgEVQRjBHEEfgSMBJoEqAS2BMQE0wThBPAE%2FgUNBRwFKwU6BUkFWAVnBXcFhgWWBaYFtQXFBdUF5QX2BgYGFgYnBjcGSAZZBmoGewaMBp0GrwbABtEG4wb1BwcHGQcrBz0HTwdhB3QHhgeZB6wHvwfSB%2BUH%2BAgLCB8IMghGCFoIbgiCCJYIqgi%2BCNII5wj7CRAJJQk6CU8JZAl5CY8JpAm6Cc8J5Qn7ChEKJwo9ClQKagqBCpgKrgrFCtwK8wsLCyILOQtRC2kLgAuYC7ALyAvhC%2FkMEgwqDEMMXAx1DI4MpwzADNkM8w0NDSYNQA1aDXQNjg2pDcMN3g34DhMOLg5JDmQOfw6bDrYO0g7uDwkPJQ9BD14Peg%2BWD7MPzw%2FsEAkQJhBDEGEQfhCbELkQ1xD1ERMRMRFPEW0RjBGqEckR6BIHEiYSRRJkEoQSoxLDEuMTAxMjE0MTYxODE6QTxRPlFAYUJxRJFGoUixStFM4U8BUSFTQVVhV4FZsVvRXgFgMWJhZJFmwWjxayFtYW%2BhcdF0EXZReJF64X0hf3GBsYQBhlGIoYrxjVGPoZIBlFGWsZkRm3Gd0aBBoqGlEadxqeGsUa7BsUGzsbYxuKG7Ib2hwCHCocUhx7HKMczBz1HR4dRx1wHZkdwx3sHhYeQB5qHpQevh7pHxMfPh9pH5Qfvx%2FqIBUgQSBsIJggxCDwIRwhSCF1IaEhziH7IiciVSKCIq8i3SMKIzgjZiOUI8Ij8CQfJE0kfCSrJNolCSU4JWgllyXHJfcmJyZXJocmtyboJxgnSSd6J6sn3CgNKD8ocSiiKNQpBik4KWspnSnQKgIqNSpoKpsqzysCKzYraSudK9EsBSw5LG4soizXLQwtQS12Last4S4WLkwugi63Lu4vJC9aL5Evxy%2F%2BMDUwbDCkMNsxEjFKMYIxujHyMioyYzKbMtQzDTNGM38zuDPxNCs0ZTSeNNg1EzVNNYc1wjX9Njc2cjauNuk3JDdgN5w31zgUOFA4jDjIOQU5Qjl%2FObw5%2BTo2OnQ6sjrvOy07azuqO%2Bg8JzxlPKQ84z0iPWE9oT3gPiA%2BYD6gPuA%2FIT9hP6I%2F4kAjQGRApkDnQSlBakGsQe5CMEJyQrVC90M6Q31DwEQDREdEikTORRJFVUWaRd5GIkZnRqtG8Ec1R3tHwEgFSEtIkUjXSR1JY0mpSfBKN0p9SsRLDEtTS5pL4kwqTHJMuk0CTUpNk03cTiVObk63TwBPSU%2BTT91QJ1BxULtRBlFQUZtR5lIxUnxSx1MTU19TqlP2VEJUj1TbVShVdVXCVg9WXFapVvdXRFeSV%2BBYL1h9WMtZGllpWbhaB1pWWqZa9VtFW5Vb5Vw1XIZc1l0nXXhdyV4aXmxevV8PX2Ffs2AFYFdgqmD8YU9homH1YklinGLwY0Njl2PrZEBklGTpZT1lkmXnZj1mkmboZz1nk2fpaD9olmjsaUNpmmnxakhqn2r3a09rp2v%2FbFdsr20IbWBtuW4SbmtuxG8eb3hv0XArcIZw4HE6cZVx8HJLcqZzAXNdc7h0FHRwdMx1KHWFdeF2Pnabdvh3VnezeBF4bnjMeSp5iXnnekZ6pXsEe2N7wnwhfIF84X1BfaF%2BAX5ifsJ%2FI3%2BEf%2BWAR4CogQqBa4HNgjCCkoL0g1eDuoQdhICE44VHhauGDoZyhteHO4efiASIaYjOiTOJmYn%2BimSKyoswi5aL%2FIxjjMqNMY2Yjf%2BOZo7OjzaPnpAGkG6Q1pE%2FkaiSEZJ6kuOTTZO2lCCUipT0lV%2BVyZY0lp%2BXCpd1l%2BCYTJi4mSSZkJn8mmia1ZtCm6%2BcHJyJnPedZJ3SnkCerp8dn4uf%2BqBpoNihR6G2oiailqMGo3aj5qRWpMelOKWpphqmi6b9p26n4KhSqMSpN6mpqhyqj6sCq3Wr6axcrNCtRK24ri2uoa8Wr4uwALB1sOqxYLHWskuywrM4s660JbSctRO1irYBtnm28Ldot%2BC4WbjRuUq5wro7urW7LrunvCG8m70VvY%2B%2BCr6Evv%2B%2Fer%2F1wHDA7MFnwePCX8Lbw1jD1MRRxM7FS8XIxkbGw8dBx7%2FIPci8yTrJuco4yrfLNsu2zDXMtc01zbXONs62zzfPuNA50LrRPNG%2B0j%2FSwdNE08bUSdTL1U7V0dZV1tjXXNfg2GTY6Nls2fHadtr724DcBdyK3RDdlt4c3qLfKd%2Bv4DbgveFE4cziU%2BLb42Pj6%2BRz5PzlhOYN5pbnH%2Bep6DLovOlG6dDqW%2Brl63Dr%2B%2ByG7RHtnO4o7rTvQO%2FM8Fjw5fFy8f%2FyjPMZ86f0NPTC9VD13vZt9vv3ivgZ%2BKj5OPnH%2Blf65%2Ft3%2FAf8mP0p%2Fbr%2BS%2F7c%2F23%2F%2F2N1cnYAAAAAAAAEAAAAAAUACgAPABQAGQAeACMAKAAtADIANwA7AEAARQBKAE8AVABZAF4AYwBoAG0AcgB3AHwAgQCGAIsAkACVAJoAnwCkAKkArgCyALcAvADBAMYAywDQANUA2wDgAOUA6wDwAPYA%2BwEBAQcBDQETARkBHwElASsBMgE4AT4BRQFMAVIBWQFgAWcBbgF1AXwBgwGLAZIBmgGhAakBsQG5AcEByQHRAdkB4QHpAfIB%2BgIDAgwCFAIdAiYCLwI4AkECSwJUAl0CZwJxAnoChAKOApgCogKsArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMtAzgDQwNPA1oDZgNyA34DigOWA6IDrgO6A8cD0wPgA%2BwD%2BQQGBBMEIAQtBDsESARVBGMEcQR%2BBIwEmgSoBLYExATTBOEE8AT%2BBQ0FHAUrBToFSQVYBWcFdwWGBZYFpgW1BcUF1QXlBfYGBgYWBicGNwZIBlkGagZ7BowGnQavBsAG0QbjBvUHBwcZBysHPQdPB2EHdAeGB5kHrAe%2FB9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiqCL4I0gjnCPsJEAklCToJTwlkCXkJjwmkCboJzwnlCfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsLIgs5C1ELaQuAC5gLsAvIC%2BEL%2BQwSDCoMQwxcDHUMjgynDMAM2QzzDQ0NJg1ADVoNdA2ODakNww3eDfgOEw4uDkkOZA5%2FDpsOtg7SDu4PCQ8lD0EPXg96D5YPsw%2FPD%2BwQCRAmEEMQYRB%2BEJsQuRDXEPURExExEU8RbRGMEaoRyRHoEgcSJhJFEmQShBKjEsMS4xMDEyMTQxNjE4MTpBPFE%2BUUBhQnFEkUahSLFK0UzhTwFRIVNBVWFXgVmxW9FeAWAxYmFkkWbBaPFrIW1hb6Fx0XQRdlF4kXrhfSF%2FcYGxhAGGUYihivGNUY%2BhkgGUUZaxmRGbcZ3RoEGioaURp3Gp4axRrsGxQbOxtjG4obshvaHAIcKhxSHHscoxzMHPUdHh1HHXAdmR3DHeweFh5AHmoelB6%2BHukfEx8%2BH2kflB%2B%2FH%2BogFSBBIGwgmCDEIPAhHCFIIXUhoSHOIfsiJyJVIoIiryLdIwojOCNmI5QjwiPwJB8kTSR8JKsk2iUJJTglaCWXJccl9yYnJlcmhya3JugnGCdJJ3onqyfcKA0oPyhxKKIo1CkGKTgpaymdKdAqAio1KmgqmyrPKwIrNitpK50r0SwFLDksbiyiLNctDC1BLXYtqy3hLhYuTC6CLrcu7i8kL1ovkS%2FHL%2F4wNTBsMKQw2zESMUoxgjG6MfIyKjJjMpsy1DMNM0YzfzO4M%2FE0KzRlNJ402DUTNU01hzXCNf02NzZyNq426TckN2A3nDfXOBQ4UDiMOMg5BTlCOX85vDn5OjY6dDqyOu87LTtrO6o76DwnPGU8pDzjPSI9YT2hPeA%2BID5gPqA%2B4D8hP2E%2Foj%2FiQCNAZECmQOdBKUFqQaxB7kIwQnJCtUL3QzpDfUPARANER0SKRM5FEkVVRZpF3kYiRmdGq0bwRzVHe0fASAVIS0iRSNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkviTCpMcky6TQJNSk2TTdxOJU5uTrdPAE9JT5NP3VAnUHFQu1EGUVBRm1HmUjFSfFLHUxNTX1OqU%2FZUQlSPVNtVKFV1VcJWD1ZcVqlW91dEV5JX4FgvWH1Yy1kaWWlZuFoHWlZaplr1W0VblVvlXDVchlzWXSddeF3JXhpebF69Xw9fYV%2BzYAVgV2CqYPxhT2GiYfViSWKcYvBjQ2OXY%2BtkQGSUZOllPWWSZedmPWaSZuhnPWeTZ%2BloP2iWaOxpQ2maafFqSGqfavdrT2una%2F9sV2yvbQhtYG25bhJua27Ebx5veG%2FRcCtwhnDgcTpxlXHwcktypnMBc11zuHQUdHB0zHUodYV14XY%2Bdpt2%2BHdWd7N4EXhueMx5KnmJeed6RnqlewR7Y3vCfCF8gXzhfUF9oX4BfmJ%2Bwn8jf4R%2F5YBHgKiBCoFrgc2CMIKSgvSDV4O6hB2EgITjhUeFq4YOhnKG14c7h5%2BIBIhpiM6JM4mZif6KZIrKizCLlov8jGOMyo0xjZiN%2F45mjs6PNo%2BekAaQbpDWkT%2BRqJIRknqS45NNk7aUIJSKlPSVX5XJljSWn5cKl3WX4JhMmLiZJJmQmfyaaJrVm0Kbr5wcnImc951kndKeQJ6unx2fi5%2F6oGmg2KFHobaiJqKWowajdqPmpFakx6U4pammGqaLpv2nbqfgqFKoxKk3qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxavi7AAsHWw6rFgsdayS7LCszizrrQltJy1E7WKtgG2ebbwt2i34LhZuNG5SrnCuju6tbsuu6e8IbybvRW9j74KvoS%2B%2F796v%2FXAcMDswWfB48JfwtvDWMPUxFHEzsVLxcjGRsbDx0HHv8g9yLzJOsm5yjjKt8s2y7bMNcy1zTXNtc42zrbPN8%2B40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1%2BDYZNjo2WzZ8dp22vvbgNwF3IrdEN2W3hzeot8p36%2FgNuC94UThzOJT4tvjY%2BPr5HPk%2FOWE5g3mlucf56noMui86Ubp0Opb6uXrcOv77IbtEe2c7ijutO9A78zwWPDl8XLx%2F%2FKM8xnzp%2FQ09ML1UPXe9m32%2B%2FeK%2BBn4qPk4%2Bcf6V%2Frn%2B3f8B%2FyY%2FSn9uv5L%2Ftz%2Fbf%2F%2FY2hybQAAAAAAAwAAAACj1wAAVHsAAEzNAACZmgAAJmYAAA9c%22%7D%2C%22cs_sRGB%22%3Atrue%7D%2C%22transparency%22%3A1%7D%2C%22queueBufferSize%22%3A1000%2C%22smtpSecure%22%3A%220%22%7D%2C%22updateSettings%22%3A%7B%7D%2C%22debugStats%22%3A%5B%5D%2C%22users%22%3A1%7D
+---
+POST http://localhost:3000/UsageStatisticsServlet
+Content-Type: application/x-www-form-urlencoded; charset=UTF-8
+User-Agent: Apache-HttpClient/4.5.13 (Java/21.0.7)
+
+serverId=49885e13-4f2e-41a6-b66a-8e65f5492d9a&version=4.5.2&server=false&data=%7B%22mirthVersion%22%3A%224.5.2%22%2C%22serverId%22%3A%2249885e13-4f2e-41a6-b66a-8e65f5492d9a%22%2C%22databaseType%22%3A%22derby%22%2C%22serverSpecs%22%3A%7B%22availableProcessors%22%3A16%2C%22osVersion%22%3A%225.15.167.4-microsoft-standard-WSL2%22%2C%22javaVersion%22%3A%2221.0.7%22%2C%22osName%22%3A%22Linux%22%2C%22maxMemory%22%3A268435456%7D%2C%22clientSpecs%22%3A%7B%22javaVersion%22%3A%221.8.0_351%22%7D%2C%22globalScripts%22%3A%7B%22deployLines%22%3A3%2C%22preprocessorLines%22%3A3%2C%22undeployLines%22%3A4%2C%22postprocessorLines%22%3A5%7D%2C%22channels%22%3A%5B%5D%2C%22invalidChannels%22%3A0%2C%22codeTemplateLibraries%22%3A%5B%5D%2C%22alerts%22%3A%5B%5D%2C%22plugins%22%3A%5B%7B%22pluginPoint%22%3A%22Server+Log%22%7D%2C%7B%22pluginPoint%22%3A%22DELIMITED%22%7D%2C%7B%22pluginPoint%22%3A%22XML%22%7D%2C%7B%22pluginPoint%22%3A%22HTTP+Auth+Service+Plugin%22%7D%2C%7B%22pluginPoint%22%3A%22HL7V2%22%7D%2C%7B%22pluginPoint%22%3A%22Data+Pruner%22%7D%2C%7B%22pluginPoint%22%3A%22RAW%22%7D%2C%7B%22pluginPoint%22%3A%22DICOM%22%7D%2C%7B%22pluginPoint%22%3A%22HL7V3%22%7D%2C%7B%22pluginPoint%22%3A%22Dashboard+Connector+Status+Service%22%7D%2C%7B%22pluginPoint%22%3A%22Directory+Resource%22%7D%2C%7B%22pluginPoint%22%3A%22NCPDP%22%7D%2C%7B%22pluginPoint%22%3A%22MLLP%22%7D%2C%7B%22pluginPoint%22%3A%22TCP+Service+Plugin%22%7D%2C%7B%22pluginPoint%22%3A%22JSON%22%7D%2C%7B%22pluginPoint%22%3A%22EDI%2FX12%22%7D%2C%7B%22pluginPoint%22%3A%22Global+Maps%22%7D%5D%2C%22pluginMetaData%22%3A%5B%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.serverlog.ServerLogProvider%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.serverlog.ServerLogClient%22%2C%22weight%22%3A120%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Server+Log%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.textviewer.TextViewer%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Text+Viewer%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.delimited.DelimitedDataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.delimited.DelimitedDataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Delimited+Data+Type%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.xml.XMLDataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.xml.XMLDataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22XML+Data+Type%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.httpauth.HttpAuthServicePlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.httpauth.HttpAuthConnectorPropertiesPlugin%22%2C%22weight%22%3A-100%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22HTTP+Authentication+Settings%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.imageviewer.ImageViewer%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Image+Viewer%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.hl7v2.HL7v2DataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.hl7v2.HL7v2DataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22HL7v2+Data+Type%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datapruner.DataPrunerService%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datapruner.DataPrunerClient%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Data+Pruner%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.raw.RawDataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.raw.RawDataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Raw+Data+Type%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.dicom.DICOMDataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.dicom.DICOMDataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22DICOM+Data+Type%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.destinationsetfilter.DestinationSetFilterPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Destination+Set+Filter+Step%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.hl7v3.HL7V3DataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.hl7v3.HL7V3DataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22HL7v3+Data+Type%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.javascriptrule.JavaScriptRulePlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22JavaScript+Filter+Rule%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.mapper.MapperStepPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Mapper+Transformer+Step%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.javascriptstep.JavaScriptStepPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22JavaScript+Transformer+Step%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.messagebuilder.MessageBuilderPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Message+Builder+Transformer+Step%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.dashboardstatus.DashboardConnectorStatusMonitor%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.dashboardstatus.DashboardConnectorStatusColumn%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%2C%7B%22name%22%3A%22com.mirth.connect.plugins.dashboardstatus.DashboardConnectorStatusClient%22%2C%22weight%22%3A110%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Dashboard+Connector+Status+Monitor%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.dicomviewer.DICOMViewer%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22DICOM+Viewer%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.scriptfilestep.ExternalScriptStepPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22External+Script+Transformer+Step%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.directoryresource.DirectoryResourcePlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.directoryresource.DirectoryResourceClientPlugin%22%2C%22weight%22%3A110%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Directory+Resource+Plugin%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.scriptfilerule.ExternalScriptRulePlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22External+Script+Filter+Step%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.ncpdp.NCPDPDataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.ncpdp.NCPDPDataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22NCPDP+Data+Type%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.mllpmode.MLLPModeProvider%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.mllpmode.MLLPModePlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Transmission+Mode+-+MLLP%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.rulebuilder.RuleBuilderPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Rule+Builder+Filter+Rule%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.connectors.tcp.TcpServicePlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.connectors.tcp.TcpClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22TCP+Connector+Service+Plugin%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.json.JSONDataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.json.JSONDataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22JSON+Data+Type%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.pdfviewer.PDFViewer%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22PDF+Viewer%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.edi.EDIDataTypeServerPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.datatypes.edi.EDIDataTypeClientPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22EDI+Data+Type%22%7D%2C%7B%22serverClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.globalmapviewer.GlobalMapProvider%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.globalmapviewer.GlobalMapClient%22%2C%22weight%22%3A100%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22Global+Map+Viewer%22%7D%2C%7B%22serverClasses%22%3Anull%2C%22clientClasses%22%3A%5B%7B%22name%22%3A%22com.mirth.connect.plugins.xsltstep.XsltStepPlugin%22%2C%22weight%22%3A0%2C%22conditionClass%22%3Anull%7D%5D%2C%22name%22%3A%22XSLT+Transformer+Step%22%7D%5D%2C%22connectorMetaData%22%3A%5B%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22smtp%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.smtp.SmtpDispatcher%22%2C%22name%22%3A%22SMTP+Sender%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.smtp.SmtpSender%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.smtp.SmtpDispatcherProperties%22%7D%2C%7B%22transformers%22%3Anull%2C%22protocol%22%3A%22file%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.file.FileDispatcher%22%2C%22name%22%3A%22File+Writer%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.file.FileWriter%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.file.FileDispatcherProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22http%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.http.HttpDispatcher%22%2C%22name%22%3A%22HTTP+Sender%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.http.HttpSender%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.http.HttpDispatcherProperties%22%7D%2C%7B%22transformers%22%3Anull%2C%22protocol%22%3A%22file%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.file.FileReceiver%22%2C%22name%22%3A%22File+Reader%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.file.FileReader%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.file.FileReceiverProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22http%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.http.HttpReceiver%22%2C%22name%22%3A%22HTTP+Listener%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.http.HttpListener%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.http.HttpReceiverProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22dicom%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.dimse.DICOMReceiver%22%2C%22name%22%3A%22DICOM+Listener%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.dimse.DICOMListener%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.dimse.DICOMReceiverProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22vm%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.vm.VmDispatcher%22%2C%22name%22%3A%22Channel+Writer%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.vm.ChannelWriter%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.vm.VmDispatcherProperties%22%7D%2C%7B%22transformers%22%3A%22ResultMapToXML%22%2C%22protocol%22%3A%22js%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.js.JavaScriptReceiver%22%2C%22name%22%3A%22JavaScript+Reader%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.js.JavaScriptReader%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.js.JavaScriptReceiverProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22tcp%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.tcp.TcpReceiver%22%2C%22name%22%3A%22TCP+Listener%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.tcp.TcpListener%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.tcp.TcpReceiverProperties%22%7D%2C%7B%22transformers%22%3Anull%2C%22protocol%22%3A%22jdbc%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.jdbc.DatabaseReceiver%22%2C%22name%22%3A%22Database+Reader%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.jdbc.DatabaseReader%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.jdbc.DatabaseReceiverProperties%22%7D%2C%7B%22transformers%22%3Anull%2C%22protocol%22%3A%22jdbc%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.jdbc.DatabaseDispatcher%22%2C%22name%22%3A%22Database+Writer%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.jdbc.DatabaseWriter%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.jdbc.DatabaseDispatcherProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22doc%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.doc.DocumentDispatcher%22%2C%22name%22%3A%22Document+Writer%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.doc.DocumentWriter%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.doc.DocumentDispatcherProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22ws%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.ws.WebServiceReceiver%22%2C%22name%22%3A%22Web+Service+Listener%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.ws.WebServiceListener%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.ws.WebServiceReceiverProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22tcp%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.tcp.TcpDispatcher%22%2C%22name%22%3A%22TCP+Sender%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.tcp.TcpSender%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.tcp.TcpDispatcherProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22js%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.js.JavaScriptDispatcher%22%2C%22name%22%3A%22JavaScript+Writer%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.js.JavaScriptWriter%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.js.JavaScriptDispatcherProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22vm%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.vm.VmReceiver%22%2C%22name%22%3A%22Channel+Reader%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.vm.ChannelReader%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.vm.VmReceiverProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22ws%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.ws.WebServiceDispatcher%22%2C%22name%22%3A%22Web+Service+Sender%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.ws.WebServiceSender%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.ws.WebServiceDispatcherProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22jms%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.jms.JmsDispatcher%22%2C%22name%22%3A%22JMS+Sender%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.jms.JmsSender%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.jms.JmsDispatcherProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22jms%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.jms.JmsReceiver%22%2C%22name%22%3A%22JMS+Listener%22%2C%22type%22%3A%22SOURCE%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.jms.JmsListener%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.jms.JmsReceiverProperties%22%7D%2C%7B%22transformers%22%3A%22%22%2C%22protocol%22%3A%22dicom%22%2C%22serverClassName%22%3A%22com.mirth.connect.connectors.dimse.DICOMDispatcher%22%2C%22name%22%3A%22DICOM+Sender%22%2C%22type%22%3A%22DESTINATION%22%2C%22clientClassName%22%3A%22com.mirth.connect.connectors.dimse.DICOMSender%22%2C%22sharedClassName%22%3A%22com.mirth.connect.connectors.dimse.DICOMDispatcherProperties%22%7D%5D%2C%22serverSettings%22%3A%7B%22clearGlobalMap%22%3Atrue%2C%22smtpTimeout%22%3A%225000%22%2C%22smtpAuth%22%3Afalse%2C%22defaultMetaDataColumns%22%3A%5B%7B%22type%22%3A%22STRING%22%7D%2C%7B%22type%22%3A%22STRING%22%7D%5D%2C%22defaultAdministratorBackgroundColor%22%3A%7B%22red%22%3A158%2C%22green%22%3A177%2C%22blue%22%3A201%2C%22alpha%22%3A255%2C%22rgb%22%3A-6377015%2C%22colorSpace%22%3A%7B%22type%22%3A5%2C%22numComponents%22%3A3%2C%22profile%22%3A%7B%22matrix%22%3A%5B%5B0.43585205%2C0.3853302%2C0.14302063%5D%2C%5B0.22238159%2C0.717041%2C0.06059265%5D%2C%5B0.013916016%2C0.09713745%2C0.71383667%5D%5D%2C%22mediaWhitePoint%22%3A%5B0.95014954%2C1.0%2C1.0882568%5D%2C%22numComponents%22%3A3%2C%22colorSpaceType%22%3A5%2C%22profileClass%22%3A1%2C%22pcstype%22%3A0%2C%22majorVersion%22%3A2%2C%22minorVersion%22%3A48%2C%22data%22%3A%22AAAa3GxjbXMCMAAAbW50clJHQiBYWVogB9YADAAcABIABwAWYWNzcE1TRlQAAAAAbGNtcwAAAAAAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1sY21zAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALZG1uZAAAAQgAAABqZGVzYwAAAXQAAABoZG1kZAAAAdwAAABod3RwdAAAAkQAAAAUclhZWgAAAlgAAAAUYlhZWgAAAmwAAAAUZ1hZWgAAAoAAAAAUclRSQwAAApQAAAgMZ1RSQwAACqAAAAgMYlRSQwAAEqwAAAgMY2hybQAAGrgAAAAkZGVzYwAAAAAAAAAQKGxjbXMgaW50ZXJuYWwpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAOc1JHQiBidWlsdC1pbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkZXNjAAAAAAAAAA5zUkdCIGJ1aWx0LWluAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAADzPQABAAAAARaYWFlaIAAAAAAAAG%2BUAAA47gAAA5BYWVogAAAAAAAAJJ0AAA%2BDAAC2vlhZWiAAAAAAAABipQAAt5AAABjeY3VydgAAAAAAAAQAAAAABQAKAA8AFAAZAB4AIwAoAC0AMgA3ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACBAIYAiwCQAJUAmgCfAKQAqQCuALIAtwC8AMEAxgDLANAA1QDbAOAA5QDrAPAA9gD7AQEBBwENARMBGQEfASUBKwEyATgBPgFFAUwBUgFZAWABZwFuAXUBfAGDAYsBkgGaAaEBqQGxAbkBwQHJAdEB2QHhAekB8gH6AgMCDAIUAh0CJgIvAjgCQQJLAlQCXQJnAnECegKEAo4CmAKiAqwCtgLBAssC1QLgAusC9QMAAwsDFgMhAy0DOANDA08DWgNmA3IDfgOKA5YDogOuA7oDxwPTA%2BAD7AP5BAYEEwQgBC0EOwRIBFUEYwRxBH4EjASaBKgEtgTEBNME4QTwBP4FDQUcBSsFOgVJBVgFZwV3BYYFlgWmBbUFxQXVBeUF9gYGBhYGJwY3BkgGWQZqBnsGjAadBq8GwAbRBuMG9QcHBxkHKwc9B08HYQd0B4YHmQesB78H0gflB%2FgICwgfCDIIRghaCG4IggiWCKoIvgjSCOcI%2BwkQCSUJOglPCWQJeQmPCaQJugnPCeUJ%2BwoRCicKPQpUCmoKgQqYCq4KxQrcCvMLCwsiCzkLUQtpC4ALmAuwC8gL4Qv5DBIMKgxDDFwMdQyODKcMwAzZDPMNDQ0mDUANWg10DY4NqQ3DDd4N%2BA4TDi4OSQ5kDn8Omw62DtIO7g8JDyUPQQ9eD3oPlg%2BzD88P7BAJECYQQxBhEH4QmxC5ENcQ9RETETERTxFtEYwRqhHJEegSBxImEkUSZBKEEqMSwxLjEwMTIxNDE2MTgxOkE8UT5RQGFCcUSRRqFIsUrRTOFPAVEhU0FVYVeBWbFb0V4BYDFiYWSRZsFo8WshbWFvoXHRdBF2UXiReuF9IX9xgbGEAYZRiKGK8Y1Rj6GSAZRRlrGZEZtxndGgQaKhpRGncanhrFGuwbFBs7G2MbihuyG9ocAhwqHFIcexyjHMwc9R0eHUcdcB2ZHcMd7B4WHkAeah6UHr4e6R8THz4faR%2BUH78f6iAVIEEgbCCYIMQg8CEcIUghdSGhIc4h%2ByInIlUigiKvIt0jCiM4I2YjlCPCI%2FAkHyRNJHwkqyTaJQklOCVoJZclxyX3JicmVyaHJrcm6CcYJ0kneierJ9woDSg%2FKHEooijUKQYpOClrKZ0p0CoCKjUqaCqbKs8rAis2K2krnSvRLAUsOSxuLKIs1y0MLUEtdi2rLeEuFi5MLoIuty7uLyQvWi%2BRL8cv%2FjA1MGwwpDDbMRIxSjGCMbox8jIqMmMymzLUMw0zRjN%2FM7gz8TQrNGU0njTYNRM1TTWHNcI1%2FTY3NnI2rjbpNyQ3YDecN9c4FDhQOIw4yDkFOUI5fzm8Ofk6Njp0OrI67zstO2s7qjvoPCc8ZTykPOM9Ij1hPaE94D4gPmA%2BoD7gPyE%2FYT%2BiP%2BJAI0BkQKZA50EpQWpBrEHuQjBCckK1QvdDOkN9Q8BEA0RHRIpEzkUSRVVFmkXeRiJGZ0arRvBHNUd7R8BIBUhLSJFI10kdSWNJqUnwSjdKfUrESwxLU0uaS%2BJMKkxyTLpNAk1KTZNN3E4lTm5Ot08AT0lPk0%2FdUCdQcVC7UQZRUFGbUeZSMVJ8UsdTE1NfU6pT9lRCVI9U21UoVXVVwlYPVlxWqVb3V0RXklfgWC9YfVjLWRpZaVm4WgdaVlqmWvVbRVuVW%2BVcNVyGXNZdJ114XcleGl5sXr1fD19hX7NgBWBXYKpg%2FGFPYaJh9WJJYpxi8GNDY5dj62RAZJRk6WU9ZZJl52Y9ZpJm6Gc9Z5Nn6Wg%2FaJZo7GlDaZpp8WpIap9q92tPa6dr%2F2xXbK9tCG1gbbluEm5rbsRvHm94b9FwK3CGcOBxOnGVcfByS3KmcwFzXXO4dBR0cHTMdSh1hXXhdj52m3b4d1Z3s3gReG54zHkqeYl553pGeqV7BHtje8J8IXyBfOF9QX2hfgF%2BYn7CfyN%2FhH%2FlgEeAqIEKgWuBzYIwgpKC9INXg7qEHYSAhOOFR4Wrhg6GcobXhzuHn4gEiGmIzokziZmJ%2FopkisqLMIuWi%2FyMY4zKjTGNmI3%2FjmaOzo82j56QBpBukNaRP5GokhGSepLjk02TtpQglIqU9JVflcmWNJaflwqXdZfgmEyYuJkkmZCZ%2FJpomtWbQpuvnByciZz3nWSd0p5Anq6fHZ%2BLn%2FqgaaDYoUehtqImopajBqN2o%2BakVqTHpTilqaYapoum%2Fadup%2BCoUqjEqTepqaocqo%2BrAqt1q%2BmsXKzQrUStuK4trqGvFq%2BLsACwdbDqsWCx1rJLssKzOLOutCW0nLUTtYq2AbZ5tvC3aLfguFm40blKucK6O7q1uy67p7whvJu9Fb2Pvgq%2BhL7%2Fv3q%2F9cBwwOzBZ8Hjwl%2FC28NYw9TEUcTOxUvFyMZGxsPHQce%2FyD3IvMk6ybnKOMq3yzbLtsw1zLXNNc21zjbOts83z7jQOdC60TzRvtI%2F0sHTRNPG1EnUy9VO1dHWVdbY11zX4Nhk2OjZbNnx2nba%2B9uA3AXcit0Q3ZbeHN6i3ynfr%2BA24L3hROHM4lPi2%2BNj4%2Bvkc%2BT85YTmDeaW5x%2Fnqegy6LzpRunQ6lvq5etw6%2Fvshu0R7ZzuKO6070DvzPBY8OXxcvH%2F8ozzGfOn9DT0wvVQ9d72bfb794r4Gfio%2BTj5x%2FpX%2Buf7d%2FwH%2FJj9Kf26%2Fkv%2B3P9t%2F%2F9jdXJ2AAAAAAAABAAAAAAFAAoADwAUABkAHgAjACgALQAyADcAOwBAAEUASgBPAFQAWQBeAGMAaABtAHIAdwB8AIEAhgCLAJAAlQCaAJ8ApACpAK4AsgC3ALwAwQDGAMsA0ADVANsA4ADlAOsA8AD2APsBAQEHAQ0BEwEZAR8BJQErATIBOAE%2BAUUBTAFSAVkBYAFnAW4BdQF8AYMBiwGSAZoBoQGpAbEBuQHBAckB0QHZAeEB6QHyAfoCAwIMAhQCHQImAi8COAJBAksCVAJdAmcCcQJ6AoQCjgKYAqICrAK2AsECywLVAuAC6wL1AwADCwMWAyEDLQM4A0MDTwNaA2YDcgN%2BA4oDlgOiA64DugPHA9MD4APsA%2FkEBgQTBCAELQQ7BEgEVQRjBHEEfgSMBJoEqAS2BMQE0wThBPAE%2FgUNBRwFKwU6BUkFWAVnBXcFhgWWBaYFtQXFBdUF5QX2BgYGFgYnBjcGSAZZBmoGewaMBp0GrwbABtEG4wb1BwcHGQcrBz0HTwdhB3QHhgeZB6wHvwfSB%2BUH%2BAgLCB8IMghGCFoIbgiCCJYIqgi%2BCNII5wj7CRAJJQk6CU8JZAl5CY8JpAm6Cc8J5Qn7ChEKJwo9ClQKagqBCpgKrgrFCtwK8wsLCyILOQtRC2kLgAuYC7ALyAvhC%2FkMEgwqDEMMXAx1DI4MpwzADNkM8w0NDSYNQA1aDXQNjg2pDcMN3g34DhMOLg5JDmQOfw6bDrYO0g7uDwkPJQ9BD14Peg%2BWD7MPzw%2FsEAkQJhBDEGEQfhCbELkQ1xD1ERMRMRFPEW0RjBGqEckR6BIHEiYSRRJkEoQSoxLDEuMTAxMjE0MTYxODE6QTxRPlFAYUJxRJFGoUixStFM4U8BUSFTQVVhV4FZsVvRXgFgMWJhZJFmwWjxayFtYW%2BhcdF0EXZReJF64X0hf3GBsYQBhlGIoYrxjVGPoZIBlFGWsZkRm3Gd0aBBoqGlEadxqeGsUa7BsUGzsbYxuKG7Ib2hwCHCocUhx7HKMczBz1HR4dRx1wHZkdwx3sHhYeQB5qHpQevh7pHxMfPh9pH5Qfvx%2FqIBUgQSBsIJggxCDwIRwhSCF1IaEhziH7IiciVSKCIq8i3SMKIzgjZiOUI8Ij8CQfJE0kfCSrJNolCSU4JWgllyXHJfcmJyZXJocmtyboJxgnSSd6J6sn3CgNKD8ocSiiKNQpBik4KWspnSnQKgIqNSpoKpsqzysCKzYraSudK9EsBSw5LG4soizXLQwtQS12Last4S4WLkwugi63Lu4vJC9aL5Evxy%2F%2BMDUwbDCkMNsxEjFKMYIxujHyMioyYzKbMtQzDTNGM38zuDPxNCs0ZTSeNNg1EzVNNYc1wjX9Njc2cjauNuk3JDdgN5w31zgUOFA4jDjIOQU5Qjl%2FObw5%2BTo2OnQ6sjrvOy07azuqO%2Bg8JzxlPKQ84z0iPWE9oT3gPiA%2BYD6gPuA%2FIT9hP6I%2F4kAjQGRApkDnQSlBakGsQe5CMEJyQrVC90M6Q31DwEQDREdEikTORRJFVUWaRd5GIkZnRqtG8Ec1R3tHwEgFSEtIkUjXSR1JY0mpSfBKN0p9SsRLDEtTS5pL4kwqTHJMuk0CTUpNk03cTiVObk63TwBPSU%2BTT91QJ1BxULtRBlFQUZtR5lIxUnxSx1MTU19TqlP2VEJUj1TbVShVdVXCVg9WXFapVvdXRFeSV%2BBYL1h9WMtZGllpWbhaB1pWWqZa9VtFW5Vb5Vw1XIZc1l0nXXhdyV4aXmxevV8PX2Ffs2AFYFdgqmD8YU9homH1YklinGLwY0Njl2PrZEBklGTpZT1lkmXnZj1mkmboZz1nk2fpaD9olmjsaUNpmmnxakhqn2r3a09rp2v%2FbFdsr20IbWBtuW4SbmtuxG8eb3hv0XArcIZw4HE6cZVx8HJLcqZzAXNdc7h0FHRwdMx1KHWFdeF2Pnabdvh3VnezeBF4bnjMeSp5iXnnekZ6pXsEe2N7wnwhfIF84X1BfaF%2BAX5ifsJ%2FI3%2BEf%2BWAR4CogQqBa4HNgjCCkoL0g1eDuoQdhICE44VHhauGDoZyhteHO4efiASIaYjOiTOJmYn%2BimSKyoswi5aL%2FIxjjMqNMY2Yjf%2BOZo7OjzaPnpAGkG6Q1pE%2FkaiSEZJ6kuOTTZO2lCCUipT0lV%2BVyZY0lp%2BXCpd1l%2BCYTJi4mSSZkJn8mmia1ZtCm6%2BcHJyJnPedZJ3SnkCerp8dn4uf%2BqBpoNihR6G2oiailqMGo3aj5qRWpMelOKWpphqmi6b9p26n4KhSqMSpN6mpqhyqj6sCq3Wr6axcrNCtRK24ri2uoa8Wr4uwALB1sOqxYLHWskuywrM4s660JbSctRO1irYBtnm28Ldot%2BC4WbjRuUq5wro7urW7LrunvCG8m70VvY%2B%2BCr6Evv%2B%2Fer%2F1wHDA7MFnwePCX8Lbw1jD1MRRxM7FS8XIxkbGw8dBx7%2FIPci8yTrJuco4yrfLNsu2zDXMtc01zbXONs62zzfPuNA50LrRPNG%2B0j%2FSwdNE08bUSdTL1U7V0dZV1tjXXNfg2GTY6Nls2fHadtr724DcBdyK3RDdlt4c3qLfKd%2Bv4DbgveFE4cziU%2BLb42Pj6%2BRz5PzlhOYN5pbnH%2Bep6DLovOlG6dDqW%2Brl63Dr%2B%2ByG7RHtnO4o7rTvQO%2FM8Fjw5fFy8f%2FyjPMZ86f0NPTC9VD13vZt9vv3ivgZ%2BKj5OPnH%2Blf65%2Ft3%2FAf8mP0p%2Fbr%2BS%2F7c%2F23%2F%2F2N1cnYAAAAAAAAEAAAAAAUACgAPABQAGQAeACMAKAAtADIANwA7AEAARQBKAE8AVABZAF4AYwBoAG0AcgB3AHwAgQCGAIsAkACVAJoAnwCkAKkArgCyALcAvADBAMYAywDQANUA2wDgAOUA6wDwAPYA%2BwEBAQcBDQETARkBHwElASsBMgE4AT4BRQFMAVIBWQFgAWcBbgF1AXwBgwGLAZIBmgGhAakBsQG5AcEByQHRAdkB4QHpAfIB%2BgIDAgwCFAIdAiYCLwI4AkECSwJUAl0CZwJxAnoChAKOApgCogKsArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMtAzgDQwNPA1oDZgNyA34DigOWA6IDrgO6A8cD0wPgA%2BwD%2BQQGBBMEIAQtBDsESARVBGMEcQR%2BBIwEmgSoBLYExATTBOEE8AT%2BBQ0FHAUrBToFSQVYBWcFdwWGBZYFpgW1BcUF1QXlBfYGBgYWBicGNwZIBlkGagZ7BowGnQavBsAG0QbjBvUHBwcZBysHPQdPB2EHdAeGB5kHrAe%2FB9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiqCL4I0gjnCPsJEAklCToJTwlkCXkJjwmkCboJzwnlCfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsLIgs5C1ELaQuAC5gLsAvIC%2BEL%2BQwSDCoMQwxcDHUMjgynDMAM2QzzDQ0NJg1ADVoNdA2ODakNww3eDfgOEw4uDkkOZA5%2FDpsOtg7SDu4PCQ8lD0EPXg96D5YPsw%2FPD%2BwQCRAmEEMQYRB%2BEJsQuRDXEPURExExEU8RbRGMEaoRyRHoEgcSJhJFEmQShBKjEsMS4xMDEyMTQxNjE4MTpBPFE%2BUUBhQnFEkUahSLFK0UzhTwFRIVNBVWFXgVmxW9FeAWAxYmFkkWbBaPFrIW1hb6Fx0XQRdlF4kXrhfSF%2FcYGxhAGGUYihivGNUY%2BhkgGUUZaxmRGbcZ3RoEGioaURp3Gp4axRrsGxQbOxtjG4obshvaHAIcKhxSHHscoxzMHPUdHh1HHXAdmR3DHeweFh5AHmoelB6%2BHukfEx8%2BH2kflB%2B%2FH%2BogFSBBIGwgmCDEIPAhHCFIIXUhoSHOIfsiJyJVIoIiryLdIwojOCNmI5QjwiPwJB8kTSR8JKsk2iUJJTglaCWXJccl9yYnJlcmhya3JugnGCdJJ3onqyfcKA0oPyhxKKIo1CkGKTgpaymdKdAqAio1KmgqmyrPKwIrNitpK50r0SwFLDksbiyiLNctDC1BLXYtqy3hLhYuTC6CLrcu7i8kL1ovkS%2FHL%2F4wNTBsMKQw2zESMUoxgjG6MfIyKjJjMpsy1DMNM0YzfzO4M%2FE0KzRlNJ402DUTNU01hzXCNf02NzZyNq426TckN2A3nDfXOBQ4UDiMOMg5BTlCOX85vDn5OjY6dDqyOu87LTtrO6o76DwnPGU8pDzjPSI9YT2hPeA%2BID5gPqA%2B4D8hP2E%2Foj%2FiQCNAZECmQOdBKUFqQaxB7kIwQnJCtUL3QzpDfUPARANER0SKRM5FEkVVRZpF3kYiRmdGq0bwRzVHe0fASAVIS0iRSNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkviTCpMcky6TQJNSk2TTdxOJU5uTrdPAE9JT5NP3VAnUHFQu1EGUVBRm1HmUjFSfFLHUxNTX1OqU%2FZUQlSPVNtVKFV1VcJWD1ZcVqlW91dEV5JX4FgvWH1Yy1kaWWlZuFoHWlZaplr1W0VblVvlXDVchlzWXSddeF3JXhpebF69Xw9fYV%2BzYAVgV2CqYPxhT2GiYfViSWKcYvBjQ2OXY%2BtkQGSUZOllPWWSZedmPWaSZuhnPWeTZ%2BloP2iWaOxpQ2maafFqSGqfavdrT2una%2F9sV2yvbQhtYG25bhJua27Ebx5veG%2FRcCtwhnDgcTpxlXHwcktypnMBc11zuHQUdHB0zHUodYV14XY%2Bdpt2%2BHdWd7N4EXhueMx5KnmJeed6RnqlewR7Y3vCfCF8gXzhfUF9oX4BfmJ%2Bwn8jf4R%2F5YBHgKiBCoFrgc2CMIKSgvSDV4O6hB2EgITjhUeFq4YOhnKG14c7h5%2BIBIhpiM6JM4mZif6KZIrKizCLlov8jGOMyo0xjZiN%2F45mjs6PNo%2BekAaQbpDWkT%2BRqJIRknqS45NNk7aUIJSKlPSVX5XJljSWn5cKl3WX4JhMmLiZJJmQmfyaaJrVm0Kbr5wcnImc951kndKeQJ6unx2fi5%2F6oGmg2KFHobaiJqKWowajdqPmpFakx6U4pammGqaLpv2nbqfgqFKoxKk3qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxavi7AAsHWw6rFgsdayS7LCszizrrQltJy1E7WKtgG2ebbwt2i34LhZuNG5SrnCuju6tbsuu6e8IbybvRW9j74KvoS%2B%2F796v%2FXAcMDswWfB48JfwtvDWMPUxFHEzsVLxcjGRsbDx0HHv8g9yLzJOsm5yjjKt8s2y7bMNcy1zTXNtc42zrbPN8%2B40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1%2BDYZNjo2WzZ8dp22vvbgNwF3IrdEN2W3hzeot8p36%2FgNuC94UThzOJT4tvjY%2BPr5HPk%2FOWE5g3mlucf56noMui86Ubp0Opb6uXrcOv77IbtEe2c7ijutO9A78zwWPDl8XLx%2F%2FKM8xnzp%2FQ09ML1UPXe9m32%2B%2FeK%2BBn4qPk4%2Bcf6V%2Frn%2B3f8B%2FyY%2FSn9uv5L%2Ftz%2Fbf%2F%2FY2hybQAAAAAAAwAAAACj1wAAVHsAAEzNAACZmgAAJmYAAA9c%22%7D%2C%22cs_sRGB%22%3Atrue%7D%2C%22transparency%22%3A1%7D%2C%22queueBufferSize%22%3A1000%2C%22smtpSecure%22%3A%220%22%7D%2C%22updateSettings%22%3A%7B%7D%2C%22debugStats%22%3A%5B%5D%2C%22users%22%3A1%7D
+---
+POST http://localhost:3000/NotificationServlet HTTP/1.1
+Content-Type: application/x-www-form-urlencoded; charset=UTF-8
+User-Agent: Apache-HttpClient/4.5.13 (Java/21.0.7)
+
+op=getNotificationCount&serverId=49885e13-4f2e-41a6-b66a-8e65f5492d9a&version=4.5.2&extensionVersions=%7B%22Server+Log%22%3A%224.5.2%22%2C%22File+Writer%22%3A%224.5.2%22%2C%22Delimited+Data+Type%22%3A%224.5.2%22%2C%22HTTP+Sender%22%3A%224.5.2%22%2C%22HTTP+Authentication+Settings%22%3A%224.5.2%22%2C%22Image+Viewer%22%3A%224.5.2%22%2C%22Data+Pruner%22%3A%224.5.2%22%2C%22Database+Writer%22%3A%224.5.2%22%2C%22TCP+Sender%22%3A%224.5.2%22%2C%22JavaScript+Filter+Rule%22%3A%224.5.2%22%2C%22Channel+Reader%22%3A%224.5.2%22%2C%22Mapper+Transformer+Step%22%3A%224.5.2%22%2C%22JMS+Listener%22%3A%224.5.2%22%2C%22Message+Builder+Transformer+Step%22%3A%224.5.2%22%2C%22DICOM+Sender%22%3A%224.5.2%22%2C%22External+Script+Transformer+Step%22%3A%224.5.2%22%2C%22External+Script+Filter+Step%22%3A%224.5.2%22%2C%22File+Reader%22%3A%224.5.2%22%2C%22HTTP+Listener%22%3A%224.5.2%22%2C%22DICOM+Listener%22%3A%224.5.2%22%2C%22TCP+Connector+Service+Plugin%22%3A%224.5.2%22%2C%22JavaScript+Reader%22%3A%224.5.2%22%2C%22JSON+Data+Type%22%3A%224.5.2%22%2C%22JavaScript+Writer%22%3A%224.5.2%22%2C%22Web+Service+Sender%22%3A%224.5.2%22%2C%22Text+Viewer%22%3A%224.5.2%22%2C%22XML+Data+Type%22%3A%224.5.2%22%2C%22HL7v2+Data+Type%22%3A%224.5.2%22%2C%22Raw+Data+Type%22%3A%224.5.2%22%2C%22DICOM+Data+Type%22%3A%224.5.2%22%2C%22Destination+Set+Filter+Step%22%3A%224.5.2%22%2C%22Document+Writer%22%3A%224.5.2%22%2C%22Web+Service+Listener%22%3A%224.5.2%22%2C%22HL7v3+Data+Type%22%3A%224.5.2%22%2C%22JavaScript+Transformer+Step%22%3A%224.5.2%22%2C%22Dashboard+Connector+Status+Monitor%22%3A%224.5.2%22%2C%22DICOM+Viewer%22%3A%224.5.2%22%2C%22Directory+Resource+Plugin%22%3A%224.5.2%22%2C%22SMTP+Sender%22%3A%224.5.2%22%2C%22NCPDP+Data+Type%22%3A%224.5.2%22%2C%22Transmission+Mode+-+MLLP%22%3A%224.5.2%22%2C%22Rule+Builder+Filter+Rule%22%3A%224.5.2%22%2C%22Channel+Writer%22%3A%224.5.2%22%2C%22TCP+Listener%22%3A%224.5.2%22%2C%22Database+Reader%22%3A%224.5.2%22%2C%22PDF+Viewer%22%3A%224.5.2%22%2C%22EDI+Data+Type%22%3A%224.5.2%22%2C%22Global+Map+Viewer%22%3A%224.5.2%22%2C%22XSLT+Transformer+Step%22%3A%224.5.2%22%2C%22JMS+Sender%22%3A%224.5.2%22%7D
+---
+POST http://localhost:3000/NotificationServlet HTTP/1.1
+Content-Type: application/x-www-form-urlencoded; charset=UTF-8
+User-Agent: Apache-HttpClient/4.5.13 (Java/21.0.7)
+
+op=getNotifications&serverId=49885e13-4f2e-41a6-b66a-8e65f5492d9a&version=4.4.0&extensionVersions=%7B%22Server+Log%22%3A%224.5.2%22%2C%22File+Writer%22%3A%224.5.2%22%2C%22Delimited+Data+Type%22%3A%224.5.2%22%2C%22HTTP+Sender%22%3A%224.5.2%22%2C%22HTTP+Authentication+Settings%22%3A%224.5.2%22%2C%22Image+Viewer%22%3A%224.5.2%22%2C%22Data+Pruner%22%3A%224.5.2%22%2C%22Database+Writer%22%3A%224.5.2%22%2C%22TCP+Sender%22%3A%224.5.2%22%2C%22JavaScript+Filter+Rule%22%3A%224.5.2%22%2C%22Channel+Reader%22%3A%224.5.2%22%2C%22Mapper+Transformer+Step%22%3A%224.5.2%22%2C%22JMS+Listener%22%3A%224.5.2%22%2C%22Message+Builder+Transformer+Step%22%3A%224.5.2%22%2C%22DICOM+Sender%22%3A%224.5.2%22%2C%22External+Script+Transformer+Step%22%3A%224.5.2%22%2C%22External+Script+Filter+Step%22%3A%224.5.2%22%2C%22File+Reader%22%3A%224.5.2%22%2C%22HTTP+Listener%22%3A%224.5.2%22%2C%22DICOM+Listener%22%3A%224.5.2%22%2C%22TCP+Connector+Service+Plugin%22%3A%224.5.2%22%2C%22JavaScript+Reader%22%3A%224.5.2%22%2C%22JSON+Data+Type%22%3A%224.5.2%22%2C%22JavaScript+Writer%22%3A%224.5.2%22%2C%22Web+Service+Sender%22%3A%224.5.2%22%2C%22Text+Viewer%22%3A%224.5.2%22%2C%22XML+Data+Type%22%3A%224.5.2%22%2C%22HL7v2+Data+Type%22%3A%224.5.2%22%2C%22Raw+Data+Type%22%3A%224.5.2%22%2C%22DICOM+Data+Type%22%3A%224.5.2%22%2C%22Destination+Set+Filter+Step%22%3A%224.5.2%22%2C%22Document+Writer%22%3A%224.5.2%22%2C%22Web+Service+Listener%22%3A%224.5.2%22%2C%22HL7v3+Data+Type%22%3A%224.5.2%22%2C%22JavaScript+Transformer+Step%22%3A%224.5.2%22%2C%22Dashboard+Connector+Status+Monitor%22%3A%224.5.2%22%2C%22DICOM+Viewer%22%3A%224.5.2%22%2C%22Directory+Resource+Plugin%22%3A%224.5.2%22%2C%22SMTP+Sender%22%3A%224.5.2%22%2C%22NCPDP+Data+Type%22%3A%224.5.2%22%2C%22Transmission+Mode+-+MLLP%22%3A%224.5.2%22%2C%22Rule+Builder+Filter+Rule%22%3A%224.5.2%22%2C%22Channel+Writer%22%3A%224.5.2%22%2C%22TCP+Listener%22%3A%224.5.2%22%2C%22Database+Reader%22%3A%224.5.2%22%2C%22PDF+Viewer%22%3A%224.5.2%22%2C%22EDI+Data+Type%22%3A%224.5.2%22%2C%22Global+Map+Viewer%22%3A%224.5.2%22%2C%22XSLT+Transformer+Step%22%3A%224.5.2%22%2C%22JMS+Sender%22%3A%224.5.2%22%7D
+---
\ No newline at end of file
diff --git a/connectservice/usage.js b/connectservice/usage.js
new file mode 100644
index 0000000000..479f0f4789
--- /dev/null
+++ b/connectservice/usage.js
@@ -0,0 +1,172 @@
+import * as yup from 'yup';
+import { parseStringPromise } from 'xml2js';
+import { client } from './elastic.js';
+
+export async function postRegistration(req, res) {
+ const userData = {
+ serverId: req.body.serverId,
+ version: req.body.version,
+ user: (await parseStringPromise(req.body.user, { explicitArray: false }))?.user,
+ };
+
+ console.log(`Received registration for ${JSON.stringify(userData)}`);
+
+ await client.index({
+ index: 'registration',
+ id: userData.serverId,
+ body: userData,
+ });
+
+ res.sendStatus(204);
+}
+
+/*
+POST http://localhost:3000/RegistrationServlet
+Content-Type: application/x-www-form-urlencoded; charset=UTF-8
+User-Agent: Apache-HttpClient/4.5.13 (Java/21.0.7)
+
+serverId=49885e13-4f2e-41a6-b66a-8e65f5492d9a&version=4.5.2&user=user_xml_data
+*/
+export const registrationBodySchema = yup.object({
+ serverId: yup.string().required(),
+ version: yup.string().required(),
+ user: yup.string().required(), // XML data as a string
+}).required();
+
+/*
+registration data:
+
+ 1
+ admin
+ admin@local
+ admin
+ admin
+ admin
+ asdg
+ +1 219-555-1212
+ Clinic
+
+
+ Etc/UTC
+
+ 0
+ United States
+ Consultant - Engineer
+ true
+
+*/
+
+export async function postUsage(req, res) {
+ let usagePayload = JSON.parse(req.body.data);
+
+ // data.serverSettings.defaultAdministratorBackgroundColor is not representable
+ // in ElasticSearch and has a crazy amount of data - so kill it.
+ delete usagePayload.serverSettings.defaultAdministratorBackgroundColor;
+
+ const usageData = {
+ serverId: req.body.serverId,
+ version: req.body.version,
+ server: req.body.server,
+ data: usagePayload
+ };
+
+ console.log(`Received usage data ${JSON.stringify(usageData)}`);
+ await client.index({
+ index: 'usage',
+ id: usageData.serverId,
+ body: usageData,
+ });
+}
+
+/*
+POST http://localhost:3000/UsageStatisticsServlet
+Content-Type: application/x-www-form-urlencoded; charset=UTF-8
+User-Agent: Apache-HttpClient/4.5.13 (Java/21.0.7)
+
+serverId=49885e13-4f2e-41a6-b66a-8e65f5492d9a&version=4.5.2&server=true&data=usage_xml_data
+*/
+export const usageBodySchema = yup.object({
+ serverId: yup.string().required(),
+ version: yup.string().required(),
+ server: yup.boolean().required(),
+ data: yup.string().required(),
+}).required();
+
+/*
+usage data:
+{
+ "mirthVersion": "4.5.2",
+ "serverId": "49885e13-4f2e-41a6-b66a-8e65f5492d9a",
+ "databaseType": "derby",
+ "serverSpecs": {
+ "availableProcessors": 16,
+ "osVersion": "5.15.167.4-microsoft-standard-WSL2",
+ "javaVersion": "21.0.7",
+ "osName": "Linux",
+ "maxMemory": 268435456
+ },
+ "clientSpecs": {
+ "javaVersion": "1.8.0_351"
+ },
+ "globalScripts": {
+ "deployLines": 3,
+ "preprocessorLines": 3,
+ "undeployLines": 4,
+ "postprocessorLines": 5
+ },
+ "channels": [],
+ "invalidChannels": 0,
+ "codeTemplateLibraries": [],
+ "alerts": [],
+ "plugins": [
+ {
+ "pluginPoint": "Server Log"
+ },
+ ...
+ ],
+ "pluginMetaData": [
+ {
+ "serverClasses": [
+ {
+ "name": "com.mirth.connect.plugins.serverlog.ServerLogProvider",
+ "weight": 0,
+ "conditionClass": null
+ }
+ ],
+ "clientClasses": [
+ {
+ "name": "com.mirth.connect.plugins.serverlog.ServerLogClient",
+ "weight": 120,
+ "conditionClass": null
+ }
+ ],
+ "name": "Server Log"
+ },
+ ...
+ ],
+ "connectorMetaData": [
+ {
+ "transformers": "",
+ "protocol": "smtp",
+ "serverClassName": "com.mirth.connect.connectors.smtp.SmtpDispatcher",
+ "name": "SMTP Sender",
+ "type": "DESTINATION",
+ "clientClassName": "com.mirth.connect.connectors.smtp.SmtpSender",
+ "sharedClassName": "com.mirth.connect.connectors.smtp.SmtpDispatcherProperties"
+ },
+ ...
+ ],
+ "serverSettings": {
+ "clearGlobalMap": true,
+ "smtpTimeout": "5000",
+ "smtpAuth": false,
+ "defaultMetaDataColumns": [ ... ],
+ "defaultAdministratorBackgroundColor": { ... },
+ "queueBufferSize": 1000,
+ "smtpSecure": "0"
+ },
+ "updateSettings": {},
+ "debugStats": [],
+ "users": 1
+ }
+*/
diff --git a/docker/README.md b/docker/README.md
new file mode 100644
index 0000000000..98ddfe172f
--- /dev/null
+++ b/docker/README.md
@@ -0,0 +1,409 @@
+
+# Table of Contents
+
+* [Supported tags and respective Dockerfile links](#supported-tags)
+* [Supported Architectures](#supported-architectures)
+* [Quick Reference](#quick-reference)
+* [What is Open Integration Engine](#what-is-connect)
+* [How to use this image](#how-to-use)
+ * [Start a Connect instance](#start-connect)
+ * [Using `docker stack deploy` or `docker-compose`](#using-docker-compose)
+ * [Environment Variables](#environment-variables)
+ * [Common mirth.properties options](#common-mirth-properties-options)
+ * [Other mirth.properties options](#other-mirth-properties-options)
+ * [Using Docker Secrets](#using-docker-secrets)
+ * [Using Volumes](#using-volumes)
+ * [The appdata folder](#the-appdata-folder)
+ * [Additional extensions](#additional-extensions)
+* [License](#license)
+
+------------
+
+
+# Supported tags and respective Dockerfile links [↑](#top)
+
+##### Eclipse Temurin OpenJDK 21
+
+* [latest-jdk](https://github.com/openintegrationengine/engine/blob/main/Dockerfile)
+
+##### Eclipse Temurin OpenJRE 21 (Alpine)
+
+* [latest](https://github.com/openintegrationengine/engine/blob/main/Dockerfile)
+
+------------
+
+
+# Supported Architectures [↑](#top)
+
+Docker images for Open Integration Engine 4.4.0 and later versions support both `linux/amd64` and `linux/arm64` architectures. Earlier versions only support `linux/amd64`. As an example, to pull the latest `linux/arm64` image, use the command
+```
+docker pull --platform linux/arm64 ghcr.io/mgaffigan/oie:latest
+```
+
+------------
+
+
+# Quick Reference [↑](#top)
+
+#### Where to get help:
+
+Engage with the community and project through [the options listed on the main Github page](https://github.com/NicoPiel/OIE/tree/feature/gradle-2?tab=readme-ov-file#community-and-governance).
+
+------------
+
+
+# What is Open Integration Engine [↑](#top)
+
+An open-source message integration engine focused on healthcare. For more information please visit our [GitHub page](https://github.com/openintegrationengine/engine).
+
+------------
+
+
+# How to use this image [↑](#top)
+
+
+## Start a Connect instance [↑](#top)
+
+Quickly start Connect using embedded Derby database and all configuration defaults. At a minimum you will likely want to use the `-p` option to expose the 8443 port so that you can login with the Administrator GUI or CLI:
+
+```bash
+docker run -p 8443:8443 ghcr.io/mgaffigan/oie
+```
+
+You can also use the `--name` option to give your container a unique name, and the `-d` option to detach the container and run it in the background:
+
+```bash
+docker run --name myconnect -d -p 8443:8443 ghcr.io/mgaffigan/oie
+```
+
+To run a specific version of Connect, specify a tag at the end:
+
+```bash
+docker run --name myconnect -d -p 8443:8443 ghcr.io/mgaffigan/oie:3.9
+```
+
+To run using a specific architecture, specify it using the `--platform` argument:
+
+```bash
+docker run --name myconnect -d -p 8443:8443 --platform linux/arm64 ghcr.io/mgaffigan/oie:4.4.0
+```
+
+Look at the [Environment Variables](#environment-variables) section for more available configuration options.
+
+------------
+
+
+## Using [`docker stack deploy`](https://docs.docker.com/engine/reference/commandline/stack_deploy/) or [`docker-compose`](https://github.com/docker/compose) [↑](#top)
+
+With `docker stack` or `docker-compose` you can easily setup and launch multiple related containers. For example you might want to launch both Connect *and* a PostgreSQL database to run alongside it.
+
+```bash
+docker-compose -f stack.yml up
+```
+
+Here's an example `stack.yml` file you can use:
+
+```yaml
+version: "3.1"
+services:
+ mc:
+ image: ghcr.io/mgaffigan/oie
+ platform: linux/amd64
+ environment:
+ - DATABASE=postgres
+ - DATABASE_URL=jdbc:postgresql://db:5432/mirthdb
+ - DATABASE_MAX_CONNECTIONS=20
+ - DATABASE_USERNAME=mirthdb
+ - DATABASE_PASSWORD=mirthdb
+ - DATABASE_MAX_RETRY=2
+ - DATABASE_RETRY_WAIT=10000
+ - KEYSTORE_STOREPASS=docker_storepass
+ - KEYSTORE_KEYPASS=docker_keypass
+ - VMOPTIONS=-Xmx512m
+ ports:
+ - 8080:8080/tcp
+ - 8443:8443/tcp
+ depends_on:
+ - db
+ db:
+ image: postgres
+ environment:
+ - POSTGRES_USER=mirthdb
+ - POSTGRES_PASSWORD=mirthdb
+ - POSTGRES_DB=mirthdb
+ expose:
+ - 5432
+```
+
+[](http://play-with-docker.com/?stack=https://raw.githubusercontent.com/OpenIntegrationEngine/engine/refs/heads/main/docker/examples/play-with-docker-example.yml)
+
+Try it out with Play With Docker! Note that in order to access the 8080/8443 ports from your workstation, follow [their guide](https://github.com/play-with-docker/play-with-docker#how-can-i-connect-to-a-published-port-from-the-outside-world) to format the URL correctly. When you login via the Administrator GUI, use port 443 on the end instead of 8443.
+
+There are other example stack files in the [examples directory](https://github.com/OpenIntegrationEngine/engine/tree/main/docker/examples)!
+
+------------
+
+
+## Environment Variables [↑](#top)
+
+You can use environment variables to configure the [mirth.properties](https://github.com/OpenIntegrationEngine/engine/blob/main/server/conf/mirth.properties) file or to add custom JVM options. More information on the available mirth.properties options can be found in the [Connect User Guide](http://downloads.mirthcorp.com/connect-user-guide/latest/mirth-connect-user-guide.pdf).
+
+To set environment variables, use the `-e` option for each variable on the command line:
+
+```bash
+docker run -e DATABASE='derby' -p 8443:8443 ghcr.io/mgaffigan/oie
+```
+
+You can also use a separate file containing all of your environment variables using the `--env-file` option. For example let's say you create a file **myenvfile.txt**:
+
+```bash
+DATABASE=postgres
+DATABASE_URL=jdbc:postgresql://serverip:5432/mirthdb
+DATABASE_USERNAME=postgres
+DATABASE_PASSWORD=postgres
+DATABASE_MAX_RETRY=2
+DATABASE_RETRY_WAIT=10000
+KEYSTORE_STOREPASS=changeme
+KEYSTORE_KEYPASS=changeme
+VMOPTIONS=-Xmx512m
+```
+
+```bash
+docker run --env-file=myenvfile.txt -p 8443:8443 ghcr.io/mgaffigan/oie
+```
+
+------------
+
+
+### Common mirth.properties options [↑](#top)
+
+
+#### `DATABASE`
+
+The database type to use for the Open Integration Engine backend database. Options:
+
+* derby
+* mysql
+* postgres
+* oracle
+* sqlserver
+
+
+#### `DATABASE_URL`
+
+The JDBC URL to use when connecting to the database. For example:
+* `jdbc:postgresql://serverip:5432/mirthdb`
+
+
+#### `DATABASE_USERNAME`
+
+The username to use when connecting to the database. If you don't want to use an environment variable to store sensitive information like this, look at the [Using Docker Secrets](#using-docker-secrets) section below.
+
+
+#### `DATABASE_PASSWORD`
+
+The password to use when connecting to the database. If you don't want to use an environment variable to store sensitive information like this, look at the [Using Docker Secrets](#using-docker-secrets) section below.
+
+
+#### `DATABASE_MAX_CONNECTIONS`
+
+The maximum number of connections to use for the internal messaging engine connection pool.
+
+
+#### `DATABASE_MAX_RETRY`
+
+On startup, if a database connection cannot be made for any reason, Connect will wait and attempt again this number of times. By default, will retry 2 times (so 3 total attempts).
+
+
+#### `DATABASE_RETRY_WAIT`
+
+The amount of time (in milliseconds) to wait between database connection attempts. By default, will wait 10 seconds between attempts.
+
+
+#### `KEYSTORE_STOREPASS`
+
+The password for the keystore file itself. If you don't want to use an environment variable to store sensitive information like this, look at the [Using Docker Secrets](#using-docker-secrets) section below.
+
+
+#### `KEYSTORE_KEYPASS`
+
+The password for the keys within the keystore, including the server certificate and the secret encryption key. If you don't want to use an environment variable to store sensitive information like this, look at the [Using Docker Secrets](#using-docker-secrets) section below.
+
+
+#### `KEYSTORE_TYPE`
+
+The type of keystore.
+
+
+#### `SESSION_STORE`
+
+If set to true, the web server sessions are stored in the database. This can be useful in situations where you have multiple Connect servers (connecting to the same database) clustered behind a load balancer.
+
+
+#### `VMOPTIONS`
+
+A comma-separated list of JVM command-line options to place in the `.vmoptions` file. For example to set the max heap size:
+
+* -Xmx512m
+
+
+#### `DELAY`
+
+This tells the entrypoint script to wait for a certain amount of time (in seconds). The entrypoint script will automatically use a command-line SQL client to check connectivity and wait until the database is up before starting Connect, but only when using PostgreSQL or MySQL. If you are using Oracle or SQL Server and the database is being started up at the same time as Connect, you may want to use this option to tell Connect to wait a bit to allow the database time to startup.
+
+
+#### `KEYSTORE_DOWNLOAD`
+
+A URL location of a Connect keystore file. This file will be downloaded into the container and Connect will use it as its keystore.
+
+
+#### `EXTENSIONS_DOWNLOAD`
+
+A URL location of a zip file containing Connect extension zip files. The extensions will be installed on the Connect server.
+
+
+#### `CUSTOM_JARS_DOWNLOAD`
+
+A URL location of a zip file containing JAR files. The JAR files will be installed into the `server-launcher-lib` folder on the Connect server, so they will be added to the server's classpath.
+
+
+#### `ALLOW_INSECURE`
+
+Allow insecure SSL connections when downloading files during startup. This applies to keystore downloads, plugin downloads, and server library downloads. By default, insecure connections are disabled but you can enable this option by setting `ALLOW_INSECURE=true`.
+
+
+#### `SERVER_ID`
+
+Set the `server.id` to a specific value. Use this to preserve or set the server ID across restarts and deployments. Using the env-var is preferred over storing `appdata` persistently
+
+------------
+
+
+### Other mirth.properties options [↑](#top)
+
+Other options in the mirth.properties file can also be changed. Any environment variable starting with the `_MP_` prefix will set the corresponding value in mirth.properties. Replace `.` with a single underscore `_` and `-` with two underscores `__`.
+
+Examples:
+
+* Set the server TLS protocols to only allow TLSv1.2 and 1.3:
+ * In the mirth.properties file:
+ * `https.server.protocols = TLSv1.3,TLSv1.2`
+ * As a Docker environment variable:
+ * `_MP_HTTPS_SERVER_PROTOCOLS='TLSv1.3,TLSv1.2'`
+
+* Set the max connections for the read-only database connection pool:
+ * In the mirth.properties file:
+ * `database-readonly.max-connections = 20`
+ * As a Docker environment variable:
+ * `_MP_DATABASE__READONLY_MAX__CONNECTIONS='20'`
+
+------------
+
+
+## Using Docker Secrets [↑](#top)
+
+For sensitive information such as the database/keystore credentials, instead of supplying them as environment variables you can use a [Docker Secret](https://docs.docker.com/engine/swarm/secrets/). There are two secret names this image supports:
+
+##### mirth_properties
+
+If present, any properties in this secret will be merged into the mirth.properties file.
+
+##### mcserver_vmoptions
+
+If present, any JVM options in this secret will be appended onto the mcserver.vmoptions file.
+
+------------
+
+Secrets are supported with [Docker Swarm](https://docs.docker.com/engine/swarm/secrets/), but you can also use them with [`docker-compose`](#using-docker-compose).
+
+For example let's say you wanted to set `keystore.storepass` and `keystore.keypass` in a secure way. You could create a new file, **secret.properties**:
+
+```bash
+keystore.storepass=changeme
+keystore.keypass=changeme
+```
+
+Then in your YAML docker-compose stack file:
+
+```yaml
+version: '3.1'
+services:
+ mc:
+ image: ghcr.io/mgaffigan/oie
+ environment:
+ - VMOPTIONS=-Xmx512m
+ secrets:
+ - mirth_properties
+ ports:
+ - 8080:8080/tcp
+ - 8443:8443/tcp
+secrets:
+ mirth_properties:
+ file: /local/path/to/secret.properties
+```
+
+The **secrets** section at the bottom specifies the local file location for each secret. Change `/local/path/to/secret.properties` to the correct local path and filename.
+
+Inside the configuration for the Connect container there is also a **secrets** section that lists the secrets you want to include for that container.
+
+------------
+
+
+## Using Volumes [↑](#top)
+
+
+#### The appdata folder [↑](#top)
+
+The application data directory (appdata) stores configuration files and temporary data created by Connect after starting up. This usually includes the keystore file and the `server.id` file that stores your server ID. If you are launching Connect as part of a stack/swarm, it's possible the container filesystem is already being preserved. But if not, you may want to consider mounting a **volume** to preserve the appdata folder.
+
+```bash
+docker run -v /local/path/to/appdata:/opt/connect/appdata -p 8443:8443 ghcr.io/mgaffigan/oie
+```
+
+The `-v` option makes a local directory from your filesystem available to the Docker container. Create a folder on your local filesystem, then change the `/local/path/to/appdata` part in the example above to the correct local path.
+
+You can also configure volumes as part of your docker-compose YAML stack file:
+
+```yaml
+version: '3.1'
+services:
+ mc:
+ image: ghcr.io/mgaffigan/oie
+ volumes:
+ - ~/Documents/appdata:/opt/connect/appdata
+```
+
+------------
+
+
+#### Additional extensions [↑](#top)
+
+The entrypoint script will automatically look for any ZIP files in the `/opt/connect/custom-extensions` folder and unzip them into the extensions folder before Connect starts up. So to launch Connect with any additional extensions not included in the base application, do this:
+
+```bash
+docker run -v /local/path/to/custom-extensions:/opt/connect/custom-extensions -p 8443:8443 ghcr.io/mgaffigan/oie
+```
+
+Create a folder on your local filesystem containing the ZIP files for your additional extensions. Then change the `/local/path/to/custom-extensions` part in the example above to the correct local path.
+
+As with the appdata example, you can also configure this volume as part of your docker-compose YAML file.
+
+------------
+
+## Known Limitations
+
+Currently, only the Debian flavored images support the newest authentication scheme in MySQL 8. All others (the Alpine based images) will need the following to force the MySQL database container to start using the old authentication scheme:
+
+```yaml
+command: --default-authentication-plugin=mysql_native_password
+```
+
+Example:
+
+```yaml
+ db:
+ image: mysql
+ command: --default-authentication-plugin=mysql_native_password
+ environment:
+ ...
+```
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
new file mode 100644
index 0000000000..027ef7ccc6
--- /dev/null
+++ b/docker/docker-compose.yml
@@ -0,0 +1,27 @@
+# Build and release compose file
+# -----------------------------------------------------------------------------
+# For production or testing use, see README.md or examples/
+name: OIE-release
+
+services:
+ jre:
+ image: ${repo}:${tag:-dev}
+ build:
+ context: ../
+ dockerfile: Dockerfile
+ target: jre-run
+ x-bake:
+ platforms:
+ - linux/amd64
+ - linux/arm64
+
+ jdk:
+ image: ${repo}:${tag:-dev}-jdk
+ build:
+ context: ../
+ dockerfile: Dockerfile
+ target: jdk-run
+ x-bake:
+ platforms:
+ - linux/amd64
+ - linux/arm64
\ No newline at end of file
diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh
new file mode 100644
index 0000000000..28b5ea148f
--- /dev/null
+++ b/docker/entrypoint.sh
@@ -0,0 +1,240 @@
+#!/bin/bash
+set -e
+
+custom_extension_count=`ls -1 /opt/connect/custom-extensions/*.zip 2>/dev/null | wc -l`
+if [ $custom_extension_count != 0 ]; then
+ echo "Found ${custom_extension_count} custom extensions."
+ for extension in $(ls -1 /opt/connect/custom-extensions/*.zip); do
+ unzip -o -q $extension -d /opt/connect/extensions
+ done
+fi
+
+# set storepass and keypass to 'changeme' so they aren't overwritten later
+KEYSTORE_PASS=changeme
+sed -i "s/^keystore\.storepass\s*=\s*.*\$/keystore.storepass = ${KEYSTORE_PASS//\//\\/}/" /opt/connect/conf/mirth.properties
+sed -i "s/^keystore\.keypass\s*=\s*.*\$/keystore.keypass = ${KEYSTORE_PASS//\//\\/}/" /opt/connect/conf/mirth.properties
+
+# merge the environment variables into /opt/connect/conf/mirth.properties
+# db type
+if ! [ -z "${DATABASE+x}" ]; then
+ sed -i "s/^database\s*=\s*.*\$/database = ${DATABASE//\//\\/}/" /opt/connect/conf/mirth.properties
+fi
+
+# db username
+if ! [ -z "${DATABASE_USERNAME+x}" ]; then
+ sed -i "s/^database\.username\s*=\s*.*\$/database.username = ${DATABASE_USERNAME//\//\\/}/" /opt/connect/conf/mirth.properties
+fi
+
+# db password
+if ! [ -z "${DATABASE_PASSWORD+x}" ]; then
+ sed -i "s/^database\.password\s*=\s*.*\$/database.password = ${DATABASE_PASSWORD//\//\\/}/" /opt/connect/conf/mirth.properties
+fi
+
+# db url
+if ! [ -z "${DATABASE_URL+x}" ]; then
+ sed -i "s/^database\.url\s*=\s*.*\$/database.url = ${DATABASE_URL//\//\\/}/" /opt/connect/conf/mirth.properties
+fi
+
+# database max connections
+if ! [ -z "${DATABASE_MAX_CONNECTIONS+x}" ]; then
+ sed -i "s/^database\.max-connections\s*=\s*.*\$/database.max-connections = ${DATABASE_MAX_CONNECTIONS//\//\\/}/" /opt/connect/conf/mirth.properties
+fi
+
+# database max retries
+if ! [ -z "${DATABASE_MAX_RETRY+x}" ]; then
+ sed -i "s/^database\.connection\.maxretry\s*=\s*.*\$/database.connection.maxretry = ${DATABASE_MAX_RETRY//\//\\/}/" /opt/connect/conf/mirth.properties
+fi
+
+# database retry wait time
+if ! [ -z "${DATABASE_RETRY_WAIT+x}" ]; then
+ sed -i "s/^database\.connection\.retrywaitinmilliseconds\s*=\s*.*\$/database.connection.retrywaitinmilliseconds = ${DATABASE_RETRY_WAIT//\//\\/}/" /opt/connect/conf/mirth.properties
+fi
+
+# keystore storepass
+if ! [ -z "${KEYSTORE_STOREPASS+x}" ]; then
+ sed -i "s/^keystore\.storepass\s*=\s*.*\$/keystore.storepass = ${KEYSTORE_STOREPASS//\//\\/}/" /opt/connect/conf/mirth.properties
+fi
+
+# keystore keypass
+if ! [ -z "${KEYSTORE_KEYPASS+x}" ]; then
+ sed -i "s/^keystore\.keypass\s*=\s*.*\$/keystore.keypass = ${KEYSTORE_KEYPASS//\//\\/}/" /opt/connect/conf/mirth.properties
+fi
+
+if ! [ -z "${KEYSTORE_TYPE+x}" ]; then
+ sed -i "s/^keystore\.type\s*=\s*.*\$/keystore.type = ${KEYSTORE_TYPE//\//\\/}/" /opt/connect/conf/mirth.properties
+fi
+
+# session store
+if ! [ -z "${SESSION_STORE+x}" ]; then
+ LINE_COUNT=`grep "server.api.sessionstore" /opt/connect/conf/mirth.properties | wc -l`
+ if [ $LINE_COUNT -lt 1 ]; then
+ echo -e "\nserver.api.sessionstore = ${SESSION_STORE//\//\\/}" >> /opt/connect/conf/mirth.properties
+ else
+ sed -i "s/^server\.api\.sessionstore\s*=\s*.*\$/server.api.sessionstore = ${SESSION_STORE//\//\\/}/" /opt/connect/conf/mirth.properties
+ fi
+fi
+
+#server ID
+if ! [ -z "${SERVER_ID+x}" ]; then
+ echo -e "server.id = ${SERVER_ID//\//\\/}" > /opt/connect/appdata/server.id
+fi
+
+# merge extra environment variables starting with _MP_ into mirth.properties
+while read -r keyvalue; do
+ KEY="${keyvalue%%=*}"
+ VALUE="${keyvalue#*=}"
+ VALUE=$(tr -dc '\40-\176' <<< "$VALUE")
+
+ if ! [ -z "${KEY}" ] && ! [ -z "${VALUE}" ] && ! [[ ${VALUE} =~ ^\ +$ ]]; then
+
+ # filter for variables starting with "_MP_"
+ if [[ ${KEY} == _MP_* ]]; then
+
+ # echo "found mirth property ${KEY}=${VALUE}"
+
+ # example: _MP_DATABASE_MAX__CONNECTIONS -> database.max-connections
+
+ # remove _MP_
+ # example: DATABASE_MAX__CONNECTIONS
+ ACTUAL_KEY=${KEY:4}
+
+ # switch '__' to '-'
+ # example: DATABASE_MAX-CONNECTIONS
+ ACTUAL_KEY="${ACTUAL_KEY//__/-}"
+
+ # switch '_' to '.'
+ # example: DATABASE.MAX-CONNECTIONS
+ ACTUAL_KEY="${ACTUAL_KEY//_/.}"
+
+ # lower case
+ # example: database.max-connections
+ ACTUAL_KEY="${ACTUAL_KEY,,}"
+
+ # if key does not exist in mirth.properties append it at bottom
+ LINE_COUNT=`grep "^${ACTUAL_KEY}" /opt/connect/conf/mirth.properties | wc -l`
+ if [ $LINE_COUNT -lt 1 ]; then
+ # echo "key ${ACTUAL_KEY} not found in mirth.properties, appending. Value = ${VALUE}"
+ echo -e "\n${ACTUAL_KEY} = ${VALUE//\//\\/}" >> /opt/connect/conf/mirth.properties
+ else # otherwise key exists, overwrite it
+ # echo "key ${ACTUAL_KEY} exists, overwriting. Value = ${VALUE}"
+ ESCAPED_KEY="${ACTUAL_KEY//./\\.}"
+ sed -i "s/^${ESCAPED_KEY}\s*=\s*.*\$/${ACTUAL_KEY} = ${VALUE//\//\\/}/" /opt/connect/conf/mirth.properties
+ fi
+ fi
+ fi
+done <<< "`printenv`"
+
+# Address reflective access by Jackson
+echo "--add-opens=java.desktop/java.awt.color=ALL-UNNAMED" >> oieserver.vmoptions
+
+# merge vmoptions into /opt/connect/oieserver.vmoptions
+if ! [ -z "${VMOPTIONS+x}" ]; then
+ PREV_IFS="$IFS"
+ IFS=","
+ read -ra vmoptions <<< "$VMOPTIONS"
+ IFS="$PREV_IFS"
+
+ for vmoption in "${vmoptions[@]}"
+ do
+ echo "${vmoption}" >> /opt/connect/oieserver.vmoptions
+ done
+fi
+
+# merge the user's secret mirth.properties
+# takes a whole mirth.properties file and merges line by line with /opt/connect/conf/mirth.properties
+if [ -f /run/secrets/mirth_properties ]; then
+
+ # add new line in case /opt/connect/conf/mirth.properties doesn't end with one
+ echo "" >> /opt/connect/conf/mirth.properties
+
+ while read -r keyvalue; do
+ KEY="${keyvalue%%=*}"
+ VALUE="${keyvalue#*=}"
+
+ # remove leading and trailing white space
+ KEY="$(echo -e "${KEY}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
+ VALUE="$(echo -e "${VALUE}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
+
+ if ! [ -z "${KEY}" ] && ! [ -z "${VALUE}" ] && ! [[ ${VALUE} =~ ^\ +$ ]]; then
+ # if key does not exist in mirth.properties append it at bottom
+ LINE_COUNT=`grep "^${KEY}" /opt/connect/conf/mirth.properties | wc -l`
+ if [ $LINE_COUNT -lt 1 ]; then
+ # echo "key ${KEY} not found in mirth.properties, appending. Value = ${VALUE}"
+ echo -e "${KEY} = ${VALUE//\//\\/}" >> /opt/connect/conf/mirth.properties
+ else # otherwise key exists, overwrite it
+ # echo "key ${KEY} exists, overwriting. Value = ${VALUE}"
+ ESCAPED_KEY="${KEY//./\\.}"
+ sed -i "s/^${ESCAPED_KEY}\s*=\s*.*\$/${KEY} = ${VALUE//\//\\/}/" /opt/connect/conf/mirth.properties
+ fi
+ fi
+ done <<< "`cat /run/secrets/mirth_properties`"
+fi
+
+# merge the user's secret vmoptions
+# takes a whole oieserver.vmoptions file and merges line by line with /opt/connect/oieserver.vmoptions
+if [ -f /run/secrets/oieserver_vmoptions ]; then
+ (cat /run/secrets/oieserver_vmoptions ; echo "") >> /opt/connect/oieserver.vmoptions
+fi
+
+# download jars from this url "$CUSTOM_JARS_DOWNLOAD", set by user
+if ! [ -z "${CUSTOM_JARS_DOWNLOAD+x}" ]; then
+ echo "Downloading Jars at ${CUSTOM_JARS_DOWNLOAD}"
+ if ! [ -z "${ALLOW_INSECURE}" ] && [ "${ALLOW_INSECURE}" == "true" ]; then
+ curl -ksSLf "${CUSTOM_JARS_DOWNLOAD}" -o userJars.zip || echo "problem with custom jars download"
+ else
+ curl -sSLf "${CUSTOM_JARS_DOWNLOAD}" -o userJars.zip || echo "problem with custom jars download"
+ fi
+
+ # Unzipping contents of userJars.zip into /opt/connect/server-launcher-lib folder
+ if [ -e "userJars.zip" ]; then
+ echo "Unzipping contents of userJars.zip into /opt/connect/server-launcher-lib"
+ unzip userJars.zip -d /opt/connect/server-launcher-lib
+ # removing the downloaded zip file
+ rm userJars.zip
+ fi
+fi
+
+# download extensions from this url "$EXTENSIONS_DOWNLOAD", set by user
+if ! [ -z "${EXTENSIONS_DOWNLOAD+x}" ]; then
+ echo "Downloading extensions at ${EXTENSIONS_DOWNLOAD}"
+ if ! [ -z "${ALLOW_INSECURE}" ] && [ "${ALLOW_INSECURE}" == "true" ]; then
+ curl -ksSLf "${EXTENSIONS_DOWNLOAD}" -o userExtensions.zip || echo "problem with extensions download"
+ else
+ curl -sSLf "${EXTENSIONS_DOWNLOAD}" -o userExtensions.zip || echo "problem with extensions download"
+ fi
+
+ # Unzipping contents of userExtensions.zip
+ if [ -e "userExtensions.zip" ]; then
+ echo "Unzipping contents of userExtensions.zip"
+ mkdir /tmp/userextensions
+ unzip userExtensions.zip -d /tmp/userextensions
+ # removing the downloaded zip file
+ rm userExtensions.zip
+
+ # Unzipping contents of individual extension zip files into /opt/connect/extensions folder
+ zipFileCount=`ls -1 /tmp/userextensions/*.zip 2>/dev/null | wc -l`
+ if [ $zipFileCount != 0 ]; then
+ echo "Unzipping contents of /tmp/userextensions/ zips into /opt/connect/extensions"
+ for f in /tmp/userextensions/*.zip; do unzip "$f" -d /opt/connect/extensions; done
+ fi
+ # removing the tmp folder
+ rm -rf /tmp/userextensions
+ fi
+fi
+
+# download keystore
+if ! [ -z "${KEYSTORE_DOWNLOAD+x}" ]; then
+ echo "Downloading keystore at ${KEYSTORE_DOWNLOAD}"
+ if ! [ -z "${ALLOW_INSECURE}" ] && [ "${ALLOW_INSECURE}" == "true" ]; then
+ curl -ksSLf "${KEYSTORE_DOWNLOAD}" -o "/opt/connect/appdata/keystore.jks" || echo "problem with keystore download"
+ else
+ curl -sSLf "${KEYSTORE_DOWNLOAD}" -o "/opt/connect/appdata/keystore.jks" || echo "problem with keystore download"
+ fi
+fi
+
+# if delay is set as an environment variable then wait that long in seconds
+if ! [ -z "${DELAY+x}" ]; then
+ sleep $DELAY
+fi
+
+exec "$@"
\ No newline at end of file
diff --git a/docker/examples/README.md b/docker/examples/README.md
new file mode 100644
index 0000000000..edf541d0b8
--- /dev/null
+++ b/docker/examples/README.md
@@ -0,0 +1,129 @@
+# Examples
+
+* [postgres-with-volume.yml](#postgres-with-volume.yml)
+* [mysql-with-volume.yml](#mysql-with-volume.yml)
+* [derby-with-volumes-and-secrets.yml](#derby-with-volumes-and-secrets.yml)
+* [postgres-with-2-connect-servers-in-cluster.yml](#postgres-with-2-connect-servers-in-cluster.yml)
+* [play-with-docker-example.yml](#play-with-docker-example.yml)
+
+------------
+
+
+### postgres-with-volume.yml
+
+This stack launches Connect along with a PostgreSQL database. It also mounts a volume for the appdata folder so that the server ID / keystore file are preserved.
+
+If you want you can edit the stack file and change the location of the appdata volume:
+
+```yaml
+ volumes:
+ - ./data/volumes/appdata:/opt/connect/appdata
+```
+
+Then use [docker-compose](https://docs.docker.com/compose/) to launch:
+
+```bash
+docker-compose -f examples/postgres-with-volume.yml up
+```
+
+------------
+
+
+### mysql-with-volume.yml
+
+This stack launches Connect along with a MySQL database. It also mounts a volume for the appdata folder so that the server ID / keystore file are preserved.
+
+If you want you can edit the stack file and change the location of the appdata volume:
+
+```yaml
+ volumes:
+ - ./data/volumes/appdata:/opt/connect/appdata
+```
+
+Then use [docker-compose](https://docs.docker.com/compose/) to launch:
+
+```bash
+docker-compose -f examples/mysql-with-volume.yml up
+```
+
+------------
+
+
+### derby-with-volumes-and-secrets.yml
+
+This stack launches Connect using its embedded Apache Derby database. It mounts a volume for the appdata folder so that the Derby database, server ID, and keystore file are preserved. It also mounts another `custom-extensions` volume to allow additional extensions (such as our [FHIR Connector](https://www.mirthcorp.com/community/wiki/pages/viewpage.action?pageId=36504815)) to be automatically installed. This file also demonstrates how to use [Docker Secrets](https://docs.docker.com/engine/swarm/secrets/) with docker-compose.
+
+If you want you can edit the stack file and change the volume/secret locations:
+
+```yaml
+ volumes:
+ - ./data/volumes/appdata:/opt/connect/appdata
+ - ./data/volumes/custom-extensions:/opt/connect/custom-extensions
+```
+
+```yaml
+secrets:
+ mirth_properties:
+ file: ./data/secret.properties
+ mcserver_vmoptions:
+ file: ./data/secret.vmoptions
+```
+
+To test installing an extension, you can download the [FHIR Connector](https://www.mirthcorp.com/community/wiki/pages/viewpage.action?pageId=36504815) extension and place the ZIP file into the `examples/data/volumes/custom-extensions` folder.
+
+Any properties you put in the `examples/data/secret.properties` file will be merged into mirth.properties. By default this file contains:
+
+```bash
+keystore.storepass = docker_storepass
+keystore.keypass = docker_keypass
+```
+
+Any entries you put in the `examples/data/secret.vmoptions` file will be appended to the `mcserver.vmoptions` file inside the container. You can use this to set sensitive Java System properties like so:
+
+```bash
+-Dmy.secret.property=thepassword
+```
+
+Finally, use [docker-compose](https://docs.docker.com/compose/) to launch:
+
+```bash
+docker-compose -f examples/derby-with-volumes-and-secrets.yml up
+```
+
+------------
+
+
+### postgres-with-2-connect-servers-in-cluster.yml
+
+This stack launches two clustered Connect servers along with a PostgreSQL database. It mounts volumes for the appdata folders for both servers, and also launches a load balancer ([HAProxy](https://hub.docker.com/_/haproxy)) to forward requests to both Connect servers.
+
+If you want you can edit the stack file and change the volume locations:
+
+```yaml
+ volumes:
+ - ./data/volumes/appdata1:/opt/connect/appdata
+...
+ volumes:
+ - ./data/volumes/appdata2:/opt/connect/appdata
+```
+
+Then use [docker-compose](https://docs.docker.com/compose/) to launch:
+
+```bash
+docker-compose -f examples/postgres-with-2-connect-servers-in-cluster.yml up
+```
+
+Once both servers come online, you can login using the Administrator GUI to the load balanced 8443 port, or you can login specifically to the `mc1` node on the 8441 port, or the `mc2` node on the 8442 port.
+
+The environment also load balances on port 9001, so you can test by creating an HTTP Listener channel on that port and deploying it on both servers. Then you can send requests to `http://localhost:9001` on your local workstation, and you should see that the requests get round-robin load balanced to both servers.
+
+------------
+
+
+### play-with-docker-example.yml
+
+This example file can be used to launch a Connect instance and PostgreSQL database using the [Play With Docker](https://github.com/play-with-docker/play-with-docker) framework. Just click the button below to launch:
+
+[](http://play-with-docker.com/?stack=https://raw.githubusercontent.com/nextgenhealthcare/connect-docker/master/examples/play-with-docker-example.yml)
+
+Note that in order to access the 8080/8443 ports from your workstation, follow [their guide](https://github.com/play-with-docker/play-with-docker#how-can-i-connect-to-a-published-port-from-the-outside-world) to format the URL correctly. When you login via the Administrator GUI, use port 443 on the end instead of 8443.
diff --git a/docker/examples/data/secret.properties b/docker/examples/data/secret.properties
new file mode 100644
index 0000000000..b6844f02c5
--- /dev/null
+++ b/docker/examples/data/secret.properties
@@ -0,0 +1,2 @@
+keystore.storepass = docker_storepass
+keystore.keypass = docker_keypass
\ No newline at end of file
diff --git a/docker/examples/data/secret.vmoptions b/docker/examples/data/secret.vmoptions
new file mode 100644
index 0000000000..bc433a09b5
--- /dev/null
+++ b/docker/examples/data/secret.vmoptions
@@ -0,0 +1 @@
+-Dmy.secret.property=thepassword
\ No newline at end of file
diff --git a/docker/examples/data/volumes/appdata/.keep b/docker/examples/data/volumes/appdata/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/docker/examples/data/volumes/appdata1/.keep b/docker/examples/data/volumes/appdata1/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/docker/examples/data/volumes/appdata2/.keep b/docker/examples/data/volumes/appdata2/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/docker/examples/data/volumes/custom-extensions/.keep b/docker/examples/data/volumes/custom-extensions/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/docker/examples/data/volumes/haproxy/haproxy.cfg b/docker/examples/data/volumes/haproxy/haproxy.cfg
new file mode 100644
index 0000000000..f94986b49e
--- /dev/null
+++ b/docker/examples/data/volumes/haproxy/haproxy.cfg
@@ -0,0 +1,38 @@
+defaults
+ mode tcp
+ option log-health-checks
+ option redispatch
+ retries 3
+ timeout queue 1m
+ timeout connect 10s
+ timeout client 1m
+ timeout server 1m
+ timeout check 10s
+ maxconn 3000
+
+backend mcserver-http
+ balance roundrobin
+ server mc1-http mc1:8080 check
+ server mc2-http mc2:8080 check
+
+frontend mc-http
+ bind *:8080
+ default_backend mcserver-http
+
+backend mcserver-https
+ balance roundrobin
+ server mc1-https mc1:8443 check
+ server mc2-https mc2:8443 check
+
+frontend mc-https
+ bind *:8443
+ default_backend mcserver-https
+
+backend mcserver-9001
+ balance roundrobin
+ server mc1-9001 mc1:9001 check
+ server mc2-9001 mc2:9001 check
+
+frontend mc-9001
+ bind *:9001
+ default_backend mcserver-9001
\ No newline at end of file
diff --git a/docker/examples/derby-with-volumes-and-secrets.yml b/docker/examples/derby-with-volumes-and-secrets.yml
new file mode 100644
index 0000000000..8dca12d66f
--- /dev/null
+++ b/docker/examples/derby-with-volumes-and-secrets.yml
@@ -0,0 +1,21 @@
+version: "3.1"
+services:
+ mc:
+ image: ghcr.io/mgaffigan/oie:latest
+ environment:
+ - VMOPTIONS=-Xmx512m
+ volumes:
+ - ./data/volumes/appdata:/opt/connect/appdata
+ - ./data/volumes/custom-extensions:/opt/connect/custom-extensions
+ secrets:
+ - mirth_properties
+ - mcserver_vmoptions
+ ports:
+ - 8080:8080/tcp
+ - 8443:8443/tcp
+
+secrets:
+ mirth_properties:
+ file: ./data/secret.properties
+ mcserver_vmoptions:
+ file: ./data/secret.vmoptions
diff --git a/docker/examples/example.env b/docker/examples/example.env
new file mode 100644
index 0000000000..d4875ddcf4
--- /dev/null
+++ b/docker/examples/example.env
@@ -0,0 +1,8 @@
+DATABASE=postgres
+DATABASE_URL=jdbc:postgresql://host.docker.internal:5432/mirthdb
+DATABASE_MAX_CONNECTIONS=20
+DATABASE_USERNAME=mirthdb
+DATABASE_PASSWORD=mirthdb
+KEYSTORE_STOREPASS=docker_storepass
+KEYSTORE_KEYPASS=docker_keypass
+VMOPTIONS=-Xmx512m
diff --git a/docker/examples/mysql-with-volume.yml b/docker/examples/mysql-with-volume.yml
new file mode 100644
index 0000000000..244d0c3a97
--- /dev/null
+++ b/docker/examples/mysql-with-volume.yml
@@ -0,0 +1,29 @@
+version: "3.1"
+services:
+ mc:
+ image: ghcr.io/mgaffigan/oie:latest
+ environment:
+ - DATABASE=mysql
+ - DATABASE_URL=jdbc:mysql://db:3306/mirthdb
+ - DATABASE_MAX_CONNECTIONS=20
+ - DATABASE_USERNAME=root
+ - DATABASE_PASSWORD=root_password
+ - KEYSTORE_STOREPASS=docker_storepass
+ - KEYSTORE_KEYPASS=docker_keypass
+ - VMOPTIONS=-Xmx512m
+ volumes:
+ - ./data/volumes/appdata:/opt/connect/appdata
+ ports:
+ - 8080:8080/tcp
+ - 8443:8443/tcp
+ depends_on:
+ - db
+ db:
+ image: mysql
+ command: --default-authentication-plugin=mysql_native_password
+ environment:
+ - MYSQL_ROOT_PASSWORD=root_password
+ - MYSQL_DATABASE=mirthdb
+ - MYSQL_ROOT_HOST=%
+ expose:
+ - 3306
diff --git a/docker/examples/play-with-docker-example.yml b/docker/examples/play-with-docker-example.yml
new file mode 100644
index 0000000000..3d1fba1f98
--- /dev/null
+++ b/docker/examples/play-with-docker-example.yml
@@ -0,0 +1,26 @@
+version: '3.1'
+services:
+ mc:
+ image: ghcr.io/mgaffigan/oie:latest
+ environment:
+ - DATABASE=postgres
+ - DATABASE_URL=jdbc:postgresql://db:5432/mirthdb
+ - DATABASE_MAX_CONNECTIONS=20
+ - DATABASE_USERNAME=mirthdb
+ - DATABASE_PASSWORD=mirthdb
+ - KEYSTORE_STOREPASS=docker_storepass
+ - KEYSTORE_KEYPASS=docker_keypass
+ - VMOPTIONS=-Xmx512m
+ ports:
+ - 8080:8080/tcp
+ - 8443:8443/tcp
+ depends_on:
+ - db
+ db:
+ image: postgres
+ environment:
+ - POSTGRES_USER=mirthdb
+ - POSTGRES_PASSWORD=mirthdb
+ - POSTGRES_DB=mirthdb
+ expose:
+ - 5432
diff --git a/docker/examples/postgres-with-2-connect-servers-in-cluster.yml b/docker/examples/postgres-with-2-connect-servers-in-cluster.yml
new file mode 100644
index 0000000000..9543d81d2c
--- /dev/null
+++ b/docker/examples/postgres-with-2-connect-servers-in-cluster.yml
@@ -0,0 +1,66 @@
+version: "3.1"
+services:
+ mc1:
+ image: ghcr.io/mgaffigan/oie:latest
+ environment:
+ - DATABASE=postgres
+ - DATABASE_URL=jdbc:postgresql://db:5432/mirthdb
+ - DATABASE_MAX_CONNECTIONS=20
+ - DATABASE_USERNAME=mirthdb
+ - DATABASE_PASSWORD=mirthdb
+ - KEYSTORE_STOREPASS=docker_storepass
+ - KEYSTORE_KEYPASS=docker_keypass
+ - SESSION_STORE=true
+ - VMOPTIONS=-Xmx512m
+ volumes:
+ - ./data/volumes/appdata1:/opt/connect/appdata
+ expose:
+ - 8080
+ - 8443
+ - 9001
+ ports:
+ - 8441:8443/tcp
+ depends_on:
+ - db
+ mc2:
+ image: ghcr.io/mgaffigan/oie:latest
+ environment:
+ - DATABASE=postgres
+ - DATABASE_URL=jdbc:postgresql://db:5432/mirthdb
+ - DATABASE_MAX_CONNECTIONS=20
+ - DATABASE_USERNAME=mirthdb
+ - DATABASE_PASSWORD=mirthdb
+ - KEYSTORE_STOREPASS=docker_storepass
+ - KEYSTORE_KEYPASS=docker_keypass
+ - SESSION_STORE=true
+ - DELAY=10
+ - VMOPTIONS=-Xmx512m
+ volumes:
+ - ./data/volumes/appdata2:/opt/connect/appdata
+ expose:
+ - 8080
+ - 8443
+ - 9001
+ ports:
+ - 8442:8443/tcp
+ depends_on:
+ - db
+ haproxy:
+ image: haproxy
+ ports:
+ - 8080:8080/tcp
+ - 8443:8443/tcp
+ - 9001:9001/tcp
+ volumes:
+ - ./data/volumes/haproxy:/usr/local/etc/haproxy:ro
+ depends_on:
+ - mc1
+ - mc2
+ db:
+ image: postgres
+ environment:
+ - POSTGRES_USER=mirthdb
+ - POSTGRES_PASSWORD=mirthdb
+ - POSTGRES_DB=mirthdb
+ expose:
+ - 5432
\ No newline at end of file
diff --git a/docker/examples/postgres-with-volume.yml b/docker/examples/postgres-with-volume.yml
new file mode 100644
index 0000000000..1eb79c0942
--- /dev/null
+++ b/docker/examples/postgres-with-volume.yml
@@ -0,0 +1,28 @@
+version: "3.1"
+services:
+ mc:
+ image: ghcr.io/mgaffigan/oie:latest
+ environment:
+ - DATABASE=postgres
+ - DATABASE_URL=jdbc:postgresql://db:5432/mirthdb
+ - DATABASE_MAX_CONNECTIONS=20
+ - DATABASE_USERNAME=mirthdb
+ - DATABASE_PASSWORD=mirthdb
+ - KEYSTORE_STOREPASS=docker_storepass
+ - KEYSTORE_KEYPASS=docker_keypass
+ - VMOPTIONS=-Xmx512m
+ volumes:
+ - ./data/volumes/appdata:/opt/connect/appdata
+ ports:
+ - 8080:8080/tcp
+ - 8443:8443/tcp
+ depends_on:
+ - db
+ db:
+ image: postgres
+ environment:
+ - POSTGRES_USER=mirthdb
+ - POSTGRES_PASSWORD=mirthdb
+ - POSTGRES_DB=mirthdb
+ expose:
+ - 5432
\ No newline at end of file
diff --git a/docker/mirth-connect.sh b/docker/mirth-connect.sh
new file mode 100644
index 0000000000..da8823176f
--- /dev/null
+++ b/docker/mirth-connect.sh
@@ -0,0 +1,93 @@
+#!/bin/bash
+
+# Open Integration Engine Server Launcher Script
+
+APP_ARGS=("$@")
+
+# Set MIRTH_HOME to the script directory
+MIRTH_HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
+CLASSPATH="$MIRTH_HOME/mirth-server-launcher.jar"
+VMOPTIONS=()
+
+# Default JAVA_PATH based on env, JAVA_HOME, or "java"
+if [[ -n "$JAVA_PATH" ]]; then
+ JAVA_PATH="$JAVA_PATH"
+elif [[ -n "$JAVA_HOME" && -x "$JAVA_HOME/bin/java" ]]; then
+ JAVA_PATH="$JAVA_HOME/bin/java"
+else
+ # Default to "java" if no other options are available
+ JAVA_PATH="java"
+fi
+
+# Set Java options
+parse_vmoptions() {
+ local file="$1"
+
+ if [[ ! -f "$file" ]]; then
+ echo "Error: VM options file not found: $file" >&2
+ return 1
+ fi
+
+ # Read the file line by line
+ while IFS= read -r line; do
+ # Trim leading/trailing whitespace
+ line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
+
+ # Skip empty lines and comments
+ if [[ -z "$line" || "$line" =~ ^# ]]; then
+ continue
+ fi
+
+ # Evaluate environment variables to be their actual values
+ # Question: Is this a security risk?
+ # Answer: No: vmoptions is trusted. We allow replacing JAVA_PATH and
+ # CLASSPATH, so there is a by-design ability for someone with
+ # write privileges to the vmoptions to execute arbitrary code.
+ line=$(eval echo "$line")
+
+ # Check for -include-options directive
+ if [[ "$line" =~ ^-include-options[[:space:]]+(.+) ]]; then
+ local included_file="${BASH_REMATCH[1]}"
+
+ # Resolve relative paths
+ if [[ ! "$included_file" =~ ^/ ]]; then # Not an absolute path
+ included_file="$(dirname "$file")/$included_file"
+ fi
+
+ # Recursively call parse_vmoptions for the included file
+ parse_vmoptions "$included_file"
+ elif [[ "$line" =~ ^-classpath[[:space:]]+(.+) ]]; then
+ # Handle -classpath directive
+ CLASSPATH="${BASH_REMATCH[1]}"
+ elif [[ "$line" =~ ^-classpath/a[[:space:]]+(.+) ]]; then
+ # Handle -classpath/a directive (append to existing classpath)
+ CLASSPATH="${CLASSPATH}:${BASH_REMATCH[1]}"
+ elif [[ "$line" =~ ^-classpath/p[[:space:]]+(.+) ]]; then
+ # Handle -classpath/p directive (prepend to existing classpath)
+ CLASSPATH="${BASH_REMATCH[1]}:${CLASSPATH}"
+ elif [[ "$line" =~ ^-java-cmd[[:space:]]+(.+) ]]; then
+ # Handle -java-cmd directive (set JAVA_PATH)
+ JAVA_PATH="${BASH_REMATCH[1]}"
+ else
+ # Add the option to the accumulated string
+ VMOPTIONS+=("$line")
+ fi
+ done < "$file"
+
+ return 0
+}
+
+# Recursively parse the VM options file
+parse_vmoptions "$MIRTH_HOME/oieserver.vmoptions"
+
+JAVA_OPTS=("${VMOPTIONS[@]}"
+ "-cp" "$CLASSPATH"
+ "com.mirth.connect.server.launcher.MirthLauncher"
+ "${APP_ARGS[@]}")
+
+# Launch Open Integration Engine (as this PID with exec)
+echo "Starting Open Integration Engine..."
+# This doesn't include quotes, which could be confusing. Not sure if there's a
+# better way to do this.
+echo "$JAVA_PATH ${JAVA_OPTS[*]}"
+exec "$JAVA_PATH" "${JAVA_OPTS[@]}"