Tuesday, August 22, 2017

Spring Boot-Jetty-Ubuntu

This post applies to:

  • Jetty version 9.4.6.v20170531
  • Spring Boot 1.5.6.RELEASE
  • Ubuntu 16.04.3 LTS

The problem

Running Spring Boot applications in Jetty environment as WARs is not as simple as the documentation states due to:

The main requirement was to run some simple Spring Boot application that performs a scheduled task. The main problem was that after installing Jetty and deploying the WAR nothing happened…Ups!

The Resolution

Step 1

The Spring Boot application was using the following entry point:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;

@SpringBootApplication
@EnableScheduling
public class SalusptApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(SalusptApplication.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(SalusptApplication.class, args);
    }
    
    @Bean
    public TaskScheduler taskScheduler() {
        return new ConcurrentTaskScheduler();
    }
    
}

At this point application started to run properly from IDE (STS) so it was the time to deploy it on Jetty: run mvn package and you obtain the WAR under two flavours:

  • target<application>.WAR
  • target<application>-original.war

The first one contains also the jars for running with embeded application server but you can safely deploy it.

Remark: Jetty was running as root since no JETTY_USER environment variable was defined yet.

Deployment looked successfull (no errors in logs) but nothing happened.

After some trial/error attempts it was quite obvious that configure method was not called so no chance for Spring Boot initialization process to be triggered. Nothing in official Spring Boot reference was mentioning about enabling anotations module on Jetty, of course we have had to be more attentive in our kindergarten Java courses…(I am a newbie in Spring/Jetty world, why not to find out things the hard way!)

Step 2

After enabling the annotation module another surprise…application still not working: I’ve got (by analysing logs) an error similar to the one described here: https://stackoverflow.com/questions/41995029/jersey-spring3–2–25–1-produces-failed-startup-of-context-error-in-jetty–9–3. Removing Jersey dependency in Maven pom.xml solved the problem (somehow, at some point in future I plan to have some REST API exposed to the world, fingers cross!)

Step 3

Without really understanding what I was doing at the phase of generatig the project scheleton through https://start.spring.io/ I added devtools to the project. Well, trying to deploy to Jetty the WAR I’ve got another error, something with not finding an entry point for restarting the application. Till restarting I neede a first proper start so…good by devtools.

Step 4

Now added JETTY_USER=jetty to /env/defaults/jetty

