diff --git a/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java b/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java
index 1fee9c6ab52f8a1e402b7f5d78cee72cacf749fd..6b7291f1e01fc6ab0c1ce1e27578a217be634603 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java
@@ -562,13 +562,23 @@ public class PluginStarter implements Runnable {
         if (log.shouldLog(Log.WARN))
             log.warn("Stopping plugin: " + appName);
 
-        // stop things in clients.config
-        File clientConfig = new File(pluginDir, "clients.config");
-        if (clientConfig.exists()) {
-            Properties props = new Properties();
-            DataHelper.loadProps(props, clientConfig);
-            List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig);
-            runClientApps(ctx, pluginDir, clients, "stop");
+        ClientApp client = ctx.clientAppManager().getRegisteredApp(appName);
+        if (client != null) {
+            try{
+                client.shutdown(null);
+            }catch(Throwable t){
+                if (log.shouldLog(Log.ERROR))
+                    log.error("Error stopping client app: " + appName, t);
+            }
+        } else {
+            // stop things in clients.config
+            File clientConfig = new File(pluginDir, "clients.config");
+            if (clientConfig.exists()) {
+                Properties props = new Properties();
+                DataHelper.loadProps(props, clientConfig);
+                List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig);
+                runClientApps(ctx, pluginDir, clients, "stop");
+            }
         }
 
         // stop console webapps in console/webapps
