From fd2752d6cb5a95aca7ed2206a9b8258942f17655 Mon Sep 17 00:00:00 2001
From: Thomas Knall
Date: Mon, 23 Feb 2015 18:57:12 +0100
Subject: Improve Process Engine signal servlet (MOAID-73)
- Update Process Engine signal servlet in order to allow module to provider their own strategy for providing the moa session id.
- Update moa id handbook.
- Update javadoc.
---
.../doc/handbook/moduledevinfo/moduledevinfo.html | 9 ++
.../moa/id/auth/modules/AuthModule.java | 5 +-
.../modules/registration/ModuleRegistration.java | 2 +-
.../auth/servlet/ProcessEngineSignalServlet.java | 27 +++--
.../springweb/SpringWebExpressionEvaluator.java | 17 ++--
id/server/modules/module-stork/pom.xml | 19 +++-
.../stork/STORKProcessEngineSignalServlet.java | 113 +++++++++++++++++++++
.../stork/STORKWebApplicationInitializer.java | 48 ---------
.../stork/STORKProcessEngineSignalServletTest.java | 27 +++++
.../moa/id/auth/modules/stork/SAMLResponse.base64 | 1 +
10 files changed, 204 insertions(+), 64 deletions(-)
create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKProcessEngineSignalServlet.java
delete mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java
create mode 100644 id/server/modules/module-stork/src/test/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKProcessEngineSignalServletTest.java
create mode 100644 id/server/modules/module-stork/src/test/resources/at/gv/egovernment/moa/id/auth/modules/stork/SAMLResponse.base64
diff --git a/id/server/doc/handbook/moduledevinfo/moduledevinfo.html b/id/server/doc/handbook/moduledevinfo/moduledevinfo.html
index 801bfcce6..28e4f1bb4 100644
--- a/id/server/doc/handbook/moduledevinfo/moduledevinfo.html
+++ b/id/server/doc/handbook/moduledevinfo/moduledevinfo.html
@@ -218,6 +218,15 @@
das auf die URL /signalProcess
gemappt wurde.
+ Hinweis: Das interne ProcessEngineSignalServlet
bzw. dessen Methode getMoaSessionId(HttpServletRequest request)
+ können bei Bedarf durch eine Modulspezifische Implementierung überschrieben werden, um ggf. speziellen
+ Anforderungen in Bezug auf die Ermittlung der jeweiligen MOA Session Id Rechnung zu tragen (STORK PEPS
+ unterstützen keine Parameter wie MOASessionID
in der assertion consumer url).
+ Als Beispiel dazu kann das Servlet at.gv.egovernment.moa.id.auth.modules.stork.STORKProcessEngineSignalServlet
+ des STORK-Moduls dienen.
+
+
+
Als Beispiele typischer Tasks können die Klassen im package at.gv.egovernment.moa.id.auth.modules.internal.tasks
herangezogen werden.
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/AuthModule.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/AuthModule.java
index a31f3ceb0..8983403d8 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/AuthModule.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/AuthModule.java
@@ -22,8 +22,9 @@ public interface AuthModule {
int getPriority();
/**
- * Checks if the module has a process, which is able to perform an authentication with the given
- * {@link ExecutionContext}.
+ * Selects a process (description), referenced by its unique id, which is able to perform authentication with the
+ * given {@link ExecutionContext}. Returns {@code null} if no appropriate process (description) was available within
+ * this module.
*
* @param context
* an ExecutionContext for a process.
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/registration/ModuleRegistration.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/registration/ModuleRegistration.java
index fa1878e74..9c950366c 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/registration/ModuleRegistration.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/registration/ModuleRegistration.java
@@ -128,7 +128,7 @@ public class ModuleRegistration {
}
/**
- * Returns the process id of the first process, in the highest ranked
+ * Returns the process description id of the first process, in the highest ranked
* module, which is able to work with the given execution context.
*
* @param context
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/ProcessEngineSignalServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/ProcessEngineSignalServlet.java
index a99b7aeef..d670cbe8a 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/ProcessEngineSignalServlet.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/ProcessEngineSignalServlet.java
@@ -9,6 +9,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringEscapeUtils;
import at.gv.egovernment.moa.id.auth.AuthenticationServer;
+import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants;
import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
import at.gv.egovernment.moa.id.auth.exception.WrongParametersException;
import at.gv.egovernment.moa.id.commons.db.MOASessionDBUtils;
@@ -23,7 +24,7 @@ import at.gv.egovernment.moa.id.util.ParamValidatorUtils;
public class ProcessEngineSignalServlet extends AuthServlet {
private static final long serialVersionUID = 1L;
-
+
/**
* Sets response headers that prevent caching (code taken from {@link AuthServlet}).
*
@@ -51,14 +52,13 @@ public class ProcessEngineSignalServlet extends AuthServlet {
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- String sessionID = StringEscapeUtils.escapeHtml(req.getParameter(PARAM_SESSIONID));
+ String sessionID = StringEscapeUtils.escapeHtml(getMoaSessionId(req));
setNoCachingHeaders(resp);
try {
-
- // check parameter
- if (!ParamValidatorUtils.isValidSessionID(sessionID)) {
- throw new WrongParametersException("ProcessEngineSignal", PARAM_SESSIONID, "auth.12");
+
+ if (sessionID == null) {
+ throw new IllegalStateException("Unable to determine MOA session id.");
}
// retrieve moa session
@@ -80,4 +80,19 @@ public class ProcessEngineSignalServlet extends AuthServlet {
}
+ /**
+ * Retrieves the current MOA session id from the HttpServletRequest parameter
+ * {@link MOAIDAuthConstants#PARAM_SESSIONID}.
+ *
+ * Note that this class/method can be overwritten by modules providing their own strategy of retrieving the
+ * respective MOA session id.
+ *
+ * @param request
+ * The unterlying HttpServletRequest.
+ * @return The current MOA session id.
+ */
+ public String getMoaSessionId(HttpServletRequest request) {
+ return StringEscapeUtils.escapeHtml(request.getParameter(PARAM_SESSIONID));
+ }
+
}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/SpringWebExpressionEvaluator.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/SpringWebExpressionEvaluator.java
index 499e86fa0..af6822ba6 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/SpringWebExpressionEvaluator.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/SpringWebExpressionEvaluator.java
@@ -124,12 +124,17 @@ public class SpringWebExpressionEvaluator implements ExpressionEvaluator {
log.trace("Evaluating '{}'.", expression);
Expression expr = parser.parseExpression(expression);
- Boolean result = expr.getValue(evaluationContext, new SpringWebExpressionEvaluationContext(expressionContext),
- Boolean.class);
- if (result == null) {
- log.warn("Evaluation of '{}' results in null-value.", expression);
- } else {
- log.debug("Expression '{}' -> {}", expression, result);
+ Boolean result = null;
+ try {
+ result = expr.getValue(evaluationContext, new SpringWebExpressionEvaluationContext(expressionContext),
+ Boolean.class);
+ if (result == null) {
+ log.warn("Evaluation of '{}' results in null-value.", expression);
+ } else {
+ log.debug("Expression '{}' -> {}", expression, result);
+ }
+ } catch (Exception e) {
+ log.warn("Expression '{}' could not be processed.", expression, e);
}
return BooleanUtils.isTrue(result);
diff --git a/id/server/modules/module-stork/pom.xml b/id/server/modules/module-stork/pom.xml
index 8761e17ee..234c8d28a 100644
--- a/id/server/modules/module-stork/pom.xml
+++ b/id/server/modules/module-stork/pom.xml
@@ -18,5 +18,22 @@
${basedir}/../../../../repository
-
+
+
+
+
+ org.springframework
+ spring-test
+ test
+
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+
+
diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKProcessEngineSignalServlet.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKProcessEngineSignalServlet.java
new file mode 100644
index 000000000..989f2b6bd
--- /dev/null
+++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKProcessEngineSignalServlet.java
@@ -0,0 +1,113 @@
+package at.gv.egovernment.moa.id.auth.modules.stork;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathFactory;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.bouncycastle.util.encoders.Base64;
+import org.springframework.util.xml.SimpleNamespaceContext;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants;
+import at.gv.egovernment.moa.id.auth.servlet.ProcessEngineSignalServlet;
+import at.gv.egovernment.moa.logging.Logger;
+
+/**
+ * STORK module specific servlet, overloading {@link ProcessEngineSignalServlet}'s method
+ * {@linkplain ProcessEngineSignalServlet#getMoaSessionId(HttpServletRequest) getMoaSessionId(HttpServletRequest)}
+ * extending its capabilities for retrieving the current moa session id.
+ *
+ * This {@code STORKProcessEngineSignalServlet} tries to resolve the moa session id using the following strategy:
+ *
+ * - Use the super class' approach, looking at the HttpServletRequest parameter
+ * {@link MOAIDAuthConstants#PARAM_SESSIONID}.
+ * - Evaluate the request parameter "{@code RelayState}".
+ *
- Finally evaluate the SAML response, which should come base64 encoded as request parameter "{@code SAMLResponse}".
+ *
+ *
+ * @author tknall
+ *
+ */
+@WebServlet(urlPatterns = { "/PEPSConnectorWithLocalSigning", "/PEPSConnector" }, loadOnStartup = 1)
+public class STORKProcessEngineSignalServlet extends ProcessEngineSignalServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ public STORKProcessEngineSignalServlet() {
+ super();
+ Logger.debug("Registering servlet " + getClass().getName() + " with mappings '/PEPSConnectorWithLocalSigning', '/PEPSConnector'.");
+ }
+
+ @Override
+ public String getMoaSessionId(HttpServletRequest request) {
+ String sessionId = super.getMoaSessionId(request);
+
+ try {
+
+ // use SAML2 relayState
+ if (sessionId == null) {
+ sessionId = StringEscapeUtils.escapeHtml(request.getParameter("RelayState"));
+ }
+
+ // take from InResponseTo attribute of SAMLResponse
+ if (sessionId == null) {
+ String base64SamlToken = request.getParameter("SAMLResponse");
+ if (base64SamlToken != null) {
+ byte[] samlToken = Base64.decode(base64SamlToken);
+ Document samlResponse = parseDocument(new ByteArrayInputStream(samlToken));
+
+ XPath xPath = XPathFactory.newInstance().newXPath();
+ SimpleNamespaceContext nsContext = new SimpleNamespaceContext();
+ nsContext.bindNamespaceUri("saml2p", "urn:oasis:names:tc:SAML:2.0:protocol");
+ xPath.setNamespaceContext(nsContext);
+ XPathExpression expression = xPath.compile("string(/saml2p:Response/@InResponseTo)");
+ sessionId = (String) expression.evaluate(samlResponse, XPathConstants.STRING);
+ sessionId = StringEscapeUtils.escapeHtml(StringUtils.trimToNull(sessionId));
+ } else {
+ Logger.warn("No parameter 'SAMLResponse'. Unable to retrieve MOA session id.");
+ }
+ }
+
+ } catch (Exception e) {
+ Logger.warn("Unable to retrieve moa session id.", e);
+ }
+
+ return sessionId;
+ }
+
+ /**
+ * Parses a xml document (namespace aware).
+ *
+ * @param in
+ * The input stream.
+ * @return The DOM document.
+ * @throws ParserConfigurationException
+ * Thrown in case of configuration error.
+ * @throws IOException
+ * Thrown in case of error reading from the input stream.
+ * @throws SAXException
+ * Thrown in case of error parsing the document.
+ */
+ public static Document parseDocument(InputStream in) throws ParserConfigurationException, SAXException, IOException {
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ documentBuilderFactory.setNamespaceAware(true);
+ documentBuilderFactory.setIgnoringElementContentWhitespace(false);
+ documentBuilderFactory.setValidating(false);
+ DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+ return documentBuilder.parse(in);
+ }
+
+}
diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java
deleted file mode 100644
index c54c9a26d..000000000
--- a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package at.gv.egovernment.moa.id.auth.modules.stork;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRegistration;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.web.WebApplicationInitializer;
-
-import at.gv.egovernment.moa.id.auth.servlet.ProcessEngineSignalServlet;
-
-/**
- * Spring automatically discovers {@link WebApplicationInitializer} implementations at startup.
- * This STORK webapp initializer adds the required servlet mappings:
- *
- * - {@code /PEPSConnector}
- * - {@code /PEPSConnectorWithLocalSigning}
- *
- * for the {@linkplain ProcessEngineSignalServlet process engine servlet} (named {@code ProcessEngineSignal}) that wakes
- * up a process in order to execute asynchronous tasks. Therefore the servlet mappings mentioned above do not need to be
- * declared in {@code web.xml}.
- *
- * @author tknall
- * @see ProcessEngineSignalServlet
- */
-public class STORKWebApplicationInitializer implements WebApplicationInitializer {
-
- private Logger log = LoggerFactory.getLogger(getClass());
-
- private static final String SIGNAL_SERVLET_NAME = "ProcessEngineSignal";
-
- private void addMapping(ServletRegistration servletRegistration, String mapping) {
- log.debug("Adding mapping '{}' to servlet '{}' ({}).", mapping, SIGNAL_SERVLET_NAME, servletRegistration.getClassName());
- servletRegistration.addMapping(mapping);
- }
-
- @Override
- public void onStartup(ServletContext servletContext) throws ServletException {
- ServletRegistration servletRegistration = servletContext.getServletRegistration(SIGNAL_SERVLET_NAME);
- if (servletRegistration == null) {
- throw new IllegalStateException("Servlet '" + SIGNAL_SERVLET_NAME + "' expected to be registered (e.g. by web.xml).");
- }
- addMapping(servletRegistration, "/PEPSConnectorWithLocalSigning");
- addMapping(servletRegistration, "/PEPSConnector");
- }
-
-}
diff --git a/id/server/modules/module-stork/src/test/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKProcessEngineSignalServletTest.java b/id/server/modules/module-stork/src/test/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKProcessEngineSignalServletTest.java
new file mode 100644
index 000000000..ab2d3071f
--- /dev/null
+++ b/id/server/modules/module-stork/src/test/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKProcessEngineSignalServletTest.java
@@ -0,0 +1,27 @@
+package at.gv.egovernment.moa.id.auth.modules.stork;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.Test;
+import org.springframework.mock.web.MockHttpServletRequest;
+
+public class STORKProcessEngineSignalServletTest {
+
+ @Test
+ public void testGetMoaSessionId() throws IOException {
+ try (InputStream in = getClass().getResourceAsStream("SAMLResponse.base64")) {
+ String samlResponse = IOUtils.toString(in);
+
+ MockHttpServletRequest request = new MockHttpServletRequest("GET", "/service/createTransactionId");
+ request.addParameter("SAMLResponse", samlResponse);
+ assertEquals("_f2358f2f4db445bd1ac75ce415d76a95",
+ new STORKProcessEngineSignalServlet().getMoaSessionId(request));
+ }
+
+ }
+
+}
diff --git a/id/server/modules/module-stork/src/test/resources/at/gv/egovernment/moa/id/auth/modules/stork/SAMLResponse.base64 b/id/server/modules/module-stork/src/test/resources/at/gv/egovernment/moa/id/auth/modules/stork/SAMLResponse.base64
new file mode 100644
index 000000000..e4061a705
--- /dev/null
+++ b/id/server/modules/module-stork/src/test/resources/at/gv/egovernment/moa/id/auth/modules/stork/SAMLResponse.base64
@@ -0,0 +1 @@
+PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c2FtbDJwOlJlc3BvbnNlIHhtbG5zOnNhbWwycD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIiB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyIgeG1sbnM6c2FtbDI9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIHhtbG5zOnN0b3JrPSJ1cm46ZXU6c3Rvcms6bmFtZXM6dGM6U1RPUks6MS4wOmFzc2VydGlvbiIgeG1sbnM6c3RvcmtwPSJ1cm46ZXU6c3Rvcms6bmFtZXM6dGM6U1RPUks6MS4wOnByb3RvY29sIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIENvbnNlbnQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpjb25zZW50Om9idGFpbmVkIiBEZXN0aW5hdGlvbj0iaHR0cHM6Ly9sb2NhbGhvc3Q6ODQ0My9tb2EtaWQtYXV0aC9QRVBTQ29ubmVjdG9yIiBJRD0iXzY0MjUzODBkMjdlNjViY2I3NDc0OGE1ZjFjOWU2Yzk5IiBJblJlc3BvbnNlVG89Il9mMjM1OGYyZjRkYjQ0NWJkMWFjNzVjZTQxNWQ3NmE5NSIgSXNzdWVJbnN0YW50PSIyMDE1LTAyLTIzVDE2OjEzOjA4LjYxMVoiIFZlcnNpb249IjIuMCI+PHNhbWwyOklzc3VlciBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpuYW1laWQtZm9ybWF0OmVudGl0eSI+aHR0cDovL0MtUEVQUy5nb3YueHg8L3NhbWwyOklzc3Vlcj48ZHM6U2lnbmF0dXJlIHhtbG5zOmRzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIj48ZHM6U2lnbmVkSW5mbz48ZHM6Q2Fub25pY2FsaXphdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNyc2Etc2hhMjU2Ii8+PGRzOlJlZmVyZW5jZSBVUkk9IiNfNjQyNTM4MGQyN2U2NWJjYjc0NzQ4YTVmMWM5ZTZjOTkiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiPjxlYzpJbmNsdXNpdmVOYW1lc3BhY2VzIHhtbG5zOmVjPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiIFByZWZpeExpc3Q9InhzIi8+PC9kczpUcmFuc2Zvcm0+PC9kczpUcmFuc2Zvcm1zPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjc2hhMSIvPjxkczpEaWdlc3RWYWx1ZT5Ha2czSHZoemNSMjlEdko2U1U5TmI2bUlNb009PC9kczpEaWdlc3RWYWx1ZT48L2RzOlJlZmVyZW5jZT48L2RzOlNpZ25lZEluZm8+PGRzOlNpZ25hdHVyZVZhbHVlPkJUOVY0SVNWa2kwdExRUk1OZU1WaTc2QTB5VHpGRXRkdGIwS1VvQVpQUTNNWkcwSmlrL09wRnhoRFdjQ2gxSFR6am5PVzhsa21sVnpJcENGQ2l2cm9GOTZoN2ZLWmloODdLNi9JL084bEhKOGR0R0NobXFERUgrQ2liNEM3K3hsaUNna0luMGZoZzhDYTVBWWtJSzBIZTVHWm9VSk5uOWNKbnFNalNuQ2ZRRzNsUHRLOURPSTVsMU9oTkdYWGIrY3JVVHo2eUVlZFB1OENNUUpiWG1PVFFsb21ud00rN2VxV0RMWnd4dzJ3VHUrV252clpvYUJ4cG8rMlNrMTRhV0gxcytzVDJYbE1URE5ubVpzb21WalYzdTUrWlhxWlZFcm9TYkNkZW9BbmFZM3o2OGkxdWYzQzYvNFRBbzhBbENkbVBYMlNUUSs1Y21OUHMvRHhCM3RrZz09PC9kczpTaWduYXR1cmVWYWx1ZT48ZHM6S2V5SW5mbz48ZHM6WDUwOURhdGE+PGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlGYkRDQ0JGU2dBd0lCQWdJRVFMSzU5ekFOQmdrcWhraUc5dzBCQVFVRkFEQStNUXN3Q1FZRFZRUUdFd0p6YVRFYk1Ca0dBMVVFCkNoTVNjM1JoZEdVdGFXNXpkR2wwZFhScGIyNXpNUkl3RUFZRFZRUUxFd2x6YVhSbGMzUXRZMkV3SGhjTk1UQXdNek13TVRNd09USXoKV2hjTk1UVXdNek13TVRNek9USXpXakNCaGpFTE1Ba0dBMVVFQmhNQ2Mya3hHekFaQmdOVkJBb1RFbk4wWVhSbExXbHVjM1JwZEhWMAphVzl1Y3pFU01CQUdBMVVFQ3hNSlUwbFVSVk5VTFVOQk1Sa3dGd1lEVlFRTEV4QmpaWEowYVdacFkyRjBaWE10ZDJWaU1Tc3dFd1lEClZRUURFd3hVUlZOVUlGQkZVRk1nVTBrd0ZBWURWUVFGRXcwek1EQXpNakF4TURBd01EQXhNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUYKQUFPQ0FROEFNSUlCQ2dLQ0FRRUE0aDZMOVB2MVRLN2Z6NUs2VXVyMFJsaTZFS3pad1R0djl4WGhTdDJ4bEk0d0ZXenpGaUN5NS9PLwpRNUdQUmExMFlvTWM4czdXbU1kTTV5SS9iVTBCRjJ0NVNZdEVIN013YkdhRlpGS0p0MTdPdGJwWkFhQ1NvaDZmbTF5TzBIdFZWa0c5ClVkSDRtc3dTM3dIcC9kMUM5MWxRTmJhMmVuVmMycDlOZDRnWW9wL3picm9FdG9GZUR5SHhUbDBtWU4vY1VIUUZUNEgyNGh6QWZXWGgKMkZPQmZOU252TmwySG5QSk9UNkhuclVCc2R5emtTekxOMEVpczJSMUc1K21Ra3pBd1c2VU9yb29qdk1jbEVKSzN6MW9la2oyT1dqMQpGaGFsVE5tQTVEOWRrRHltVFJuNG8zQlcyUzdvdm1XUG14WVVXOXMyNmJrUGh6L0NiQ1F3SUY5eVBRSURBUUFCbzRJQ0p6Q0NBaU13CkRnWURWUjBQQVFIL0JBUURBZ1dnTUNzR0ExVWRFQVFrTUNLQUR6SXdNVEF3TXpNd01UTXdPVEl6V29FUE1qQXhOVEF6TXpBeE16TTUKTWpOYU1Fc0dBMVVkSUFSRU1FSXdOZ1lMS3dZQkJBR3ZXUUlCQVFJd0p6QWxCZ2dyQmdFRkJRY0NBUllaYUhSMGNEb3ZMM2QzZHk1agpZUzVuYjNZdWMya3ZZM0J6THpBSUJnWUVBSXN3QVFJd0dBWUlLd1lCQlFVSEFRTUVEREFLTUFnR0JnUUFqa1lCQVRBZUJnTlZIUkVFCkZ6QVZnUk4wWlhOMExuTnBMWEJsY0hOQVoyOTJMbk5wTUlIMkJnTlZIUjhFZ2U0d2dlc3dWYUJUb0ZHa1R6Qk5NUXN3Q1FZRFZRUUcKRXdKemFURWJNQmtHQTFVRUNoTVNjM1JoZEdVdGFXNXpkR2wwZFhScGIyNXpNUkl3RUFZRFZRUUxFd2x6YVhSbGMzUXRZMkV4RFRBTApCZ05WQkFNVEJFTlNURE13Z1pHZ2dZNmdnWXVHV0d4a1lYQTZMeTk0TlRBd0xtZHZkaTV6YVM5dmRUMXphWFJsYzNRdFkyRXNiejF6CmRHRjBaUzFwYm5OMGFYUjFkR2x2Ym5Nc1l6MXphVDlqWlhKMGFXWnBZMkYwWlZKbGRtOWpZWFJwYjI1TWFYTjBQMkpoYzJXR0wyaDAKZEhBNkx5OTNkM2N1YzJsblpXNHRZMkV1YzJrdlkzSnNMM05wZEdWemRDOXphWFJsYzNRdFkyRXVZM0pzTUI4R0ExVWRJd1FZTUJhQQpGRlJKQjBhSHp4MkpuY3F1Y3Flb29LQnB0eUhuTUIwR0ExVWREZ1FXQkJReVNlbWVEaTEwRGJlVFlqMXRrR1o1Wm80bXdqQUpCZ05WCkhSTUVBakFBTUJrR0NTcUdTSWIyZlFkQkFBUU1NQW9iQkZZM0xqRURBZ09vTUEwR0NTcUdTSWIzRFFFQkJRVUFBNElCQVFBU1E0bDEKVmQrTVJETEZvMkE2cVlZV0xWcVR2dFBMSWs3djdCc3dtcTJTRkFMMlhtUG9MNXhiUUZlRFcrTGlXaFFCbXJsZ1d5STdnYmkvMS9ycwoxRTAwWjRTa244bDk3dHVJeXV4dkNLVEZoSkR4OXB6Z1VRR293b0NZbzlJemNNTlFweHg2bGtlcHJlQ0R1YytlMGZBYnZUTkdFcHZRCjdEa2dyd0pkY3NVQUVsUTRPSjBpZkVMb2FoMURIOHdwVTMxenI3RDNZc2l6WmdwdTVURUlHUDU0QU9oYkZlWkVtWmxUVTZnd053NGkKVGY2blZRa0dheHNKdDZnR0dzeUw4UlV1dndwVlJSM1dtcGxDdGpYcnlHQ2U0Qi9hZ0FlM0VLVWgxNUlhUHZXcWRpeFNqeVN4akJJMQpiTjhJRUZIWVBabXV3aDdZMUZRdU9ZUUdqdVNMc0p5OTwvZHM6WDUwOUNlcnRpZmljYXRlPjwvZHM6WDUwOURhdGE+PC9kczpLZXlJbmZvPjwvZHM6U2lnbmF0dXJlPjxzYW1sMnA6U3RhdHVzPjxzYW1sMnA6U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIi8+PHNhbWwycDpTdGF0dXNNZXNzYWdlPnVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpzdGF0dXM6U3VjY2Vzczwvc2FtbDJwOlN0YXR1c01lc3NhZ2U+PC9zYW1sMnA6U3RhdHVzPjxzYW1sMjpBc3NlcnRpb24gSUQ9Il8zNzhiMGNjNTk0YThkMzhmMzJjN2M3NjQ5NTQ0OWQ1ZCIgSXNzdWVJbnN0YW50PSIyMDE1LTAyLTIzVDE2OjEzOjA4LjYxMVoiIFZlcnNpb249IjIuMCIgeG1sbnM6eHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIj48c2FtbDI6SXNzdWVyIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOm5hbWVpZC1mb3JtYXQ6ZW50aXR5Ij5odHRwOi8vQy1QRVBTLmdvdi54eDwvc2FtbDI6SXNzdWVyPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI3JzYS1zaGEyNTYiLz48ZHM6UmVmZXJlbmNlIFVSST0iI18zNzhiMGNjNTk0YThkMzhmMzJjN2M3NjQ5NTQ0OWQ1ZCI+PGRzOlRyYW5zZm9ybXM+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIi8+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyI+PGVjOkluY2x1c2l2ZU5hbWVzcGFjZXMgeG1sbnM6ZWM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIgUHJlZml4TGlzdD0ieHMiLz48L2RzOlRyYW5zZm9ybT48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNzaGExIi8+PGRzOkRpZ2VzdFZhbHVlPnJCYTMrbTU0RXVVZzgzSzhpTnVPVDlTaktQcz08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjwvZHM6U2lnbmVkSW5mbz48ZHM6U2lnbmF0dXJlVmFsdWU+RGlZc3UxRXRzMzFocEJySEtvT2IvVnloRisxL1dxYjI5akE4T1J6cnZZb2h1WUlUdjV2V3oxcjhKdkpkK2NubVRNSFlZSU9hQ2V6SXd6L08yUlZ1K3IwWHEwdWNKbmhhcnQ3aUcwTTdFSGR4MVdFaGVzMWtHcHd2c1VjbnlLbm9tdnlSVklNVC80YmU3YTJLRTJZNzJkMGg3bVBsZmV4bVNvUENiaGJYSDIzc0grNTlVYjM1d3pwaXRUUFFtREFmOU5ibVAzV1I2OHpFS0VMTnRuaEZ2VUIyMHZVaGxGNi9hN3pPMlhRTmdFbzFaZW53RlBtWjdYbFhIK29BT3Q1cnFwUXNyMjN4R0tpYXV5YUpjRXpzQ0E5Z0I4YVhMYlQxR0xta1IwTndVa0RMWWxzcWwyeVZ2M01ZaHI5VjU3enk2T3dDR0dzUEltNTdlYnZ1d3RSbE5RPT08L2RzOlNpZ25hdHVyZVZhbHVlPjxkczpLZXlJbmZvPjxkczpYNTA5RGF0YT48ZHM6WDUwOUNlcnRpZmljYXRlPk1JSUZiRENDQkZTZ0F3SUJBZ0lFUUxLNTl6QU5CZ2txaGtpRzl3MEJBUVVGQURBK01Rc3dDUVlEVlFRR0V3SnphVEViTUJrR0ExVUUKQ2hNU2MzUmhkR1V0YVc1emRHbDBkWFJwYjI1ek1SSXdFQVlEVlFRTEV3bHphWFJsYzNRdFkyRXdIaGNOTVRBd016TXdNVE13T1RJegpXaGNOTVRVd016TXdNVE16T1RJeldqQ0JoakVMTUFrR0ExVUVCaE1DYzJreEd6QVpCZ05WQkFvVEVuTjBZWFJsTFdsdWMzUnBkSFYwCmFXOXVjekVTTUJBR0ExVUVDeE1KVTBsVVJWTlVMVU5CTVJrd0Z3WURWUVFMRXhCalpYSjBhV1pwWTJGMFpYTXRkMlZpTVNzd0V3WUQKVlFRREV3eFVSVk5VSUZCRlVGTWdVMGt3RkFZRFZRUUZFdzB6TURBek1qQXhNREF3TURBeE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRgpBQU9DQVE4QU1JSUJDZ0tDQVFFQTRoNkw5UHYxVEs3Zno1SzZVdXIwUmxpNkVLelp3VHR2OXhYaFN0MnhsSTR3Rld6ekZpQ3k1L08vClE1R1BSYTEwWW9NYzhzN1dtTWRNNXlJL2JVMEJGMnQ1U1l0RUg3TXdiR2FGWkZLSnQxN090YnBaQWFDU29oNmZtMXlPMEh0VlZrRzkKVWRING1zd1Mzd0hwL2QxQzkxbFFOYmEyZW5WYzJwOU5kNGdZb3AvemJyb0V0b0ZlRHlIeFRsMG1ZTi9jVUhRRlQ0SDI0aHpBZldYaAoyRk9CZk5TbnZObDJIblBKT1Q2SG5yVUJzZHl6a1N6TE4wRWlzMlIxRzUrbVFrekF3VzZVT3Jvb2p2TWNsRUpLM3oxb2VrajJPV2oxCkZoYWxUTm1BNUQ5ZGtEeW1UUm40bzNCVzJTN292bVdQbXhZVVc5czI2YmtQaHovQ2JDUXdJRjl5UFFJREFRQUJvNElDSnpDQ0FpTXcKRGdZRFZSMFBBUUgvQkFRREFnV2dNQ3NHQTFVZEVBUWtNQ0tBRHpJd01UQXdNek13TVRNd09USXpXb0VQTWpBeE5UQXpNekF4TXpNNQpNak5hTUVzR0ExVWRJQVJFTUVJd05nWUxLd1lCQkFHdldRSUJBUUl3SnpBbEJnZ3JCZ0VGQlFjQ0FSWVphSFIwY0RvdkwzZDNkeTVqCllTNW5iM1l1YzJrdlkzQnpMekFJQmdZRUFJc3dBUUl3R0FZSUt3WUJCUVVIQVFNRUREQUtNQWdHQmdRQWprWUJBVEFlQmdOVkhSRUUKRnpBVmdSTjBaWE4wTG5OcExYQmxjSE5BWjI5MkxuTnBNSUgyQmdOVkhSOEVnZTR3Z2Vzd1ZhQlRvRkdrVHpCTk1Rc3dDUVlEVlFRRwpFd0p6YVRFYk1Ca0dBMVVFQ2hNU2MzUmhkR1V0YVc1emRHbDBkWFJwYjI1ek1SSXdFQVlEVlFRTEV3bHphWFJsYzNRdFkyRXhEVEFMCkJnTlZCQU1UQkVOU1RETXdnWkdnZ1k2Z2dZdUdXR3hrWVhBNkx5OTROVEF3TG1kdmRpNXphUzl2ZFQxemFYUmxjM1F0WTJFc2J6MXoKZEdGMFpTMXBibk4wYVhSMWRHbHZibk1zWXoxemFUOWpaWEowYVdacFkyRjBaVkpsZG05allYUnBiMjVNYVhOMFAySmhjMldHTDJoMApkSEE2THk5M2QzY3VjMmxuWlc0dFkyRXVjMmt2WTNKc0wzTnBkR1Z6ZEM5emFYUmxjM1F0WTJFdVkzSnNNQjhHQTFVZEl3UVlNQmFBCkZGUkpCMGFIengySm5jcXVjcWVvb0tCcHR5SG5NQjBHQTFVZERnUVdCQlF5U2VtZURpMTBEYmVUWWoxdGtHWjVabzRtd2pBSkJnTlYKSFJNRUFqQUFNQmtHQ1NxR1NJYjJmUWRCQUFRTU1Bb2JCRlkzTGpFREFnT29NQTBHQ1NxR1NJYjNEUUVCQlFVQUE0SUJBUUFTUTRsMQpWZCtNUkRMRm8yQTZxWVlXTFZxVHZ0UExJazd2N0Jzd21xMlNGQUwyWG1Qb0w1eGJRRmVEVytMaVdoUUJtcmxnV3lJN2diaS8xL3JzCjFFMDBaNFNrbjhsOTd0dUl5dXh2Q0tURmhKRHg5cHpnVVFHb3dvQ1lvOUl6Y01OUXB4eDZsa2VwcmVDRHVjK2UwZkFidlROR0VwdlEKN0RrZ3J3SmRjc1VBRWxRNE9KMGlmRUxvYWgxREg4d3BVMzF6cjdEM1lzaXpaZ3B1NVRFSUdQNTRBT2hiRmVaRW1abFRVNmd3Tnc0aQpUZjZuVlFrR2F4c0p0NmdHR3N5TDhSVXV2d3BWUlIzV21wbEN0alhyeUdDZTRCL2FnQWUzRUtVaDE1SWFQdldxZGl4U2p5U3hqQkkxCmJOOElFRkhZUFptdXdoN1kxRlF1T1lRR2p1U0xzSnk5PC9kczpYNTA5Q2VydGlmaWNhdGU+PC9kczpYNTA5RGF0YT48L2RzOktleUluZm8+PC9kczpTaWduYXR1cmU+PHNhbWwyOlN1YmplY3Q+PHNhbWwyOk5hbWVJRCBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OnVuc3BlY2lmaWVkIiBOYW1lUXVhbGlmaWVyPSJodHRwOi8vQy1QRVBTLmdvdi54eCI+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4xOm5hbWVpZC1mb3JtYXQ6dW5zcGVjaWZpZWQ8L3NhbWwyOk5hbWVJRD48c2FtbDI6U3ViamVjdENvbmZpcm1hdGlvbiBNZXRob2Q9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpjbTpiZWFyZXIiPjxzYW1sMjpTdWJqZWN0Q29uZmlybWF0aW9uRGF0YSBBZGRyZXNzPSI5MS4xNDMuMTA1LjM3IiBJblJlc3BvbnNlVG89Il9mMjM1OGYyZjRkYjQ0NWJkMWFjNzVjZTQxNWQ3NmE5NSIgTm90T25PckFmdGVyPSIyMDE1LTAyLTIzVDE2OjE4OjA4LjYxMVoiIFJlY2lwaWVudD0iaHR0cHM6Ly9sb2NhbGhvc3Q6ODQ0My9tb2EtaWQtYXV0aC9QRVBTQ29ubmVjdG9yIi8+PC9zYW1sMjpTdWJqZWN0Q29uZmlybWF0aW9uPjwvc2FtbDI6U3ViamVjdD48c2FtbDI6Q29uZGl0aW9ucyBOb3RCZWZvcmU9IjIwMTUtMDItMjNUMTY6MTM6MDguNjExWiIgTm90T25PckFmdGVyPSIyMDE1LTAyLTIzVDE2OjE4OjA4LjYxMVoiPjxzYW1sMjpBdWRpZW5jZVJlc3RyaWN0aW9uPjxzYW1sMjpBdWRpZW5jZT5odHRwczovL2xvY2FsaG9zdDo4NDQzL21vYS1pZC1hdXRoPC9zYW1sMjpBdWRpZW5jZT48L3NhbWwyOkF1ZGllbmNlUmVzdHJpY3Rpb24+PHNhbWwyOk9uZVRpbWVVc2UvPjwvc2FtbDI6Q29uZGl0aW9ucz48c2FtbDI6QXV0aG5TdGF0ZW1lbnQgQXV0aG5JbnN0YW50PSIyMDE1LTAyLTIzVDE2OjEzOjA4LjYxMloiPjxzYW1sMjpTdWJqZWN0TG9jYWxpdHkgQWRkcmVzcz0iOTEuMTQzLjEwNS4zNyIvPjxzYW1sMjpBdXRobkNvbnRleHQ+PHNhbWwyOkF1dGhuQ29udGV4dERlY2wvPjwvc2FtbDI6QXV0aG5Db250ZXh0Pjwvc2FtbDI6QXV0aG5TdGF0ZW1lbnQ+PHNhbWwyOkF0dHJpYnV0ZVN0YXRlbWVudD48c2FtbDI6QXR0cmlidXRlIE5hbWU9Imh0dHA6Ly93d3cuc3RvcmsuZ292LmV1LzEuMC9lSWRlbnRpZmllciIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDp1cmkiIHN0b3JrOkF0dHJpYnV0ZVN0YXR1cz0iQXZhaWxhYmxlIj48c2FtbDI6QXR0cmlidXRlVmFsdWUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzOmFueVR5cGUiPlNJL0FUL1E4Ny93WkcrYWYxOGZ3d1orUjJ6SlNVOG5rSGFOVWh0QW9KRTJ6RTF5SldQdjBvWjRGd2srRFJUYTZNPTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PC9zYW1sMjpBdHRyaWJ1dGU+PHNhbWwyOkF0dHJpYnV0ZSBOYW1lPSJodHRwOi8vd3d3LnN0b3JrLmdvdi5ldS8xLjAvZ2l2ZW5OYW1lIiBOYW1lRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXR0cm5hbWUtZm9ybWF0OnVyaSIgc3Rvcms6QXR0cmlidXRlU3RhdHVzPSJBdmFpbGFibGUiPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZSB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4c2k6dHlwZT0ieHM6YW55VHlwZSI+SmFuZXo8L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDI6QXR0cmlidXRlPjxzYW1sMjpBdHRyaWJ1dGUgTmFtZT0iaHR0cDovL3d3dy5zdG9yay5nb3YuZXUvMS4wL2RhdGVPZkJpcnRoIiBOYW1lRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXR0cm5hbWUtZm9ybWF0OnVyaSIgc3Rvcms6QXR0cmlidXRlU3RhdHVzPSJBdmFpbGFibGUiPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZSB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4c2k6dHlwZT0ieHM6YW55VHlwZSI+MTk5OTA2MDM8L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDI6QXR0cmlidXRlPjxzYW1sMjpBdHRyaWJ1dGUgTmFtZT0iaHR0cDovL3d3dy5zdG9yay5nb3YuZXUvMS4wL3NpZ25lZERvYyIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDp1cmkiIHN0b3JrOkF0dHJpYnV0ZVN0YXR1cz0iQXZhaWxhYmxlIj48c2FtbDI6QXR0cmlidXRlVmFsdWUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzOmFueVR5cGUiPjxuczI6U2lnblJlc3BvbnNlIHhtbG5zOm5zMj0idXJuOm9hc2lzOm5hbWVzOnRjOmRzczoxLjA6Y29yZTpzY2hlbWEiIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjA6YXNzZXJ0aW9uIiB4bWxuczpuczM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiIERvY1VJPSJMT0NBTC9TSS83NDljOWNiOS01YzAzLTQwY2UtYmZmOC00NTc4MDJiMzk2OTUiIFByb2ZpbGU9InVybjpvYXNpczpuYW1lczp0Yzpkc3M6MS4wOnByb2ZpbGVzOlhBZEVTOmZvcm1zOkJFUyIgUmVxdWVzdElEPSJfMWUxNjkyODliZjEwMmNlMmViYzYyMDY4Nzc4OTNjMjQiPjxuczI6UmVzdWx0PjxuczI6UmVzdWx0TWFqb3I+dXJuOm9hc2lzOm5hbWVzOnRjOmRzczoxLjA6cmVzdWx0bWFqb3I6U3VjY2VzczwvbnMyOlJlc3VsdE1ham9yPjwvbnMyOlJlc3VsdD48bnMyOk9wdGlvbmFsT3V0cHV0cz48bnMyOkRvY3VtZW50V2l0aFNpZ25hdHVyZT48bnMyOkRvY3VtZW50PjxuczI6RG9jdW1lbnRVUkw+aHR0cHM6Ly9wZXBzLXRlc3QubWp1Lmdvdi5zaS9Eb2N1bWVudFNlcnZpY2UvRG9jdW1lbnRTZXJ2aWNlPC9uczI6RG9jdW1lbnRVUkw+PC9uczI6RG9jdW1lbnQ+PC9uczI6RG9jdW1lbnRXaXRoU2lnbmF0dXJlPjwvbnMyOk9wdGlvbmFsT3V0cHV0cz48L25zMjpTaWduUmVzcG9uc2U+PC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48L3NhbWwyOkF0dHJpYnV0ZT48c2FtbDI6QXR0cmlidXRlIE5hbWU9Imh0dHA6Ly93d3cuc3RvcmsuZ292LmV1LzEuMC9zdXJuYW1lIiBOYW1lRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXR0cm5hbWUtZm9ybWF0OnVyaSIgc3Rvcms6QXR0cmlidXRlU3RhdHVzPSJBdmFpbGFibGUiPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZSB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4c2k6dHlwZT0ieHM6YW55VHlwZSI+VnpvcmVjPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48L3NhbWwyOkF0dHJpYnV0ZT48L3NhbWwyOkF0dHJpYnV0ZVN0YXRlbWVudD48L3NhbWwyOkFzc2VydGlvbj48L3NhbWwycDpSZXNwb25zZT4=
\ No newline at end of file
--
cgit v1.2.3