Another surprise…Jetty would not start. After another late night hours of trial and error attempts I noticed that if I change ownership of \run\jetty to user jetty the server starts and I can deploy the WAR. The problem was that after restrating the server the permissions on /run directory were lost. Ok, time to analyze /etc/init.d/jetty. The short story (also described here: https://stackoverflow.com/questions/17999729/jetty-bash-script-works-only-with-root-user):

The evil hides behind the following snippet: if [ -z "$JETTY_RUN" ] then JETTY_RUN=$(findDirectory -w /var/run /usr/var/run $JETTY_BASE /tmp)/jetty [ -d "$JETTY_RUN" ] || mkdir $JETTY_RUN fi If no JETTY_RUN environment variable is defined the script attempts to build a base one and appends jetty to it; so the directory is created (surprise) under root account and later attempt to start jetty (start-stop-daemon -S -p"$JETTY_PID" $CH_USER -d"$JETTY_BASE" -b -m -a "$JAVA" -- "${RUN_ARGS[@]}" start-log-file="$JETTY_START_LOG") with JETTY_START_LOG="$JETTY_RUN/$NAME-start.log" will fail since jetty user will not be able to create the log file.

The solution was to pre-define the JETTY_RUN environment variable pointing to a directory where jetty is owner.

Appendix

Full Jetty installation steps

Java 8

sudo -i

Run one by one the following commands;watch out for capitalized Y on answers.

apt install software-properties-common
add-apt-repository ppa:webupd8team/java
apt-get update
apt-get install oracle-java8-installer

#apt-get install  oracle-java8-set-default

Download and install Jetty

sudo -i
mkdir -p /opt/jetty
mkdir -p /opt/web/jettybase
mkdir /opt/web/jettybase/run
mkdir -p /opt/jetty/temp
useradd --user-group --shell /bin/false --home-dir /opt/jetty/temp jetty
chown -R jetty:jetty /opt/jetty
chown -R jetty:jetty /opt/web/jettybase
chown -R jetty:jetty /opt/jetty/temp
cd /tmp
wget http://central.maven.org/maven2/org/eclipse/jetty/jetty-distribution/9.4.6.v20170531/jetty-distribution-9.4.6.v20170531.tar.gz
cd /opt/jetty

tar -zxf /tmp/jetty-distribution-9.4.6.v20170531.tar.gz 
cd /opt/jetty/jetty-distribution-9.4.6.v20170531

cp bin/jetty.sh /etc/init.d/jetty

cd /opt/web/jettybase

java -jar /opt/jetty/jetty-distribution-9.4.6.v20170531/start.jar --add-to-start=deploy,http,console-capture,annotations
#configures Java for debug, must be removed from production environmemnts
echo "JETTY_HOME=/opt/jetty/jetty-distribution-9.4.6.v20170531" > /etc/default/jetty
echo "JETTY_BASE=/opt/web/jettybase" >> /etc/default/jetty
echo "JETTY_RUN=/opt/web/jettybase/run" >> /etc/default/jetty
echo "TMPDIR=/opt/jetty/temp" >> /etc/default/jetty
echo "JAVA_OPTIONS=\"-Xdebug -agentlib:jdwp=transport=dt_socket,address=9999,server=y,suspend=n\"" >> /etc/default/jetty
echo "JETTY_USER=jetty" >> /etc/default/jetty


service jetty check

update-rc.d jetty defaults

service jetty start

service jetty status

# if service not starting check all involved directories that jetty user is owner

# just for development, in order to be able to copy files through WinSCP:
chmod o+w /opt/web/jettybase/webapps

How Spring Boot Bootsrap Should Work

See also http://piotrnowicki.com/2011/03/using-servlets–3–0-servletcontainerinitializer/

The >=3.0 Servlet Container (Jetty in our case) will try (if annotations module is activated!) to find in class path all implementations of javax.servlet.ServletContainerInitializer and will call its onStartup method with a Set of all implementations of the @HandlesTypes mentioned class:

package org.springframework.web;
...

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {

    /**
     * Delegate the {@code ServletContext} to any {@link WebApplicationInitializer}
     * implementations present on the application classpath.
     * <p>Because this class declares @{@code HandlesTypes(WebApplicationInitializer.class)},
     * Servlet 3.0+ containers will automatically scan the classpath for implementations
     * of Spring's {@code WebApplicationInitializer} interface and provide the set of all
     * such types to the {@code webAppInitializerClasses} parameter of this method.
     * <p>If no {@code WebApplicationInitializer} implementations are found on the classpath,
     * this method is effectively a no-op. An INFO-level log message will be issued notifying
     * the user that the {@code ServletContainerInitializer} has indeed been invoked but that
     * no {@code WebApplicationInitializer} implementations were found.
     * <p>Assuming that one or more {@code WebApplicationInitializer} types are detected,
     * they will be instantiated (and <em>sorted</em> if the @{@link
     * org.springframework.core.annotation.Order @Order} annotation is present or
     * the {@link org.springframework.core.Ordered Ordered} interface has been
     * implemented). Then the {@link WebApplicationInitializer#onStartup(ServletContext)}
     * method will be invoked on each instance, delegating the {@code ServletContext} such
     * that each instance may register and configure servlets such as Spring's
     * {@code DispatcherServlet}, listeners such as Spring's {@code ContextLoaderListener},
     * or any other Servlet API componentry such as filters.
     * @param webAppInitializerClasses all implementations of
     * {@link WebApplicationInitializer} found on the application classpath
     * @param servletContext the servlet context to be initialized
     * @see WebApplicationInitializer#onStartup(ServletContext)
     * @see AnnotationAwareOrderComparator
     */
    @Override
    public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
            throws ServletException {

        List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();

        if (webAppInitializerClasses != null) {
            for (Class<?> waiClass : webAppInitializerClasses) {
                // Be defensive: Some servlet containers provide us with invalid classes,
                // no matter what @HandlesTypes says...
...

PHA+VGhpcyBwb3N0IGFwcGxpZXMgdG86PC9wPg0KDQo8dWw+DQo8bGk+SmV0dHkgdmVyc2lv biA5LjQuNi52MjAxNzA1MzE8L2xpPg0KPGxpPlNwcmluZyBCb290IDEuNS42LlJFTEVBU0U8 L2xpPg0KPGxpPlVidW50dSAxNi4wNC4zIExUUzwvbGk+DQo8L3VsPg0KDQo8aDEgaWQ9InRo ZXByb2JsZW0iPlRoZSBwcm9ibGVtPC9oMT4NCg0KPHA+UnVubmluZyBTcHJpbmcgQm9vdCBh cHBsaWNhdGlvbnMgaW4gSmV0dHkgZW52aXJvbm1lbnQgYXMgV0FScyBpcyBub3QgYXMgc2lt cGxlIGFzIHRoZSBkb2N1bWVudGF0aW9uIHN0YXRlcyBkdWUgdG86PC9wPg0KDQo8dWw+DQo8 bGk+TGFjayBvZiBkb2N1bWVudGF0aW9uIGFib3V0IGluc3RhbGxpbmcgSmV0dHkgKHNwZWNp ZmllZCB2ZXJzaW9uKSBvbiBVYnVudHUgKHNwZWNpZmllZCB2ZXJzaW9uKSAoc29tZSBzYW1w bGVzIEkgdXNlZCk6DQoNCjx1bD4NCjxsaT48YSBocmVmPSJodHRwOi8vd3d3LnVidW50dWdl ZWsuY29tL2luc3RhbGwtamV0dHktOS1qYXZhLXNlcnZsZXQtZW5naW5lLWFuZC13ZWJzZXJ2 ZXItb24tdWJ1bnR1LTE1LTA0LXNlcnZlci5odG1sIj5odHRwOi8vd3d3LnVidW50dWdlZWsu Y29tL2luc3RhbGwtamV0dHkmIzgyMTE7OS1qYXZhLXNlcnZsZXQtZW5naW5lLWFuZC13ZWJz ZXJ2ZXItb24tdWJ1bnR1JiM4MjExOzE1JiM4MjExOzA0LXNlcnZlci5odG1sPC9hPjwvbGk+ DQo8bGk+PGEgaHJlZj0iaHR0cHM6Ly9ob3N0cHJlc3RvLmNvbS9jb21tdW5pdHkvdHV0b3Jp YWxzL2hvdy10by1pbnN0YWxsLWpldHR5LTktb24tdWJ1bnR1LTE0LTA0LyI+aHR0cHM6Ly9o b3N0cHJlc3RvLmNvbS9jb21tdW5pdHkvdHV0b3JpYWxzL2hvdy10by1pbnN0YWxsLWpldHR5 JiM4MjExOzktb24tdWJ1bnR1JiM4MjExOzE0JiM4MjExOzA0LzwvYT48L2xpPg0KPC91bD48 L2xpPg0KPGxpPkNvbXBsZXRlbHkgb3V0ZGF0ZWQvd3JvbmcgSmV0dHkgaW5zdGFsbGF0aW9u IGluc3RydWN0aW9ucyAoPGEgaHJlZj0iaHR0cHM6Ly93d3cuZWNsaXBzZS5vcmcvamV0dHkv ZG9jdW1lbnRhdGlvbi85LjQueC9zdGFydHVwLXVuaXgtc2VydmljZS5odG1sIj5odHRwczov L3d3dy5lY2xpcHNlLm9yZy9qZXR0eS9kb2N1bWVudGF0aW9uLzkuNC54L3N0YXJ0dXAtdW5p eC1zZXJ2aWNlLmh0bWw8L2E+KTwvbGk+DQo8L3VsPg0KDQo8cD5UaGUgbWFpbiByZXF1aXJl bWVudCB3YXMgdG8gcnVuIHNvbWUgc2ltcGxlIFNwcmluZyBCb290IGFwcGxpY2F0aW9uIHRo YXQgcGVyZm9ybXMgYSBzY2hlZHVsZWQgdGFzay4NClRoZSBtYWluIHByb2JsZW0gd2FzIHRo YXQgYWZ0ZXIgaW5zdGFsbGluZyBKZXR0eSBhbmQgZGVwbG95aW5nIHRoZSBXQVIgbm90aGlu ZyBoYXBwZW5lZCYjODIzMDtVcHMhPC9wPg0KDQo8aDEgaWQ9InRoZXJlc29sdXRpb24iPlRo ZSBSZXNvbHV0aW9uPC9oMT4NCg0KPGgyIGlkPSJzdGVwMSI+U3RlcCAxPC9oMj4NCg0KPHA+ VGhlIFNwcmluZyBCb290IGFwcGxpY2F0aW9uIHdhcyB1c2luZyB0aGUgZm9sbG93aW5nIGVu dHJ5IHBvaW50OjwvcD4NCg0KPHByZT48Y29kZSBjbGFzcz0iamF2YSI+aW1wb3J0IG9yZy5z cHJpbmdmcmFtZXdvcmsuYm9vdC5TcHJpbmdBcHBsaWNhdGlvbjsNCmltcG9ydCBvcmcuc3By aW5nZnJhbWV3b3JrLmJvb3QuYXV0b2NvbmZpZ3VyZS5TcHJpbmdCb290QXBwbGljYXRpb247 DQppbXBvcnQgb3JnLnNwcmluZ2ZyYW1ld29yay5ib290LmJ1aWxkZXIuU3ByaW5nQXBwbGlj YXRpb25CdWlsZGVyOw0KaW1wb3J0IG9yZy5zcHJpbmdmcmFtZXdvcmsuYm9vdC53ZWIuc3Vw cG9ydC5TcHJpbmdCb290U2VydmxldEluaXRpYWxpemVyOw0KaW1wb3J0IG9yZy5zcHJpbmdm cmFtZXdvcmsuY29udGV4dC5hbm5vdGF0aW9uLkJlYW47DQppbXBvcnQgb3JnLnNwcmluZ2Zy YW1ld29yay5zY2hlZHVsaW5nLlRhc2tTY2hlZHVsZXI7DQppbXBvcnQgb3JnLnNwcmluZ2Zy YW1ld29yay5zY2hlZHVsaW5nLmFubm90YXRpb24uRW5hYmxlU2NoZWR1bGluZzsNCmltcG9y dCBvcmcuc3ByaW5nZnJhbWV3b3JrLnNjaGVkdWxpbmcuY29uY3VycmVudC5Db25jdXJyZW50 VGFza1NjaGVkdWxlcjsNCg0KQFNwcmluZ0Jvb3RBcHBsaWNhdGlvbg0KQEVuYWJsZVNjaGVk dWxpbmcNCnB1YmxpYyBjbGFzcyBTYWx1c3B0QXBwbGljYXRpb24gZXh0ZW5kcyBTcHJpbmdC b290U2VydmxldEluaXRpYWxpemVyIHsNCg0KICAgIEBPdmVycmlkZQ0KICAgIHByb3RlY3Rl ZCBTcHJpbmdBcHBsaWNhdGlvbkJ1aWxkZXIgY29uZmlndXJlKFNwcmluZ0FwcGxpY2F0aW9u QnVpbGRlciBhcHBsaWNhdGlvbikgew0KICAgICAgICByZXR1cm4gYXBwbGljYXRpb24uc291 cmNlcyhTYWx1c3B0QXBwbGljYXRpb24uY2xhc3MpOw0KICAgIH0NCg0KICAgIHB1YmxpYyBz dGF0aWMgdm9pZCBtYWluKFN0cmluZ1tdIGFyZ3MpIHsNCiAgICAgICAgU3ByaW5nQXBwbGlj YXRpb24ucnVuKFNhbHVzcHRBcHBsaWNhdGlvbi5jbGFzcywgYXJncyk7DQogICAgfQ0KICAg IA0KICAgIEBCZWFuDQogICAgcHVibGljIFRhc2tTY2hlZHVsZXIgdGFza1NjaGVkdWxlcigp IHsNCiAgICAgICAgcmV0dXJuIG5ldyBDb25jdXJyZW50VGFza1NjaGVkdWxlcigpOw0KICAg IH0NCiAgICANCn0NCjwvY29kZT48L3ByZT4NCg0KPHA+QXQgdGhpcyBwb2ludCBhcHBsaWNh dGlvbiBzdGFydGVkIHRvIHJ1biBwcm9wZXJseSBmcm9tIElERSAoU1RTKSBzbyBpdCB3YXMg dGhlIHRpbWUgdG8gZGVwbG95IGl0IG9uIEpldHR5OiBydW4gPGNvZGU+bXZuIHBhY2thZ2U8 L2NvZGU+IGFuZCB5b3Ugb2J0YWluIHRoZSBXQVIgdW5kZXIgdHdvIGZsYXZvdXJzOjwvcD4N Cg0KPHVsPg0KPGxpPnRhcmdldCZsdDthcHBsaWNhdGlvbiZndDsuV0FSPC9saT4NCjxsaT50 YXJnZXQmbHQ7YXBwbGljYXRpb24mZ3Q7LW9yaWdpbmFsLndhcjwvbGk+DQo8L3VsPg0KDQo8 cD5UaGUgZmlyc3Qgb25lIGNvbnRhaW5zIGFsc28gdGhlIGphcnMgZm9yIHJ1bm5pbmcgd2l0 aCBlbWJlZGVkIGFwcGxpY2F0aW9uIHNlcnZlciBidXQgeW91IGNhbiBzYWZlbHkgZGVwbG95 IGl0LjwvcD4NCg0KPHA+PHN0cm9uZz5SZW1hcms6PC9zdHJvbmc+IEpldHR5IHdhcyBydW5u aW5nIGFzIDxjb2RlPnJvb3Q8L2NvZGU+IHNpbmNlIG5vIDxjb2RlPkpFVFRZX1VTRVI8L2Nv ZGU+IGVudmlyb25tZW50IHZhcmlhYmxlIHdhcyBkZWZpbmVkIHlldC48L3A+DQoNCjxwPkRl cGxveW1lbnQgbG9va2VkIHN1Y2Nlc3NmdWxsIChubyBlcnJvcnMgaW4gbG9ncykgYnV0IG5v dGhpbmcgaGFwcGVuZWQuIDwvcD4NCg0KPHA+QWZ0ZXIgc29tZSB0cmlhbC9lcnJvciBhdHRl bXB0cyBpdCB3YXMgcXVpdGUgb2J2aW91cyB0aGF0IDxjb2RlPmNvbmZpZ3VyZTwvY29kZT4g bWV0aG9kIHdhcyBub3QgY2FsbGVkIHNvIG5vIGNoYW5jZSBmb3IgU3ByaW5nIEJvb3QgaW5p dGlhbGl6YXRpb24gcHJvY2VzcyB0byBiZSB0cmlnZ2VyZWQuIE5vdGhpbmcgaW4gb2ZmaWNp YWwgU3ByaW5nIEJvb3QgcmVmZXJlbmNlIHdhcyBtZW50aW9uaW5nIGFib3V0IGVuYWJsaW5n IDxjb2RlPmFub3RhdGlvbnM8L2NvZGU+IG1vZHVsZSBvbiBKZXR0eSwgb2YgY291cnNlIHdl IGhhdmUgaGFkIHRvIGJlIG1vcmUgYXR0ZW50aXZlIGluIG91ciBraW5kZXJnYXJ0ZW4gSmF2 YSBjb3Vyc2VzJiM4MjMwOyhJIGFtIGEgbmV3YmllIGluIFNwcmluZy9KZXR0eSB3b3JsZCwg d2h5IG5vdCB0byBmaW5kIG91dCB0aGluZ3MgdGhlIGhhcmQgd2F5ISk8L3A+DQoNCjxoMiBp ZD0ic3RlcDIiPlN0ZXAgMjwvaDI+DQoNCjxwPkFmdGVyIGVuYWJsaW5nIHRoZSA8Y29kZT5h bm5vdGF0aW9uPC9jb2RlPiBtb2R1bGUgYW5vdGhlciBzdXJwcmlzZSYjODIzMDthcHBsaWNh dGlvbiBzdGlsbCBub3Qgd29ya2luZzogSSYjODIxNzt2ZSBnb3QgKGJ5IGFuYWx5c2luZyBs b2dzKSBhbiBlcnJvciBzaW1pbGFyIHRvIHRoZSBvbmUgZGVzY3JpYmVkIGhlcmU6IDxhIGhy ZWY9Imh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzQxOTk1MDI5L2plcnNl eS1zcHJpbmczLTItMjUtMS1wcm9kdWNlcy1mYWlsZWQtc3RhcnR1cC1vZi1jb250ZXh0LWVy cm9yLWluLWpldHR5LTktMyI+aHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMv NDE5OTUwMjkvamVyc2V5LXNwcmluZzMmIzgyMTE7MiYjODIxMTsyNSYjODIxMTsxLXByb2R1 Y2VzLWZhaWxlZC1zdGFydHVwLW9mLWNvbnRleHQtZXJyb3ItaW4tamV0dHkmIzgyMTE7OSYj ODIxMTszPC9hPi4gUmVtb3ZpbmcgSmVyc2V5IGRlcGVuZGVuY3kgaW4gTWF2ZW4gcG9tLnht bCBzb2x2ZWQgdGhlIHByb2JsZW0gKHNvbWVob3csIGF0IHNvbWUgcG9pbnQgaW4gZnV0dXJl IEkgcGxhbiB0byBoYXZlIHNvbWUgUkVTVCBBUEkgZXhwb3NlZCB0byB0aGUgd29ybGQsIGZp bmdlcnMgY3Jvc3MhKTwvcD4NCg0KPGgyIGlkPSJzdGVwMyI+U3RlcCAzPC9oMj4NCg0KPHA+ V2l0aG91dCByZWFsbHkgdW5kZXJzdGFuZGluZyB3aGF0IEkgd2FzIGRvaW5nIGF0IHRoZSBw aGFzZSBvZiBnZW5lcmF0aWcgdGhlIHByb2plY3Qgc2NoZWxldG9uIHRocm91Z2ggPGEgaHJl Zj0iaHR0cHM6Ly9zdGFydC5zcHJpbmcuaW8vIj5odHRwczovL3N0YXJ0LnNwcmluZy5pby88 L2E+IEkgYWRkZWQgPGNvZGU+ZGV2dG9vbHM8L2NvZGU+IHRvIHRoZSBwcm9qZWN0LiBXZWxs LCB0cnlpbmcgdG8gZGVwbG95IHRvIEpldHR5IHRoZSBXQVIgSSYjODIxNzt2ZSBnb3QgYW5v dGhlciBlcnJvciwgc29tZXRoaW5nIHdpdGggbm90IGZpbmRpbmcgYW4gZW50cnkgcG9pbnQg Zm9yIHJlc3RhcnRpbmcgdGhlIGFwcGxpY2F0aW9uLiBUaWxsIHJlc3RhcnRpbmcgSSBuZWVk ZSBhIGZpcnN0IHByb3BlciBzdGFydCBzbyYjODIzMDtnb29kIGJ5IDxjb2RlPmRldnRvb2xz PC9jb2RlPi48L3A+DQoNCjxoMiBpZD0ic3RlcDQiPlN0ZXAgNDwvaDI+DQoNCjxwPk5vdyBh ZGRlZCA8Y29kZT5KRVRUWV9VU0VSPWpldHR5PC9jb2RlPiB0byA8Y29kZT4vZW52L2RlZmF1 bHRzL2pldHR5PC9jb2RlPjwvcD4NCg0KPHA+QW5vdGhlciBzdXJwcmlzZSYjODIzMDtKZXR0 eSB3b3VsZCBub3Qgc3RhcnQuIEFmdGVyIGFub3RoZXIgbGF0ZSBuaWdodCBob3VycyBvZiB0 cmlhbCBhbmQgZXJyb3IgYXR0ZW1wdHMgSSBub3RpY2VkIHRoYXQgaWYgSSBjaGFuZ2Ugb3du ZXJzaGlwIG9mIFxydW5camV0dHkgdG8gdXNlciBqZXR0eSB0aGUgc2VydmVyIHN0YXJ0cyBh bmQgSSBjYW4gZGVwbG95IHRoZSBXQVIuIFRoZSBwcm9ibGVtIHdhcyB0aGF0IGFmdGVyIHJl c3RyYXRpbmcgdGhlIHNlcnZlciB0aGUgcGVybWlzc2lvbnMgb24gL3J1biBkaXJlY3Rvcnkg d2VyZSBsb3N0Lg0KT2ssIHRpbWUgdG8gYW5hbHl6ZSA8Y29kZT4vZXRjL2luaXQuZC9qZXR0 eTwvY29kZT4uIFRoZSBzaG9ydCBzdG9yeSAoYWxzbyBkZXNjcmliZWQgaGVyZTogPGEgaHJl Zj0iaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMTc5OTk3MjkvamV0dHkt YmFzaC1zY3JpcHQtd29ya3Mtb25seS13aXRoLXJvb3QtdXNlciI+aHR0cHM6Ly9zdGFja292 ZXJmbG93LmNvbS9xdWVzdGlvbnMvMTc5OTk3MjkvamV0dHktYmFzaC1zY3JpcHQtd29ya3Mt b25seS13aXRoLXJvb3QtdXNlcjwvYT4pOjwvcD4NCg0KPHA+VGhlIGV2aWwgaGlkZXMgYmVo aW5kIHRoZSBmb2xsb3dpbmcgc25pcHBldDoNCjxjb2RlPg0KaWYgWyAteiAmcXVvdDskSkVU VFlfUlVOJnF1b3Q7IF0NCnRoZW4NCiAgSkVUVFlfUlVOPSQoZmluZERpcmVjdG9yeSAtdyAv dmFyL3J1biAvdXNyL3Zhci9ydW4gJEpFVFRZX0JBU0UgL3RtcCkvamV0dHkNCiAgWyAtZCAm cXVvdDskSkVUVFlfUlVOJnF1b3Q7IF0gfHwgbWtkaXIgJEpFVFRZX1JVTg0KZmkNCjwvY29k ZT4NCklmIG5vIDxjb2RlPkpFVFRZX1JVTjwvY29kZT4gZW52aXJvbm1lbnQgdmFyaWFibGUg aXMgZGVmaW5lZCB0aGUgc2NyaXB0IGF0dGVtcHRzIHRvIGJ1aWxkIGEgYmFzZSBvbmUgYW5k IGFwcGVuZHMgPGNvZGU+amV0dHk8L2NvZGU+IHRvIGl0OyBzbyB0aGUgZGlyZWN0b3J5IGlz IGNyZWF0ZWQgKHN1cnByaXNlKSB1bmRlciA8Y29kZT5yb290PC9jb2RlPiBhY2NvdW50IGFu ZCBsYXRlciBhdHRlbXB0IHRvIHN0YXJ0IGpldHR5ICg8Y29kZT5zdGFydC1zdG9wLWRhZW1v biAtUyAtcCZxdW90OyRKRVRUWV9QSUQmcXVvdDsgJENIX1VTRVIgLWQmcXVvdDskSkVUVFlf QkFTRSZxdW90OyAtYiAtbSAtYSAmcXVvdDskSkFWQSZxdW90OyAtLSAmcXVvdDske1JVTl9B UkdTW0BdfSZxdW90OyBzdGFydC1sb2ctZmlsZT0mcXVvdDskSkVUVFlfU1RBUlRfTE9HJnF1 b3Q7PC9jb2RlPikgd2l0aCA8Y29kZT5KRVRUWV9TVEFSVF9MT0c9JnF1b3Q7JEpFVFRZX1JV Ti8kTkFNRS1zdGFydC5sb2cmcXVvdDs8L2NvZGU+IHdpbGwgZmFpbCBzaW5jZSBqZXR0eSB1 c2VyIHdpbGwgbm90IGJlIGFibGUgdG8gY3JlYXRlIHRoZSBsb2cgZmlsZS48L3A+DQoNCjxw PlRoZSBzb2x1dGlvbiB3YXMgdG8gcHJlLWRlZmluZSB0aGUgPGNvZGU+SkVUVFlfUlVOPC9j b2RlPiBlbnZpcm9ubWVudCB2YXJpYWJsZSBwb2ludGluZyB0byBhIGRpcmVjdG9yeSB3aGVy ZSBqZXR0eSBpcyBvd25lci48L3A+DQoNCjxoMSBpZD0iYXBwZW5kaXgiPkFwcGVuZGl4PC9o MT4NCg0KPGgyIGlkPSJmdWxsamV0dHlpbnN0YWxsYXRpb25zdGVwcyI+RnVsbCBKZXR0eSBp bnN0YWxsYXRpb24gc3RlcHM8L2gyPg0KDQo8aDMgaWQ9ImphdmE4Ij5KYXZhIDg8L2gzPg0K DQo8cHJlPjxjb2RlPnN1ZG8gLWkNCjwvY29kZT48L3ByZT4NCg0KPHA+UnVuIG9uZSBieSBv bmUgdGhlIGZvbGxvd2luZyBjb21tYW5kczt3YXRjaCBvdXQgZm9yIGNhcGl0YWxpemVkIDxj b2RlPlk8L2NvZGU+IG9uIGFuc3dlcnMuPC9wPg0KDQo8cHJlPjxjb2RlPmFwdCBpbnN0YWxs IHNvZnR3YXJlLXByb3BlcnRpZXMtY29tbW9uDQphZGQtYXB0LXJlcG9zaXRvcnkgcHBhOndl YnVwZDh0ZWFtL2phdmENCmFwdC1nZXQgdXBkYXRlDQphcHQtZ2V0IGluc3RhbGwgb3JhY2xl LWphdmE4LWluc3RhbGxlcg0KDQojYXB0LWdldCBpbnN0YWxsICBvcmFjbGUtamF2YTgtc2V0 LWRlZmF1bHQNCjwvY29kZT48L3ByZT4NCg0KPGgzIGlkPSJkb3dubG9hZGFuZGluc3RhbGxq ZXR0eSI+RG93bmxvYWQgYW5kIGluc3RhbGwgSmV0dHk8L2gzPg0KDQo8cHJlPjxjb2RlPnN1 ZG8gLWkNCjwvY29kZT48L3ByZT4NCg0KPHByZT48Y29kZT5ta2RpciAtcCAvb3B0L2pldHR5 DQpta2RpciAtcCAvb3B0L3dlYi9qZXR0eWJhc2UNCm1rZGlyIC9vcHQvd2ViL2pldHR5YmFz ZS9ydW4NCm1rZGlyIC1wIC9vcHQvamV0dHkvdGVtcA0KdXNlcmFkZCAtLXVzZXItZ3JvdXAg LS1zaGVsbCAvYmluL2ZhbHNlIC0taG9tZS1kaXIgL29wdC9qZXR0eS90ZW1wIGpldHR5DQpj aG93biAtUiBqZXR0eTpqZXR0eSAvb3B0L2pldHR5DQpjaG93biAtUiBqZXR0eTpqZXR0eSAv b3B0L3dlYi9qZXR0eWJhc2UNCmNob3duIC1SIGpldHR5OmpldHR5IC9vcHQvamV0dHkvdGVt cA0KPC9jb2RlPjwvcHJlPg0KDQo8cHJlPjxjb2RlPmNkIC90bXANCndnZXQgaHR0cDovL2Nl bnRyYWwubWF2ZW4ub3JnL21hdmVuMi9vcmcvZWNsaXBzZS9qZXR0eS9qZXR0eS1kaXN0cmli dXRpb24vOS40LjYudjIwMTcwNTMxL2pldHR5LWRpc3RyaWJ1dGlvbi05LjQuNi52MjAxNzA1 MzEudGFyLmd6DQpjZCAvb3B0L2pldHR5DQoNCnRhciAtenhmIC90bXAvamV0dHktZGlzdHJp YnV0aW9uLTkuNC42LnYyMDE3MDUzMS50YXIuZ3ogDQpjZCAvb3B0L2pldHR5L2pldHR5LWRp c3RyaWJ1dGlvbi05LjQuNi52MjAxNzA1MzENCg0KY3AgYmluL2pldHR5LnNoIC9ldGMvaW5p dC5kL2pldHR5DQoNCmNkIC9vcHQvd2ViL2pldHR5YmFzZQ0KDQpqYXZhIC1qYXIgL29wdC9q ZXR0eS9qZXR0eS1kaXN0cmlidXRpb24tOS40LjYudjIwMTcwNTMxL3N0YXJ0LmphciAtLWFk ZC10by1zdGFydD1kZXBsb3ksaHR0cCxjb25zb2xlLWNhcHR1cmUsYW5ub3RhdGlvbnMNCjwv Y29kZT48L3ByZT4NCg0KPHByZT48Y29kZT4jY29uZmlndXJlcyBKYXZhIGZvciBkZWJ1Zywg bXVzdCBiZSByZW1vdmVkIGZyb20gcHJvZHVjdGlvbiBlbnZpcm9ubWVtbnRzDQplY2hvICZx dW90O0pFVFRZX0hPTUU9L29wdC9qZXR0eS9qZXR0eS1kaXN0cmlidXRpb24tOS40LjYudjIw MTcwNTMxJnF1b3Q7ICZndDsgL2V0Yy9kZWZhdWx0L2pldHR5DQplY2hvICZxdW90O0pFVFRZ X0JBU0U9L29wdC93ZWIvamV0dHliYXNlJnF1b3Q7ICZndDsmZ3Q7IC9ldGMvZGVmYXVsdC9q ZXR0eQ0KZWNobyAmcXVvdDtKRVRUWV9SVU49L29wdC93ZWIvamV0dHliYXNlL3J1biZxdW90 OyAmZ3Q7Jmd0OyAvZXRjL2RlZmF1bHQvamV0dHkNCmVjaG8gJnF1b3Q7VE1QRElSPS9vcHQv amV0dHkvdGVtcCZxdW90OyAmZ3Q7Jmd0OyAvZXRjL2RlZmF1bHQvamV0dHkNCmVjaG8gJnF1 b3Q7SkFWQV9PUFRJT05TPVwmcXVvdDstWGRlYnVnIC1hZ2VudGxpYjpqZHdwPXRyYW5zcG9y dD1kdF9zb2NrZXQsYWRkcmVzcz05OTk5LHNlcnZlcj15LHN1c3BlbmQ9blwmcXVvdDsmcXVv dDsgJmd0OyZndDsgL2V0Yy9kZWZhdWx0L2pldHR5DQplY2hvICZxdW90O0pFVFRZX1VTRVI9 amV0dHkmcXVvdDsgJmd0OyZndDsgL2V0Yy9kZWZhdWx0L2pldHR5DQoNCg0Kc2VydmljZSBq ZXR0eSBjaGVjaw0KDQp1cGRhdGUtcmMuZCBqZXR0eSBkZWZhdWx0cw0KDQpzZXJ2aWNlIGpl dHR5IHN0YXJ0DQoNCnNlcnZpY2UgamV0dHkgc3RhdHVzDQoNCiMgaWYgc2VydmljZSBub3Qg c3RhcnRpbmcgY2hlY2sgYWxsIGludm9sdmVkIGRpcmVjdG9yaWVzIHRoYXQgamV0dHkgdXNl ciBpcyBvd25lcg0KDQojIGp1c3QgZm9yIGRldmVsb3BtZW50LCBpbiBvcmRlciB0byBiZSBh YmxlIHRvIGNvcHkgZmlsZXMgdGhyb3VnaCBXaW5TQ1A6DQpjaG1vZCBvK3cgL29wdC93ZWIv amV0dHliYXNlL3dlYmFwcHMNCjwvY29kZT48L3ByZT4NCg0KPGgyIGlkPSJob3dzcHJpbmdi b290Ym9vdHNyYXBzaG91bGR3b3JrIj5Ib3cgU3ByaW5nIEJvb3QgQm9vdHNyYXAgU2hvdWxk IFdvcms8L2gyPg0KDQo8cD5TZWUgYWxzbyA8YSBocmVmPSJodHRwOi8vcGlvdHJub3dpY2tp LmNvbS8yMDExLzAzL3VzaW5nLXNlcnZsZXRzLTMtMC1zZXJ2bGV0Y29udGFpbmVyaW5pdGlh bGl6ZXIvIj5odHRwOi8vcGlvdHJub3dpY2tpLmNvbS8yMDExLzAzL3VzaW5nLXNlcnZsZXRz JiM4MjExOzMmIzgyMTE7MC1zZXJ2bGV0Y29udGFpbmVyaW5pdGlhbGl6ZXIvPC9hPjwvcD4N Cg0KPHA+VGhlICZndDs9My4wIFNlcnZsZXQgQ29udGFpbmVyIChKZXR0eSBpbiBvdXIgY2Fz ZSkgd2lsbCB0cnkgKGlmIGFubm90YXRpb25zIG1vZHVsZSBpcyBhY3RpdmF0ZWQhKSB0byBm aW5kIGluIGNsYXNzIHBhdGggYWxsIGltcGxlbWVudGF0aW9ucyBvZiA8Y29kZT5qYXZheC5z ZXJ2bGV0LlNlcnZsZXRDb250YWluZXJJbml0aWFsaXplcjwvY29kZT4gYW5kIHdpbGwgY2Fs bCBpdHMgPGNvZGU+b25TdGFydHVwPC9jb2RlPiBtZXRob2Qgd2l0aCBhIDxjb2RlPlNldDwv Y29kZT4gb2YgYWxsIGltcGxlbWVudGF0aW9ucyBvZiB0aGUgPGNvZGU+QEhhbmRsZXNUeXBl czwvY29kZT4gbWVudGlvbmVkIGNsYXNzOjwvcD4NCg0KPHByZT48Y29kZT5wYWNrYWdlIG9y Zy5zcHJpbmdmcmFtZXdvcmsud2ViOw0KLi4uDQoNCkBIYW5kbGVzVHlwZXMoV2ViQXBwbGlj YXRpb25Jbml0aWFsaXplci5jbGFzcykNCnB1YmxpYyBjbGFzcyBTcHJpbmdTZXJ2bGV0Q29u dGFpbmVySW5pdGlhbGl6ZXIgaW1wbGVtZW50cyBTZXJ2bGV0Q29udGFpbmVySW5pdGlhbGl6 ZXIgew0KDQogICAgLyoqDQogICAgICogRGVsZWdhdGUgdGhlIHtAY29kZSBTZXJ2bGV0Q29u dGV4dH0gdG8gYW55IHtAbGluayBXZWJBcHBsaWNhdGlvbkluaXRpYWxpemVyfQ0KICAgICAq IGltcGxlbWVudGF0aW9ucyBwcmVzZW50IG9uIHRoZSBhcHBsaWNhdGlvbiBjbGFzc3BhdGgu DQogICAgICogJmx0O3AmZ3Q7QmVjYXVzZSB0aGlzIGNsYXNzIGRlY2xhcmVzIEB7QGNvZGUg SGFuZGxlc1R5cGVzKFdlYkFwcGxpY2F0aW9uSW5pdGlhbGl6ZXIuY2xhc3MpfSwNCiAgICAg KiBTZXJ2bGV0IDMuMCsgY29udGFpbmVycyB3aWxsIGF1dG9tYXRpY2FsbHkgc2NhbiB0aGUg Y2xhc3NwYXRoIGZvciBpbXBsZW1lbnRhdGlvbnMNCiAgICAgKiBvZiBTcHJpbmcncyB7QGNv ZGUgV2ViQXBwbGljYXRpb25Jbml0aWFsaXplcn0gaW50ZXJmYWNlIGFuZCBwcm92aWRlIHRo ZSBzZXQgb2YgYWxsDQogICAgICogc3VjaCB0eXBlcyB0byB0aGUge0Bjb2RlIHdlYkFwcElu aXRpYWxpemVyQ2xhc3Nlc30gcGFyYW1ldGVyIG9mIHRoaXMgbWV0aG9kLg0KICAgICAqICZs dDtwJmd0O0lmIG5vIHtAY29kZSBXZWJBcHBsaWNhdGlvbkluaXRpYWxpemVyfSBpbXBsZW1l bnRhdGlvbnMgYXJlIGZvdW5kIG9uIHRoZSBjbGFzc3BhdGgsDQogICAgICogdGhpcyBtZXRo b2QgaXMgZWZmZWN0aXZlbHkgYSBuby1vcC4gQW4gSU5GTy1sZXZlbCBsb2cgbWVzc2FnZSB3 aWxsIGJlIGlzc3VlZCBub3RpZnlpbmcNCiAgICAgKiB0aGUgdXNlciB0aGF0IHRoZSB7QGNv ZGUgU2VydmxldENvbnRhaW5lckluaXRpYWxpemVyfSBoYXMgaW5kZWVkIGJlZW4gaW52b2tl ZCBidXQgdGhhdA0KICAgICAqIG5vIHtAY29kZSBXZWJBcHBsaWNhdGlvbkluaXRpYWxpemVy fSBpbXBsZW1lbnRhdGlvbnMgd2VyZSBmb3VuZC4NCiAgICAgKiAmbHQ7cCZndDtBc3N1bWlu ZyB0aGF0IG9uZSBvciBtb3JlIHtAY29kZSBXZWJBcHBsaWNhdGlvbkluaXRpYWxpemVyfSB0 eXBlcyBhcmUgZGV0ZWN0ZWQsDQogICAgICogdGhleSB3aWxsIGJlIGluc3RhbnRpYXRlZCAo YW5kICZsdDtlbSZndDtzb3J0ZWQmbHQ7L2VtJmd0OyBpZiB0aGUgQHtAbGluaw0KICAgICAq IG9yZy5zcHJpbmdmcmFtZXdvcmsuY29yZS5hbm5vdGF0aW9uLk9yZGVyIEBPcmRlcn0gYW5u b3RhdGlvbiBpcyBwcmVzZW50IG9yDQogICAgICogdGhlIHtAbGluayBvcmcuc3ByaW5nZnJh bWV3b3JrLmNvcmUuT3JkZXJlZCBPcmRlcmVkfSBpbnRlcmZhY2UgaGFzIGJlZW4NCiAgICAg KiBpbXBsZW1lbnRlZCkuIFRoZW4gdGhlIHtAbGluayBXZWJBcHBsaWNhdGlvbkluaXRpYWxp emVyI29uU3RhcnR1cChTZXJ2bGV0Q29udGV4dCl9DQogICAgICogbWV0aG9kIHdpbGwgYmUg aW52b2tlZCBvbiBlYWNoIGluc3RhbmNlLCBkZWxlZ2F0aW5nIHRoZSB7QGNvZGUgU2Vydmxl dENvbnRleHR9IHN1Y2gNCiAgICAgKiB0aGF0IGVhY2ggaW5zdGFuY2UgbWF5IHJlZ2lzdGVy IGFuZCBjb25maWd1cmUgc2VydmxldHMgc3VjaCBhcyBTcHJpbmcncw0KICAgICAqIHtAY29k ZSBEaXNwYXRjaGVyU2VydmxldH0sIGxpc3RlbmVycyBzdWNoIGFzIFNwcmluZydzIHtAY29k ZSBDb250ZXh0TG9hZGVyTGlzdGVuZXJ9LA0KICAgICAqIG9yIGFueSBvdGhlciBTZXJ2bGV0 IEFQSSBjb21wb25lbnRyeSBzdWNoIGFzIGZpbHRlcnMuDQogICAgICogQHBhcmFtIHdlYkFw cEluaXRpYWxpemVyQ2xhc3NlcyBhbGwgaW1wbGVtZW50YXRpb25zIG9mDQogICAgICoge0Bs aW5rIFdlYkFwcGxpY2F0aW9uSW5pdGlhbGl6ZXJ9IGZvdW5kIG9uIHRoZSBhcHBsaWNhdGlv biBjbGFzc3BhdGgNCiAgICAgKiBAcGFyYW0gc2VydmxldENvbnRleHQgdGhlIHNlcnZsZXQg Y29udGV4dCB0byBiZSBpbml0aWFsaXplZA0KICAgICAqIEBzZWUgV2ViQXBwbGljYXRpb25J bml0aWFsaXplciNvblN0YXJ0dXAoU2VydmxldENvbnRleHQpDQogICAgICogQHNlZSBBbm5v dGF0aW9uQXdhcmVPcmRlckNvbXBhcmF0b3INCiAgICAgKi8NCiAgICBAT3ZlcnJpZGUNCiAg ICBwdWJsaWMgdm9pZCBvblN0YXJ0dXAoU2V0Jmx0O0NsYXNzJmx0Oz8mZ3Q7Jmd0OyB3ZWJB cHBJbml0aWFsaXplckNsYXNzZXMsIFNlcnZsZXRDb250ZXh0IHNlcnZsZXRDb250ZXh0KQ0K ICAgICAgICAgICAgdGhyb3dzIFNlcnZsZXRFeGNlcHRpb24gew0KDQogICAgICAgIExpc3Qm bHQ7V2ViQXBwbGljYXRpb25Jbml0aWFsaXplciZndDsgaW5pdGlhbGl6ZXJzID0gbmV3IExp bmtlZExpc3QmbHQ7V2ViQXBwbGljYXRpb25Jbml0aWFsaXplciZndDsoKTsNCg0KICAgICAg ICBpZiAod2ViQXBwSW5pdGlhbGl6ZXJDbGFzc2VzICE9IG51bGwpIHsNCiAgICAgICAgICAg IGZvciAoQ2xhc3MmbHQ7PyZndDsgd2FpQ2xhc3MgOiB3ZWJBcHBJbml0aWFsaXplckNsYXNz ZXMpIHsNCiAgICAgICAgICAgICAgICAvLyBCZSBkZWZlbnNpdmU6IFNvbWUgc2VydmxldCBj b250YWluZXJzIHByb3ZpZGUgdXMgd2l0aCBpbnZhbGlkIGNsYXNzZXMsDQogICAgICAgICAg ICAgICAgLy8gbm8gbWF0dGVyIHdoYXQgQEhhbmRsZXNUeXBlcyBzYXlzLi4uDQouLi4NCg0K PC9jb2RlPjwvcHJlPg0K

Tuesday, June 20, 2017

Building pgModeler

Building pgModeler

This apply to version 0.9.0 and Windows OS. Read first installer instruction on https://pgmodeler.com.br/support/installation; this just adding some clarifications, the instructions (mainly related to QT paths) are a little bit “confused”.

Download and install the prerequisites

Be sure to:

  • Download 32 bits versions for all prerequisites
  • Install them in paths without spaces, like D:\PostgreSQL32\9.6

Qt framework

Download the MingW32 bits version from http://download.qt.io/archive/qt/5.6/5.6.2/qt-opensource-windows-x86-mingw492–5.6.2.exe

Install it in default location; otherwise change the paths below accordingly.

Add C:/Qt/Qt5.6.2/Tools/mingw492_32/bin to system path; at some point the make process will invoke g++ and will not find it otherwise.

PostgreSQL

Download from EnterpriseDB the 32 bits version and install it in D:\PostgreSQL32; otherwise change the paths below accordingly.

If you already have a 64 bits version installed be sure to go services and stop/disable the 32 bits service.

Git

Install Git as instructed

Run the build

Download source code from https://github.com/pgmodeler/pgmodeler.git (watch out the path: no spaces…). Check-out version 0.9.0

Change the pgmodeler.pri acordingly:

windows {
  !defined(PGSQL_LIB, var): PGSQL_LIB = "D:/PostgreSQL32/9.6/lib/libpq.dll"
  !defined(PGSQL_INC, var): PGSQL_INC = "D:/PostgreSQL32/9.6/include"
  !defined(XML_INC, var): XML_INC = "D:/PostgreSQL32/9.6/include"
  !defined(XML_LIB, var): XML_LIB = "D:/PostgreSQL32/9.6/bin/libxml2.dll"
...

Start bash from a command window in pgmodeler directory.

At the command prompt run the commands:

C:/Qt/Qt5.6.2/5.6/mingw49_32/bin/qmake.exe pgmodeler.pro
C:/Qt/Qt5.6.2/Tools/mingw492_32/bin/mingw32-make.exe
C:/Qt/Qt5.6.2/Tools/mingw492_32/bin/mingw32-make.exe  install
cd build
C:/Qt/Qt5.6.2/5.6/mingw49_32/bin/windeployqt pgmodeler.exe

Please be patient, it might take more than 30 minutes…

In order to run build\pgmodeler.exe you have to copy in several libraries from:

  • C:/Qt/Qt5.6.2/5.6/mingw49_32/bin:
    • Qt5*.dll.
  • D:/PostgreSQL32/9.6/
    • lib/libpq.dll
    • bin/libxml2.dll

Now run build\pgmodeler.exe…fingers cross!

PGgxIGlkPSJidWlsZGluZ3BnbW9kZWxlciI+QnVpbGRpbmcgcGdNb2RlbGVyPC9oMT4NCg0K PHA+VGhpcyBhcHBseSB0byB2ZXJzaW9uIDAuOS4wIGFuZCBXaW5kb3dzIE9TLiBSZWFkIGZp cnN0IGluc3RhbGxlciBpbnN0cnVjdGlvbiBvbiA8YSBocmVmPSJodHRwczovL3BnbW9kZWxl ci5jb20uYnIvc3VwcG9ydC9pbnN0YWxsYXRpb24iPmh0dHBzOi8vcGdtb2RlbGVyLmNvbS5i ci9zdXBwb3J0L2luc3RhbGxhdGlvbjwvYT47IHRoaXMganVzdCBhZGRpbmcgc29tZSBjbGFy aWZpY2F0aW9ucywgdGhlIGluc3RydWN0aW9ucyAobWFpbmx5IHJlbGF0ZWQgdG8gUVQgcGF0 aHMpIGFyZSBhIGxpdHRsZSBiaXQgJiM4MjIwO2NvbmZ1c2VkJiM4MjIxOy48L3A+DQoNCjxo MiBpZD0iZG93bmxvYWRhbmRpbnN0YWxsdGhlcHJlcmVxdWlzaXRlcyI+RG93bmxvYWQgYW5k IGluc3RhbGwgdGhlIHByZXJlcXVpc2l0ZXM8L2gyPg0KDQo8cD5CZSBzdXJlIHRvOjwvcD4N Cg0KPHVsPg0KPGxpPkRvd25sb2FkIDMyIGJpdHMgdmVyc2lvbnMgZm9yIGFsbCBwcmVyZXF1 aXNpdGVzPC9saT4NCjxsaT5JbnN0YWxsIHRoZW0gaW4gcGF0aHMgd2l0aG91dCBzcGFjZXMs IGxpa2UgPGNvZGU+RDpcUG9zdGdyZVNRTDMyXDkuNjwvY29kZT48L2xpPg0KPC91bD4NCg0K PGgzIGlkPSJxdGZyYW1ld29yayI+UXQgZnJhbWV3b3JrPC9oMz4NCg0KPHA+RG93bmxvYWQg dGhlIE1pbmdXMzIgYml0cyB2ZXJzaW9uIGZyb20gPGEgaHJlZj0iaHR0cDovL2Rvd25sb2Fk LnF0LmlvL2FyY2hpdmUvcXQvNS42LzUuNi4yL3F0LW9wZW5zb3VyY2Utd2luZG93cy14ODYt bWluZ3c0OTItNS42LjIuZXhlIj5odHRwOi8vZG93bmxvYWQucXQuaW8vYXJjaGl2ZS9xdC81 LjYvNS42LjIvcXQtb3BlbnNvdXJjZS13aW5kb3dzLXg4Ni1taW5ndzQ5MiYjODIxMTs1LjYu Mi5leGU8L2E+IDwvcD4NCg0KPHA+SW5zdGFsbCBpdCBpbiBkZWZhdWx0IGxvY2F0aW9uOyBv dGhlcndpc2UgY2hhbmdlIHRoZSBwYXRocyBiZWxvdyBhY2NvcmRpbmdseS48L3A+DQoNCjxw PkFkZCA8Y29kZT5DOi9RdC9RdDUuNi4yL1Rvb2xzL21pbmd3NDkyXzMyL2JpbjwvY29kZT4g dG8gc3lzdGVtIHBhdGg7IGF0IHNvbWUgcG9pbnQgdGhlIG1ha2UgcHJvY2VzcyB3aWxsIGlu dm9rZSA8Y29kZT5nKys8L2NvZGU+IGFuZCB3aWxsIG5vdCBmaW5kIGl0IG90aGVyd2lzZS48 L3A+DQoNCjxoMyBpZD0icG9zdGdyZXNxbCI+UG9zdGdyZVNRTDwvaDM+DQoNCjxwPkRvd25s b2FkIGZyb20gRW50ZXJwcmlzZURCIHRoZSAzMiBiaXRzIHZlcnNpb24gYW5kIGluc3RhbGwg aXQgaW4gPGNvZGU+RDpcUG9zdGdyZVNRTDMyPC9jb2RlPjsgb3RoZXJ3aXNlIGNoYW5nZSB0 aGUgcGF0aHMgYmVsb3cgYWNjb3JkaW5nbHkuPC9wPg0KDQo8cD5JZiB5b3UgYWxyZWFkeSBo YXZlIGEgNjQgYml0cyB2ZXJzaW9uIGluc3RhbGxlZCBiZSBzdXJlIHRvIGdvIHNlcnZpY2Vz IGFuZCBzdG9wL2Rpc2FibGUgdGhlIDMyIGJpdHMgc2VydmljZS48L3A+DQoNCjxoMyBpZD0i Z2l0Ij5HaXQ8L2gzPg0KDQo8cD5JbnN0YWxsIEdpdCBhcyBpbnN0cnVjdGVkPC9wPg0KDQo8 aDIgaWQ9InJ1bnRoZWJ1aWxkIj5SdW4gdGhlIGJ1aWxkPC9oMj4NCg0KPHA+RG93bmxvYWQg c291cmNlIGNvZGUgZnJvbSA8Y29kZT5odHRwczovL2dpdGh1Yi5jb20vcGdtb2RlbGVyL3Bn bW9kZWxlci5naXQ8L2NvZGU+ICh3YXRjaCBvdXQgdGhlIHBhdGg6IG5vIHNwYWNlcyYjODIz MDspLiBDaGVjay1vdXQgdmVyc2lvbiAwLjkuMCA8L3A+DQoNCjxwPkNoYW5nZSB0aGUgPGNv ZGU+cGdtb2RlbGVyLnByaTwvY29kZT4gYWNvcmRpbmdseTo8L3A+DQoNCjxwcmU+PGNvZGU+ d2luZG93cyB7DQogICFkZWZpbmVkKFBHU1FMX0xJQiwgdmFyKTogUEdTUUxfTElCID0gJnF1 b3Q7RDovUG9zdGdyZVNRTDMyLzkuNi9saWIvbGlicHEuZGxsJnF1b3Q7DQogICFkZWZpbmVk KFBHU1FMX0lOQywgdmFyKTogUEdTUUxfSU5DID0gJnF1b3Q7RDovUG9zdGdyZVNRTDMyLzku Ni9pbmNsdWRlJnF1b3Q7DQogICFkZWZpbmVkKFhNTF9JTkMsIHZhcik6IFhNTF9JTkMgPSAm cXVvdDtEOi9Qb3N0Z3JlU1FMMzIvOS42L2luY2x1ZGUmcXVvdDsNCiAgIWRlZmluZWQoWE1M X0xJQiwgdmFyKTogWE1MX0xJQiA9ICZxdW90O0Q6L1Bvc3RncmVTUUwzMi85LjYvYmluL2xp YnhtbDIuZGxsJnF1b3Q7DQouLi4NCjwvY29kZT48L3ByZT4NCg0KPHA+U3RhcnQgPGNvZGU+ YmFzaDwvY29kZT4gZnJvbSBhIGNvbW1hbmQgd2luZG93IGluIDxzdHJvbmc+cGdtb2RlbGVy PC9zdHJvbmc+IGRpcmVjdG9yeS48L3A+DQoNCjxwPkF0IHRoZSBjb21tYW5kIHByb21wdCBy dW4gdGhlIGNvbW1hbmRzOjwvcD4NCg0KPHByZT48Y29kZT5DOi9RdC9RdDUuNi4yLzUuNi9t aW5ndzQ5XzMyL2Jpbi9xbWFrZS5leGUgcGdtb2RlbGVyLnBybw0KQzovUXQvUXQ1LjYuMi9U b29scy9taW5ndzQ5Ml8zMi9iaW4vbWluZ3czMi1tYWtlLmV4ZQ0KQzovUXQvUXQ1LjYuMi9U b29scy9taW5ndzQ5Ml8zMi9iaW4vbWluZ3czMi1tYWtlLmV4ZSAgaW5zdGFsbA0KY2QgYnVp bGQNCkM6L1F0L1F0NS42LjIvNS42L21pbmd3NDlfMzIvYmluL3dpbmRlcGxveXF0IHBnbW9k ZWxlci5leGUNCjwvY29kZT48L3ByZT4NCg0KPHA+UGxlYXNlIGJlIHBhdGllbnQsIGl0IG1p Z2h0IHRha2UgbW9yZSB0aGFuIDMwIG1pbnV0ZXMmIzgyMzA7PC9wPg0KDQo8cD5JbiBvcmRl ciB0byBydW4gPGNvZGU+YnVpbGRccGdtb2RlbGVyLmV4ZTwvY29kZT4geW91IGhhdmUgdG8g Y29weSBpbiBzZXZlcmFsIGxpYnJhcmllcyBmcm9tOjwvcD4NCg0KPHVsPg0KPGxpPkM6L1F0 L1F0NS42LjIvNS42L21pbmd3NDlfMzIvYmluOg0KDQo8dWw+DQo8bGk+UXQ1Ki5kbGwuPC9s aT4NCjwvdWw+PC9saT4NCjxsaT5EOi9Qb3N0Z3JlU1FMMzIvOS42Lw0KDQo8dWw+DQo8bGk+ bGliL2xpYnBxLmRsbDwvbGk+DQo8bGk+YmluL2xpYnhtbDIuZGxsPC9saT4NCjwvdWw+PC9s aT4NCjwvdWw+DQoNCjxwPk5vdyBydW4gPGNvZGU+YnVpbGRccGdtb2RlbGVyLmV4ZTwvY29k ZT4mIzgyMzA7ZmluZ2VycyBjcm9zcyE8L3A+DQo=

Wednesday, February 8, 2017

Jira SSO

This post applies to cloud hosted Jira, version v1000.747.0 and ADFS as included in Windows Server 2012.

Be sure to add first an administrator with an email outside your mycompany.com domain so that you can connect to Jira if SAML is not configured correctly

Step 1

In order to configure SSO integration we must first register our domain (SITE ADMINISTRATION->User Management), let’s say mycompany.com. A file generated by Jira must be made available over HTTPS at https://mycompany.com/atlassian-domain-verification.html. Plase notice the format of the URL, the right DNS redirection to https://www.mycompany.com/atlassian-domain-verification.html must be configured.

Step 2

Fill in the required information about our Identity Provider (exposed only in Intranet):

  • Identity provider Entity ID: http://ts-adfs.mycompany.local/adfs/services/trust
  • Identity provider SSO URL: https://ts-adfs.mycompany.local/adfs/ls/
  • Public x509 certificate

Step 3

In ADFS create a new Service Provider using the information provided by Jira SAML configuration page:

  • SP Entity ID: https://id.atlassian.com/login
  • SP Assertion Consumer Service URL: https://id.atlassian.com/login/saml/acs

As specified at https://confluence.atlassian.com/purchasing/saml-single-sign-on-for-atlassian-account–860002668.html edit the claim rules adding the following entries (using Active Directory as attribute store):

  • E-Mail-Addresses->E-Mail Addresses
  • Given-Name->Given Name
  • Surname->Surname
  • SAM-Account-Name->UPN

Step 4

Trying to login to Jira now will result in an error (not very specific). By looking into ADFS Windows Logs (Applications and Services Logs->AD FS Tracing->Debug) you will notice something about Name Id not supported format (email). I found the solution at http://wiki.servicenow.com/index.php?title=Configuring_ADFS_3.0_to_Communicate_with_SAML_2.0#ADFS_Relying_Party_Configuration&gsc.tab=0:

  • Add a new rule to existing claims rules, type Transform an Incoming Claim:
  • Select Incoming claim type: E-Mail Address
  • Select Outgoing claim type: Name ID
  • Outgoing name ID format: email

The resulted claim Rule language is:

c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]
 => issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, Value = c.Value, ValueType = c.ValueType, Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"] = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress");

Step 5

Trying to login to Jira now will result in an error about resource not found, this time due by the IIS exposing the ADFS endpoint.

The cause is the default URL limitation of IIS. Perform the steps explaind in https://www.iis.net/configreference/system.webserver/security/requestfiltering/requestlimits:

  • Use IIS administration interface
  • Select Default Site and double click Request Filtering
  • Click on Edit Feature Settings
  • Change:
    • Maximum URL length to 8192
    • Maximum query string to 8000

Step 6

We get now another error due to the query string limitation in ASP.Net as controlled by web.config. Edit web.config as mentioned at https://msdn.microsoft.com/en-us/library/e1f13641(v=vs.100).aspx

  <system.web>
...
    <httpRuntime requestValidationMode="2.0" maxQueryStringLength = "8000" maxUrlLength ="8192"/>
  </system.web>

Finaly

You can login now by just providing email@mycompany.com (depending your browser configuration you will or not be prompted with authentication form by ADFS: see WIA configuration for IE/Chrome for instance).

PHA+VGhpcyBwb3N0IGFwcGxpZXMgdG8gY2xvdWQgaG9zdGVkIEppcmEsIHZlcnNpb24gdjEw MDAuNzQ3LjAgYW5kIEFERlMgYXMgaW5jbHVkZWQgaW4gV2luZG93cyBTZXJ2ZXIgMjAxMi48 L3A+DQoNCjxwPkJlIHN1cmUgdG8gYWRkIGZpcnN0IGFuIGFkbWluaXN0cmF0b3Igd2l0aCBh biBlbWFpbCBvdXRzaWRlIHlvdXIgPGNvZGU+bXljb21wYW55LmNvbTwvY29kZT4gZG9tYWlu IHNvIHRoYXQgeW91IGNhbiBjb25uZWN0IHRvIEppcmEgaWYgU0FNTCBpcyBub3QgY29uZmln dXJlZCBjb3JyZWN0bHk8L3A+DQoNCjxoMSBpZD0ic3RlcDEiPlN0ZXAgMTwvaDE+DQoNCjxw PkluIG9yZGVyIHRvIGNvbmZpZ3VyZSBTU08gaW50ZWdyYXRpb24gd2UgbXVzdCBmaXJzdCBy ZWdpc3RlciBvdXIgZG9tYWluIChTSVRFIEFETUlOSVNUUkFUSU9OLSZndDtVc2VyIE1hbmFn ZW1lbnQpLCBsZXQmIzgyMTc7cyBzYXkgPGNvZGU+bXljb21wYW55LmNvbTwvY29kZT4uIEEg ZmlsZSBnZW5lcmF0ZWQgYnkgSmlyYSBtdXN0IGJlIG1hZGUgYXZhaWxhYmxlIG92ZXIgSFRU UFMgYXQgPGNvZGU+aHR0cHM6Ly9teWNvbXBhbnkuY29tL2F0bGFzc2lhbi1kb21haW4tdmVy aWZpY2F0aW9uLmh0bWw8L2NvZGU+LiBQbGFzZSBub3RpY2UgdGhlIGZvcm1hdCBvZiB0aGUg VVJMLCB0aGUgcmlnaHQgRE5TIHJlZGlyZWN0aW9uIHRvIDxjb2RlPmh0dHBzOi8vd3d3Lm15 Y29tcGFueS5jb20vYXRsYXNzaWFuLWRvbWFpbi12ZXJpZmljYXRpb24uaHRtbDwvY29kZT4g bXVzdCBiZSBjb25maWd1cmVkLjwvcD4NCg0KPGgxIGlkPSJzdGVwMiI+U3RlcCAyPC9oMT4N Cg0KPHA+RmlsbCBpbiB0aGUgcmVxdWlyZWQgaW5mb3JtYXRpb24gYWJvdXQgb3VyIElkZW50 aXR5IFByb3ZpZGVyIChleHBvc2VkIG9ubHkgaW4gSW50cmFuZXQpOjwvcD4NCg0KPHVsPg0K PGxpPklkZW50aXR5IHByb3ZpZGVyIEVudGl0eSBJRDogPGNvZGU+aHR0cDovL3RzLWFkZnMu bXljb21wYW55LmxvY2FsL2FkZnMvc2VydmljZXMvdHJ1c3Q8L2NvZGU+PC9saT4NCjxsaT5J ZGVudGl0eSBwcm92aWRlciBTU08gVVJMOiA8Y29kZT5odHRwczovL3RzLWFkZnMubXljb21w YW55LmxvY2FsL2FkZnMvbHMvPC9jb2RlPjwvbGk+DQo8bGk+UHVibGljIHg1MDkgY2VydGlm aWNhdGU8L2xpPg0KPC91bD4NCg0KPGgxIGlkPSJzdGVwMyI+U3RlcCAzPC9oMT4NCg0KPHA+ SW4gQURGUyBjcmVhdGUgYSBuZXcgU2VydmljZSBQcm92aWRlciB1c2luZyB0aGUgaW5mb3Jt YXRpb24gcHJvdmlkZWQgYnkgSmlyYSBTQU1MIGNvbmZpZ3VyYXRpb24gcGFnZTo8L3A+DQoN Cjx1bD4NCjxsaT5TUCBFbnRpdHkgSUQ6IDxjb2RlPmh0dHBzOi8vaWQuYXRsYXNzaWFuLmNv bS9sb2dpbjwvY29kZT48L2xpPg0KPGxpPlNQIEFzc2VydGlvbiBDb25zdW1lciBTZXJ2aWNl IFVSTDogPGNvZGU+aHR0cHM6Ly9pZC5hdGxhc3NpYW4uY29tL2xvZ2luL3NhbWwvYWNzPC9j b2RlPjwvbGk+DQo8L3VsPg0KDQo8cD5BcyBzcGVjaWZpZWQgYXQgPGEgaHJlZj0iaHR0cHM6 Ly9jb25mbHVlbmNlLmF0bGFzc2lhbi5jb20vcHVyY2hhc2luZy9zYW1sLXNpbmdsZS1zaWdu LW9uLWZvci1hdGxhc3NpYW4tYWNjb3VudC04NjAwMDI2NjguaHRtbCI+aHR0cHM6Ly9jb25m bHVlbmNlLmF0bGFzc2lhbi5jb20vcHVyY2hhc2luZy9zYW1sLXNpbmdsZS1zaWduLW9uLWZv ci1hdGxhc3NpYW4tYWNjb3VudCYjODIxMTs4NjAwMDI2NjguaHRtbDwvYT4gZWRpdCB0aGUg Y2xhaW0gcnVsZXMgYWRkaW5nIHRoZSBmb2xsb3dpbmcgZW50cmllcyAodXNpbmcgQWN0aXZl IERpcmVjdG9yeSBhcyBhdHRyaWJ1dGUgc3RvcmUpOjwvcD4NCg0KPHVsPg0KPGxpPkUtTWFp bC1BZGRyZXNzZXMtJmd0O0UtTWFpbCBBZGRyZXNzZXM8L2xpPg0KPGxpPkdpdmVuLU5hbWUt Jmd0O0dpdmVuIE5hbWU8L2xpPg0KPGxpPlN1cm5hbWUtJmd0O1N1cm5hbWU8L2xpPg0KPGxp PlNBTS1BY2NvdW50LU5hbWUtJmd0O1VQTjwvbGk+DQo8L3VsPg0KDQo8aDEgaWQ9InN0ZXA0 Ij5TdGVwIDQ8L2gxPg0KDQo8cD5UcnlpbmcgdG8gbG9naW4gdG8gSmlyYSBub3cgd2lsbCBy ZXN1bHQgaW4gYW4gZXJyb3IgKG5vdCB2ZXJ5IHNwZWNpZmljKS4gQnkgbG9va2luZyBpbnRv IEFERlMgV2luZG93cyBMb2dzIChBcHBsaWNhdGlvbnMgYW5kIFNlcnZpY2VzIExvZ3MtJmd0 O0FEIEZTIFRyYWNpbmctJmd0O0RlYnVnKSB5b3Ugd2lsbCBub3RpY2Ugc29tZXRoaW5nIGFi b3V0IE5hbWUgSWQgbm90IHN1cHBvcnRlZCBmb3JtYXQgKGVtYWlsKS4NCkkgZm91bmQgdGhl IHNvbHV0aW9uIGF0IDxhIGhyZWY9Imh0dHA6Ly93aWtpLnNlcnZpY2Vub3cuY29tL2luZGV4 LnBocD90aXRsZT1Db25maWd1cmluZ19BREZTXzMuMF90b19Db21tdW5pY2F0ZV93aXRoX1NB TUxfMi4wI0FERlNfUmVseWluZ19QYXJ0eV9Db25maWd1cmF0aW9uJmFtcDtnc2MudGFiPTAi Pmh0dHA6Ly93aWtpLnNlcnZpY2Vub3cuY29tL2luZGV4LnBocD90aXRsZT1Db25maWd1cmlu Z19BREZTXzMuMF90b19Db21tdW5pY2F0ZV93aXRoX1NBTUxfMi4wI0FERlNfUmVseWluZ19Q YXJ0eV9Db25maWd1cmF0aW9uJmFtcDtnc2MudGFiPTA8L2E+OjwvcD4NCg0KPHVsPg0KPGxp PkFkZCBhIG5ldyBydWxlIHRvIGV4aXN0aW5nIGNsYWltcyBydWxlcywgdHlwZSA8Y29kZT5U cmFuc2Zvcm0gYW4gSW5jb21pbmcgQ2xhaW08L2NvZGU+OjwvbGk+DQo8bGk+U2VsZWN0IElu Y29taW5nIGNsYWltIHR5cGU6IEUtTWFpbCBBZGRyZXNzPC9saT4NCjxsaT5TZWxlY3QgT3V0 Z29pbmcgY2xhaW0gdHlwZTogTmFtZSBJRDwvbGk+DQo8bGk+T3V0Z29pbmcgbmFtZSBJRCBm b3JtYXQ6IGVtYWlsPC9saT4NCjwvdWw+DQoNCjxwPlRoZSByZXN1bHRlZCBjbGFpbSBSdWxl IGxhbmd1YWdlIGlzOjwvcD4NCg0KPHByZT48Y29kZT5jOltUeXBlID09ICZxdW90O2h0dHA6 Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWls YWRkcmVzcyZxdW90O10NCiA9Jmd0OyBpc3N1ZShUeXBlID0gJnF1b3Q7aHR0cDovL3NjaGVt YXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZWlkZW50aWZp ZXImcXVvdDssIElzc3VlciA9IGMuSXNzdWVyLCBPcmlnaW5hbElzc3VlciA9IGMuT3JpZ2lu YWxJc3N1ZXIsIFZhbHVlID0gYy5WYWx1ZSwgVmFsdWVUeXBlID0gYy5WYWx1ZVR5cGUsIFBy b3BlcnRpZXNbJnF1b3Q7aHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9p ZGVudGl0eS9jbGFpbXByb3BlcnRpZXMvZm9ybWF0JnF1b3Q7XSA9ICZxdW90O3VybjpvYXNp czpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OmVtYWlsQWRkcmVzcyZxdW90Oyk7 DQoNCjwvY29kZT48L3ByZT4NCg0KPGgxIGlkPSJzdGVwNSI+U3RlcCA1PC9oMT4NCg0KPHA+ VHJ5aW5nIHRvIGxvZ2luIHRvIEppcmEgbm93IHdpbGwgcmVzdWx0IGluIGFuIGVycm9yIGFi b3V0IHJlc291cmNlIG5vdCBmb3VuZCwgdGhpcyB0aW1lIGR1ZSBieSB0aGUgSUlTIGV4cG9z aW5nIHRoZSBBREZTIGVuZHBvaW50LjwvcD4NCg0KPHA+VGhlIGNhdXNlIGlzIHRoZSBkZWZh dWx0IFVSTCBsaW1pdGF0aW9uIG9mIElJUy4gUGVyZm9ybSB0aGUgc3RlcHMgZXhwbGFpbmQg aW4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuaWlzLm5ldC9jb25maWdyZWZlcmVuY2Uvc3lzdGVt LndlYnNlcnZlci9zZWN1cml0eS9yZXF1ZXN0ZmlsdGVyaW5nL3JlcXVlc3RsaW1pdHMiPmh0 dHBzOi8vd3d3Lmlpcy5uZXQvY29uZmlncmVmZXJlbmNlL3N5c3RlbS53ZWJzZXJ2ZXIvc2Vj dXJpdHkvcmVxdWVzdGZpbHRlcmluZy9yZXF1ZXN0bGltaXRzPC9hPjo8L3A+DQoNCjx1bD4N CjxsaT5Vc2UgSUlTIGFkbWluaXN0cmF0aW9uIGludGVyZmFjZTwvbGk+DQo8bGk+U2VsZWN0 IERlZmF1bHQgU2l0ZSBhbmQgZG91YmxlIGNsaWNrIFJlcXVlc3QgRmlsdGVyaW5nPC9saT4N CjxsaT5DbGljayBvbiBFZGl0IEZlYXR1cmUgU2V0dGluZ3M8L2xpPg0KPGxpPkNoYW5nZToN Cg0KPHVsPg0KPGxpPk1heGltdW0gVVJMIGxlbmd0aCB0byA4MTkyPC9saT4NCjxsaT5NYXhp bXVtIHF1ZXJ5IHN0cmluZyB0byA4MDAwPC9saT4NCjwvdWw+PC9saT4NCjwvdWw+DQoNCjxo MSBpZD0ic3RlcDYiPlN0ZXAgNjwvaDE+DQoNCjxwPldlIGdldCBub3cgYW5vdGhlciBlcnJv ciBkdWUgdG8gdGhlIHF1ZXJ5IHN0cmluZyBsaW1pdGF0aW9uIGluIEFTUC5OZXQgYXMgY29u dHJvbGxlZCBieSA8Y29kZT53ZWIuY29uZmlnPC9jb2RlPi4NCkVkaXQgPGNvZGU+d2ViLmNv bmZpZzwvY29kZT4gYXMgbWVudGlvbmVkIGF0IDxhIGhyZWY9Imh0dHBzOi8vbXNkbi5taWNy b3NvZnQuY29tL2VuLXVzL2xpYnJhcnkvZTFmMTM2NDEodj12cy4xMDApLmFzcHgiPmh0dHBz Oi8vbXNkbi5taWNyb3NvZnQuY29tL2VuLXVzL2xpYnJhcnkvZTFmMTM2NDEodj12cy4xMDAp LmFzcHg8L2E+PC9wPg0KDQo8cHJlPjxjb2RlIGNsYXNzPSJ4bWwiPiAgJmx0O3N5c3RlbS53 ZWImZ3Q7DQouLi4NCiAgICAmbHQ7aHR0cFJ1bnRpbWUgcmVxdWVzdFZhbGlkYXRpb25Nb2Rl PSZxdW90OzIuMCZxdW90OyBtYXhRdWVyeVN0cmluZ0xlbmd0aCA9ICZxdW90OzgwMDAmcXVv dDsgbWF4VXJsTGVuZ3RoID0mcXVvdDs4MTkyJnF1b3Q7LyZndDsNCiAgJmx0Oy9zeXN0ZW0u d2ViJmd0Ow0KPC9jb2RlPjwvcHJlPg0KDQo8aDEgaWQ9ImZpbmFseSI+RmluYWx5PC9oMT4N Cg0KPHA+WW91IGNhbiBsb2dpbiBub3cgYnkganVzdCBwcm92aWRpbmcgPGNvZGU+ZW1haWxA bXljb21wYW55LmNvbTwvY29kZT4gKGRlcGVuZGluZyB5b3VyIGJyb3dzZXIgY29uZmlndXJh dGlvbiB5b3Ugd2lsbCBvciBub3QgYmUgcHJvbXB0ZWQgd2l0aCBhdXRoZW50aWNhdGlvbiBm b3JtIGJ5IEFERlM6IHNlZSBXSUEgY29uZmlndXJhdGlvbiBmb3IgSUUvQ2hyb21lIGZvciBp bnN0YW5jZSkuPC9wPg0K

OTRS Too Many Connections

Running OTRS on MySQL you might get seldom ‘Too Many Connections’ Error.

This happened recently on my company’s OTRS implementation; I’m just recording findings, nothing to blame neither OTRS nor MySQL!

Facts

After several years of successfully running OTRS on CENTOS/MySQL (MyISAM storage engine) we suddenly started facing daily customers/agents complaining about not being able to use the system any more while getting ‘Too Many Connections’ error. Outage lasted tens of minutes and disappeared without any intervention.

During outage we were unable to open MySQL Workbrench to check through Client Connections what was happening.

Findings

After several such events we decided to leave open an instance of MySQL Workbrench with Client Connection active. When next event occurred we noticed that there was a client connection running a long lasting query with state ‘Copy data to tmp table’ while all other connections were in ‘Locked’ state. Please notice that MyISAM:

  • Has only full table lock granularity;
  • Caches only indexes, not data
  • Data cache is left at OS operating mercy

Running the query once again we noticed: - it took no time to complete - after clearing the query cache (RESET QUERY CACHE;) it took 5 seconds - after clearing OS disk cache (CentOS) through echo 3 > /proc/sys/vm/drop_caches (see Clear Disk Cache ) the query took over 180 seconds.

Conclusion

Due to some facts (…?) at some point there was a query triggered by a client action, query that lasts very long. During this period one of the most used table becomes locked so any subsequent queries will become locked waiting the initial query to finish. OTRS client, noticing no response from the system, will try refreshing the page or clicking once again some link which in turn will trigger server side opening of a new MySQL connection till the default 151 connections is hit.

Solution

After increasing the OS memory from 6 GB to 12 GB and key_buffer_size to 3 GB (a little bit to defensive) we encountered no more errors.

Some useful MySQL queries

SHOW STATUS LIKE 'key%';
SHOW VARIABLES LIKE 'key%';

SHOW VARIABLES LIKE 'max_heap_table_size';

SHOW STATUS LIKE '%tmp%';

RESET QUERY CACHE;

show engines;

PGgxIGlkPSJydW5uaW5nb3Ryc29ubXlzcWx5b3VtaWdodGdldHNlbGRvbXRvb21hbnljb25u ZWN0aW9uc2Vycm9yLiI+UnVubmluZyBPVFJTIG9uIE15U1FMIHlvdSBtaWdodCBnZXQgc2Vs ZG9tICYjODIxNjtUb28gTWFueSBDb25uZWN0aW9ucyYjODIxNzsgRXJyb3IuPC9oMT4NCg0K PHA+VGhpcyBoYXBwZW5lZCByZWNlbnRseSBvbiBteSBjb21wYW55JiM4MjE3O3MgT1RSUyBp bXBsZW1lbnRhdGlvbjsgSSYjODIxNzttIGp1c3QgcmVjb3JkaW5nIGZpbmRpbmdzLCBub3Ro aW5nIHRvIGJsYW1lIG5laXRoZXIgT1RSUyBub3IgTXlTUUwhPC9wPg0KDQo8aDIgaWQ9ImZh Y3RzIj5GYWN0czwvaDI+DQoNCjxwPkFmdGVyIHNldmVyYWwgeWVhcnMgb2Ygc3VjY2Vzc2Z1 bGx5IHJ1bm5pbmcgT1RSUyBvbiBDRU5UT1MvTXlTUUwgKE15SVNBTSBzdG9yYWdlIGVuZ2lu ZSkgd2Ugc3VkZGVubHkgc3RhcnRlZCBmYWNpbmcgZGFpbHkgY3VzdG9tZXJzL2FnZW50cyBj b21wbGFpbmluZyBhYm91dCBub3QgYmVpbmcgYWJsZSB0byB1c2UgdGhlIHN5c3RlbSBhbnkg bW9yZSB3aGlsZSBnZXR0aW5nICYjODIxNjtUb28gTWFueSBDb25uZWN0aW9ucyYjODIxNzsg ZXJyb3IuIE91dGFnZSBsYXN0ZWQgdGVucyBvZiBtaW51dGVzIGFuZCBkaXNhcHBlYXJlZCB3 aXRob3V0IGFueSBpbnRlcnZlbnRpb24uPC9wPg0KDQo8cD5EdXJpbmcgb3V0YWdlIHdlIHdl cmUgdW5hYmxlIHRvIG9wZW4gTXlTUUwgV29ya2JyZW5jaCB0byBjaGVjayB0aHJvdWdoIENs aWVudCBDb25uZWN0aW9ucyB3aGF0IHdhcyBoYXBwZW5pbmcuPC9wPg0KDQo8aDIgaWQ9ImZp bmRpbmdzIj5GaW5kaW5nczwvaDI+DQoNCjxwPkFmdGVyIHNldmVyYWwgc3VjaCBldmVudHMg d2UgZGVjaWRlZCB0byBsZWF2ZSBvcGVuIGFuIGluc3RhbmNlIG9mIE15U1FMIFdvcmticmVu Y2ggd2l0aCBDbGllbnQgQ29ubmVjdGlvbiBhY3RpdmUuIFdoZW4gbmV4dCBldmVudCBvY2N1 cnJlZCB3ZSBub3RpY2VkIHRoYXQgdGhlcmUgd2FzIGEgY2xpZW50IGNvbm5lY3Rpb24gcnVu bmluZyBhIGxvbmcgbGFzdGluZyBxdWVyeSB3aXRoIHN0YXRlICYjODIxNjtDb3B5IGRhdGEg dG8gdG1wIHRhYmxlJiM4MjE3OyB3aGlsZSBhbGwgb3RoZXIgY29ubmVjdGlvbnMgd2VyZSBp biAmIzgyMTY7TG9ja2VkJiM4MjE3OyBzdGF0ZS4NClBsZWFzZSBub3RpY2UgdGhhdCBNeUlT QU06PC9wPg0KDQo8dWw+DQo8bGk+SGFzIG9ubHkgZnVsbCB0YWJsZSBsb2NrIGdyYW51bGFy aXR5OzwvbGk+DQo8bGk+Q2FjaGVzIG9ubHkgaW5kZXhlcywgbm90IGRhdGE8L2xpPg0KPGxp PkRhdGEgY2FjaGUgaXMgbGVmdCBhdCBPUyBvcGVyYXRpbmcgbWVyY3k8L2xpPg0KPC91bD4N Cg0KPHA+UnVubmluZyB0aGUgcXVlcnkgb25jZSBhZ2FpbiB3ZSBub3RpY2VkOg0KLSBpdCB0 b29rIG5vIHRpbWUgdG8gY29tcGxldGUNCi0gYWZ0ZXIgY2xlYXJpbmcgdGhlIHF1ZXJ5IGNh Y2hlICg8Y29kZT5SRVNFVCBRVUVSWSBDQUNIRTs8L2NvZGU+KSBpdCB0b29rIDUgc2Vjb25k cw0KLSBhZnRlciBjbGVhcmluZyBPUyBkaXNrIGNhY2hlIChDZW50T1MpIHRocm91Z2ggPGNv ZGU+ZWNobyAzICZndDsgL3Byb2Mvc3lzL3ZtL2Ryb3BfY2FjaGVzPC9jb2RlPiAoc2VlIDxh IGhyZWY9Imh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvOTU1MTgzOC9ob3ct dG8tcHVyZ2UtZGlzay1pLW8tY2FjaGVzLW9uLWxpbnV4IiB0aXRsZT0iQ2xlYXIgRGlzayBD YWNoZSI+Q2xlYXIgRGlzayBDYWNoZTwvYT4gKSB0aGUgcXVlcnkgdG9vayBvdmVyIDE4MCBz ZWNvbmRzLjwvcD4NCg0KPGgyIGlkPSJjb25jbHVzaW9uIj5Db25jbHVzaW9uPC9oMj4NCg0K PHA+RHVlIHRvIHNvbWUgZmFjdHMgKCYjODIzMDs/KSBhdCBzb21lIHBvaW50IHRoZXJlIHdh cyBhIHF1ZXJ5IHRyaWdnZXJlZCBieSBhIGNsaWVudCBhY3Rpb24sIHF1ZXJ5IHRoYXQgbGFz dHMgdmVyeSBsb25nLiBEdXJpbmcgdGhpcyBwZXJpb2Qgb25lIG9mIHRoZSBtb3N0IHVzZWQg dGFibGUgYmVjb21lcyBsb2NrZWQgc28gYW55IHN1YnNlcXVlbnQgcXVlcmllcyB3aWxsIGJl Y29tZSBsb2NrZWQgd2FpdGluZyB0aGUgaW5pdGlhbCBxdWVyeSB0byBmaW5pc2guIE9UUlMg Y2xpZW50LCBub3RpY2luZyBubyByZXNwb25zZSBmcm9tIHRoZSBzeXN0ZW0sIHdpbGwgdHJ5 IHJlZnJlc2hpbmcgdGhlIHBhZ2Ugb3IgY2xpY2tpbmcgb25jZSBhZ2FpbiBzb21lIGxpbmsg d2hpY2ggaW4gdHVybiB3aWxsIHRyaWdnZXIgc2VydmVyIHNpZGUgb3BlbmluZyBvZiBhIG5l dyBNeVNRTCBjb25uZWN0aW9uIHRpbGwgdGhlIGRlZmF1bHQgMTUxIGNvbm5lY3Rpb25zIGlz IGhpdC48L3A+DQoNCjxoMiBpZD0ic29sdXRpb24iPlNvbHV0aW9uPC9oMj4NCg0KPHA+QWZ0 ZXIgaW5jcmVhc2luZyB0aGUgT1MgbWVtb3J5IGZyb20gNiBHQiB0byAxMiBHQiBhbmQgPGNv ZGU+a2V5X2J1ZmZlcl9zaXplPC9jb2RlPiB0byAzIEdCIChhIGxpdHRsZSBiaXQgdG8gZGVm ZW5zaXZlKSB3ZSBlbmNvdW50ZXJlZCBubyBtb3JlIGVycm9ycy48L3A+DQoNCjxoMiBpZD0i c29tZXVzZWZ1bG15c3FscXVlcmllcyI+U29tZSB1c2VmdWwgTXlTUUwgcXVlcmllczwvaDI+ DQoNCjxwcmU+PGNvZGUgY2xhc3M9InNxbCI+U0hPVyBTVEFUVVMgTElLRSAna2V5JSc7DQpT SE9XIFZBUklBQkxFUyBMSUtFICdrZXklJzsNCg0KU0hPVyBWQVJJQUJMRVMgTElLRSAnbWF4 X2hlYXBfdGFibGVfc2l6ZSc7DQoNClNIT1cgU1RBVFVTIExJS0UgJyV0bXAlJzsNCg0KUkVT RVQgUVVFUlkgQ0FDSEU7DQoNCnNob3cgZW5naW5lczsNCg0KPC9jb2RlPjwvcHJlPg0K

Piwik Installation

This applies to Ubuntu 16.04 LTS.

Compiled from https://www.howtoforge.com/tutorial/installing-nginx-with-php7-fpm-and-mysql-on-ubuntu–16.04-lts-lemp/

Install MySQL

See also https://support.rackspace.com/how-to/configuring-mysql-server-on-ubuntu/

Run the following and provide the appropriate answers to subsequent prompts: apt-get -y install mysql-server mysql_secure_installation If you want to manage your MySQL instance from external computers choose No to the question Disallow root login remotely? and change the mysql.conf (usually found in /etc/mysql/mysql.conf.d/mysqld.cnf) and set the bind-address parameter to 0.0.0.0. To find the actual path for the configuration file run /usr/sbin/mysqld --help --verbose If you install Piwik on the same machine this is not required.

Create database/user for Piwik

$ mysql -u root -p
mysql> CREATE DATABASE piwik;
mysql> CREATE USER 'piwik'@'localhost' IDENTIFIED BY 'change_to_real_password';
mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES ON piwik.* TO 'piwik'@'localhost';
mysql> EXIT

Install Nginx

If you have already installed Apache, remove it:

service apache2 stop
update-rc.d -f apache2 remove
apt-get remove apache2
sudo -i
apt-get update
apt-get -y install nginx

Check the status of the firewall

Nginx registers itself with ufw so:

  • Check of ufw is enabled: ufw status
  • If enabled then register one of the Nginx registered profiles (found out by running ufw app list) like:
    • ufw allow 'Nginx HTTP'

Check Nginx

From within a browser try http://\<IP\>

Install PHP 7

apt-get -y install php7.0-fpm

Modify default site configuration file /etc/nginx/sites-available/default by de-commenting the following lines:

...
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
...
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    }

...
    location ~ /\.ht {
        deny all;
    }

Reload Nginx:

service nginx reload

Open /etc/php/7.0/fpm/php.ini and set cgi.fix_pathinfo=0: Restart php:

service php7.0-fpm reload

Check the installation

Create info.php in /var/www/html/info.php with the following content:

<?php
phpinfo();
?>

Watch out for CRLFs on Windows (end of line should be \n regularly in Linux).

Try now http://<IP>/info.php

Install additional packages required by Piwik

apt-get -y install php7.0-curl php7.0-gd php7.0-cli php-geoip php7.0-mysql
apt-get -y install php-mbstring php7.0-mbstring
apt-get -y install php-xml

Install Piwik

Run:

cd /tmp
apt-get install unzip
wget https://builds.piwik.org/piwik.zip && unzip piwik.zip
mkdir /var/www//html/piwik
cp -R ./piwik/* /var/www/html/piwik
chown -R www-data:www-data /var/www/html/piwik
chmod -R 0755 /var/www/html/piwik/tmp

Now browse to http://<FQDN>/piwik/index.php

Configure your Piwik instance. The following script-let should be included in each page of your site (as specified by the setup:Make sure this code is on every page of your website. We recommend to paste it immediately before the closing </head> tag.). Be sure to change the <FQDN> with the appropriate value.

<!-- Piwik -->
<script type="text/javascript">
  var _paq = _paq || [];
  // tracker methods like "setCustomDimension" should be called before "trackPageView"
  _paq.push(['trackPageView']);
  _paq.push(['enableLinkTracking']);
  (function() {
    var u="//<FQDN>/piwik/";
    _paq.push(['setTrackerUrl', u+'piwik.php']);
    _paq.push(['setSiteId', '1']);
    var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
    g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
  })();
</script>
<!-- End Piwik Code -->

Publishing Problem

The monitored site had some peculiarities:

  • It is used from intranet or from internet, published through a reverse proxy
  • It can be used over plain HTTP or over HTTPS (through SSO or from internet); when used over HTTP from intranet it worked fine but over HTTPS (also from intranet) the request to Piwik (due to security reasons) was also done over HTTPS which obviously failed (the //<FQDN>/piwik/ syntax indicates to the browser to make the request over the same protocol as the referral page was loaded)

So overall the default Piwik installation didn’t work since it was not accessible through HTTPS nor from internet.

The first step was to publish the site through the same reverse proxy, both HTTP and HTTPS (with the tunnel being terminated at proxy level) with Forward Original HOST Header set to Off. Trying to access the administrative interface through the public FQDN led to a security error (something with actual Referral not matching the expected one).

Next step was to change the proxy settings so that the original HOST header was forwarded to Piwik. Another error popped up stating (as a conclusion, the error text was rather stupid like Piwik was accessed from [URL] but it was configured to be accessed from [URL]) that the value of the HOST header is not registered as safe in config\config.ini.php.

By adding the FQDN in [General] section as:

trusted_hosts[] = "FQDN"

the integration works just fine.

PHA+VGhpcyBhcHBsaWVzIHRvIFVidW50dSAxNi4wNCBMVFMuPC9wPg0KDQo8cD5Db21waWxl ZCBmcm9tIDxhIGhyZWY9Imh0dHBzOi8vd3d3Lmhvd3RvZm9yZ2UuY29tL3R1dG9yaWFsL2lu c3RhbGxpbmctbmdpbngtd2l0aC1waHA3LWZwbS1hbmQtbXlzcWwtb24tdWJ1bnR1LTE2LjA0 LWx0cy1sZW1wLyI+aHR0cHM6Ly93d3cuaG93dG9mb3JnZS5jb20vdHV0b3JpYWwvaW5zdGFs bGluZy1uZ2lueC13aXRoLXBocDctZnBtLWFuZC1teXNxbC1vbi11YnVudHUmIzgyMTE7MTYu MDQtbHRzLWxlbXAvPC9hPjwvcD4NCg0KPGgxIGlkPSJpbnN0YWxsbXlzcWwiPkluc3RhbGwg TXlTUUw8L2gxPg0KDQo8cD5TZWUgYWxzbyA8YSBocmVmPSJodHRwczovL3N1cHBvcnQucmFj a3NwYWNlLmNvbS9ob3ctdG8vY29uZmlndXJpbmctbXlzcWwtc2VydmVyLW9uLXVidW50dS8i Pmh0dHBzOi8vc3VwcG9ydC5yYWNrc3BhY2UuY29tL2hvdy10by9jb25maWd1cmluZy1teXNx bC1zZXJ2ZXItb24tdWJ1bnR1LzwvYT48L3A+DQoNCjxwPlJ1biB0aGUgZm9sbG93aW5nIGFu ZCBwcm92aWRlIHRoZSBhcHByb3ByaWF0ZSBhbnN3ZXJzIHRvIHN1YnNlcXVlbnQgcHJvbXB0 czoNCjxjb2RlPg0KYXB0LWdldCAteSBpbnN0YWxsIG15c3FsLXNlcnZlcg0KbXlzcWxfc2Vj dXJlX2luc3RhbGxhdGlvbg0KPC9jb2RlPg0KSWYgeW91IHdhbnQgdG8gbWFuYWdlIHlvdXIg TXlTUUwgaW5zdGFuY2UgZnJvbSBleHRlcm5hbCBjb21wdXRlcnMgY2hvb3NlIE5vIHRvIHRo ZSBxdWVzdGlvbiA8Y29kZT5EaXNhbGxvdyByb290IGxvZ2luIHJlbW90ZWx5PzwvY29kZT4g YW5kIGNoYW5nZSB0aGUgPGNvZGU+bXlzcWwuY29uZjwvY29kZT4gKHVzdWFsbHkgZm91bmQg aW4gPGNvZGU+L2V0Yy9teXNxbC9teXNxbC5jb25mLmQvbXlzcWxkLmNuZjwvY29kZT4pIGFu ZCBzZXQgdGhlIDxjb2RlPmJpbmQtYWRkcmVzczwvY29kZT4gcGFyYW1ldGVyIHRvIDxjb2Rl PjAuMC4wLjA8L2NvZGU+Lg0KVG8gZmluZCB0aGUgYWN0dWFsIHBhdGggZm9yIHRoZSBjb25m aWd1cmF0aW9uIGZpbGUgcnVuIDxjb2RlPi91c3Ivc2Jpbi9teXNxbGQgLS1oZWxwIC0tdmVy Ym9zZTwvY29kZT4NCklmIHlvdSBpbnN0YWxsIFBpd2lrIG9uIHRoZSBzYW1lIG1hY2hpbmUg dGhpcyBpcyBub3QgcmVxdWlyZWQuPC9wPg0KDQo8aDIgaWQ9ImNyZWF0ZWRhdGFiYXNldXNl cmZvcnBpd2lrIj5DcmVhdGUgZGF0YWJhc2UvdXNlciBmb3IgUGl3aWs8L2gyPg0KDQo8cHJl Pjxjb2RlPiQgbXlzcWwgLXUgcm9vdCAtcA0KbXlzcWwmZ3Q7IENSRUFURSBEQVRBQkFTRSBw aXdpazsNCm15c3FsJmd0OyBDUkVBVEUgVVNFUiAncGl3aWsnQCdsb2NhbGhvc3QnIElERU5U SUZJRUQgQlkgJ2NoYW5nZV90b19yZWFsX3Bhc3N3b3JkJzsNCm15c3FsJmd0OyBHUkFOVCBT RUxFQ1QsIElOU0VSVCwgVVBEQVRFLCBERUxFVEUsIENSRUFURSwgRFJPUCwgQUxURVIsIENS RUFURSBURU1QT1JBUlkgVEFCTEVTLCBMT0NLIFRBQkxFUyBPTiBwaXdpay4qIFRPICdwaXdp aydAJ2xvY2FsaG9zdCc7DQpteXNxbCZndDsgRVhJVA0KPC9jb2RlPjwvcHJlPg0KDQo8aDEg aWQ9Imluc3RhbGxuZ2lueCI+SW5zdGFsbCBOZ2lueDwvaDE+DQoNCjxwPklmIHlvdSBoYXZl IGFscmVhZHkgaW5zdGFsbGVkIEFwYWNoZSwgcmVtb3ZlIGl0OjwvcD4NCg0KPHByZT48Y29k ZT5zZXJ2aWNlIGFwYWNoZTIgc3RvcA0KdXBkYXRlLXJjLmQgLWYgYXBhY2hlMiByZW1vdmUN CmFwdC1nZXQgcmVtb3ZlIGFwYWNoZTINCjwvY29kZT48L3ByZT4NCg0KPHByZT48Y29kZT5z dWRvIC1pDQphcHQtZ2V0IHVwZGF0ZQ0KYXB0LWdldCAteSBpbnN0YWxsIG5naW54DQo8L2Nv ZGU+PC9wcmU+DQoNCjxoMiBpZD0iY2hlY2t0aGVzdGF0dXNvZnRoZWZpcmV3YWxsIj5DaGVj ayB0aGUgc3RhdHVzIG9mIHRoZSBmaXJld2FsbDwvaDI+DQoNCjxwPjxjb2RlPk5naW54PC9j b2RlPiByZWdpc3RlcnMgaXRzZWxmIHdpdGggPGNvZGU+dWZ3PC9jb2RlPiBzbzo8L3A+DQoN Cjx1bD4NCjxsaT5DaGVjayBvZiA8Y29kZT51Znc8L2NvZGU+IGlzIGVuYWJsZWQ6IDxjb2Rl PnVmdyBzdGF0dXM8L2NvZGU+PC9saT4NCjxsaT5JZiBlbmFibGVkIHRoZW4gcmVnaXN0ZXIg b25lIG9mIHRoZSA8Y29kZT5OZ2lueDwvY29kZT4gcmVnaXN0ZXJlZCBwcm9maWxlcyAoZm91 bmQgb3V0IGJ5IHJ1bm5pbmcgPGNvZGU+dWZ3IGFwcCBsaXN0PC9jb2RlPikgbGlrZToNCg0K PHVsPg0KPGxpPjxjb2RlPnVmdyBhbGxvdyAnTmdpbnggSFRUUCc8L2NvZGU+PC9saT4NCjwv dWw+PC9saT4NCjwvdWw+DQoNCjxoMiBpZD0iY2hlY2tuZ2lueCI+Q2hlY2sgTmdpbng8L2gy Pg0KDQo8cD5Gcm9tIHdpdGhpbiBhIGJyb3dzZXIgdHJ5IDxjb2RlPmh0dHA6Ly9cJmx0O0lQ XCZndDs8L2NvZGU+PC9wPg0KDQo8aDEgaWQ9Imluc3RhbGxwaHA3Ij5JbnN0YWxsIFBIUCA3 PC9oMT4NCg0KPHByZT48Y29kZT5hcHQtZ2V0IC15IGluc3RhbGwgcGhwNy4wLWZwbQ0KPC9j b2RlPjwvcHJlPg0KDQo8cD5Nb2RpZnkgZGVmYXVsdCBzaXRlIGNvbmZpZ3VyYXRpb24gZmls ZSA8Y29kZT4vZXRjL25naW54L3NpdGVzLWF2YWlsYWJsZS9kZWZhdWx0PC9jb2RlPiBieSBk ZS1jb21tZW50aW5nIHRoZSBmb2xsb3dpbmcgbGluZXM6PC9wPg0KDQo8cHJlPjxjb2RlPi4u Lg0KICAgIGxvY2F0aW9uIH4gXC5waHAkIHsNCiAgICAgICAgaW5jbHVkZSBzbmlwcGV0cy9m YXN0Y2dpLXBocC5jb25mOw0KLi4uDQogICAgICAgIGZhc3RjZ2lfcGFzcyB1bml4Oi9ydW4v cGhwL3BocDcuMC1mcG0uc29jazsNCiAgICB9DQoNCi4uLg0KICAgIGxvY2F0aW9uIH4gL1wu aHQgew0KICAgICAgICBkZW55IGFsbDsNCiAgICB9DQo8L2NvZGU+PC9wcmU+DQoNCjxwPlJl bG9hZCBOZ2lueDo8L3A+DQoNCjxwcmU+PGNvZGU+c2VydmljZSBuZ2lueCByZWxvYWQNCjwv Y29kZT48L3ByZT4NCg0KPHA+T3BlbiA8Y29kZT4vZXRjL3BocC83LjAvZnBtL3BocC5pbmk8 L2NvZGU+IGFuZCBzZXQgPGNvZGU+Y2dpLmZpeF9wYXRoaW5mbz0wOjwvY29kZT4NClJlc3Rh cnQgcGhwOjwvcD4NCg0KPHByZT48Y29kZT5zZXJ2aWNlIHBocDcuMC1mcG0gcmVsb2FkDQo8 L2NvZGU+PC9wcmU+DQoNCjxoMiBpZD0iY2hlY2t0aGVpbnN0YWxsYXRpb24iPkNoZWNrIHRo ZSBpbnN0YWxsYXRpb248L2gyPg0KDQo8cD5DcmVhdGUgPGNvZGU+aW5mby5waHA8L2NvZGU+ IGluIDxjb2RlPi92YXIvd3d3L2h0bWwvaW5mby5waHA8L2NvZGU+IHdpdGggdGhlIGZvbGxv d2luZyBjb250ZW50OjwvcD4NCg0KPHByZT48Y29kZT4mbHQ7P3BocA0KcGhwaW5mbygpOw0K PyZndDsNCjwvY29kZT48L3ByZT4NCg0KPHA+V2F0Y2ggb3V0IGZvciBDUkxGcyBvbiBXaW5k b3dzIChlbmQgb2YgbGluZSBzaG91bGQgYmUgXG4gcmVndWxhcmx5IGluIExpbnV4KS48L3A+ DQoNCjxwPlRyeSBub3cgPGNvZGU+aHR0cDovLyZsdDtJUCZndDsvaW5mby5waHA8L2NvZGU+ PC9wPg0KDQo8aDIgaWQ9Imluc3RhbGxhZGRpdGlvbmFscGFja2FnZXNyZXF1aXJlZGJ5cGl3 aWsiPkluc3RhbGwgYWRkaXRpb25hbCBwYWNrYWdlcyByZXF1aXJlZCBieSBQaXdpazwvaDI+ DQoNCjxwcmU+PGNvZGU+YXB0LWdldCAteSBpbnN0YWxsIHBocDcuMC1jdXJsIHBocDcuMC1n ZCBwaHA3LjAtY2xpIHBocC1nZW9pcCBwaHA3LjAtbXlzcWwNCmFwdC1nZXQgLXkgaW5zdGFs bCBwaHAtbWJzdHJpbmcgcGhwNy4wLW1ic3RyaW5nDQphcHQtZ2V0IC15IGluc3RhbGwgcGhw LXhtbA0KPC9jb2RlPjwvcHJlPg0KDQo8aDEgaWQ9Imluc3RhbGxwaXdpayI+SW5zdGFsbCBQ aXdpazwvaDE+DQoNCjxwPlJ1bjo8L3A+DQoNCjxwcmU+PGNvZGU+Y2QgL3RtcA0KYXB0LWdl dCBpbnN0YWxsIHVuemlwDQp3Z2V0IGh0dHBzOi8vYnVpbGRzLnBpd2lrLm9yZy9waXdpay56 aXAgJmFtcDsmYW1wOyB1bnppcCBwaXdpay56aXANCm1rZGlyIC92YXIvd3d3Ly9odG1sL3Bp d2lrDQpjcCAtUiAuL3Bpd2lrLyogL3Zhci93d3cvaHRtbC9waXdpaw0KY2hvd24gLVIgd3d3 LWRhdGE6d3d3LWRhdGEgL3Zhci93d3cvaHRtbC9waXdpaw0KY2htb2QgLVIgMDc1NSAvdmFy L3d3dy9odG1sL3Bpd2lrL3RtcA0KPC9jb2RlPjwvcHJlPg0KDQo8cD5Ob3cgYnJvd3NlIHRv IDxjb2RlPmh0dHA6Ly8mbHQ7RlFETiZndDsvcGl3aWsvaW5kZXgucGhwPC9jb2RlPjwvcD4N Cg0KPHA+Q29uZmlndXJlIHlvdXIgUGl3aWsgaW5zdGFuY2UuIFRoZSBmb2xsb3dpbmcgc2Ny aXB0LWxldCBzaG91bGQgYmUgaW5jbHVkZWQgaW4gZWFjaCBwYWdlIG9mIHlvdXIgc2l0ZSAo YXMgc3BlY2lmaWVkIGJ5IHRoZSBzZXR1cDo8Y29kZT5NYWtlIHN1cmUgdGhpcyBjb2RlIGlz IG9uIGV2ZXJ5IHBhZ2Ugb2YgeW91ciB3ZWJzaXRlLiBXZSByZWNvbW1lbmQgdG8gcGFzdGUg aXQgaW1tZWRpYXRlbHkgYmVmb3JlIHRoZSBjbG9zaW5nICZsdDsvaGVhZCZndDsgdGFnLjwv Y29kZT4pLg0KQmUgc3VyZSB0byBjaGFuZ2UgdGhlIDxjb2RlPiZsdDtGUUROJmd0OzwvY29k ZT4gd2l0aCB0aGUgYXBwcm9wcmlhdGUgdmFsdWUuPC9wPg0KDQo8cHJlPjxjb2RlPiZsdDsh LS0gUGl3aWsgLS0mZ3Q7DQombHQ7c2NyaXB0IHR5cGU9JnF1b3Q7dGV4dC9qYXZhc2NyaXB0 JnF1b3Q7Jmd0Ow0KICB2YXIgX3BhcSA9IF9wYXEgfHwgW107DQogIC8vIHRyYWNrZXIgbWV0 aG9kcyBsaWtlICZxdW90O3NldEN1c3RvbURpbWVuc2lvbiZxdW90OyBzaG91bGQgYmUgY2Fs bGVkIGJlZm9yZSAmcXVvdDt0cmFja1BhZ2VWaWV3JnF1b3Q7DQogIF9wYXEucHVzaChbJ3Ry YWNrUGFnZVZpZXcnXSk7DQogIF9wYXEucHVzaChbJ2VuYWJsZUxpbmtUcmFja2luZyddKTsN CiAgKGZ1bmN0aW9uKCkgew0KICAgIHZhciB1PSZxdW90Oy8vJmx0O0ZRRE4mZ3Q7L3Bpd2lr LyZxdW90OzsNCiAgICBfcGFxLnB1c2goWydzZXRUcmFja2VyVXJsJywgdSsncGl3aWsucGhw J10pOw0KICAgIF9wYXEucHVzaChbJ3NldFNpdGVJZCcsICcxJ10pOw0KICAgIHZhciBkPWRv Y3VtZW50LCBnPWQuY3JlYXRlRWxlbWVudCgnc2NyaXB0JyksIHM9ZC5nZXRFbGVtZW50c0J5 VGFnTmFtZSgnc2NyaXB0JylbMF07DQogICAgZy50eXBlPSd0ZXh0L2phdmFzY3JpcHQnOyBn LmFzeW5jPXRydWU7IGcuZGVmZXI9dHJ1ZTsgZy5zcmM9dSsncGl3aWsuanMnOyBzLnBhcmVu dE5vZGUuaW5zZXJ0QmVmb3JlKGcscyk7DQogIH0pKCk7DQombHQ7L3NjcmlwdCZndDsNCiZs dDshLS0gRW5kIFBpd2lrIENvZGUgLS0mZ3Q7DQo8L2NvZGU+PC9wcmU+DQoNCjxoMSBpZD0i cHVibGlzaGluZ3Byb2JsZW0iPlB1Ymxpc2hpbmcgUHJvYmxlbTwvaDE+DQoNCjxwPlRoZSBt b25pdG9yZWQgc2l0ZSBoYWQgc29tZSBwZWN1bGlhcml0aWVzOjwvcD4NCg0KPHVsPg0KPGxp Pkl0IGlzIHVzZWQgZnJvbSBpbnRyYW5ldCBvciBmcm9tIGludGVybmV0LCBwdWJsaXNoZWQg dGhyb3VnaCBhIHJldmVyc2UgcHJveHk8L2xpPg0KPGxpPkl0IGNhbiBiZSB1c2VkIG92ZXIg cGxhaW4gSFRUUCBvciBvdmVyIEhUVFBTICh0aHJvdWdoIFNTTyBvciBmcm9tIGludGVybmV0 KTsgd2hlbiB1c2VkIG92ZXIgSFRUUCBmcm9tIGludHJhbmV0IGl0IHdvcmtlZCBmaW5lIGJ1 dCBvdmVyIEhUVFBTIChhbHNvIGZyb20gaW50cmFuZXQpIHRoZSByZXF1ZXN0IHRvIFBpd2lr IChkdWUgdG8gc2VjdXJpdHkgcmVhc29ucykgd2FzIGFsc28gZG9uZSBvdmVyIEhUVFBTIHdo aWNoIG9idmlvdXNseSBmYWlsZWQgKHRoZSA8Y29kZT4vLyZsdDtGUUROJmd0Oy9waXdpay88 L2NvZGU+IHN5bnRheCBpbmRpY2F0ZXMgdG8gdGhlIGJyb3dzZXIgdG8gbWFrZSB0aGUgcmVx dWVzdCBvdmVyIHRoZSBzYW1lIHByb3RvY29sIGFzIHRoZSByZWZlcnJhbCBwYWdlIHdhcyBs b2FkZWQpPC9saT4NCjwvdWw+DQoNCjxwPlNvIG92ZXJhbGwgdGhlIGRlZmF1bHQgUGl3aWsg aW5zdGFsbGF0aW9uIGRpZG4mIzgyMTc7dCB3b3JrIHNpbmNlIGl0IHdhcyBub3QgYWNjZXNz aWJsZSB0aHJvdWdoIEhUVFBTIG5vciBmcm9tIGludGVybmV0LjwvcD4NCg0KPHA+VGhlIGZp cnN0IHN0ZXAgd2FzIHRvIHB1Ymxpc2ggdGhlIHNpdGUgdGhyb3VnaCB0aGUgc2FtZSByZXZl cnNlIHByb3h5LCBib3RoIEhUVFAgYW5kIEhUVFBTICh3aXRoIHRoZSB0dW5uZWwgYmVpbmcg dGVybWluYXRlZCBhdCBwcm94eSBsZXZlbCkgd2l0aCA8Y29kZT5Gb3J3YXJkIE9yaWdpbmFs IEhPU1QgSGVhZGVyPC9jb2RlPiBzZXQgdG8gT2ZmLiBUcnlpbmcgdG8gYWNjZXNzIHRoZSBh ZG1pbmlzdHJhdGl2ZSBpbnRlcmZhY2UgdGhyb3VnaCB0aGUgcHVibGljIEZRRE4gbGVkIHRv IGEgc2VjdXJpdHkgZXJyb3IgKHNvbWV0aGluZyB3aXRoIGFjdHVhbCBSZWZlcnJhbCBub3Qg bWF0Y2hpbmcgdGhlIGV4cGVjdGVkIG9uZSkuPC9wPg0KDQo8cD5OZXh0IHN0ZXAgd2FzIHRv IGNoYW5nZSB0aGUgcHJveHkgc2V0dGluZ3Mgc28gdGhhdCB0aGUgb3JpZ2luYWwgSE9TVCBo ZWFkZXIgd2FzIGZvcndhcmRlZCB0byBQaXdpay4gQW5vdGhlciBlcnJvciBwb3BwZWQgdXAg c3RhdGluZyAoYXMgYSBjb25jbHVzaW9uLCB0aGUgZXJyb3IgdGV4dCB3YXMgcmF0aGVyIHN0 dXBpZCBsaWtlIDxzdHJvbmc+UGl3aWsgd2FzIGFjY2Vzc2VkIGZyb20gW1VSTF0gYnV0IGl0 IHdhcyBjb25maWd1cmVkIHRvIGJlIGFjY2Vzc2VkIGZyb20gW1VSTF08L3N0cm9uZz4pIHRo YXQgdGhlIHZhbHVlIG9mIHRoZSBIT1NUIGhlYWRlciBpcyBub3QgcmVnaXN0ZXJlZCBhcyBz YWZlIGluIDxjb2RlPmNvbmZpZ1xjb25maWcuaW5pLnBocDwvY29kZT4uPC9wPg0KDQo8cD5C eSBhZGRpbmcgdGhlIEZRRE4gaW4gPGNvZGU+W0dlbmVyYWxdPC9jb2RlPiBzZWN0aW9uIGFz OjwvcD4NCg0KPHByZT48Y29kZT50cnVzdGVkX2hvc3RzW10gPSAmcXVvdDtGUUROJnF1b3Q7 DQo8L2NvZGU+PC9wcmU+DQoNCjxwPnRoZSBpbnRlZ3JhdGlvbiB3b3JrcyBqdXN0IGZpbmUu PC9wPg0K

Monitoring WildFly with VisualVM

Monitoring Wildfly 10 with JVisual VM

We have a performance problem on our Wildfly server (running as a Windows service) and we want to use jVisualVM (VisualVM actually).

  • Download the latest version from https://visualvm.github.io/
  • Unpack the archieve
  • Create the following batch in the root folder of the unpacked archieve(change the path to jboss-client.jar acordingly): cd bin visualvm.exe -cp:a C:\Java\wildfly-10.0.0.Final\bin\client\jboss-client.jar
  • Run the batch; you will not see (most probably) the Wildfly server in the identified applications because it is running as a different user (see http://stackoverflow.com/questions/32281266/why-java-visualvm-is-not-showing-wildfly-when-it-is-started-as-a-service)
  • Add a JMX connection by specifying the connection as service:jmx:remote+http://127.0.0.1:9990; be sure you have creted an admin user on your Wildfly instance
  • Open the connection
PGgxIGlkPSJtb25pdG9yaW5nd2lsZGZseTEwd2l0aGp2aXN1YWx2bSI+TW9uaXRvcmluZyBX aWxkZmx5IDEwIHdpdGggSlZpc3VhbCBWTTwvaDE+DQoNCjxwPldlIGhhdmUgYSBwZXJmb3Jt YW5jZSBwcm9ibGVtIG9uIG91ciBXaWxkZmx5IHNlcnZlciAocnVubmluZyBhcyBhIFdpbmRv d3Mgc2VydmljZSkgYW5kIHdlIHdhbnQgdG8gdXNlIGpWaXN1YWxWTSAoVmlzdWFsVk0gYWN0 dWFsbHkpLjwvcD4NCg0KPHVsPg0KPGxpPkRvd25sb2FkIHRoZSBsYXRlc3QgdmVyc2lvbiBm cm9tIDxhIGhyZWY9Imh0dHBzOi8vdmlzdWFsdm0uZ2l0aHViLmlvLyI+aHR0cHM6Ly92aXN1 YWx2bS5naXRodWIuaW8vPC9hPjwvbGk+DQo8bGk+VW5wYWNrIHRoZSBhcmNoaWV2ZTwvbGk+ DQo8bGk+Q3JlYXRlIHRoZSBmb2xsb3dpbmcgYmF0Y2ggaW4gdGhlIHJvb3QgZm9sZGVyIG9m IHRoZSB1bnBhY2tlZCBhcmNoaWV2ZShjaGFuZ2UgdGhlIHBhdGggdG8gamJvc3MtY2xpZW50 LmphciBhY29yZGluZ2x5KToNCjxjb2RlPg0KY2QgYmluDQp2aXN1YWx2bS5leGUgLWNwOmEg QzpcSmF2YVx3aWxkZmx5LTEwLjAuMC5GaW5hbFxiaW5cY2xpZW50XGpib3NzLWNsaWVudC5q YXINCjwvY29kZT48L2xpPg0KPGxpPlJ1biB0aGUgYmF0Y2g7IHlvdSB3aWxsIG5vdCBzZWUg KG1vc3QgcHJvYmFibHkpIHRoZSBXaWxkZmx5IHNlcnZlciBpbiB0aGUgaWRlbnRpZmllZCBh cHBsaWNhdGlvbnMgYmVjYXVzZSBpdCBpcyBydW5uaW5nIGFzIGEgZGlmZmVyZW50IHVzZXIg KHNlZSA8YSBocmVmPSJodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzMyMjgx MjY2L3doeS1qYXZhLXZpc3VhbHZtLWlzLW5vdC1zaG93aW5nLXdpbGRmbHktd2hlbi1pdC1p cy1zdGFydGVkLWFzLWEtc2VydmljZSI+aHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0 aW9ucy8zMjI4MTI2Ni93aHktamF2YS12aXN1YWx2bS1pcy1ub3Qtc2hvd2luZy13aWxkZmx5 LXdoZW4taXQtaXMtc3RhcnRlZC1hcy1hLXNlcnZpY2U8L2E+KTwvbGk+DQo8bGk+QWRkIGEg Sk1YIGNvbm5lY3Rpb24gYnkgc3BlY2lmeWluZyB0aGUgY29ubmVjdGlvbiBhcyA8Y29kZT5z ZXJ2aWNlOmpteDpyZW1vdGUraHR0cDovLzEyNy4wLjAuMTo5OTkwPC9jb2RlPjsgYmUgc3Vy ZSB5b3UgaGF2ZSBjcmV0ZWQgYW4gYWRtaW4gdXNlciBvbiB5b3VyIFdpbGRmbHkgaW5zdGFu Y2U8L2xpPg0KPGxpPk9wZW4gdGhlIGNvbm5lY3Rpb248L2xpPg0KPC91bD4NCg==

SSH Port Forwarding S2C

Server2Client (S2C) Port Forwarding

Server install

  • Install a Linux virtual machine (Ubuntu 16.04 in my case).
  • Install ssh server apt-get install openssh-server.
  • Edit /etc/ssh/sshd_config and add the following line (otherwise ssh will publish the forwarding port only on local host nevermind the client’s rule):
    • GatewayPorts clientspecified
  • Restart ssh service or the whole server (shutdown -r now); watch out that restarting ssh service (like service ssh restart or service ssh stop+service ssh start will not kill existing established ssh sessions because they are run as separate sshd processes
  • Configure the client
  • Check that the ssh service listens on 3389 by running lsof -i :3389 (we target RDP protocol, see Client Install section)
  • Check all sshd processes lsof -i -n | egrep '\<sshd\>'

Client Install

Download and install Bitvise Tunnelier client https://www.bitvise.com/ssh-client-download

Run Bitvise SSH Client:

  • Create/save a profile by specifying:
    • Login tab
      • Host
      • Username (SSH user)
      • Initial Method password
      • Password
      • Store encrypted password in profile
    • Options tab:
      • Allways reconnect automatically
      • Un-check the On-login options
    • S2C tab:
      • Add as many rules as required by specifying:
        • Enabled
        • Listen interface: 0.0.0.0 (this means that the SSH server will accept connections on all interfaces)
        • Listen port: 3389 (for instance, SSH server will wait connections on this port)
        • Destination host (where on the client’s side the connection will be redirected):
          • localhost for the local computer
          • IP/FQDN for another computer
        • Destination port: 3389, to redirect to a local computer RDP requests
  • Press Login

Use the Forwarded Port

Suppose that our Linux machine is called sshs2c we can now open a RDP connection on the remote host (the one specified in <Destination host:Destination port>) by connecting to sshs2c:<Listen port>

Windows ssh servers

Remark: I haven’t fully tried the below mentioned OpenSSH approaches but I just would mention them in case you are interested in bypassing the installation of the Linux virtual machine (which actually brings an additional layer of security since you are not exposing your workstation directly over internet on highly sensitive port 22)

PGgxIGlkPSJzZXJ2ZXIyY2xpZW50czJjcG9ydGZvcndhcmRpbmciPlNlcnZlcjJDbGllbnQg KFMyQykgUG9ydCBGb3J3YXJkaW5nPC9oMT4NCg0KPGgyIGlkPSJzZXJ2ZXJpbnN0YWxsIj5T ZXJ2ZXIgaW5zdGFsbDwvaDI+DQoNCjx1bD4NCjxsaT5JbnN0YWxsIGEgTGludXggdmlydHVh bCBtYWNoaW5lIChVYnVudHUgMTYuMDQgaW4gbXkgY2FzZSkuPC9saT4NCjxsaT5JbnN0YWxs IHNzaCBzZXJ2ZXIgPGNvZGU+YXB0LWdldCBpbnN0YWxsIG9wZW5zc2gtc2VydmVyPC9jb2Rl Pi48L2xpPg0KPGxpPkVkaXQgPGNvZGU+L2V0Yy9zc2gvc3NoZF9jb25maWc8L2NvZGU+IGFu ZCBhZGQgdGhlIGZvbGxvd2luZyBsaW5lIChvdGhlcndpc2Ugc3NoIHdpbGwgcHVibGlzaCB0 aGUgZm9yd2FyZGluZyBwb3J0IG9ubHkgb24gbG9jYWwgaG9zdCBuZXZlcm1pbmQgdGhlIGNs aWVudCYjODIxNztzIHJ1bGUpOg0KDQo8dWw+DQo8bGk+R2F0ZXdheVBvcnRzIGNsaWVudHNw ZWNpZmllZDwvbGk+DQo8L3VsPjwvbGk+DQo8bGk+UmVzdGFydCBzc2ggc2VydmljZSBvciB0 aGUgd2hvbGUgc2VydmVyICg8Y29kZT5zaHV0ZG93biAtciBub3c8L2NvZGU+KTsgd2F0Y2gg b3V0IHRoYXQgcmVzdGFydGluZyBzc2ggc2VydmljZSAobGlrZSA8Y29kZT5zZXJ2aWNlIHNz aCByZXN0YXJ0PC9jb2RlPiBvciA8Y29kZT5zZXJ2aWNlIHNzaCBzdG9wPC9jb2RlPis8Y29k ZT5zZXJ2aWNlIHNzaCBzdGFydDwvY29kZT4gd2lsbCBub3Qga2lsbCBleGlzdGluZyBlc3Rh Ymxpc2hlZCBzc2ggc2Vzc2lvbnMgYmVjYXVzZSB0aGV5IGFyZSBydW4gYXMgc2VwYXJhdGUg PGNvZGU+c3NoZDwvY29kZT4gcHJvY2Vzc2VzPC9saT4NCjxsaT5Db25maWd1cmUgdGhlIGNs aWVudDwvbGk+DQo8bGk+Q2hlY2sgdGhhdCB0aGUgc3NoIHNlcnZpY2UgbGlzdGVucyBvbiAz Mzg5IGJ5IHJ1bm5pbmcgPGNvZGU+bHNvZiAtaSA6MzM4OTwvY29kZT4gKHdlIHRhcmdldCBS RFAgcHJvdG9jb2wsIHNlZSBDbGllbnQgSW5zdGFsbCBzZWN0aW9uKTwvbGk+DQo8bGk+Q2hl Y2sgYWxsIHNzaGQgcHJvY2Vzc2VzIDxjb2RlPmxzb2YgLWkgLW4gfCBlZ3JlcCAnXCZsdDtz c2hkXCZndDsnPC9jb2RlPjwvbGk+DQo8L3VsPg0KDQo8aDIgaWQ9ImNsaWVudGluc3RhbGwi PkNsaWVudCBJbnN0YWxsPC9oMj4NCg0KPHA+RG93bmxvYWQgYW5kIGluc3RhbGwgQml0dmlz ZSBUdW5uZWxpZXIgY2xpZW50IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmJpdHZpc2UuY29tL3Nz aC1jbGllbnQtZG93bmxvYWQiPmh0dHBzOi8vd3d3LmJpdHZpc2UuY29tL3NzaC1jbGllbnQt ZG93bmxvYWQ8L2E+PC9wPg0KDQo8cD5SdW4gQml0dmlzZSBTU0ggQ2xpZW50OjwvcD4NCg0K PHVsPg0KPGxpPkNyZWF0ZS9zYXZlIGEgcHJvZmlsZSBieSBzcGVjaWZ5aW5nOg0KDQo8dWw+ DQo8bGk+TG9naW4gdGFiDQoNCjx1bD4NCjxsaT5Ib3N0PC9saT4NCjxsaT5Vc2VybmFtZSAo U1NIIHVzZXIpPC9saT4NCjxsaT5Jbml0aWFsIE1ldGhvZCA8Y29kZT5wYXNzd29yZDwvY29k ZT48L2xpPg0KPGxpPlBhc3N3b3JkPC9saT4NCjxsaT5TdG9yZSBlbmNyeXB0ZWQgcGFzc3dv cmQgaW4gcHJvZmlsZTwvbGk+DQo8L3VsPjwvbGk+DQo8bGk+T3B0aW9ucyB0YWI6DQoNCjx1 bD4NCjxsaT5BbGx3YXlzIHJlY29ubmVjdCBhdXRvbWF0aWNhbGx5PC9saT4NCjxsaT5Vbi1j aGVjayB0aGUgT24tbG9naW4gb3B0aW9uczwvbGk+DQo8L3VsPjwvbGk+DQo8bGk+UzJDIHRh YjoNCg0KPHVsPg0KPGxpPkFkZCBhcyBtYW55IHJ1bGVzIGFzIHJlcXVpcmVkIGJ5IHNwZWNp Znlpbmc6DQoNCjx1bD4NCjxsaT5FbmFibGVkPC9saT4NCjxsaT5MaXN0ZW4gaW50ZXJmYWNl OiAwLjAuMC4wICh0aGlzIG1lYW5zIHRoYXQgdGhlIFNTSCBzZXJ2ZXIgd2lsbCBhY2NlcHQg Y29ubmVjdGlvbnMgb24gYWxsIGludGVyZmFjZXMpPC9saT4NCjxsaT5MaXN0ZW4gcG9ydDog MzM4OSAoZm9yIGluc3RhbmNlLCBTU0ggc2VydmVyIHdpbGwgd2FpdCBjb25uZWN0aW9ucyBv biB0aGlzIHBvcnQpPC9saT4NCjxsaT5EZXN0aW5hdGlvbiBob3N0ICh3aGVyZSBvbiB0aGUg Y2xpZW50JiM4MjE3O3Mgc2lkZSB0aGUgY29ubmVjdGlvbiB3aWxsIGJlIHJlZGlyZWN0ZWQp Og0KDQo8dWw+DQo8bGk+bG9jYWxob3N0IGZvciB0aGUgbG9jYWwgY29tcHV0ZXI8L2xpPg0K PGxpPklQL0ZRRE4gZm9yIGFub3RoZXIgY29tcHV0ZXI8L2xpPg0KPC91bD48L2xpPg0KPGxp PkRlc3RpbmF0aW9uIHBvcnQ6IDMzODksIHRvIHJlZGlyZWN0IHRvIGEgbG9jYWwgY29tcHV0 ZXIgUkRQIHJlcXVlc3RzPC9saT4NCjwvdWw+PC9saT4NCjwvdWw+PC9saT4NCjwvdWw+PC9s aT4NCjxsaT5QcmVzcyBMb2dpbjwvbGk+DQo8L3VsPg0KDQo8aDIgaWQ9InVzZXRoZWZvcndh cmRlZHBvcnQiPlVzZSB0aGUgRm9yd2FyZGVkIFBvcnQ8L2gyPg0KDQo8cD5TdXBwb3NlIHRo YXQgb3VyIExpbnV4IG1hY2hpbmUgaXMgY2FsbGVkIHNzaHMyYyB3ZSBjYW4gbm93IG9wZW4g YSBSRFAgY29ubmVjdGlvbiBvbiB0aGUgcmVtb3RlIGhvc3QgKHRoZSBvbmUgc3BlY2lmaWVk IGluICZsdDtEZXN0aW5hdGlvbiBob3N0OkRlc3RpbmF0aW9uIHBvcnQmZ3Q7KSBieSBjb25u ZWN0aW5nIHRvIHNzaHMyYzombHQ7TGlzdGVuIHBvcnQmZ3Q7PC9wPg0KDQo8aDIgaWQ9Indp bmRvd3Nzc2hzZXJ2ZXJzIj5XaW5kb3dzIHNzaCBzZXJ2ZXJzPC9oMj4NCg0KPHA+UmVtYXJr OiBJIGhhdmVuJiM4MjE3O3QgZnVsbHkgdHJpZWQgdGhlIGJlbG93IG1lbnRpb25lZCBPcGVu U1NIIGFwcHJvYWNoZXMgYnV0IEkganVzdCB3b3VsZCBtZW50aW9uIHRoZW0gaW4gY2FzZSB5 b3UgYXJlIGludGVyZXN0ZWQgaW4gYnlwYXNzaW5nIHRoZSBpbnN0YWxsYXRpb24gb2YgdGhl IExpbnV4IHZpcnR1YWwgbWFjaGluZSAod2hpY2ggYWN0dWFsbHkgYnJpbmdzIGFuIGFkZGl0 aW9uYWwgbGF5ZXIgb2Ygc2VjdXJpdHkgc2luY2UgeW91IGFyZSBub3QgZXhwb3NpbmcgeW91 ciB3b3Jrc3RhdGlvbiBkaXJlY3RseSBvdmVyIGludGVybmV0IG9uIGhpZ2hseSBzZW5zaXRp dmUgcG9ydCAyMik8L3A+DQoNCjx1bD4NCjxsaT5XaW5TQ1AgbWVudGlvbmVkIE1pY3Jvc29m dCAoISkgaW1wbGVtZW50YXRpb24gb2Ygc3NoIHNlcnZlciAoPGEgaHJlZj0iaHR0cHM6Ly93 aW5zY3AubmV0L2VuZy9kb2NzL2d1aWRlX3dpbmRvd3Nfb3BlbnNzaF9zZXJ2ZXIiPmh0dHBz Oi8vd2luc2NwLm5ldC9lbmcvZG9jcy9ndWlkZV93aW5kb3dzX29wZW5zc2hfc2VydmVyPC9h Pik6DQoNCjx1bD4NCjxsaT5IYXZlIGEgbG9vayBvbiBnaXRodWIgcHJvamVjdCB3aWtpPC9s aT4NCjxsaT5XaW5kb3dzIHVzZXJzIHVzZWQgZm9yIHVzZXIvcGFzc3dvcmQgYXV0aGVudGlj YXRpb24vYXV0aG9yaXphdGlvbiBhcmUgbG9jYWwgdXNlcnMsIG5vdCBkb21haW4gdXNlcnM8 L2xpPg0KPC91bD48L2xpPg0KPGxpPjxhIGhyZWY9Imh0dHA6Ly93d3cubWxzLXNvZnR3YXJl LmNvbS9vcGVuc3NoZC5odG1sI2JvdHBhZ2UiPmh0dHA6Ly93d3cubWxzLXNvZnR3YXJlLmNv bS9vcGVuc3NoZC5odG1sI2JvdHBhZ2U8L2E+PC9saT4NCjwvdWw+DQo=

Install ApacheDS

sudo -i
cd /tmp
wget http://apache.javapipe.com//directory/apacheds/dist/2.0.0-M23/apacheds-2.0.0-M23-amd64.deb
chmod +x apacheds-2.0.0-M23-amd64.deb
dpkg -i apacheds-2.0.0-M23-amd64.deb
update-rc.d apacheds-2.0.0-M23-default defaults
shutdown -r now

  • Check the log in /var/lib/apacheds…/default/log/apacheds.log for successful start-up; a single line should be present (something like [13:19:14] WARN [org.apache.directory.server.core.DefaultDirectoryService] - You didn't change the admin password of directory service instance 'default'. Please update the admin password as soon as possible to prevent a possible security breach.
  • Download latest ApacheDS Studio and install it
    • Create a new connection specifying:
      • Network parameters:
        • Connection name
        • Hostname
        • Port: 10389
        • Press "Check Network Parameters’
      • Authentication
        • Bind dn ou user : uid=admin,ou=system
        • Bind password : secret
        • Press ‘Check Authetication’
      • Finish
    • Change adminstrator’s password by editing ou=system->uid=admin and choosing anything else than plain text
      • SSHA, for instance
    • Close the connection, reconfigure the connection’s stored password and reopen it
    • Create a new partition by selecting ‘Open Configuration’ in the contextual menu (right click) of the newly created connection:
      • Advanced Partition Configuration…
      • Add..
        • Specify ID (like mycompany)and partition suffix like dc=mycompany)
        • Save
      • Restart the service service apacheds restart
    • Refresh the browser tree by selecting Reload from contextual menu
    • Perform any data import as required (from LDIF files for instance)

Important remark: Please notice that ldapsearch or the data export from ApacheDS Studio do not save info in the right sequence for importing (dependent objects after the objects they depend on)

PHByZT48Y29kZT5zdWRvIC1pDQpjZCAvdG1wDQp3Z2V0IGh0dHA6Ly9hcGFjaGUuamF2YXBp cGUuY29tLy9kaXJlY3RvcnkvYXBhY2hlZHMvZGlzdC8yLjAuMC1NMjMvYXBhY2hlZHMtMi4w LjAtTTIzLWFtZDY0LmRlYg0KY2htb2QgK3ggYXBhY2hlZHMtMi4wLjAtTTIzLWFtZDY0LmRl Yg0KZHBrZyAtaSBhcGFjaGVkcy0yLjAuMC1NMjMtYW1kNjQuZGViDQp1cGRhdGUtcmMuZCBh cGFjaGVkcy0yLjAuMC1NMjMtZGVmYXVsdCBkZWZhdWx0cw0Kc2h1dGRvd24gLXIgbm93DQoN CjwvY29kZT48L3ByZT4NCg0KPHVsPg0KPGxpPkNoZWNrIHRoZSBsb2cgaW4gL3Zhci9saWIv YXBhY2hlZHMmIzgyMzA7L2RlZmF1bHQvbG9nL2FwYWNoZWRzLmxvZyBmb3Igc3VjY2Vzc2Z1 bCBzdGFydC11cDsgYSBzaW5nbGUgbGluZSBzaG91bGQgYmUgcHJlc2VudCAoc29tZXRoaW5n IGxpa2UgPGNvZGU+WzEzOjE5OjE0XSBXQVJOIFtvcmcuYXBhY2hlLmRpcmVjdG9yeS5zZXJ2 ZXIuY29yZS5EZWZhdWx0RGlyZWN0b3J5U2VydmljZV0gLSBZb3UgZGlkbid0IGNoYW5nZSB0 aGUgYWRtaW4gcGFzc3dvcmQgb2YgZGlyZWN0b3J5IHNlcnZpY2UgaW5zdGFuY2UgJ2RlZmF1 bHQnLiAgUGxlYXNlIHVwZGF0ZSB0aGUgYWRtaW4gcGFzc3dvcmQgYXMgc29vbiBhcyBwb3Nz aWJsZSB0byBwcmV2ZW50IGEgcG9zc2libGUgc2VjdXJpdHkgYnJlYWNoLjwvY29kZT48L2xp Pg0KPGxpPkRvd25sb2FkIGxhdGVzdCBBcGFjaGVEUyBTdHVkaW8gYW5kIGluc3RhbGwgaXQN Cg0KPHVsPg0KPGxpPkNyZWF0ZSBhIG5ldyBjb25uZWN0aW9uIHNwZWNpZnlpbmc6DQoNCjx1 bD4NCjxsaT5OZXR3b3JrIHBhcmFtZXRlcnM6DQoNCjx1bD4NCjxsaT5Db25uZWN0aW9uIG5h bWU8L2xpPg0KPGxpPkhvc3RuYW1lPC9saT4NCjxsaT5Qb3J0OiAxMDM4OTwvbGk+DQo8bGk+ UHJlc3MgJnF1b3Q7Q2hlY2sgTmV0d29yayBQYXJhbWV0ZXJzJiM4MjE3OzwvbGk+DQo8L3Vs PjwvbGk+DQo8bGk+QXV0aGVudGljYXRpb24NCg0KPHVsPg0KPGxpPkJpbmQgZG4gb3UgdXNl ciA6IDxjb2RlPnVpZD1hZG1pbixvdT1zeXN0ZW08L2NvZGU+PC9saT4NCjxsaT5CaW5kIHBh c3N3b3JkIDogPGNvZGU+c2VjcmV0PC9jb2RlPjwvbGk+DQo8bGk+UHJlc3MgJiM4MjE2O0No ZWNrIEF1dGhldGljYXRpb24mIzgyMTc7PC9saT4NCjwvdWw+PC9saT4NCjxsaT5GaW5pc2g8 L2xpPg0KPC91bD48L2xpPg0KPGxpPkNoYW5nZSBhZG1pbnN0cmF0b3ImIzgyMTc7cyBwYXNz d29yZCBieSBlZGl0aW5nIDxjb2RlPm91PXN5c3RlbTwvY29kZT4tJmd0Ozxjb2RlPnVpZD1h ZG1pbjwvY29kZT4gYW5kIGNob29zaW5nIGFueXRoaW5nIGVsc2UgdGhhbiBwbGFpbiB0ZXh0 DQoNCjx1bD4NCjxsaT5TU0hBLCBmb3IgaW5zdGFuY2U8L2xpPg0KPC91bD48L2xpPg0KPGxp PkNsb3NlIHRoZSBjb25uZWN0aW9uLCByZWNvbmZpZ3VyZSB0aGUgY29ubmVjdGlvbiYjODIx NztzIHN0b3JlZCBwYXNzd29yZCBhbmQgcmVvcGVuIGl0PC9saT4NCjxsaT5DcmVhdGUgYSBu ZXcgcGFydGl0aW9uIGJ5IHNlbGVjdGluZyAmIzgyMTY7T3BlbiBDb25maWd1cmF0aW9uJiM4 MjE3OyBpbiB0aGUgY29udGV4dHVhbCBtZW51IChyaWdodCBjbGljaykgb2YgdGhlIG5ld2x5 IGNyZWF0ZWQgY29ubmVjdGlvbjoNCg0KPHVsPg0KPGxpPkFkdmFuY2VkIFBhcnRpdGlvbiBD b25maWd1cmF0aW9uJiM4MjMwOzwvbGk+DQo8bGk+QWRkLi4NCg0KPHVsPg0KPGxpPlNwZWNp ZnkgSUQgKGxpa2UgPGNvZGU+bXljb21wYW55PC9jb2RlPilhbmQgcGFydGl0aW9uIHN1ZmZp eCBsaWtlIDxjb2RlPmRjPW15Y29tcGFueTwvY29kZT4pPC9saT4NCjxsaT5TYXZlPC9saT4N CjwvdWw+PC9saT4NCjxsaT5SZXN0YXJ0IHRoZSBzZXJ2aWNlIDxjb2RlPnNlcnZpY2UgYXBh Y2hlZHMgcmVzdGFydDwvY29kZT48L2xpPg0KPC91bD48L2xpPg0KPGxpPlJlZnJlc2ggdGhl IGJyb3dzZXIgdHJlZSBieSBzZWxlY3RpbmcgUmVsb2FkIGZyb20gY29udGV4dHVhbCBtZW51 PC9saT4NCjxsaT5QZXJmb3JtIGFueSBkYXRhIGltcG9ydCBhcyByZXF1aXJlZCAoZnJvbSBM RElGIGZpbGVzIGZvciBpbnN0YW5jZSk8L2xpPg0KPC91bD48L2xpPg0KPC91bD4NCg0KPHA+ PHN0cm9uZz5JbXBvcnRhbnQgcmVtYXJrPC9zdHJvbmc+OiBQbGVhc2Ugbm90aWNlIHRoYXQg PGNvZGU+bGRhcHNlYXJjaDwvY29kZT4gb3IgdGhlIGRhdGEgZXhwb3J0IGZyb20gQXBhY2hl RFMgU3R1ZGlvIGRvIG5vdCBzYXZlIGluZm8gaW4gdGhlIHJpZ2h0IHNlcXVlbmNlIGZvciBp bXBvcnRpbmcgKGRlcGVuZGVudCBvYmplY3RzIGFmdGVyIHRoZSBvYmplY3RzIHRoZXkgZGVw ZW5kIG9uKTwvcD4NCg==

JPA Persist vs Merge

Once again, Persist versus Merge

There are tons of posts on internet on this topic; I will not duplicate already existing info but just emphasize a simple sample showing that not understanding the basics of JPA notions can lead to very unpleasant side effects.

To began with some (very) simplified assertions on above mentioned operations:

  • Persist will:
    • turn your newly created entity into a managed one and will issue an INSERT statement at transaction commit or flush operation;
    • For IDENTITY/SEQUENCE based PK generation the latest PK value is retrieved from the database and filled in the managed entity (which is the original one passed to the Persist operation!)
  • Merge will:

    • Create a managed copy of your entity; this copy will be returned by the merge call while your original entity will not become managed(!)
    • SELECT SQL statements will be issued in order to decide if and INSERT or UPDATE will be used prior the end of transaction/flush operation
    • The appropriate SQL statement will be then issued (INSERT/UPDATE)
    • For IDENTITY/SEQUENCE based PK generation the latest PK value is retrieved from the database and filled in the managed entity (not in the original one!)

Now, in conjunction with CascadeType.Persist/All applied on a @OneToMany relationship the disaster is eminent. Let me explain on a simple sample.

Suppose we have a Car entity (owned by a company) having as a property the current driver and we want to manage also the history of allocated drivers. We will be tempted to have something like this:

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "carId")
    private Collection<PersonHistory> personHistoryCollection;

Imagine the following scenario:

  • We change the driver for a Car; the back end action automatically does the following operations:
    • add a new driver to the personHistoryCollection
    • changes the previous current driver in personHistoryCollection last date he owned the car
    • changes the current driver reference in the Car instance
  • We call merge operation on the Car instance

At the moment of calling the merge we have the following situation:

  • Car instance modified
  • Previous PersonHistory ( member in personHistoryCollection) having last date modified
  • A new PersonHistory entity added to the collection

The Persist operation will update in the database the Car and, due to the CascadeType.All, will be subsequently applied also to all members of personHistoryCollection updating the previous PersonHistory entity and inserting a new PersonHistory. The INSERT will not update the PK of the newly created PersonHistory (the PK will remain NULL) due to the way Merge operation works on copies of original entity and thus leaving the collection in an inconsistent state.

Suppose you have chosen the @SessionScoped model for your backing bean and during the same Web session you add a new driver: the next merge operation sees that the previous PersonHistory has a NULL PK and performs an INSERT instead on an UPDATE. Nice, isn’t it?

So, be sure you have a at least a basic understanding of persist/merge JPA operations and be cautious using CascadeTpe attributes. Apart from the inconsistencies between in session image and database image the merge operation applied in conjunction with CascadeType.* will lead to a lot of futile SQLECT statements.

PGgxIGlkPSJvbmNlYWdhaW5wZXJzaXN0dmVyc3VzbWVyZ2UiPk9uY2UgYWdhaW4sIFBlcnNp c3QgdmVyc3VzIE1lcmdlPC9oMT4NCg0KPHA+VGhlcmUgYXJlIHRvbnMgb2YgcG9zdHMgb24g aW50ZXJuZXQgb24gdGhpcyB0b3BpYzsgSSB3aWxsIG5vdCBkdXBsaWNhdGUgYWxyZWFkeSBl eGlzdGluZyBpbmZvIGJ1dCBqdXN0IGVtcGhhc2l6ZSBhIHNpbXBsZSBzYW1wbGUgc2hvd2lu ZyB0aGF0IG5vdCB1bmRlcnN0YW5kaW5nIHRoZSBiYXNpY3Mgb2YgSlBBIG5vdGlvbnMgY2Fu IGxlYWQgdG8gdmVyeSB1bnBsZWFzYW50IHNpZGUgZWZmZWN0cy48L3A+DQoNCjxwPlRvIGJl Z2FuIHdpdGggc29tZSAodmVyeSkgc2ltcGxpZmllZCBhc3NlcnRpb25zIG9uIGFib3ZlIG1l bnRpb25lZCBvcGVyYXRpb25zOjwvcD4NCg0KPHVsPg0KPGxpPlBlcnNpc3Qgd2lsbDoNCg0K PHVsPg0KPGxpPnR1cm4geW91ciBuZXdseSBjcmVhdGVkIGVudGl0eSBpbnRvIGEgbWFuYWdl ZCBvbmUgYW5kIHdpbGwgaXNzdWUgYW4gSU5TRVJUIHN0YXRlbWVudCBhdCB0cmFuc2FjdGlv biBjb21taXQgb3IgZmx1c2ggb3BlcmF0aW9uOzwvbGk+DQo8bGk+Rm9yIElERU5USVRZL1NF UVVFTkNFIGJhc2VkIFBLIGdlbmVyYXRpb24gdGhlIGxhdGVzdCBQSyB2YWx1ZSBpcyByZXRy aWV2ZWQgZnJvbSB0aGUgZGF0YWJhc2UgYW5kIGZpbGxlZCBpbiB0aGUgbWFuYWdlZCBlbnRp dHkgKHdoaWNoIGlzIHRoZSBvcmlnaW5hbCBvbmUgcGFzc2VkIHRvIHRoZSBQZXJzaXN0IG9w ZXJhdGlvbiEpPC9saT4NCjwvdWw+PC9saT4NCjxsaT48cD5NZXJnZSB3aWxsOjwvcD4NCg0K PHVsPg0KPGxpPkNyZWF0ZSBhIG1hbmFnZWQgY29weSBvZiB5b3VyIGVudGl0eTsgdGhpcyBj b3B5IHdpbGwgYmUgcmV0dXJuZWQgYnkgdGhlIG1lcmdlIGNhbGwgd2hpbGUgeW91ciBvcmln aW5hbCBlbnRpdHkgd2lsbCBub3QgYmVjb21lIG1hbmFnZWQoISk8L2xpPg0KPGxpPlNFTEVD VCBTUUwgc3RhdGVtZW50cyB3aWxsIGJlIGlzc3VlZCBpbiBvcmRlciB0byBkZWNpZGUgaWYg YW5kIElOU0VSVCBvciBVUERBVEUgd2lsbCBiZSB1c2VkIHByaW9yIHRoZSBlbmQgb2YgdHJh bnNhY3Rpb24vZmx1c2ggb3BlcmF0aW9uPC9saT4NCjxsaT5UaGUgYXBwcm9wcmlhdGUgU1FM IHN0YXRlbWVudCB3aWxsIGJlIHRoZW4gaXNzdWVkIChJTlNFUlQvVVBEQVRFKTwvbGk+DQo8 bGk+Rm9yIElERU5USVRZL1NFUVVFTkNFIGJhc2VkIFBLIGdlbmVyYXRpb24gdGhlIGxhdGVz dCBQSyB2YWx1ZSBpcyByZXRyaWV2ZWQgZnJvbSB0aGUgZGF0YWJhc2UgYW5kIGZpbGxlZCBp biB0aGUgbWFuYWdlZCBlbnRpdHkgKG5vdCBpbiB0aGUgb3JpZ2luYWwgb25lISk8L2xpPg0K PC91bD48L2xpPg0KPC91bD4NCg0KPHA+Tm93LCBpbiBjb25qdW5jdGlvbiB3aXRoIENhc2Nh ZGVUeXBlLlBlcnNpc3QvQWxsIGFwcGxpZWQgb24gYSBAT25lVG9NYW55IHJlbGF0aW9uc2hp cCB0aGUgZGlzYXN0ZXIgaXMgZW1pbmVudC4gTGV0IG1lIGV4cGxhaW4gb24gYSBzaW1wbGUg c2FtcGxlLjwvcD4NCg0KPHA+U3VwcG9zZSB3ZSBoYXZlIGEgQ2FyIGVudGl0eSAob3duZWQg YnkgYSBjb21wYW55KSBoYXZpbmcgYXMgYSBwcm9wZXJ0eSB0aGUgY3VycmVudCBkcml2ZXIg YW5kIHdlIHdhbnQgdG8gbWFuYWdlIGFsc28gdGhlIGhpc3Rvcnkgb2YgYWxsb2NhdGVkIGRy aXZlcnMuIFdlIHdpbGwgYmUgdGVtcHRlZCB0byBoYXZlIHNvbWV0aGluZyBsaWtlIHRoaXM6 PC9wPg0KDQo8cHJlPjxjb2RlIGNsYXNzPSJqYXZhIj4gICAgQE9uZVRvTWFueShjYXNjYWRl ID0gQ2FzY2FkZVR5cGUuQUxMLCBtYXBwZWRCeSA9ICZxdW90O2NhcklkJnF1b3Q7KQ0KICAg IHByaXZhdGUgQ29sbGVjdGlvbiZsdDtQZXJzb25IaXN0b3J5Jmd0OyBwZXJzb25IaXN0b3J5 Q29sbGVjdGlvbjsNCjwvY29kZT48L3ByZT4NCg0KPHA+SW1hZ2luZSB0aGUgZm9sbG93aW5n IHNjZW5hcmlvOjwvcD4NCg0KPHVsPg0KPGxpPldlIGNoYW5nZSB0aGUgZHJpdmVyIGZvciBh IENhcjsgdGhlIGJhY2sgZW5kIGFjdGlvbiBhdXRvbWF0aWNhbGx5IGRvZXMgdGhlIGZvbGxv d2luZyBvcGVyYXRpb25zOg0KDQo8dWw+DQo8bGk+YWRkIGEgbmV3IGRyaXZlciB0byB0aGUg PGNvZGU+cGVyc29uSGlzdG9yeUNvbGxlY3Rpb248L2NvZGU+PC9saT4NCjxsaT5jaGFuZ2Vz IHRoZSBwcmV2aW91cyBjdXJyZW50IGRyaXZlciBpbiA8Y29kZT5wZXJzb25IaXN0b3J5Q29s bGVjdGlvbjwvY29kZT4gbGFzdCBkYXRlIGhlIG93bmVkIHRoZSBjYXI8L2xpPg0KPGxpPmNo YW5nZXMgdGhlIGN1cnJlbnQgZHJpdmVyIHJlZmVyZW5jZSBpbiB0aGUgQ2FyIGluc3RhbmNl PC9saT4NCjwvdWw+PC9saT4NCjxsaT5XZSBjYWxsIG1lcmdlIG9wZXJhdGlvbiBvbiB0aGUg Q2FyIGluc3RhbmNlPC9saT4NCjwvdWw+DQoNCjxwPkF0IHRoZSBtb21lbnQgb2YgY2FsbGlu ZyB0aGUgbWVyZ2Ugd2UgaGF2ZSB0aGUgZm9sbG93aW5nIHNpdHVhdGlvbjo8L3A+DQoNCjx1 bD4NCjxsaT5DYXIgaW5zdGFuY2UgbW9kaWZpZWQ8L2xpPg0KPGxpPlByZXZpb3VzIDxjb2Rl PlBlcnNvbkhpc3Rvcnk8L2NvZGU+ICggbWVtYmVyIGluIDxjb2RlPnBlcnNvbkhpc3RvcnlD b2xsZWN0aW9uPC9jb2RlPikgaGF2aW5nIGxhc3QgZGF0ZSBtb2RpZmllZDwvbGk+DQo8bGk+ QSBuZXcgPGNvZGU+UGVyc29uSGlzdG9yeTwvY29kZT4gZW50aXR5IGFkZGVkIHRvIHRoZSBj b2xsZWN0aW9uPC9saT4NCjwvdWw+DQoNCjxwPlRoZSBQZXJzaXN0IG9wZXJhdGlvbiB3aWxs IHVwZGF0ZSBpbiB0aGUgZGF0YWJhc2UgdGhlIDxjb2RlPkNhcjwvY29kZT4gYW5kLCBkdWUg dG8gdGhlIENhc2NhZGVUeXBlLkFsbCwgd2lsbCBiZSBzdWJzZXF1ZW50bHkgYXBwbGllZCBh bHNvIHRvIGFsbCBtZW1iZXJzIG9mIDxjb2RlPnBlcnNvbkhpc3RvcnlDb2xsZWN0aW9uPC9j b2RlPiB1cGRhdGluZyB0aGUgcHJldmlvdXMgPGNvZGU+UGVyc29uSGlzdG9yeTwvY29kZT4g ZW50aXR5IGFuZCBpbnNlcnRpbmcgYSBuZXcgPGNvZGU+UGVyc29uSGlzdG9yeTwvY29kZT4u IFRoZSBJTlNFUlQgd2lsbCBub3QgdXBkYXRlIHRoZSBQSyBvZiB0aGUgbmV3bHkgY3JlYXRl ZCA8Y29kZT5QZXJzb25IaXN0b3J5PC9jb2RlPiAodGhlIFBLIHdpbGwgcmVtYWluIE5VTEwp IGR1ZSB0byB0aGUgd2F5IE1lcmdlIG9wZXJhdGlvbiB3b3JrcyBvbiBjb3BpZXMgb2Ygb3Jp Z2luYWwgZW50aXR5IGFuZCB0aHVzIGxlYXZpbmcgdGhlIGNvbGxlY3Rpb24gaW4gYW4gaW5j b25zaXN0ZW50IHN0YXRlLjwvcD4NCg0KPHA+U3VwcG9zZSB5b3UgaGF2ZSBjaG9zZW4gdGhl IEBTZXNzaW9uU2NvcGVkIG1vZGVsIGZvciB5b3VyIGJhY2tpbmcgYmVhbiBhbmQgZHVyaW5n IHRoZSBzYW1lIFdlYiBzZXNzaW9uIHlvdSBhZGQgYSBuZXcgZHJpdmVyOiB0aGUgbmV4dCBt ZXJnZSBvcGVyYXRpb24gc2VlcyB0aGF0IHRoZSBwcmV2aW91cyA8Y29kZT5QZXJzb25IaXN0 b3J5PC9jb2RlPiBoYXMgYSBOVUxMIFBLIGFuZCBwZXJmb3JtcyBhbiBJTlNFUlQgaW5zdGVh ZCBvbiBhbiBVUERBVEUuIE5pY2UsIGlzbiYjODIxNzt0IGl0PzwvcD4NCg0KPHA+U28sIGJl IHN1cmUgeW91IGhhdmUgYSBhdCBsZWFzdCBhIGJhc2ljIHVuZGVyc3RhbmRpbmcgb2YgcGVy c2lzdC9tZXJnZSBKUEEgb3BlcmF0aW9ucyBhbmQgYmUgY2F1dGlvdXMgdXNpbmcgQ2FzY2Fk ZVRwZSBhdHRyaWJ1dGVzLiBBcGFydCBmcm9tIHRoZSBpbmNvbnNpc3RlbmNpZXMgYmV0d2Vl biBpbiBzZXNzaW9uIGltYWdlIGFuZCBkYXRhYmFzZSBpbWFnZSB0aGUgbWVyZ2Ugb3BlcmF0 aW9uIGFwcGxpZWQgaW4gY29uanVuY3Rpb24gd2l0aCBDYXNjYWRlVHlwZS4qIHdpbGwgbGVh ZCB0byBhIGxvdCBvZiBmdXRpbGUgU1FMRUNUIHN0YXRlbWVudHMuPC9wPg0K

Log JPA Queries

Log JPA Queries in WildFly (10.1)

Do the following changes in server configuration file (like standalone.xml); restart the server after wise.

Change the console handler to look like:

            <console-handler name="CONSOLE">
                <level name="TRACE"/>
                <formatter>
                    <named-formatter name="COLOR-PATTERN"/>
                </formatter>
            </console-handler>

Add a logger for org.eclipse.persistence.sql:

            <logger category="org.eclipse.persistence.sql">
                <level name="DEBUG"/>
            </logger>
PGgxIGlkPSJsb2dqcGFxdWVyaWVzaW53aWxkZmx5MTAuMSI+TG9nIEpQQSBRdWVyaWVzIGlu IFdpbGRGbHkgKDEwLjEpPC9oMT4NCg0KPHA+RG8gdGhlIGZvbGxvd2luZyBjaGFuZ2VzIGlu IHNlcnZlciBjb25maWd1cmF0aW9uIGZpbGUgKGxpa2Ugc3RhbmRhbG9uZS54bWwpOyByZXN0 YXJ0IHRoZSBzZXJ2ZXIgYWZ0ZXIgd2lzZS48L3A+DQoNCjxwPkNoYW5nZSB0aGUgY29uc29s ZSBoYW5kbGVyIHRvIGxvb2sgbGlrZTo8L3A+DQoNCjxwcmU+PGNvZGUgY2xhc3M9InhtbCI+ ICAgICAgICAgICAgJmx0O2NvbnNvbGUtaGFuZGxlciBuYW1lPSZxdW90O0NPTlNPTEUmcXVv dDsmZ3Q7DQogICAgICAgICAgICAgICAgJmx0O2xldmVsIG5hbWU9JnF1b3Q7VFJBQ0UmcXVv dDsvJmd0Ow0KICAgICAgICAgICAgICAgICZsdDtmb3JtYXR0ZXImZ3Q7DQogICAgICAgICAg ICAgICAgICAgICZsdDtuYW1lZC1mb3JtYXR0ZXIgbmFtZT0mcXVvdDtDT0xPUi1QQVRURVJO JnF1b3Q7LyZndDsNCiAgICAgICAgICAgICAgICAmbHQ7L2Zvcm1hdHRlciZndDsNCiAgICAg ICAgICAgICZsdDsvY29uc29sZS1oYW5kbGVyJmd0Ow0KDQo8L2NvZGU+PC9wcmU+DQoNCjxw PkFkZCBhIGxvZ2dlciBmb3IgPGNvZGU+b3JnLmVjbGlwc2UucGVyc2lzdGVuY2Uuc3FsPC9j b2RlPjo8L3A+DQoNCjxwcmU+PGNvZGUgY2xhc3M9InhtbCI+ICAgICAgICAgICAgJmx0O2xv Z2dlciBjYXRlZ29yeT0mcXVvdDtvcmcuZWNsaXBzZS5wZXJzaXN0ZW5jZS5zcWwmcXVvdDsm Z3Q7DQogICAgICAgICAgICAgICAgJmx0O2xldmVsIG5hbWU9JnF1b3Q7REVCVUcmcXVvdDsv Jmd0Ow0KICAgICAgICAgICAgJmx0Oy9sb2dnZXImZ3Q7DQo8L2NvZGU+PC9wcmU+DQo=

Run WildFly 10.1 as a Service on Windows

  • Copy docs\contrib\scripts\service directory to bin
  • Run cmd as an adminsitrator and go to bin\scripts
  • Run service.bat install /startup
  • Start the service

Before running the service.bat replace its contents with the following (or download the latest version from gitHub https://github.com/wildfly/wildfly-core/blob/master/core-feature-pack/src/main/resources/content/docs/contrib/scripts/service/service.bat). The problem with 10.1 release is that instead of

set DESCRIPTION=WildFly Application Server

we have

set DESCRIPTION="WildFly Application Server" which leads to double quoting in prunsrv parameters

@echo off
REM -------------------------------------------------------------------------
REM  WildFly Service Script for Windows
REM    It has to reside in %JBOSS_HOME%\bin
REM    It is expecting that prunsrv.exe reside in:
REM      %JBOSS_HOME%\bin\service\
REM Easiest way to make it work is to copy whole "service" directory to %JBOSS_HOME%\bin
REM
REM  v9 2016-02-16 customize for WildFly, fix working on paths with spaces (Tomaz Cerar)
REM  v8 2016-01-20 customize for EAP 7 (Petr Sakar)
REM  v7 2014-07-09 added /logpath /startup /config /hostconfig /base /debug
REM                      simplified/corrected use of quotes
REM
REM  v6 was shipped with EAP 6.2.0 and supports all previous versions of 6.x as well.
REM  v6 2013-08-21 added /name /desc
REM                added /serviceuser /servicepass
REM                extended directory checking for versions and locations
REM                extended checking on option usage
REM  v5 2013-06-10 adapted for EAP 6.1.0
REM  v4 2012-10-03 Small changes to properly handles spaces in LogPath, StartPath,
REM                and StopPath (George Rypysc)
REM  v3 2012-09-14 fixed service log path
REM                cmd line options for controller,domain host, loglevel,
REM        username,password
REM  v2 2012-09-05 NOPAUSE support
REM  v1 2012-08-20 initial edit
REM
REM Author: Tom Fonteyne (unless noted above)
REM ========================================================
setlocal EnableExtensions EnableDelayedExpansion

set DEBUG=0
if "%DEBUG%" == "1" (
    echo "Debug info enabled"
    echo on
)

set "DIRNAME=%~dp0%"
if "%DEBUG%" == "1" (
    echo DIRNAME "%DIRNAME%x"
)

if exist "%DIRNAME%..\jboss-modules.jar" (
  REM we are in JBOSS_HOME/bin
  set "WE=%DIRNAME%..\"
  goto :WE_FOUND
) else if exist "%DIRNAME%..\..\jboss-modules.jar" (
  REM we are in bin\service in a WildFly installation
  set "WE=%DIRNAME%..\..\"
  goto :WE_FOUND
) else if exist "%DIRNAME%..\..\..\jboss-modules.jar" (
  REM we are in sbin in a 6.0.x installation
  set "WE=%DIRNAME%..\..\..\"
  goto :WE_FOUND
) else (
  REM we should be in sbin in 6.1 and up
  set "WE=%DIRNAME%..\..\..\..\..\..\"
)

if "%DEBUG%" == "1" (
    echo WE was not found, using "%WE%"
)

:WE_FOUND
if "%DEBUG%" == "1" (
    echo WE "%WE%"
)
pushd "%WE%"
set "RESOLVED_JBOSS_HOME=%CD%"
popd
set WE=
set DIRNAME=
if "x%JBOSS_HOME%" == "x" (
  set "JBOSS_HOME=%RESOLVED_JBOSS_HOME%"
)

pushd "%JBOSS_HOME%"
set "SANITIZED_JBOSS_HOME=%CD%"
popd

if "%DEBUG%" == "1" (
    echo SANITIZED_JBOSS_HOME="%SANITIZED_JBOSS_HOME%"
    echo RESOLVED_JBOSS_HOME="%RESOLVED_JBOSS_HOME%"
    echo JBOSS_HOME="%JBOSS_HOME%"
)

if not "%RESOLVED_JBOSS_HOME%x" == "%SANITIZED_JBOSS_HOME%x" (
    echo WARNING JBOSS_HOME may be pointing to a different installation - unpredictable results may occur.
    goto cmdEnd
)

rem Find jboss-modules.jar to check JBOSS_HOME
if not exist "%JBOSS_HOME%\jboss-modules.jar" (
  echo Could not locate "%JBOSS_HOME%\jboss-modules.jar"
  goto cmdEnd
)

set PRUNSRV=
if "%PROCESSOR_ARCHITECTURE%"=="AMD64" (
  echo Using the X86-64bit version of prunsrv
  set PRUNSRV="%JBOSS_HOME%\bin\service\amd64\wildfly-service"
) else (
  echo Using the X86-32bit version of prunsrv
  set PRUNSRV="%JBOSS_HOME%\bin\service\wildfly-service"
)

if "%DEBUG%" == "1" (
    echo PRUNSRV %PRUNSRV%
)

echo(

rem defaults
set SHORTNAME=Wildfly
set DISPLAYNAME=WildFly
rem NO quotes around the description here !
set DESCRIPTION=WildFly Application Server
set CONTROLLER=localhost:9990
set DC_HOST=master
set IS_DOMAIN=false
set LOGLEVEL=INFO
set LOGPATH=
set JBOSSUSER=
set JBOSSPASS=
set SERVICE_USER=
set SERVICE_PASS=
set STARTUP_MODE=manual
set ISDEBUG=
set CONFIG=
set HOSTCONFIG=host.xml
set BASE=

set COMMAND=%1
shift
if /I "%COMMAND%" == "install"   goto cmdInstall
if /I "%COMMAND%" == "uninstall" goto cmdUninstall
if /I "%COMMAND%" == "start"     goto cmdStart
if /I "%COMMAND%" == "stop"      goto cmdStop
if /I "%COMMAND%" == "restart"   goto cmdRestart

echo ERROR: invalid command

:cmdUsage
echo WildFly Service Script for Windows
echo Usage:
echo(
echo   service install ^<options^>  , where the options are:
echo(
echo     /startup                  : Set the service to auto start
echo                                 Not specifying sets the service to manual
echo(
echo     /jbossuser ^<username^>     : JBoss username to use for the shutdown command.
echo     /jbosspass ^<password^>     : Password for /jbossuser
echo(
echo     /controller ^<host:port^>   : The host:port of the management interface.
echo                                 default: %CONTROLLER%
echo(
echo     /host [^<domainhost^>]      : Indicates that domain mode is to be used with an
echo                                 optional domain controller name.
echo                                 default: %DC_HOST%
echo                                 Not specifying /host will install JBoss in
echo                                 standalone mode.
echo(
echo Options to use when multiple services or different accounts are needed:
echo(
echo     /name ^<servicename^>       : The name of the service
echo(
echo                                 default: %SHORTNAME%
echo     /desc ^<description^>       : The description of the service, use double
echo                                 quotes to allow spaces.
echo                                 Maximum 1024 characters.
echo                                 default: %DESCRIPTION%
echo(
echo     /serviceuser ^<username^>   : Specifies the name of the account under which
echo                                 the service should run.
echo                                 Use an account name in the form of
echo                                 DomainName\UserName
echo                                 default: not used, the service runs as
echo                                 Local System Account.
echo     /servicepass ^<password^>   : password for /serviceuser
echo(
echo Advanced options:
echo(
echo     /config ^<xmlfile^>         : The server-config to use
echo                                 default: standalone.xml / domain.xml
echo     /hostconfig ^<xmlfile^>     : domain mode only, the host config to use
echo                                 default: host.xml
echo(
echo     /base ^<directory^>         : The base directory for server/domain content
echo                                 Must be specified as a fully qualified path
echo                                 default: %JBOSS_HOME%\standalone or
echo                                          %JBOSS_HOME%\domain
echo(
echo     /loglevel ^<level^>         : The log level for the service:  Error, Info,
echo                                 Warn or Debug ^(Case insensitive^)
echo                                 default: %LOGLEVEL%
echo     /logpath ^<path^>           : Path of the log
echo                                 default depends on domain or standalone mode
echo                                 /base applies when /logpath is not set.
echo                                   %JBOSS_HOME%\domain\log
echo                                   %JBOSS_HOME%\standalone\log
echo(
echo     /debug                    : run the service install in debug mode
echo(
echo Other commands:
echo(
echo   service uninstall [/name ^<servicename^>]
echo   service start [/name ^<servicename^>]
echo   service stop [/name ^<servicename^>]
echo   service restart [/name ^<servicename^>]
echo(
echo     /name  ^<servicename^>      : Name of the service: should not contain spaces
echo                                 default: %SHORTNAME%
echo(
goto endBatch

:cmdInstall

:LoopArgs
if "%~1" == "" goto doInstall

if /I "%~1"== "/debug" (
  set ISDEBUG=true
  shift
  goto LoopArgs
)
if /I "%~1"== "/startup" (
  set STARTUP_MODE=auto
  shift
  goto LoopArgs
)
if /I "%~1"== "/config" (
  set CONFIG=
  if not "%~2"=="" (
    set T=%~2
    if not "!T:~0,1!"=="/" (
      set CONFIG=%~2
    )
  )
  if "!CONFIG!" == "" (
    echo ERROR: You need to specify a config name
    goto endBatch
  )
  shift
  shift
  goto LoopArgs
)
if /I "%~1"== "/hostconfig" (
  set HOSTCONFIG=
  if not "%~2"=="" (
    set T=%~2
    if not "!T:~0,1!"=="/" (
      set HOSTCONFIG=%~2
    )
  )
  if "!HOSTCONFIG!" == "" (
    echo ERROR: You need to specify a host-config name
    goto endBatch
  )
  shift
  shift
  goto LoopArgs
)
if /I "%~1"== "/base" (
  set BASE=
  if not "%~2"=="" (
    set T=%~2
    if not "!T:~0,1!"=="/" (
      set BASE=%~2
    )
  )
  if "!BASE!" == "" (
    echo ERROR: You need to specify a base directory name
    goto endBatch
  )
  shift
  shift
  goto LoopArgs
)
if /I "%~1"== "/controller" (
  set CONTROLLER=
  if not "%~2"=="" (
    set T=%~2
    if not "!T:~0,1!"=="/" (
      set CONTROLLER=%~2
    )
  )
  if "!CONTROLLER!" == "" (
    echo ERROR: The management interface should be specified in the format host:port, example:  127.0.0.1:9999
    goto endBatch
  )
  shift
  shift
  goto LoopArgs
)
if /I "%~1"== "/name" (
  set SHORTNAME=
  if not "%~2"=="" (
    set T=%~2
    if not "!T:~0,1!"=="/" (
      set SHORTNAME=%~2
      set DISPLAYNAME=%~2
    )
  )
  if "!SHORTNAME!" == "" (
    echo ERROR: You need to specify a service name
    goto endBatch
  )
  shift
  shift
  goto LoopArgs
)
if /I "%~1"== "/desc" (
  set DESCRIPTION=
  if not "%~2"=="" (
    set T=%~2
    if not "!T:~0,1!"=="/" (
      set DESCRIPTION=%~2
    )
  )
  if "!DESCRIPTION!" == "" (
    echo ERROR: You need to specify a description, maximum of 1024 characters
    goto endBatch
  )
  shift
  shift
  goto LoopArgs
)
if /I "%~1"== "/jbossuser" (
  set JBOSSUSER=
  if not "%~2"=="" (
    set T=%~2
    if not "!T:~0,1!"=="/" (
      set JBOSSUSER=%~2
    )
  )
  if "!JBOSSUSER!" == "" (
    echo ERROR: You need to specify a username
    goto endBatch
  )
  shift
  shift
  goto LoopArgs
)
if /I "%~1"== "/jbosspass" (
  set JBOSSPASS=
  if not "%~2"=="" (
    set T=%~2
    if not "!T:~0,1!"=="/" (
      set JBOSSPASS=%~2
    )
  )
  if "!JBOSSPASS!" == "" (
    echo ERROR: You need to specify a password for /jbosspass
    goto endBatch
  )
  shift
  shift
  goto LoopArgs
)
if /I "%~1"== "/serviceuser" (
  set SERVICE_USER=
  if not "%~2"=="" (
    set T=%~2
    if not "!T:~0,1!"=="/" (
      set SERVICE_USER=%~2
    )
  )
  if "!SERVICE_USER!" == "" (
    echo ERROR: You need to specify a username in the format DOMAIN\USER, or .\USER for the local domain
    goto endBatch
  )
  shift
  shift
  goto LoopArgs
)
if /I "%~1"== "/servicepass" (
  set SERVICE_PASS=
  if not "%~2"=="" (
    set T=%~2
    if not "!T:~0,1!"=="/" (
      set SERVICE_PASS=%~2
    )
  )
  if "!SERVICE_PASS!" == "" (
    echo ERROR: You need to specify a password for /servicepass
    goto endBatch
  )
  shift
  shift
  goto LoopArgs
)
rem the hostname is optional
if /I "%~1"== "/host" (
  set IS_DOMAIN=true
  if not "%~2"=="" (
    set T=%~2
    if not "!T:~0,1!"=="/" (
      set DC_HOST=%~2
      shift
    )
  )
  shift
  goto LoopArgs
)
if /I "%~1"== "/loglevel" (
  if /I not "%~2"=="Error" if /I not "%~2"=="Info" if /I not "%~2"=="Warn" if /I not "%~2"=="Debug" (
    echo ERROR: /loglevel must be set to Error, Info, Warn or Debug ^(Case insensitive^)
    goto endBatch
  )
  set LOGLEVEL=%~2
  shift
  shift
  goto LoopArgs
)
if /I "%~1"== "/logpath" (
  set LOGPATH=
  if not "%~2"=="" (
    set T=%~2
    if not "!T:~0,1!"=="/" (
      set LOGPATH=%~2
    )
  )
  if "!LOGPATH!" == "" (
    echo ERROR: You need to specify a path for the service log
    goto endBatch
  )
  shift
  shift
  goto LoopArgs
)
echo ERROR: Unrecognised option: %1
echo(
goto cmdUsage

:doInstall
set CREDENTIALS=
if not "%JBOSSUSER%" == "" (
  if "%JBOSSPASS%" == "" (
    echo When specifying a user, you need to specify the password
    goto endBatch
  )
  set CREDENTIALS=--user=%JBOSSUSER% --password=%JBOSSPASS%
)

set RUNAS=
if not "%SERVICE_USER%" == "" (
  if "%SERVICE_PASS%" == "" (
    echo When specifying a user, you need to specify the password
    goto endBatch
  )
  set RUNAS=--ServiceUser=%SERVICE_USER% --ServicePassword=%SERVICE_PASS%
)

if "%STDOUT%"=="" set STDOUT=auto
if "%STDERR%"=="" set STDERR=auto

if "%START_PATH%"=="" set START_PATH="%JBOSS_HOME%\bin"
if "%STOP_PATH%"=="" set STOP_PATH="%JBOSS_HOME%\bin"

if "%STOP_SCRIPT%"=="" set STOP_SCRIPT=jboss-cli.bat

if /I "%IS_DOMAIN%" == "true" (
  if "%BASE%"=="" set BASE="%JBOSS_HOME%\domain"
  if "%CONFIG%"=="" set CONFIG=domain.xml
  if "%START_SCRIPT%"=="" set START_SCRIPT=domain.bat
  set STARTPARAM="/c#set#NOPAUSE=Y#&&#!START_SCRIPT!#-Djboss.domain.base.dir=!BASE!#--domain-config=!CONFIG!#--host-config=!HOSTCONFIG!"
  set STOPPARAM="/c %STOP_SCRIPT% --controller=%CONTROLLER% --connect %CREDENTIALS% --command=/host=!DC_HOST!:shutdown"
) else (
  if "%BASE%"=="" set "BASE=%JBOSS_HOME%\standalone"
  if "%CONFIG%"=="" set CONFIG=standalone.xml
  if "%START_SCRIPT%"=="" set START_SCRIPT=standalone.bat
  set STARTPARAM="/c#set#NOPAUSE=Y#&&#!START_SCRIPT!#-Djboss.server.base.dir=!BASE!#--server-config=!CONFIG!"
  set STOPPARAM="/c !STOP_SCRIPT! --controller=%CONTROLLER% --connect %CREDENTIALS% --command=:shutdown"
)

if "%LOGPATH%"=="" set LOGPATH="!BASE!\log"

if not exist "%BASE%" (
  echo The base directory does not exist: "%BASE%"
  goto endBatch
)

if not exist "%BASE%\configuration\%CONFIG%" (
  echo The configuration does not exist: "%BASE%\configuration\%CONFIG%"
  goto endBatch
)

if /I "%ISDEBUG%" == "true" (
  echo JBOSS_HOME="%JBOSS_HOME%"
  echo RUNAS=%RUNAS%
  echo SHORTNAME="%SHORTNAME%"
  echo DESCRIPTION="%DESCRIPTION%"
  echo STARTPARAM=%STARTPARAM%
  echo STOPPARAM=%STOPPARAM%
  echo LOGLEVEL=%LOGLEVEL%
  echo LOGPATH=%LOGPATH%
  echo CREDENTIALS=%CREDENTIALS%
  echo BASE="%BASE%"
  echo CONFIG="%CONFIG%"
  echo START_SCRIPT=%START_SCRIPT%
  echo START_PATH=%START_PATH%
  echo STOP_SCRIPT=%STOP_SCRIPT%
  echo STOP_PATH=%STOP_PATH%
  echo STDOUT="%STDOUT%"
  echo STDERR="%STDERR%"
)
if /I "%ISDEBUG%" == "true" (
  @echo on
)

@rem quotes around the "%DESCRIPTION%" but nowhere else
echo %PRUNSRV% install %SHORTNAME% %RUNAS% --DisplayName=%DISPLAYNAME% --Description="%DESCRIPTION%" --LogLevel=%LOGLEVEL% --LogPath=%LOGPATH% --LogPrefix=service --StdOutput=%STDOUT% --StdError=%STDERR% --StartMode=exe --Startup=%STARTUP_MODE% --StartImage=cmd.exe --StartPath=%START_PATH% ++StartParams=%STARTPARAM% --StopMode=exe --StopImage=cmd.exe --StopPath=%STOP_PATH%  ++StopParams=%STOPPARAM%

%PRUNSRV% install %SHORTNAME% %RUNAS% --DisplayName=%DISPLAYNAME% --Description="%DESCRIPTION%" --LogLevel=%LOGLEVEL% --LogPath=%LOGPATH% --LogPrefix=service --StdOutput=%STDOUT% --StdError=%STDERR% --StartMode=exe --Startup=%STARTUP_MODE% --StartImage=cmd.exe --StartPath=%START_PATH% ++StartParams=%STARTPARAM% --StopMode=exe --StopImage=cmd.exe --StopPath=%STOP_PATH%  ++StopParams=%STOPPARAM%
@rem %PRUNSRV% install "%SHORTNAME%" "%RUNAS%" --DisplayName="%DISPLAYNAME%" --Description="%DESCRIPTION%" --LogLevel="%LOGLEVEL%" --LogPath="%LOGPATH%" --LogPrefix=service --StdOutput="%STDOUT%" --StdError="%STDERR%" --StartMode=exe --Startup="%STARTUP_MODE%" --StartImage=cmd.exe --StartPath="%START_PATH%" ++StartParams="%STARTPARAM%" --StopMode=exe --StopImage=cmd.exe --StopPath="%STOP_PATH%"  ++StopParams="%STOPPARAM%"

@if /I "%ISDEBUG%" == "true" (
  @echo off
)

if errorlevel 8 (
  echo ERROR: The service %SHORTNAME% already exists
  goto endBatch
)
if errorlevel 0 (
  echo Service %SHORTNAME% installed
  goto endBatch
)
goto cmdEnd


REM the other commands take a /name parameter - if there is no ^<servicename^> passed as second parameter,
REM we silently ignore this and use the default SHORTNAME

:cmdUninstall
if /I "%~1"=="/name" (
  if not "%~2"=="" (
    set SHORTNAME="%~2"
  )
)
%PRUNSRV% stop %SHORTNAME%
if errorlevel 0 (
  %PRUNSRV% delete %SHORTNAME%
  if errorlevel 0 (
    echo Service %SHORTNAME% uninstalled
  )
) else (
  echo Unable to stop the service %SHORTNAME%
)
goto cmdEnd

:cmdStart
if /I "%~1"=="/name" (
  if not "%~2"=="" (
    set SHORTNAME="%~2"
  )
)
%PRUNSRV% start %SHORTNAME%
echo Service %SHORTNAME% starting...
goto cmdEnd

:cmdStop
if /I "%~1"=="/name" (
  if not "%~2"=="" (
    set SHORTNAME="%~2"
  )
)
%PRUNSRV% stop %SHORTNAME%
echo Service %SHORTNAME% stopping...
goto cmdEnd

:cmdRestart
if /I "%~1"=="/name" (
  if not "%~2"=="" (
    set SHORTNAME="%~2"
  )
)
%PRUNSRV% stop %SHORTNAME%
echo Service %SHORTNAME% stopping...
if "%errorlevel%" == "0" (
  %PRUNSRV% start %SHORTNAME%
  echo Service %SHORTNAME% starting...
) else (
  echo Unable to stop the service %SHORTNAME%
)
goto cmdEnd


:cmdEnd
REM if there is a need to add other error messages, make sure to list higher numbers first !
if errorlevel 2 (
  echo ERROR: Failed to load service %SHORTNAME% configuration
  goto endBatch
)
if errorlevel 0 (
  goto endBatch
)
echo "Unforseen error=%errorlevel%"

rem nothing below, exit
:endBatch
PHVsPg0KPGxpPkNvcHkgZG9jc1xjb250cmliXHNjcmlwdHNcc2VydmljZSBkaXJlY3Rvcnkg dG8gYmluPC9saT4NCjxsaT5SdW4gY21kIGFzIGFuIGFkbWluc2l0cmF0b3IgYW5kIGdvIHRv IGJpblxzY3JpcHRzPC9saT4NCjxsaT5SdW4gPGNvZGU+c2VydmljZS5iYXQgaW5zdGFsbCAv c3RhcnR1cDwvY29kZT48L2xpPg0KPGxpPlN0YXJ0IHRoZSBzZXJ2aWNlPC9saT4NCjwvdWw+ DQoNCjxwPkJlZm9yZSBydW5uaW5nIHRoZSBzZXJ2aWNlLmJhdCByZXBsYWNlIGl0cyBjb250 ZW50cyB3aXRoIHRoZSBmb2xsb3dpbmcgKG9yIGRvd25sb2FkIHRoZSBsYXRlc3QgdmVyc2lv biBmcm9tIGdpdEh1YiA8YSBocmVmPSJodHRwczovL2dpdGh1Yi5jb20vd2lsZGZseS93aWxk Zmx5LWNvcmUvYmxvYi9tYXN0ZXIvY29yZS1mZWF0dXJlLXBhY2svc3JjL21haW4vcmVzb3Vy Y2VzL2NvbnRlbnQvZG9jcy9jb250cmliL3NjcmlwdHMvc2VydmljZS9zZXJ2aWNlLmJhdCI+ aHR0cHM6Ly9naXRodWIuY29tL3dpbGRmbHkvd2lsZGZseS1jb3JlL2Jsb2IvbWFzdGVyL2Nv cmUtZmVhdHVyZS1wYWNrL3NyYy9tYWluL3Jlc291cmNlcy9jb250ZW50L2RvY3MvY29udHJp Yi9zY3JpcHRzL3NlcnZpY2Uvc2VydmljZS5iYXQ8L2E+KS4NClRoZSBwcm9ibGVtIHdpdGgg MTAuMSByZWxlYXNlIGlzIHRoYXQgaW5zdGVhZCBvZjwvcD4NCg0KPHA+PGNvZGU+c2V0IERF U0NSSVBUSU9OPVdpbGRGbHkgQXBwbGljYXRpb24gU2VydmVyPC9jb2RlPjwvcD4NCg0KPHA+ d2UgaGF2ZTwvcD4NCg0KPHA+PGNvZGU+c2V0IERFU0NSSVBUSU9OPSZxdW90O1dpbGRGbHkg QXBwbGljYXRpb24gU2VydmVyJnF1b3Q7PC9jb2RlPiB3aGljaCBsZWFkcyB0byBkb3VibGUg cXVvdGluZyBpbiBwcnVuc3J2IHBhcmFtZXRlcnM8L3A+DQoNCjxwcmU+PGNvZGU+QGVjaG8g b2ZmDQpSRU0gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KUkVNICBXaWxkRmx5IFNlcnZpY2UgU2Ny aXB0IGZvciBXaW5kb3dzDQpSRU0gICAgSXQgaGFzIHRvIHJlc2lkZSBpbiAlSkJPU1NfSE9N RSVcYmluDQpSRU0gICAgSXQgaXMgZXhwZWN0aW5nIHRoYXQgcHJ1bnNydi5leGUgcmVzaWRl IGluOg0KUkVNICAgICAgJUpCT1NTX0hPTUUlXGJpblxzZXJ2aWNlXA0KUkVNIEVhc2llc3Qg d2F5IHRvIG1ha2UgaXQgd29yayBpcyB0byBjb3B5IHdob2xlICZxdW90O3NlcnZpY2UmcXVv dDsgZGlyZWN0b3J5IHRvICVKQk9TU19IT01FJVxiaW4NClJFTQ0KUkVNICB2OSAyMDE2LTAy LTE2IGN1c3RvbWl6ZSBmb3IgV2lsZEZseSwgZml4IHdvcmtpbmcgb24gcGF0aHMgd2l0aCBz cGFjZXMgKFRvbWF6IENlcmFyKQ0KUkVNICB2OCAyMDE2LTAxLTIwIGN1c3RvbWl6ZSBmb3Ig RUFQIDcgKFBldHIgU2FrYXIpDQpSRU0gIHY3IDIwMTQtMDctMDkgYWRkZWQgL2xvZ3BhdGgg L3N0YXJ0dXAgL2NvbmZpZyAvaG9zdGNvbmZpZyAvYmFzZSAvZGVidWcNClJFTSAgICAgICAg ICAgICAgICAgICAgICBzaW1wbGlmaWVkL2NvcnJlY3RlZCB1c2Ugb2YgcXVvdGVzDQpSRU0N ClJFTSAgdjYgd2FzIHNoaXBwZWQgd2l0aCBFQVAgNi4yLjAgYW5kIHN1cHBvcnRzIGFsbCBw cmV2aW91cyB2ZXJzaW9ucyBvZiA2LnggYXMgd2VsbC4NClJFTSAgdjYgMjAxMy0wOC0yMSBh ZGRlZCAvbmFtZSAvZGVzYw0KUkVNICAgICAgICAgICAgICAgIGFkZGVkIC9zZXJ2aWNldXNl ciAvc2VydmljZXBhc3MNClJFTSAgICAgICAgICAgICAgICBleHRlbmRlZCBkaXJlY3Rvcnkg Y2hlY2tpbmcgZm9yIHZlcnNpb25zIGFuZCBsb2NhdGlvbnMNClJFTSAgICAgICAgICAgICAg ICBleHRlbmRlZCBjaGVja2luZyBvbiBvcHRpb24gdXNhZ2UNClJFTSAgdjUgMjAxMy0wNi0x MCBhZGFwdGVkIGZvciBFQVAgNi4xLjANClJFTSAgdjQgMjAxMi0xMC0wMyBTbWFsbCBjaGFu Z2VzIHRvIHByb3Blcmx5IGhhbmRsZXMgc3BhY2VzIGluIExvZ1BhdGgsIFN0YXJ0UGF0aCwN ClJFTSAgICAgICAgICAgICAgICBhbmQgU3RvcFBhdGggKEdlb3JnZSBSeXB5c2MpDQpSRU0g IHYzIDIwMTItMDktMTQgZml4ZWQgc2VydmljZSBsb2cgcGF0aA0KUkVNICAgICAgICAgICAg ICAgIGNtZCBsaW5lIG9wdGlvbnMgZm9yIGNvbnRyb2xsZXIsZG9tYWluIGhvc3QsIGxvZ2xl dmVsLA0KUkVNICAgICAgICB1c2VybmFtZSxwYXNzd29yZA0KUkVNICB2MiAyMDEyLTA5LTA1 IE5PUEFVU0Ugc3VwcG9ydA0KUkVNICB2MSAyMDEyLTA4LTIwIGluaXRpYWwgZWRpdA0KUkVN DQpSRU0gQXV0aG9yOiBUb20gRm9udGV5bmUgKHVubGVzcyBub3RlZCBhYm92ZSkNClJFTSA9 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PQ0Kc2V0bG9jYWwgRW5hYmxlRXh0ZW5zaW9ucyBFbmFibGVEZWxheWVkRXhwYW5zaW9uDQoN CnNldCBERUJVRz0wDQppZiAmcXVvdDslREVCVUclJnF1b3Q7ID09ICZxdW90OzEmcXVvdDsg KA0KICAgIGVjaG8gJnF1b3Q7RGVidWcgaW5mbyBlbmFibGVkJnF1b3Q7DQogICAgZWNobyBv bg0KKQ0KDQpzZXQgJnF1b3Q7RElSTkFNRT0lfmRwMCUmcXVvdDsNCmlmICZxdW90OyVERUJV RyUmcXVvdDsgPT0gJnF1b3Q7MSZxdW90OyAoDQogICAgZWNobyBESVJOQU1FICZxdW90OyVE SVJOQU1FJXgmcXVvdDsNCikNCg0KaWYgZXhpc3QgJnF1b3Q7JURJUk5BTUUlLi5camJvc3Mt bW9kdWxlcy5qYXImcXVvdDsgKA0KICBSRU0gd2UgYXJlIGluIEpCT1NTX0hPTUUvYmluDQog IHNldCAmcXVvdDtXRT0lRElSTkFNRSUuLlwmcXVvdDsNCiAgZ290byA6V0VfRk9VTkQNCikg ZWxzZSBpZiBleGlzdCAmcXVvdDslRElSTkFNRSUuLlwuLlxqYm9zcy1tb2R1bGVzLmphciZx dW90OyAoDQogIFJFTSB3ZSBhcmUgaW4gYmluXHNlcnZpY2UgaW4gYSBXaWxkRmx5IGluc3Rh bGxhdGlvbg0KICBzZXQgJnF1b3Q7V0U9JURJUk5BTUUlLi5cLi5cJnF1b3Q7DQogIGdvdG8g OldFX0ZPVU5EDQopIGVsc2UgaWYgZXhpc3QgJnF1b3Q7JURJUk5BTUUlLi5cLi5cLi5camJv c3MtbW9kdWxlcy5qYXImcXVvdDsgKA0KICBSRU0gd2UgYXJlIGluIHNiaW4gaW4gYSA2LjAu eCBpbnN0YWxsYXRpb24NCiAgc2V0ICZxdW90O1dFPSVESVJOQU1FJS4uXC4uXC4uXCZxdW90 Ow0KICBnb3RvIDpXRV9GT1VORA0KKSBlbHNlICgNCiAgUkVNIHdlIHNob3VsZCBiZSBpbiBz YmluIGluIDYuMSBhbmQgdXANCiAgc2V0ICZxdW90O1dFPSVESVJOQU1FJS4uXC4uXC4uXC4u XC4uXC4uXCZxdW90Ow0KKQ0KDQppZiAmcXVvdDslREVCVUclJnF1b3Q7ID09ICZxdW90OzEm cXVvdDsgKA0KICAgIGVjaG8gV0Ugd2FzIG5vdCBmb3VuZCwgdXNpbmcgJnF1b3Q7JVdFJSZx dW90Ow0KKQ0KDQo6V0VfRk9VTkQNCmlmICZxdW90OyVERUJVRyUmcXVvdDsgPT0gJnF1b3Q7 MSZxdW90OyAoDQogICAgZWNobyBXRSAmcXVvdDslV0UlJnF1b3Q7DQopDQpwdXNoZCAmcXVv dDslV0UlJnF1b3Q7DQpzZXQgJnF1b3Q7UkVTT0xWRURfSkJPU1NfSE9NRT0lQ0QlJnF1b3Q7 DQpwb3BkDQpzZXQgV0U9DQpzZXQgRElSTkFNRT0NCmlmICZxdW90O3glSkJPU1NfSE9NRSUm cXVvdDsgPT0gJnF1b3Q7eCZxdW90OyAoDQogIHNldCAmcXVvdDtKQk9TU19IT01FPSVSRVNP TFZFRF9KQk9TU19IT01FJSZxdW90Ow0KKQ0KDQpwdXNoZCAmcXVvdDslSkJPU1NfSE9NRSUm cXVvdDsNCnNldCAmcXVvdDtTQU5JVElaRURfSkJPU1NfSE9NRT0lQ0QlJnF1b3Q7DQpwb3Bk DQoNCmlmICZxdW90OyVERUJVRyUmcXVvdDsgPT0gJnF1b3Q7MSZxdW90OyAoDQogICAgZWNo byBTQU5JVElaRURfSkJPU1NfSE9NRT0mcXVvdDslU0FOSVRJWkVEX0pCT1NTX0hPTUUlJnF1 b3Q7DQogICAgZWNobyBSRVNPTFZFRF9KQk9TU19IT01FPSZxdW90OyVSRVNPTFZFRF9KQk9T U19IT01FJSZxdW90Ow0KICAgIGVjaG8gSkJPU1NfSE9NRT0mcXVvdDslSkJPU1NfSE9NRSUm cXVvdDsNCikNCg0KaWYgbm90ICZxdW90OyVSRVNPTFZFRF9KQk9TU19IT01FJXgmcXVvdDsg PT0gJnF1b3Q7JVNBTklUSVpFRF9KQk9TU19IT01FJXgmcXVvdDsgKA0KICAgIGVjaG8gV0FS TklORyBKQk9TU19IT01FIG1heSBiZSBwb2ludGluZyB0byBhIGRpZmZlcmVudCBpbnN0YWxs YXRpb24gLSB1bnByZWRpY3RhYmxlIHJlc3VsdHMgbWF5IG9jY3VyLg0KICAgIGdvdG8gY21k RW5kDQopDQoNCnJlbSBGaW5kIGpib3NzLW1vZHVsZXMuamFyIHRvIGNoZWNrIEpCT1NTX0hP TUUNCmlmIG5vdCBleGlzdCAmcXVvdDslSkJPU1NfSE9NRSVcamJvc3MtbW9kdWxlcy5qYXIm cXVvdDsgKA0KICBlY2hvIENvdWxkIG5vdCBsb2NhdGUgJnF1b3Q7JUpCT1NTX0hPTUUlXGpi b3NzLW1vZHVsZXMuamFyJnF1b3Q7DQogIGdvdG8gY21kRW5kDQopDQoNCnNldCBQUlVOU1JW PQ0KaWYgJnF1b3Q7JVBST0NFU1NPUl9BUkNISVRFQ1RVUkUlJnF1b3Q7PT0mcXVvdDtBTUQ2 NCZxdW90OyAoDQogIGVjaG8gVXNpbmcgdGhlIFg4Ni02NGJpdCB2ZXJzaW9uIG9mIHBydW5z cnYNCiAgc2V0IFBSVU5TUlY9JnF1b3Q7JUpCT1NTX0hPTUUlXGJpblxzZXJ2aWNlXGFtZDY0 XHdpbGRmbHktc2VydmljZSZxdW90Ow0KKSBlbHNlICgNCiAgZWNobyBVc2luZyB0aGUgWDg2 LTMyYml0IHZlcnNpb24gb2YgcHJ1bnNydg0KICBzZXQgUFJVTlNSVj0mcXVvdDslSkJPU1Nf SE9NRSVcYmluXHNlcnZpY2Vcd2lsZGZseS1zZXJ2aWNlJnF1b3Q7DQopDQoNCmlmICZxdW90 OyVERUJVRyUmcXVvdDsgPT0gJnF1b3Q7MSZxdW90OyAoDQogICAgZWNobyBQUlVOU1JWICVQ UlVOU1JWJQ0KKQ0KDQplY2hvKA0KDQpyZW0gZGVmYXVsdHMNCnNldCBTSE9SVE5BTUU9V2ls ZGZseQ0Kc2V0IERJU1BMQVlOQU1FPVdpbGRGbHkNCnJlbSBOTyBxdW90ZXMgYXJvdW5kIHRo ZSBkZXNjcmlwdGlvbiBoZXJlICENCnNldCBERVNDUklQVElPTj1XaWxkRmx5IEFwcGxpY2F0 aW9uIFNlcnZlcg0Kc2V0IENPTlRST0xMRVI9bG9jYWxob3N0Ojk5OTANCnNldCBEQ19IT1NU PW1hc3Rlcg0Kc2V0IElTX0RPTUFJTj1mYWxzZQ0Kc2V0IExPR0xFVkVMPUlORk8NCnNldCBM T0dQQVRIPQ0Kc2V0IEpCT1NTVVNFUj0NCnNldCBKQk9TU1BBU1M9DQpzZXQgU0VSVklDRV9V U0VSPQ0Kc2V0IFNFUlZJQ0VfUEFTUz0NCnNldCBTVEFSVFVQX01PREU9bWFudWFsDQpzZXQg SVNERUJVRz0NCnNldCBDT05GSUc9DQpzZXQgSE9TVENPTkZJRz1ob3N0LnhtbA0Kc2V0IEJB U0U9DQoNCnNldCBDT01NQU5EPSUxDQpzaGlmdA0KaWYgL0kgJnF1b3Q7JUNPTU1BTkQlJnF1 b3Q7ID09ICZxdW90O2luc3RhbGwmcXVvdDsgICBnb3RvIGNtZEluc3RhbGwNCmlmIC9JICZx dW90OyVDT01NQU5EJSZxdW90OyA9PSAmcXVvdDt1bmluc3RhbGwmcXVvdDsgZ290byBjbWRV bmluc3RhbGwNCmlmIC9JICZxdW90OyVDT01NQU5EJSZxdW90OyA9PSAmcXVvdDtzdGFydCZx dW90OyAgICAgZ290byBjbWRTdGFydA0KaWYgL0kgJnF1b3Q7JUNPTU1BTkQlJnF1b3Q7ID09 ICZxdW90O3N0b3AmcXVvdDsgICAgICBnb3RvIGNtZFN0b3ANCmlmIC9JICZxdW90OyVDT01N QU5EJSZxdW90OyA9PSAmcXVvdDtyZXN0YXJ0JnF1b3Q7ICAgZ290byBjbWRSZXN0YXJ0DQoN CmVjaG8gRVJST1I6IGludmFsaWQgY29tbWFuZA0KDQo6Y21kVXNhZ2UNCmVjaG8gV2lsZEZs eSBTZXJ2aWNlIFNjcmlwdCBmb3IgV2luZG93cw0KZWNobyBVc2FnZToNCmVjaG8oDQplY2hv ICAgc2VydmljZSBpbnN0YWxsIF4mbHQ7b3B0aW9uc14mZ3Q7ICAsIHdoZXJlIHRoZSBvcHRp b25zIGFyZToNCmVjaG8oDQplY2hvICAgICAvc3RhcnR1cCAgICAgICAgICAgICAgICAgIDog U2V0IHRoZSBzZXJ2aWNlIHRvIGF1dG8gc3RhcnQNCmVjaG8gICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICBOb3Qgc3BlY2lmeWluZyBzZXRzIHRoZSBzZXJ2aWNlIHRvIG1hbnVh bA0KZWNobygNCmVjaG8gICAgIC9qYm9zc3VzZXIgXiZsdDt1c2VybmFtZV4mZ3Q7ICAgICA6 IEpCb3NzIHVzZXJuYW1lIHRvIHVzZSBmb3IgdGhlIHNodXRkb3duIGNvbW1hbmQuDQplY2hv ICAgICAvamJvc3NwYXNzIF4mbHQ7cGFzc3dvcmReJmd0OyAgICAgOiBQYXNzd29yZCBmb3Ig L2pib3NzdXNlcg0KZWNobygNCmVjaG8gICAgIC9jb250cm9sbGVyIF4mbHQ7aG9zdDpwb3J0 XiZndDsgICA6IFRoZSBob3N0OnBvcnQgb2YgdGhlIG1hbmFnZW1lbnQgaW50ZXJmYWNlLg0K ZWNobyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHQ6ICVDT05UUk9M TEVSJQ0KZWNobygNCmVjaG8gICAgIC9ob3N0IFteJmx0O2RvbWFpbmhvc3ReJmd0O10gICAg ICA6IEluZGljYXRlcyB0aGF0IGRvbWFpbiBtb2RlIGlzIHRvIGJlIHVzZWQgd2l0aCBhbg0K ZWNobyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbmFsIGRvbWFpbiBj b250cm9sbGVyIG5hbWUuDQplY2hvICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ZGVmYXVsdDogJURDX0hPU1QlDQplY2hvICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgTm90IHNwZWNpZnlpbmcgL2hvc3Qgd2lsbCBpbnN0YWxsIEpCb3NzIGluDQplY2hvICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhbmRhbG9uZSBtb2RlLg0KZWNobygN CmVjaG8gT3B0aW9ucyB0byB1c2Ugd2hlbiBtdWx0aXBsZSBzZXJ2aWNlcyBvciBkaWZmZXJl bnQgYWNjb3VudHMgYXJlIG5lZWRlZDoNCmVjaG8oDQplY2hvICAgICAvbmFtZSBeJmx0O3Nl cnZpY2VuYW1lXiZndDsgICAgICAgOiBUaGUgbmFtZSBvZiB0aGUgc2VydmljZQ0KZWNobygN CmVjaG8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWZhdWx0OiAlU0hPUlRO QU1FJQ0KZWNobyAgICAgL2Rlc2MgXiZsdDtkZXNjcmlwdGlvbl4mZ3Q7ICAgICAgIDogVGhl IGRlc2NyaXB0aW9uIG9mIHRoZSBzZXJ2aWNlLCB1c2UgZG91YmxlDQplY2hvICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgcXVvdGVzIHRvIGFsbG93IHNwYWNlcy4NCmVjaG8g ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNYXhpbXVtIDEwMjQgY2hhcmFjdGVy cy4NCmVjaG8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWZhdWx0OiAlREVT Q1JJUFRJT04lDQplY2hvKA0KZWNobyAgICAgL3NlcnZpY2V1c2VyIF4mbHQ7dXNlcm5hbWVe Jmd0OyAgIDogU3BlY2lmaWVzIHRoZSBuYW1lIG9mIHRoZSBhY2NvdW50IHVuZGVyIHdoaWNo DQplY2hvICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIHNlcnZpY2Ugc2hv dWxkIHJ1bi4NCmVjaG8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBVc2UgYW4g YWNjb3VudCBuYW1lIGluIHRoZSBmb3JtIG9mDQplY2hvICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgRG9tYWluTmFtZVxVc2VyTmFtZQ0KZWNobyAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgIGRlZmF1bHQ6IG5vdCB1c2VkLCB0aGUgc2VydmljZSBydW5zIGFz DQplY2hvICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTG9jYWwgU3lzdGVtIEFj Y291bnQuDQplY2hvICAgICAvc2VydmljZXBhc3MgXiZsdDtwYXNzd29yZF4mZ3Q7ICAgOiBw YXNzd29yZCBmb3IgL3NlcnZpY2V1c2VyDQplY2hvKA0KZWNobyBBZHZhbmNlZCBvcHRpb25z Og0KZWNobygNCmVjaG8gICAgIC9jb25maWcgXiZsdDt4bWxmaWxlXiZndDsgICAgICAgICA6 IFRoZSBzZXJ2ZXItY29uZmlnIHRvIHVzZQ0KZWNobyAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgIGRlZmF1bHQ6IHN0YW5kYWxvbmUueG1sIC8gZG9tYWluLnhtbA0KZWNobyAg ICAgL2hvc3Rjb25maWcgXiZsdDt4bWxmaWxlXiZndDsgICAgIDogZG9tYWluIG1vZGUgb25s eSwgdGhlIGhvc3QgY29uZmlnIHRvIHVzZQ0KZWNobyAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgIGRlZmF1bHQ6IGhvc3QueG1sDQplY2hvKA0KZWNobyAgICAgL2Jhc2UgXiZs dDtkaXJlY3RvcnleJmd0OyAgICAgICAgIDogVGhlIGJhc2UgZGlyZWN0b3J5IGZvciBzZXJ2 ZXIvZG9tYWluIGNvbnRlbnQNCmVjaG8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICBNdXN0IGJlIHNwZWNpZmllZCBhcyBhIGZ1bGx5IHF1YWxpZmllZCBwYXRoDQplY2hvICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdDogJUpCT1NTX0hPTUUlXHN0 YW5kYWxvbmUgb3INCmVjaG8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAlSkJPU1NfSE9NRSVcZG9tYWluDQplY2hvKA0KZWNobyAgICAgL2xvZ2xldmVsIF4m bHQ7bGV2ZWxeJmd0OyAgICAgICAgIDogVGhlIGxvZyBsZXZlbCBmb3IgdGhlIHNlcnZpY2U6 ICBFcnJvciwgSW5mbywNCmVjaG8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBX YXJuIG9yIERlYnVnIF4oQ2FzZSBpbnNlbnNpdGl2ZV4pDQplY2hvICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgZGVmYXVsdDogJUxPR0xFVkVMJQ0KZWNobyAgICAgL2xvZ3Bh dGggXiZsdDtwYXRoXiZndDsgICAgICAgICAgIDogUGF0aCBvZiB0aGUgbG9nDQplY2hvICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdCBkZXBlbmRzIG9uIGRvbWFp biBvciBzdGFuZGFsb25lIG1vZGUNCmVjaG8gICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAvYmFzZSBhcHBsaWVzIHdoZW4gL2xvZ3BhdGggaXMgbm90IHNldC4NCmVjaG8gICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICVKQk9TU19IT01FJVxkb21haW5cbG9n DQplY2hvICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAlSkJPU1NfSE9NRSVc c3RhbmRhbG9uZVxsb2cNCmVjaG8oDQplY2hvICAgICAvZGVidWcgICAgICAgICAgICAgICAg ICAgIDogcnVuIHRoZSBzZXJ2aWNlIGluc3RhbGwgaW4gZGVidWcgbW9kZQ0KZWNobygNCmVj aG8gT3RoZXIgY29tbWFuZHM6DQplY2hvKA0KZWNobyAgIHNlcnZpY2UgdW5pbnN0YWxsIFsv bmFtZSBeJmx0O3NlcnZpY2VuYW1lXiZndDtdDQplY2hvICAgc2VydmljZSBzdGFydCBbL25h bWUgXiZsdDtzZXJ2aWNlbmFtZV4mZ3Q7XQ0KZWNobyAgIHNlcnZpY2Ugc3RvcCBbL25hbWUg XiZsdDtzZXJ2aWNlbmFtZV4mZ3Q7XQ0KZWNobyAgIHNlcnZpY2UgcmVzdGFydCBbL25hbWUg XiZsdDtzZXJ2aWNlbmFtZV4mZ3Q7XQ0KZWNobygNCmVjaG8gICAgIC9uYW1lICBeJmx0O3Nl cnZpY2VuYW1lXiZndDsgICAgICA6IE5hbWUgb2YgdGhlIHNlcnZpY2U6IHNob3VsZCBub3Qg Y29udGFpbiBzcGFjZXMNCmVjaG8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBk ZWZhdWx0OiAlU0hPUlROQU1FJQ0KZWNobygNCmdvdG8gZW5kQmF0Y2gNCg0KOmNtZEluc3Rh bGwNCg0KOkxvb3BBcmdzDQppZiAmcXVvdDslfjEmcXVvdDsgPT0gJnF1b3Q7JnF1b3Q7IGdv dG8gZG9JbnN0YWxsDQoNCmlmIC9JICZxdW90OyV+MSZxdW90Oz09ICZxdW90Oy9kZWJ1ZyZx dW90OyAoDQogIHNldCBJU0RFQlVHPXRydWUNCiAgc2hpZnQNCiAgZ290byBMb29wQXJncw0K KQ0KaWYgL0kgJnF1b3Q7JX4xJnF1b3Q7PT0gJnF1b3Q7L3N0YXJ0dXAmcXVvdDsgKA0KICBz ZXQgU1RBUlRVUF9NT0RFPWF1dG8NCiAgc2hpZnQNCiAgZ290byBMb29wQXJncw0KKQ0KaWYg L0kgJnF1b3Q7JX4xJnF1b3Q7PT0gJnF1b3Q7L2NvbmZpZyZxdW90OyAoDQogIHNldCBDT05G SUc9DQogIGlmIG5vdCAmcXVvdDslfjImcXVvdDs9PSZxdW90OyZxdW90OyAoDQogICAgc2V0 IFQ9JX4yDQogICAgaWYgbm90ICZxdW90OyFUOn4wLDEhJnF1b3Q7PT0mcXVvdDsvJnF1b3Q7 ICgNCiAgICAgIHNldCBDT05GSUc9JX4yDQogICAgKQ0KICApDQogIGlmICZxdW90OyFDT05G SUchJnF1b3Q7ID09ICZxdW90OyZxdW90OyAoDQogICAgZWNobyBFUlJPUjogWW91IG5lZWQg dG8gc3BlY2lmeSBhIGNvbmZpZyBuYW1lDQogICAgZ290byBlbmRCYXRjaA0KICApDQogIHNo aWZ0DQogIHNoaWZ0DQogIGdvdG8gTG9vcEFyZ3MNCikNCmlmIC9JICZxdW90OyV+MSZxdW90 Oz09ICZxdW90Oy9ob3N0Y29uZmlnJnF1b3Q7ICgNCiAgc2V0IEhPU1RDT05GSUc9DQogIGlm IG5vdCAmcXVvdDslfjImcXVvdDs9PSZxdW90OyZxdW90OyAoDQogICAgc2V0IFQ9JX4yDQog ICAgaWYgbm90ICZxdW90OyFUOn4wLDEhJnF1b3Q7PT0mcXVvdDsvJnF1b3Q7ICgNCiAgICAg IHNldCBIT1NUQ09ORklHPSV+Mg0KICAgICkNCiAgKQ0KICBpZiAmcXVvdDshSE9TVENPTkZJ RyEmcXVvdDsgPT0gJnF1b3Q7JnF1b3Q7ICgNCiAgICBlY2hvIEVSUk9SOiBZb3UgbmVlZCB0 byBzcGVjaWZ5IGEgaG9zdC1jb25maWcgbmFtZQ0KICAgIGdvdG8gZW5kQmF0Y2gNCiAgKQ0K ICBzaGlmdA0KICBzaGlmdA0KICBnb3RvIExvb3BBcmdzDQopDQppZiAvSSAmcXVvdDslfjEm cXVvdDs9PSAmcXVvdDsvYmFzZSZxdW90OyAoDQogIHNldCBCQVNFPQ0KICBpZiBub3QgJnF1 b3Q7JX4yJnF1b3Q7PT0mcXVvdDsmcXVvdDsgKA0KICAgIHNldCBUPSV+Mg0KICAgIGlmIG5v dCAmcXVvdDshVDp+MCwxISZxdW90Oz09JnF1b3Q7LyZxdW90OyAoDQogICAgICBzZXQgQkFT RT0lfjINCiAgICApDQogICkNCiAgaWYgJnF1b3Q7IUJBU0UhJnF1b3Q7ID09ICZxdW90OyZx dW90OyAoDQogICAgZWNobyBFUlJPUjogWW91IG5lZWQgdG8gc3BlY2lmeSBhIGJhc2UgZGly ZWN0b3J5IG5hbWUNCiAgICBnb3RvIGVuZEJhdGNoDQogICkNCiAgc2hpZnQNCiAgc2hpZnQN CiAgZ290byBMb29wQXJncw0KKQ0KaWYgL0kgJnF1b3Q7JX4xJnF1b3Q7PT0gJnF1b3Q7L2Nv bnRyb2xsZXImcXVvdDsgKA0KICBzZXQgQ09OVFJPTExFUj0NCiAgaWYgbm90ICZxdW90OyV+ MiZxdW90Oz09JnF1b3Q7JnF1b3Q7ICgNCiAgICBzZXQgVD0lfjINCiAgICBpZiBub3QgJnF1 b3Q7IVQ6fjAsMSEmcXVvdDs9PSZxdW90Oy8mcXVvdDsgKA0KICAgICAgc2V0IENPTlRST0xM RVI9JX4yDQogICAgKQ0KICApDQogIGlmICZxdW90OyFDT05UUk9MTEVSISZxdW90OyA9PSAm cXVvdDsmcXVvdDsgKA0KICAgIGVjaG8gRVJST1I6IFRoZSBtYW5hZ2VtZW50IGludGVyZmFj ZSBzaG91bGQgYmUgc3BlY2lmaWVkIGluIHRoZSBmb3JtYXQgaG9zdDpwb3J0LCBleGFtcGxl OiAgMTI3LjAuMC4xOjk5OTkNCiAgICBnb3RvIGVuZEJhdGNoDQogICkNCiAgc2hpZnQNCiAg c2hpZnQNCiAgZ290byBMb29wQXJncw0KKQ0KaWYgL0kgJnF1b3Q7JX4xJnF1b3Q7PT0gJnF1 b3Q7L25hbWUmcXVvdDsgKA0KICBzZXQgU0hPUlROQU1FPQ0KICBpZiBub3QgJnF1b3Q7JX4y JnF1b3Q7PT0mcXVvdDsmcXVvdDsgKA0KICAgIHNldCBUPSV+Mg0KICAgIGlmIG5vdCAmcXVv dDshVDp+MCwxISZxdW90Oz09JnF1b3Q7LyZxdW90OyAoDQogICAgICBzZXQgU0hPUlROQU1F PSV+Mg0KICAgICAgc2V0IERJU1BMQVlOQU1FPSV+Mg0KICAgICkNCiAgKQ0KICBpZiAmcXVv dDshU0hPUlROQU1FISZxdW90OyA9PSAmcXVvdDsmcXVvdDsgKA0KICAgIGVjaG8gRVJST1I6 IFlvdSBuZWVkIHRvIHNwZWNpZnkgYSBzZXJ2aWNlIG5hbWUNCiAgICBnb3RvIGVuZEJhdGNo DQogICkNCiAgc2hpZnQNCiAgc2hpZnQNCiAgZ290byBMb29wQXJncw0KKQ0KaWYgL0kgJnF1 b3Q7JX4xJnF1b3Q7PT0gJnF1b3Q7L2Rlc2MmcXVvdDsgKA0KICBzZXQgREVTQ1JJUFRJT049 DQogIGlmIG5vdCAmcXVvdDslfjImcXVvdDs9PSZxdW90OyZxdW90OyAoDQogICAgc2V0IFQ9 JX4yDQogICAgaWYgbm90ICZxdW90OyFUOn4wLDEhJnF1b3Q7PT0mcXVvdDsvJnF1b3Q7ICgN CiAgICAgIHNldCBERVNDUklQVElPTj0lfjINCiAgICApDQogICkNCiAgaWYgJnF1b3Q7IURF U0NSSVBUSU9OISZxdW90OyA9PSAmcXVvdDsmcXVvdDsgKA0KICAgIGVjaG8gRVJST1I6IFlv dSBuZWVkIHRvIHNwZWNpZnkgYSBkZXNjcmlwdGlvbiwgbWF4aW11bSBvZiAxMDI0IGNoYXJh Y3RlcnMNCiAgICBnb3RvIGVuZEJhdGNoDQogICkNCiAgc2hpZnQNCiAgc2hpZnQNCiAgZ290 byBMb29wQXJncw0KKQ0KaWYgL0kgJnF1b3Q7JX4xJnF1b3Q7PT0gJnF1b3Q7L2pib3NzdXNl ciZxdW90OyAoDQogIHNldCBKQk9TU1VTRVI9DQogIGlmIG5vdCAmcXVvdDslfjImcXVvdDs9 PSZxdW90OyZxdW90OyAoDQogICAgc2V0IFQ9JX4yDQogICAgaWYgbm90ICZxdW90OyFUOn4w LDEhJnF1b3Q7PT0mcXVvdDsvJnF1b3Q7ICgNCiAgICAgIHNldCBKQk9TU1VTRVI9JX4yDQog ICAgKQ0KICApDQogIGlmICZxdW90OyFKQk9TU1VTRVIhJnF1b3Q7ID09ICZxdW90OyZxdW90 OyAoDQogICAgZWNobyBFUlJPUjogWW91IG5lZWQgdG8gc3BlY2lmeSBhIHVzZXJuYW1lDQog ICAgZ290byBlbmRCYXRjaA0KICApDQogIHNoaWZ0DQogIHNoaWZ0DQogIGdvdG8gTG9vcEFy Z3MNCikNCmlmIC9JICZxdW90OyV+MSZxdW90Oz09ICZxdW90Oy9qYm9zc3Bhc3MmcXVvdDsg KA0KICBzZXQgSkJPU1NQQVNTPQ0KICBpZiBub3QgJnF1b3Q7JX4yJnF1b3Q7PT0mcXVvdDsm cXVvdDsgKA0KICAgIHNldCBUPSV+Mg0KICAgIGlmIG5vdCAmcXVvdDshVDp+MCwxISZxdW90 Oz09JnF1b3Q7LyZxdW90OyAoDQogICAgICBzZXQgSkJPU1NQQVNTPSV+Mg0KICAgICkNCiAg KQ0KICBpZiAmcXVvdDshSkJPU1NQQVNTISZxdW90OyA9PSAmcXVvdDsmcXVvdDsgKA0KICAg IGVjaG8gRVJST1I6IFlvdSBuZWVkIHRvIHNwZWNpZnkgYSBwYXNzd29yZCBmb3IgL2pib3Nz cGFzcw0KICAgIGdvdG8gZW5kQmF0Y2gNCiAgKQ0KICBzaGlmdA0KICBzaGlmdA0KICBnb3Rv IExvb3BBcmdzDQopDQppZiAvSSAmcXVvdDslfjEmcXVvdDs9PSAmcXVvdDsvc2VydmljZXVz ZXImcXVvdDsgKA0KICBzZXQgU0VSVklDRV9VU0VSPQ0KICBpZiBub3QgJnF1b3Q7JX4yJnF1 b3Q7PT0mcXVvdDsmcXVvdDsgKA0KICAgIHNldCBUPSV+Mg0KICAgIGlmIG5vdCAmcXVvdDsh VDp+MCwxISZxdW90Oz09JnF1b3Q7LyZxdW90OyAoDQogICAgICBzZXQgU0VSVklDRV9VU0VS PSV+Mg0KICAgICkNCiAgKQ0KICBpZiAmcXVvdDshU0VSVklDRV9VU0VSISZxdW90OyA9PSAm cXVvdDsmcXVvdDsgKA0KICAgIGVjaG8gRVJST1I6IFlvdSBuZWVkIHRvIHNwZWNpZnkgYSB1 c2VybmFtZSBpbiB0aGUgZm9ybWF0IERPTUFJTlxVU0VSLCBvciAuXFVTRVIgZm9yIHRoZSBs b2NhbCBkb21haW4NCiAgICBnb3RvIGVuZEJhdGNoDQogICkNCiAgc2hpZnQNCiAgc2hpZnQN CiAgZ290byBMb29wQXJncw0KKQ0KaWYgL0kgJnF1b3Q7JX4xJnF1b3Q7PT0gJnF1b3Q7L3Nl cnZpY2VwYXNzJnF1b3Q7ICgNCiAgc2V0IFNFUlZJQ0VfUEFTUz0NCiAgaWYgbm90ICZxdW90 OyV+MiZxdW90Oz09JnF1b3Q7JnF1b3Q7ICgNCiAgICBzZXQgVD0lfjINCiAgICBpZiBub3Qg JnF1b3Q7IVQ6fjAsMSEmcXVvdDs9PSZxdW90Oy8mcXVvdDsgKA0KICAgICAgc2V0IFNFUlZJ Q0VfUEFTUz0lfjINCiAgICApDQogICkNCiAgaWYgJnF1b3Q7IVNFUlZJQ0VfUEFTUyEmcXVv dDsgPT0gJnF1b3Q7JnF1b3Q7ICgNCiAgICBlY2hvIEVSUk9SOiBZb3UgbmVlZCB0byBzcGVj aWZ5IGEgcGFzc3dvcmQgZm9yIC9zZXJ2aWNlcGFzcw0KICAgIGdvdG8gZW5kQmF0Y2gNCiAg KQ0KICBzaGlmdA0KICBzaGlmdA0KICBnb3RvIExvb3BBcmdzDQopDQpyZW0gdGhlIGhvc3Ru YW1lIGlzIG9wdGlvbmFsDQppZiAvSSAmcXVvdDslfjEmcXVvdDs9PSAmcXVvdDsvaG9zdCZx dW90OyAoDQogIHNldCBJU19ET01BSU49dHJ1ZQ0KICBpZiBub3QgJnF1b3Q7JX4yJnF1b3Q7 PT0mcXVvdDsmcXVvdDsgKA0KICAgIHNldCBUPSV+Mg0KICAgIGlmIG5vdCAmcXVvdDshVDp+ MCwxISZxdW90Oz09JnF1b3Q7LyZxdW90OyAoDQogICAgICBzZXQgRENfSE9TVD0lfjINCiAg ICAgIHNoaWZ0DQogICAgKQ0KICApDQogIHNoaWZ0DQogIGdvdG8gTG9vcEFyZ3MNCikNCmlm IC9JICZxdW90OyV+MSZxdW90Oz09ICZxdW90Oy9sb2dsZXZlbCZxdW90OyAoDQogIGlmIC9J IG5vdCAmcXVvdDslfjImcXVvdDs9PSZxdW90O0Vycm9yJnF1b3Q7IGlmIC9JIG5vdCAmcXVv dDslfjImcXVvdDs9PSZxdW90O0luZm8mcXVvdDsgaWYgL0kgbm90ICZxdW90OyV+MiZxdW90 Oz09JnF1b3Q7V2FybiZxdW90OyBpZiAvSSBub3QgJnF1b3Q7JX4yJnF1b3Q7PT0mcXVvdDtE ZWJ1ZyZxdW90OyAoDQogICAgZWNobyBFUlJPUjogL2xvZ2xldmVsIG11c3QgYmUgc2V0IHRv IEVycm9yLCBJbmZvLCBXYXJuIG9yIERlYnVnIF4oQ2FzZSBpbnNlbnNpdGl2ZV4pDQogICAg Z290byBlbmRCYXRjaA0KICApDQogIHNldCBMT0dMRVZFTD0lfjINCiAgc2hpZnQNCiAgc2hp ZnQNCiAgZ290byBMb29wQXJncw0KKQ0KaWYgL0kgJnF1b3Q7JX4xJnF1b3Q7PT0gJnF1b3Q7 L2xvZ3BhdGgmcXVvdDsgKA0KICBzZXQgTE9HUEFUSD0NCiAgaWYgbm90ICZxdW90OyV+MiZx dW90Oz09JnF1b3Q7JnF1b3Q7ICgNCiAgICBzZXQgVD0lfjINCiAgICBpZiBub3QgJnF1b3Q7 IVQ6fjAsMSEmcXVvdDs9PSZxdW90Oy8mcXVvdDsgKA0KICAgICAgc2V0IExPR1BBVEg9JX4y DQogICAgKQ0KICApDQogIGlmICZxdW90OyFMT0dQQVRIISZxdW90OyA9PSAmcXVvdDsmcXVv dDsgKA0KICAgIGVjaG8gRVJST1I6IFlvdSBuZWVkIHRvIHNwZWNpZnkgYSBwYXRoIGZvciB0 aGUgc2VydmljZSBsb2cNCiAgICBnb3RvIGVuZEJhdGNoDQogICkNCiAgc2hpZnQNCiAgc2hp ZnQNCiAgZ290byBMb29wQXJncw0KKQ0KZWNobyBFUlJPUjogVW5yZWNvZ25pc2VkIG9wdGlv bjogJTENCmVjaG8oDQpnb3RvIGNtZFVzYWdlDQoNCjpkb0luc3RhbGwNCnNldCBDUkVERU5U SUFMUz0NCmlmIG5vdCAmcXVvdDslSkJPU1NVU0VSJSZxdW90OyA9PSAmcXVvdDsmcXVvdDsg KA0KICBpZiAmcXVvdDslSkJPU1NQQVNTJSZxdW90OyA9PSAmcXVvdDsmcXVvdDsgKA0KICAg IGVjaG8gV2hlbiBzcGVjaWZ5aW5nIGEgdXNlciwgeW91IG5lZWQgdG8gc3BlY2lmeSB0aGUg cGFzc3dvcmQNCiAgICBnb3RvIGVuZEJhdGNoDQogICkNCiAgc2V0IENSRURFTlRJQUxTPS0t dXNlcj0lSkJPU1NVU0VSJSAtLXBhc3N3b3JkPSVKQk9TU1BBU1MlDQopDQoNCnNldCBSVU5B Uz0NCmlmIG5vdCAmcXVvdDslU0VSVklDRV9VU0VSJSZxdW90OyA9PSAmcXVvdDsmcXVvdDsg KA0KICBpZiAmcXVvdDslU0VSVklDRV9QQVNTJSZxdW90OyA9PSAmcXVvdDsmcXVvdDsgKA0K ICAgIGVjaG8gV2hlbiBzcGVjaWZ5aW5nIGEgdXNlciwgeW91IG5lZWQgdG8gc3BlY2lmeSB0 aGUgcGFzc3dvcmQNCiAgICBnb3RvIGVuZEJhdGNoDQogICkNCiAgc2V0IFJVTkFTPS0tU2Vy dmljZVVzZXI9JVNFUlZJQ0VfVVNFUiUgLS1TZXJ2aWNlUGFzc3dvcmQ9JVNFUlZJQ0VfUEFT UyUNCikNCg0KaWYgJnF1b3Q7JVNURE9VVCUmcXVvdDs9PSZxdW90OyZxdW90OyBzZXQgU1RE T1VUPWF1dG8NCmlmICZxdW90OyVTVERFUlIlJnF1b3Q7PT0mcXVvdDsmcXVvdDsgc2V0IFNU REVSUj1hdXRvDQoNCmlmICZxdW90OyVTVEFSVF9QQVRIJSZxdW90Oz09JnF1b3Q7JnF1b3Q7 IHNldCBTVEFSVF9QQVRIPSZxdW90OyVKQk9TU19IT01FJVxiaW4mcXVvdDsNCmlmICZxdW90 OyVTVE9QX1BBVEglJnF1b3Q7PT0mcXVvdDsmcXVvdDsgc2V0IFNUT1BfUEFUSD0mcXVvdDsl SkJPU1NfSE9NRSVcYmluJnF1b3Q7DQoNCmlmICZxdW90OyVTVE9QX1NDUklQVCUmcXVvdDs9 PSZxdW90OyZxdW90OyBzZXQgU1RPUF9TQ1JJUFQ9amJvc3MtY2xpLmJhdA0KDQppZiAvSSAm cXVvdDslSVNfRE9NQUlOJSZxdW90OyA9PSAmcXVvdDt0cnVlJnF1b3Q7ICgNCiAgaWYgJnF1 b3Q7JUJBU0UlJnF1b3Q7PT0mcXVvdDsmcXVvdDsgc2V0IEJBU0U9JnF1b3Q7JUpCT1NTX0hP TUUlXGRvbWFpbiZxdW90Ow0KICBpZiAmcXVvdDslQ09ORklHJSZxdW90Oz09JnF1b3Q7JnF1 b3Q7IHNldCBDT05GSUc9ZG9tYWluLnhtbA0KICBpZiAmcXVvdDslU1RBUlRfU0NSSVBUJSZx dW90Oz09JnF1b3Q7JnF1b3Q7IHNldCBTVEFSVF9TQ1JJUFQ9ZG9tYWluLmJhdA0KICBzZXQg U1RBUlRQQVJBTT0mcXVvdDsvYyNzZXQjTk9QQVVTRT1ZIyZhbXA7JmFtcDsjIVNUQVJUX1ND UklQVCEjLURqYm9zcy5kb21haW4uYmFzZS5kaXI9IUJBU0UhIy0tZG9tYWluLWNvbmZpZz0h Q09ORklHISMtLWhvc3QtY29uZmlnPSFIT1NUQ09ORklHISZxdW90Ow0KICBzZXQgU1RPUFBB UkFNPSZxdW90Oy9jICVTVE9QX1NDUklQVCUgLS1jb250cm9sbGVyPSVDT05UUk9MTEVSJSAt LWNvbm5lY3QgJUNSRURFTlRJQUxTJSAtLWNvbW1hbmQ9L2hvc3Q9IURDX0hPU1QhOnNodXRk b3duJnF1b3Q7DQopIGVsc2UgKA0KICBpZiAmcXVvdDslQkFTRSUmcXVvdDs9PSZxdW90OyZx dW90OyBzZXQgJnF1b3Q7QkFTRT0lSkJPU1NfSE9NRSVcc3RhbmRhbG9uZSZxdW90Ow0KICBp ZiAmcXVvdDslQ09ORklHJSZxdW90Oz09JnF1b3Q7JnF1b3Q7IHNldCBDT05GSUc9c3RhbmRh bG9uZS54bWwNCiAgaWYgJnF1b3Q7JVNUQVJUX1NDUklQVCUmcXVvdDs9PSZxdW90OyZxdW90 OyBzZXQgU1RBUlRfU0NSSVBUPXN0YW5kYWxvbmUuYmF0DQogIHNldCBTVEFSVFBBUkFNPSZx dW90Oy9jI3NldCNOT1BBVVNFPVkjJmFtcDsmYW1wOyMhU1RBUlRfU0NSSVBUISMtRGpib3Nz LnNlcnZlci5iYXNlLmRpcj0hQkFTRSEjLS1zZXJ2ZXItY29uZmlnPSFDT05GSUchJnF1b3Q7 DQogIHNldCBTVE9QUEFSQU09JnF1b3Q7L2MgIVNUT1BfU0NSSVBUISAtLWNvbnRyb2xsZXI9 JUNPTlRST0xMRVIlIC0tY29ubmVjdCAlQ1JFREVOVElBTFMlIC0tY29tbWFuZD06c2h1dGRv d24mcXVvdDsNCikNCg0KaWYgJnF1b3Q7JUxPR1BBVEglJnF1b3Q7PT0mcXVvdDsmcXVvdDsg c2V0IExPR1BBVEg9JnF1b3Q7IUJBU0UhXGxvZyZxdW90Ow0KDQppZiBub3QgZXhpc3QgJnF1 b3Q7JUJBU0UlJnF1b3Q7ICgNCiAgZWNobyBUaGUgYmFzZSBkaXJlY3RvcnkgZG9lcyBub3Qg ZXhpc3Q6ICZxdW90OyVCQVNFJSZxdW90Ow0KICBnb3RvIGVuZEJhdGNoDQopDQoNCmlmIG5v dCBleGlzdCAmcXVvdDslQkFTRSVcY29uZmlndXJhdGlvblwlQ09ORklHJSZxdW90OyAoDQog IGVjaG8gVGhlIGNvbmZpZ3VyYXRpb24gZG9lcyBub3QgZXhpc3Q6ICZxdW90OyVCQVNFJVxj b25maWd1cmF0aW9uXCVDT05GSUclJnF1b3Q7DQogIGdvdG8gZW5kQmF0Y2gNCikNCg0KaWYg L0kgJnF1b3Q7JUlTREVCVUclJnF1b3Q7ID09ICZxdW90O3RydWUmcXVvdDsgKA0KICBlY2hv IEpCT1NTX0hPTUU9JnF1b3Q7JUpCT1NTX0hPTUUlJnF1b3Q7DQogIGVjaG8gUlVOQVM9JVJV TkFTJQ0KICBlY2hvIFNIT1JUTkFNRT0mcXVvdDslU0hPUlROQU1FJSZxdW90Ow0KICBlY2hv IERFU0NSSVBUSU9OPSZxdW90OyVERVNDUklQVElPTiUmcXVvdDsNCiAgZWNobyBTVEFSVFBB UkFNPSVTVEFSVFBBUkFNJQ0KICBlY2hvIFNUT1BQQVJBTT0lU1RPUFBBUkFNJQ0KICBlY2hv IExPR0xFVkVMPSVMT0dMRVZFTCUNCiAgZWNobyBMT0dQQVRIPSVMT0dQQVRIJQ0KICBlY2hv IENSRURFTlRJQUxTPSVDUkVERU5USUFMUyUNCiAgZWNobyBCQVNFPSZxdW90OyVCQVNFJSZx dW90Ow0KICBlY2hvIENPTkZJRz0mcXVvdDslQ09ORklHJSZxdW90Ow0KICBlY2hvIFNUQVJU X1NDUklQVD0lU1RBUlRfU0NSSVBUJQ0KICBlY2hvIFNUQVJUX1BBVEg9JVNUQVJUX1BBVEgl DQogIGVjaG8gU1RPUF9TQ1JJUFQ9JVNUT1BfU0NSSVBUJQ0KICBlY2hvIFNUT1BfUEFUSD0l U1RPUF9QQVRIJQ0KICBlY2hvIFNURE9VVD0mcXVvdDslU1RET1VUJSZxdW90Ow0KICBlY2hv IFNUREVSUj0mcXVvdDslU1RERVJSJSZxdW90Ow0KKQ0KaWYgL0kgJnF1b3Q7JUlTREVCVUcl JnF1b3Q7ID09ICZxdW90O3RydWUmcXVvdDsgKA0KICBAZWNobyBvbg0KKQ0KDQpAcmVtIHF1 b3RlcyBhcm91bmQgdGhlICZxdW90OyVERVNDUklQVElPTiUmcXVvdDsgYnV0IG5vd2hlcmUg ZWxzZQ0KZWNobyAlUFJVTlNSViUgaW5zdGFsbCAlU0hPUlROQU1FJSAlUlVOQVMlIC0tRGlz cGxheU5hbWU9JURJU1BMQVlOQU1FJSAtLURlc2NyaXB0aW9uPSZxdW90OyVERVNDUklQVElP TiUmcXVvdDsgLS1Mb2dMZXZlbD0lTE9HTEVWRUwlIC0tTG9nUGF0aD0lTE9HUEFUSCUgLS1M b2dQcmVmaXg9c2VydmljZSAtLVN0ZE91dHB1dD0lU1RET1VUJSAtLVN0ZEVycm9yPSVTVERF UlIlIC0tU3RhcnRNb2RlPWV4ZSAtLVN0YXJ0dXA9JVNUQVJUVVBfTU9ERSUgLS1TdGFydElt YWdlPWNtZC5leGUgLS1TdGFydFBhdGg9JVNUQVJUX1BBVEglICsrU3RhcnRQYXJhbXM9JVNU QVJUUEFSQU0lIC0tU3RvcE1vZGU9ZXhlIC0tU3RvcEltYWdlPWNtZC5leGUgLS1TdG9wUGF0 aD0lU1RPUF9QQVRIJSAgKytTdG9wUGFyYW1zPSVTVE9QUEFSQU0lDQoNCiVQUlVOU1JWJSBp bnN0YWxsICVTSE9SVE5BTUUlICVSVU5BUyUgLS1EaXNwbGF5TmFtZT0lRElTUExBWU5BTUUl IC0tRGVzY3JpcHRpb249JnF1b3Q7JURFU0NSSVBUSU9OJSZxdW90OyAtLUxvZ0xldmVsPSVM T0dMRVZFTCUgLS1Mb2dQYXRoPSVMT0dQQVRIJSAtLUxvZ1ByZWZpeD1zZXJ2aWNlIC0tU3Rk T3V0cHV0PSVTVERPVVQlIC0tU3RkRXJyb3I9JVNUREVSUiUgLS1TdGFydE1vZGU9ZXhlIC0t U3RhcnR1cD0lU1RBUlRVUF9NT0RFJSAtLVN0YXJ0SW1hZ2U9Y21kLmV4ZSAtLVN0YXJ0UGF0 aD0lU1RBUlRfUEFUSCUgKytTdGFydFBhcmFtcz0lU1RBUlRQQVJBTSUgLS1TdG9wTW9kZT1l eGUgLS1TdG9wSW1hZ2U9Y21kLmV4ZSAtLVN0b3BQYXRoPSVTVE9QX1BBVEglICArK1N0b3BQ YXJhbXM9JVNUT1BQQVJBTSUNCkByZW0gJVBSVU5TUlYlIGluc3RhbGwgJnF1b3Q7JVNIT1JU TkFNRSUmcXVvdDsgJnF1b3Q7JVJVTkFTJSZxdW90OyAtLURpc3BsYXlOYW1lPSZxdW90OyVE SVNQTEFZTkFNRSUmcXVvdDsgLS1EZXNjcmlwdGlvbj0mcXVvdDslREVTQ1JJUFRJT04lJnF1 b3Q7IC0tTG9nTGV2ZWw9JnF1b3Q7JUxPR0xFVkVMJSZxdW90OyAtLUxvZ1BhdGg9JnF1b3Q7 JUxPR1BBVEglJnF1b3Q7IC0tTG9nUHJlZml4PXNlcnZpY2UgLS1TdGRPdXRwdXQ9JnF1b3Q7 JVNURE9VVCUmcXVvdDsgLS1TdGRFcnJvcj0mcXVvdDslU1RERVJSJSZxdW90OyAtLVN0YXJ0 TW9kZT1leGUgLS1TdGFydHVwPSZxdW90OyVTVEFSVFVQX01PREUlJnF1b3Q7IC0tU3RhcnRJ bWFnZT1jbWQuZXhlIC0tU3RhcnRQYXRoPSZxdW90OyVTVEFSVF9QQVRIJSZxdW90OyArK1N0 YXJ0UGFyYW1zPSZxdW90OyVTVEFSVFBBUkFNJSZxdW90OyAtLVN0b3BNb2RlPWV4ZSAtLVN0 b3BJbWFnZT1jbWQuZXhlIC0tU3RvcFBhdGg9JnF1b3Q7JVNUT1BfUEFUSCUmcXVvdDsgICsr U3RvcFBhcmFtcz0mcXVvdDslU1RPUFBBUkFNJSZxdW90Ow0KDQpAaWYgL0kgJnF1b3Q7JUlT REVCVUclJnF1b3Q7ID09ICZxdW90O3RydWUmcXVvdDsgKA0KICBAZWNobyBvZmYNCikNCg0K aWYgZXJyb3JsZXZlbCA4ICgNCiAgZWNobyBFUlJPUjogVGhlIHNlcnZpY2UgJVNIT1JUTkFN RSUgYWxyZWFkeSBleGlzdHMNCiAgZ290byBlbmRCYXRjaA0KKQ0KaWYgZXJyb3JsZXZlbCAw ICgNCiAgZWNobyBTZXJ2aWNlICVTSE9SVE5BTUUlIGluc3RhbGxlZA0KICBnb3RvIGVuZEJh dGNoDQopDQpnb3RvIGNtZEVuZA0KDQoNClJFTSB0aGUgb3RoZXIgY29tbWFuZHMgdGFrZSBh IC9uYW1lIHBhcmFtZXRlciAtIGlmIHRoZXJlIGlzIG5vIF4mbHQ7c2VydmljZW5hbWVeJmd0 OyBwYXNzZWQgYXMgc2Vjb25kIHBhcmFtZXRlciwNClJFTSB3ZSBzaWxlbnRseSBpZ25vcmUg dGhpcyBhbmQgdXNlIHRoZSBkZWZhdWx0IFNIT1JUTkFNRQ0KDQo6Y21kVW5pbnN0YWxsDQpp ZiAvSSAmcXVvdDslfjEmcXVvdDs9PSZxdW90Oy9uYW1lJnF1b3Q7ICgNCiAgaWYgbm90ICZx dW90OyV+MiZxdW90Oz09JnF1b3Q7JnF1b3Q7ICgNCiAgICBzZXQgU0hPUlROQU1FPSZxdW90 OyV+MiZxdW90Ow0KICApDQopDQolUFJVTlNSViUgc3RvcCAlU0hPUlROQU1FJQ0KaWYgZXJy b3JsZXZlbCAwICgNCiAgJVBSVU5TUlYlIGRlbGV0ZSAlU0hPUlROQU1FJQ0KICBpZiBlcnJv cmxldmVsIDAgKA0KICAgIGVjaG8gU2VydmljZSAlU0hPUlROQU1FJSB1bmluc3RhbGxlZA0K ICApDQopIGVsc2UgKA0KICBlY2hvIFVuYWJsZSB0byBzdG9wIHRoZSBzZXJ2aWNlICVTSE9S VE5BTUUlDQopDQpnb3RvIGNtZEVuZA0KDQo6Y21kU3RhcnQNCmlmIC9JICZxdW90OyV+MSZx dW90Oz09JnF1b3Q7L25hbWUmcXVvdDsgKA0KICBpZiBub3QgJnF1b3Q7JX4yJnF1b3Q7PT0m cXVvdDsmcXVvdDsgKA0KICAgIHNldCBTSE9SVE5BTUU9JnF1b3Q7JX4yJnF1b3Q7DQogICkN CikNCiVQUlVOU1JWJSBzdGFydCAlU0hPUlROQU1FJQ0KZWNobyBTZXJ2aWNlICVTSE9SVE5B TUUlIHN0YXJ0aW5nLi4uDQpnb3RvIGNtZEVuZA0KDQo6Y21kU3RvcA0KaWYgL0kgJnF1b3Q7 JX4xJnF1b3Q7PT0mcXVvdDsvbmFtZSZxdW90OyAoDQogIGlmIG5vdCAmcXVvdDslfjImcXVv dDs9PSZxdW90OyZxdW90OyAoDQogICAgc2V0IFNIT1JUTkFNRT0mcXVvdDslfjImcXVvdDsN CiAgKQ0KKQ0KJVBSVU5TUlYlIHN0b3AgJVNIT1JUTkFNRSUNCmVjaG8gU2VydmljZSAlU0hP UlROQU1FJSBzdG9wcGluZy4uLg0KZ290byBjbWRFbmQNCg0KOmNtZFJlc3RhcnQNCmlmIC9J ICZxdW90OyV+MSZxdW90Oz09JnF1b3Q7L25hbWUmcXVvdDsgKA0KICBpZiBub3QgJnF1b3Q7 JX4yJnF1b3Q7PT0mcXVvdDsmcXVvdDsgKA0KICAgIHNldCBTSE9SVE5BTUU9JnF1b3Q7JX4y JnF1b3Q7DQogICkNCikNCiVQUlVOU1JWJSBzdG9wICVTSE9SVE5BTUUlDQplY2hvIFNlcnZp Y2UgJVNIT1JUTkFNRSUgc3RvcHBpbmcuLi4NCmlmICZxdW90OyVlcnJvcmxldmVsJSZxdW90 OyA9PSAmcXVvdDswJnF1b3Q7ICgNCiAgJVBSVU5TUlYlIHN0YXJ0ICVTSE9SVE5BTUUlDQog IGVjaG8gU2VydmljZSAlU0hPUlROQU1FJSBzdGFydGluZy4uLg0KKSBlbHNlICgNCiAgZWNo byBVbmFibGUgdG8gc3RvcCB0aGUgc2VydmljZSAlU0hPUlROQU1FJQ0KKQ0KZ290byBjbWRF bmQNCg0KDQo6Y21kRW5kDQpSRU0gaWYgdGhlcmUgaXMgYSBuZWVkIHRvIGFkZCBvdGhlciBl cnJvciBtZXNzYWdlcywgbWFrZSBzdXJlIHRvIGxpc3QgaGlnaGVyIG51bWJlcnMgZmlyc3Qg IQ0KaWYgZXJyb3JsZXZlbCAyICgNCiAgZWNobyBFUlJPUjogRmFpbGVkIHRvIGxvYWQgc2Vy dmljZSAlU0hPUlROQU1FJSBjb25maWd1cmF0aW9uDQogIGdvdG8gZW5kQmF0Y2gNCikNCmlm IGVycm9ybGV2ZWwgMCAoDQogIGdvdG8gZW5kQmF0Y2gNCikNCmVjaG8gJnF1b3Q7VW5mb3Jz ZWVuIGVycm9yPSVlcnJvcmxldmVsJSZxdW90Ow0KDQpyZW0gbm90aGluZyBiZWxvdywgZXhp dA0KOmVuZEJhdGNoDQo8L2NvZGU+PC9wcmU+DQo=