@@ -681,7 +691,7 @@ public class PluginStarter implements Runnable {
         File dir = I2PAppContext.getGlobalContext().getConfigDir();
         Properties rv = new Properties();
         File cfgFile = new File(dir, CONFIG_FILE);
-        
+
         try {
             DataHelper.loadProps(rv, cfgFile);
         } catch (IOException ioe) {}
@@ -792,7 +802,7 @@ public class PluginStarter implements Runnable {
      */
     private static void runClientApps(RouterContext ctx, File pluginDir, List<ClientAppConfig> apps, String action) throws Exception {
         Log log = ctx.logManager().getLog(PluginStarter.class);
-        
+
         // initialize pluginThreadGroup and _pendingPluginClients
         String pluginName = pluginDir.getName();
         if (!pluginThreadGroups.containsKey(pluginName))
@@ -800,7 +810,7 @@ public class PluginStarter implements Runnable {
         ThreadGroup pluginThreadGroup = pluginThreadGroups.get(pluginName);
         if (action.equals("start"))
             _pendingPluginClients.put(pluginName, new ConcurrentHashSet<SimpleTimer2.TimedEvent>());
-        
+
         for(ClientAppConfig app : apps) {
             // If the client is a running ClientApp that we want to stop,
             // bypass all the logic below.
@@ -903,7 +913,7 @@ public class PluginStarter implements Runnable {
                     // quick check
                     LoadClientAppsJob.testClient(app.className, cl);
                 } catch (ClassNotFoundException ex) {
-                    // Try again 1 or 2 seconds later. 
+                    // Try again 1 or 2 seconds later.
                     // This should be enough time. Although it is a lousy hack
                     // it should work for most cases.
                     // Perhaps it may be even better to delay a percentage
@@ -966,7 +976,7 @@ public class PluginStarter implements Runnable {
      */
     protected static boolean isPluginRunning(String pluginName, RouterContext ctx, Server s) {
         Log log = ctx.logManager().getLog(PluginStarter.class);
-        
+
         boolean isJobRunning = false;
         Collection<SimpleTimer2.TimedEvent> pending = _pendingPluginClients.get(pluginName);
         if (pending != null && !pending.isEmpty()) {
@@ -987,17 +997,35 @@ public class PluginStarter implements Runnable {
             }
         }
 
+        // load and check for ShellServices.
+        boolean isProcessRunning = false;
+        ClientApp client = ctx.clientAppManager().getRegisteredApp(pluginName);
+        if (client != null) {
+            if (log.shouldLog(Log.DEBUG))
+                log.debug("Checking state of client " + pluginName + client.getState());
+            if (client.getState() == ClientAppState.RUNNING) {
+                isProcessRunning = true;
+            }
+        } else {
+            if (log.shouldLog(Log.DEBUG))
+                log.debug("No client found for plugin " + pluginName);
+        }
+
         boolean isClientThreadRunning = isClientThreadRunning(pluginName, ctx);
         if (log.shouldLog(Log.DEBUG))
-            log.debug("plugin name = <" + pluginName + ">; threads running? " + isClientThreadRunning + "; webapp running? " + isWarRunning + "; jobs running? " + isJobRunning);
-        return isClientThreadRunning || isWarRunning || isJobRunning;
+            log.debug("plugin name = <" + pluginName +
+            ">; threads running? " + isClientThreadRunning +
+            "; webapp running? " + isWarRunning +
+            "; jobs running? " + isJobRunning +
+            "; process running? " + isProcessRunning);
+        return isClientThreadRunning || isWarRunning || isJobRunning || isProcessRunning;
         //
         //if (log.shouldLog(Log.DEBUG))
         //    log.debug("plugin name = <" + pluginName + ">; threads running? " + isClientThreadRunning(pluginName) + "; webapp running? " + WebAppStarter.isWebAppRunning(pluginName) + "; jobs running? " + isJobRunning);
         //return isClientThreadRunning(pluginName) || WebAppStarter.isWebAppRunning(pluginName) || isJobRunning;
         //
     }
-    
+
     /**
      * Returns <code>true</code> if one or more client threads are running in a given plugin.
      * @param pluginName
@@ -1008,7 +1036,7 @@ public class PluginStarter implements Runnable {
         if (group == null)
             return false;
         boolean rv = group.activeCount() > 0;
-        
+
         // Plugins start before the I2P Site, and will create the static Timer thread
         // in RolloverFileOutputStream, which never stops. Don't count it.
         // Ditto HSQLDB Timer (jwebcache)
@@ -1032,7 +1060,7 @@ public class PluginStarter implements Runnable {
 
         return rv;
     }
-    
+
     /**
      *  Perhaps there's an easy way to use Thread.setContextClassLoader()
      *  but I don't see how to make it magically get used for everything.
diff --git a/core/java/src/net/i2p/app/ShellService.java b/core/java/src/net/i2p/app/ShellService.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ba2759a2d53df28d8f16190558e7f24c55d09c5
--- /dev/null
+++ b/core/java/src/net/i2p/app/ShellService.java
@@ -0,0 +1,473 @@
+/*
+ * I2P - An anonymous, secure, and fully-distributed communication network.
+ *
+ * ShellService.java
+ * 2021 The I2P Project
+ * http://www.geti2p.net
+ * This code is public domain.
+ */
+
+package net.i2p.app;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+import java.lang.IllegalArgumentException;
+import java.lang.NullPointerException;
+import java.lang.IndexOutOfBoundsException;
+import java.lang.SecurityException;
+import java.lang.ProcessBuilder;
+import java.lang.reflect.Field;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+
+import java.util.HashMap;
+
+import net.i2p.I2PAppContext;
+import net.i2p.app.ClientApp;
+import net.i2p.app.ClientAppManager;
+import net.i2p.app.ClientAppState;
+import net.i2p.util.Log;
+import net.i2p.util.ShellCommand;
+import net.i2p.util.SystemVersion;
+
+/**
+ * Alternative to ShellCommand based on ProcessBuilder, which manages
+ * a process and keeps track of it's state by PID when a plugin cannot be
+ * managed otherwise. Eliminates the need for a bespoke shell script to manage
+ * application state for forked plugins.
+ *
+ * Keeps track of the PID of the plugin, reports start/stop status correctly
+ * on configplugins. When running a ShellService from a clients.config file,
+ * the user MUST pass -shellservice.name in the args field in clients.config
+ * to override the plugin name. The name passed to -shellservice.name should
+ * be unique to avoid causing issues. (https://i2pgit.org/i2p-hackers/i2p.i2p/-/merge_requests/39#note_4234)
+ * -shellservice.displayName is optional and configures the name of the plugin
+ * which is shown on the console. In most cases, the -shellservice.name must be
+ * the same as the plugin name in order for the $PLUGIN field in clients.config
+ * to match the expected value. If this is not the case, i.e.
+ * (-shellservice.name != plugin.name), you must not use $PLUGIN in your
+ * clients.config file.
+ *
+ * The recommended way to use this tool is to manage a single forked app/process,
+ * with a single ShellService, in a single plugin.
+ *
+ * When you are writing your clients.config file, please take note that $PLUGIN
+ * will be derived from the `shellservice.name` field in the config file args.
+ *
+ * Works on Windows, OSX, and Linux.
+ *
+ * @author eyedeekay
+ * @since 1.6.0/0.9.52
+ */
+public class ShellService implements ClientApp {
+    private static final String NAME_OPTION = "-shellservice.name";
+    private static final String DISPLAY_NAME_OPTION = "-shellservice.displayname";
+    private static final String PLUGIN_DIR = "plugins";
+
+    private final Log _log;
+    private final ProcessBuilder _pb;
+    private final I2PAppContext _context;
+    private final ClientAppManager _cmgr;
+
+    private ClientAppState _state = ClientAppState.UNINITIALIZED;
+
+    private volatile String name = "unnamedClient";
+    private volatile String displayName = "unnamedClient";
+
+    private Process _p;
+    private volatile long _pid;
+
+    public ShellService(I2PAppContext context, ClientAppManager listener, String[] args) {
+        _context = context;
+        _cmgr = listener;
+        _log = context.logManager().getLog(ShellService.class);
+
+        String[] procArgs = trimArgs(args);
+
+        String process = writeScript(procArgs);
+
+        if(_log.shouldLog(Log.DEBUG)){
+            _log.debug("Process: " + process);
+            _log.debug("Name: " + this.getName() + ", DisplayName: " + this.getDisplayName());
+        }
+
+        _pb = new ProcessBuilder(process);
+
+        File pluginDir = new File(_context.getConfigDir(), PLUGIN_DIR + '/' + this.getName());
+        _pb.directory(pluginDir);
+        changeState(ClientAppState.INITIALIZED, "ShellService: "+getName()+" set up and initialized");
+    }
+
+    private String scriptArgs(String[] procArgs) {
+        StringBuilder tidiedArgs = new StringBuilder();
+        for (int i = 0; i < procArgs.length; i++) {
+            tidiedArgs.append(" \""+procArgs[i]+"\" ");
+        }
+        return tidiedArgs.toString();
+    }
+
+    private String batchScript(String[] procArgs) {
+        String cmd = procArgs[0];
+        if(_log.shouldLog(Log.DEBUG))
+            _log.debug("cmd: " + cmd);
+        String Script = "start \""+getName()+"\" "+scriptArgs(procArgs)+System.lineSeparator();
+        Script += "tasklist /V /FI \"WindowTitle eq "+getName()+"*\""+System.lineSeparator();
+        return Script;
+    }
+
+    private String shellScript(String[] procArgs) {
+        String cmd = procArgs[0];
+        if(_log.shouldLog(Log.DEBUG))
+            _log.debug("cmd: " + cmd);
+        File file = new File(cmd);
+        if(file.exists()){
+            if (!file.isDirectory() && !file.canExecute()) {
+                file.setExecutable(true);
+            }
+        }
+        String Script = "nohup "+scriptArgs(procArgs)+" 1>/dev/null 2>/dev/null & echo $!"+System.lineSeparator();
+        return Script;
+    }
+
+    private void deleteScript() {
+        File dir = _context.getTempDir();
+        if (SystemVersion.isWindows()) {
+            File bat = new File(dir, "shellservice-"+getName()+".bat");
+            bat.delete();
+        } else {
+            File sh = new File(dir, "shellservice-"+getName()+".sh");
+            sh.delete();
+        }
+    }
+
+    private String writeScript(File dir, String extension, String[] procArgs){
+        File script = new File(dir, "shellservice-"+getName()+extension);
+        script.delete();
+        if (_log.shouldLog(Log.DEBUG))
+            _log.debug("Writing Batch Script " + script.toString());
+        FileWriter scriptWriter = null;
+        try {
+            script.createNewFile();
+            scriptWriter = new FileWriter(script);
+            if (extension == ".bat" || extension == "")
+                scriptWriter.write(batchScript(procArgs));
+            if (extension == ".sh")
+                scriptWriter.write(shellScript(procArgs));
+            changeState(ClientAppState.INITIALIZED, "ShellService: "+getName()+" initialized");
+        } catch (IOException ioe) {
+            if (_log.shouldLog(Log.ERROR))
+                _log.error("Error writing wrapper script shellservice-" + getName() + extension, ioe);
+            script.delete();
+            changeState(ClientAppState.START_FAILED, "ShellService: "+getName()+" failed to start, error writing script.", ioe);
+        } finally {
+            try {
+                if (scriptWriter != null)
+                    scriptWriter.close();
+            } catch (IOException ioe) {
+                if (_log.shouldLog(Log.ERROR)){
+                    _log.error("Error writing wrapper script shellservice-" + getName() + extension, ioe);
+                    changeState(ClientAppState.START_FAILED, "ShellService: "+getName()+" failed to start, error closing script writer", ioe);
+                }
+            }
+        }
+        script.setExecutable(true);
+        return script.getAbsolutePath();
+    }
+
+    private String writeScript(String[] procArgs){
+        File dir = _context.getTempDir();
+        if (SystemVersion.isWindows()) {
+            return writeScript(dir, ".bat", procArgs);
+        } else {
+            return writeScript(dir, ".sh", procArgs);
+        }
+    }
+
+    private String getPID() {
+        return String.valueOf(_pid);
+    }
+
+    /**
+     * Queries {@code tasklist} if the process ID {@code pid} is running.
+     *
+     * Contain code from Stack Overflow(https://stackoverflow.com/questions/2533984/java-checking-if-any-process-id-is-currently-running-on-windows/41489635)
+     *
+     * @param pid the PID to check
+     * @return {@code true} if the PID is running, {@code false} otherwise
+     */
+    private boolean isProcessIdRunningOnWindows(String pid){
+        try {
+            String cmds[] = {"cmd", "/c", "tasklist /FI \"PID eq " + pid + "\""};
+            ShellCommand _shellCommand = new ShellCommand();
+            return _shellCommand.executeSilentAndWaitTimed(cmds, 240);
+        } catch (Exception ex) {
+            if (_log.shouldLog(Log.DEBUG))
+                _log.debug("Error checking if process is running", ex);
+            changeState(ClientAppState.CRASHED, "ShellService: "+getName()+" status unknowable", ex);
+        }
+        return false;
+    }
+
+    private boolean isProcessIdRunningOnUnix(String pid) {
+        try {
+            String cmds[] = {"ps", "-p", pid};
+            ShellCommand _shellCommand = new ShellCommand();
+            return _shellCommand.executeSilentAndWaitTimed(cmds, 240);
+        } catch (Exception ex) {
+            if (_log.shouldLog(Log.DEBUG))
+                _log.debug("Error checking if process is running", ex);
+            changeState(ClientAppState.CRASHED, "ShellService: "+getName()+" status unknowable", ex);
+        }
+        return false;
+    }
+
+    private boolean isProcessIdRunning(String pid) {
+        boolean running = false;
+        if (SystemVersion.isWindows()) {
+            running = isProcessIdRunningOnWindows(pid);
+        } else {
+            running = isProcessIdRunningOnUnix(pid);
+        }
+        return running;
+    }
+
+    private long getPidOfProcess() {
+        if (_log.shouldLog(Log.DEBUG))
+            _log.debug("Finding the PID of: " + getName());
+        if (isProcessIdRunning(getPID())) {
+            if (_log.shouldLog(Log.DEBUG))
+                _log.debug("Read PID in from " + getPID().toString());
+            return Long.valueOf(getPID());
+        }
+        BufferedInputStream bis = null;
+        ByteArrayOutputStream buf = null;
+        try {
+            if (_log.shouldLog(Log.DEBUG))
+                _log.debug("Getting PID from output");
+            if (_p == null) {
+                if (_log.shouldLog(Log.WARN)) {
+                    _log.warn("Process is null, something is wrong");
+                    changeState(ClientAppState.CRASHED, "ShellService: "+getName()+" should be runnning but the process is null.");
+                    return -1;
+                }
+            }
+            bis = new BufferedInputStream(_p.getInputStream());
+            buf = new ByteArrayOutputStream();
+            for (int result = bis.read(); result != -1; result = bis.read()) {
+                buf.write((byte) result);
+                if (result == 10)
+                    break;
+            }
+            String pidString = buf.toString("UTF-8").replaceAll("[\\r\\n\\t ]", "");
+            long pid = Long.valueOf(pidString);
+            if (_log.shouldLog(Log.DEBUG))
+                _log.debug("Found " + getName() + "process with PID: " + pid);
+            return pid;
+        } catch (IOException ioe) {
+            if (_log.shouldLog(Log.ERROR))
+                _log.error("Error getting PID of application started by shellservice-" + getName() , ioe);
+            changeState(ClientAppState.CRASHED, "ShellService: "+getName()+" PID could not be discovered", ioe);
+        } finally {
+            if (bis != null) {
+                try {
+                    bis.close();   // close the input stream
+                } catch (IOException ioe) {
+                    if (_log.shouldLog(Log.ERROR))
+                        _log.error("Error closing input stream", ioe);
+                }
+            }
+            if (buf != null) {
+                try {
+                    buf.close();   // close the output stream
+                } catch (IOException ioe) {
+                    if (_log.shouldLog(Log.ERROR))
+                        _log.error("Error closing output stream", ioe);
+                }
+            }
+
+        }
+        return -1;
+    }
+
+    private String[] trimArgs(String[] args) {
+        ArrayList<String> newargs = new ArrayList<String>();
+        for (int i = 0; i < args.length; i++) {
+            if ( args[i].startsWith(NAME_OPTION) ) {
+                if (args[i].contains("=")){
+                    name = args[i].split("=")[1];
+                }else{
+                    name = args[i+1];
+                    i++;
+                }
+            } else if ( args[i].startsWith(DISPLAY_NAME_OPTION) ) {
+                if (args[i].contains("=")) {
+                    displayName = args[i].split("=")[1];
+                } else {
+                    displayName = args[i+1];
+                    i++;
+                }
+            } else {
+                newargs.add(args[i]);
+            }
+        }
+        if (getName() == null)
+            throw new IllegalArgumentException("ShellService: ShellService passed with args="+args+" must have a name");
+        if (getDisplayName() == null)
+            displayName = name;
+        String arr[] = new String[newargs.size()];
+        return newargs.toArray(arr);
+    }
+
+    private synchronized void changeState(ClientAppState newState, String message, Exception ex){
+        if (_state != newState) {
+            _state = newState;
+            _cmgr.notify(this, newState, message, ex);
+        }
+    }
+
+    private synchronized void changeState(ClientAppState newState, String message){
+        changeState(newState, message, null);
+    }
+
+    /**
+     *  Determine if a ShellService corresponding to the wrapped application
+     *  has been started yet. If it hasn't, attempt to start the process and
+     *  notify the router that it has been started.
+     */
+    public synchronized void startup() throws Throwable {
+        if (getName().equals("unnamedClient")){
+            if (_log.shouldLog(Log.WARN))
+                _log.warn("ShellService has no name, not starting");
+            return;
+        }
+        changeState(ClientAppState.STARTING, "ShellService: "+getName()+" starting");
+        boolean start = checkIsStopped();
+        if (start) {
+            _p = _pb.start();
+            long pid = getPidOfProcess();
+            if (pid == -1 && _log.shouldLog(Log.ERROR))
+                _log.error("Error getting PID of application from recently instantiated shellservice" + getName());
+            if (_log.shouldLog(Log.DEBUG))
+                _log.debug("Started " + getName() + "process with PID: " + pid);
+            this._pid = pid;
+            deleteScript();
+        }
+        changeState(ClientAppState.RUNNING, "ShellService: "+getName()+" started");
+        Boolean reg = _cmgr.register(this);
+        if (reg){
+            if (_log.shouldLog(Log.DEBUG))
+                _log.debug("ShellService: "+getName()+" registered with the router");
+        } else {
+            if (_log.shouldLog(Log.WARN))
+                _log.warn("ShellService: "+getName()+" failed to register with the router");
+            _cmgr.unregister(this);
+            _cmgr.register(this);
+        }
+        return;
+    }
+
+    /**
+     *  Determine if the PID found in "shellservice"+getName()+".pid" is
+     *  running or not. Result is the answer to the question "Should I attempt
+     *  to start the process" so returns false when PID corresponds to a running
+     *  process and true if it does not.
+     *
+     *  Usage in PluginStarter.isClientThreadRunning requires the !inverse of
+     *  the result.
+     *
+     *  @return {@code true} if the PID is NOT running, {@code false} if the PID is running
+     */
+    public boolean checkIsStopped() {
+        if (_log.shouldLog(Log.DEBUG))
+            _log.debug("Checking process status " + getName());
+        return !isProcessIdRunning(getPID());
+    }
+
+    /**
+     *  Query the stored PID of the previously launched ShellService and attempt
+     *  to send SIGINT on Unix, SIGKILL on Windows in order to stop the wrapped
+     *  application.
+     *
+     *  @param args generally null but could be stopArgs from clients.config
+     */
+    public synchronized void shutdown(String[] args) throws Throwable {
+        String pid = getPID();
+        if (getName().equals("unnamedClient")){
+            if (_log.shouldLog(Log.WARN))
+                _log.warn("ShellService has no name, not shutting down");
+            return;
+        }
+        changeState(ClientAppState.STOPPING, "ShellService: "+getName()+" stopping");
+        if (_p != null) {
+            if (_log.shouldLog(Log.DEBUG))
+                _log.debug("Stopping " + getName() + "process started with ShellService, PID: " + pid);
+            _p.destroy();
+        }
+        ShellCommand _shellCommand = new ShellCommand();
+        if (SystemVersion.isWindows()) {
+            if (_log.shouldLog(Log.DEBUG))
+                _log.debug("Stopping " + getName() + "process with PID: " + pid + "on Windows");
+            String cmd[] = {"cmd", "/c", "taskkill /F /T /PID " + pid};
+            _shellCommand.executeSilentAndWaitTimed(cmd, 240);
+        } else {
+            if (_log.shouldLog(Log.DEBUG))
+                _log.debug("Stopping " + getName() + "process with PID: " + pid + "on Unix");
+            String cmd[] = {"kill", pid};
+            _shellCommand.executeSilentAndWaitTimed(cmd, 240);
+        }
+        deleteScript();
+        changeState(ClientAppState.STOPPED, "ShellService: "+getName()+" stopped");
+        _cmgr.unregister(this);
+    }
+
+    /**
+     *  Query the PID of the wrapped application and determine if it is running
+     *  or not. Convert to corresponding ClientAppState and return the correct
+     *  value.
+     *
+     *  @return non-null
+     */
+    public ClientAppState getState() {
+        String pid = getPID();
+        if (!isProcessIdRunning(pid)) {
+            changeState(ClientAppState.STOPPED, "ShellService: "+getName()+" stopped");
+            _cmgr.unregister(this);
+        }
+        return _state;
+    }
+
+    /**
+     *  The generic name of the ClientApp, used for registration,
+     *  e.g. "console". Do not translate. Has a special use in the context of
+     *  ShellService, it is used to name the file which contains the PID of the
+     *  process ShellService is wrapping.
+     *
+     *  @return non-null
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     *  The display name of the ClientApp, used in user interfaces.
+     *  The app must translate.
+     *  @return non-null
+     */
+    public String getDisplayName() {
+        return displayName;
+    }
+
+}
diff --git a/installer/resources/certificates/plugin/hankhill19580_at_gmail.com.crt b/installer/resources/certificates/plugin/hankhill19580_at_gmail.com.crt
new file mode 100644
index 0000000000000000000000000000000000000000..4752e422b68d8ebe44517a66ec2ff1f29483c1f5
--- /dev/null
+++ b/installer/resources/certificates/plugin/hankhill19580_at_gmail.com.crt
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+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
++rk8M5oGGIQr6dAgBkpRHg==
+-----END CERTIFICATE-----