Commit b663ee20 authored by Luke Patterson's avatar Luke Patterson

$ docker build --tag layers-blog:step-0-initial-build .

...
Step 9/24 : WORKDIR ./layers-blog-snapshot-dependency/
 ---> 88b225936bee
Step 10/24 : COPY ./layers-blog-snapshot-dependency/ ./
 ---> 96178605fb19
Step 11/24 : RUN mvn install --quiet --update-snapshots --strict-checksums --batch-mode
 ---> e2d1d22c9519
Step 12/24 : WORKDIR ../layers-blog-app/
 ---> e7bb8e108b94
Step 13/24 : COPY layers-blog-app ./
 ---> 01cb36659cb6
Step 14/24 : RUN mvn package --quiet --update-snapshots --strict-checksums --batch-mode
 ---> cd6abb394e3e
Step 15/24 : WORKDIR ./target/
 ---> 2c6272c90ef4
Step 16/24 : RUN unzip -q *.jar -d ./unzipped/     && tree ./unzipped/     && mkdir --parents /layers/3-app/BOOT-INF/     && mv ./unzipped/BOOT-INF/classes/ /layers/3-app/BOOT-INF/     && mv ./unzipped/META-INF/ /layers/3-app/     && mkdir --parents /layers/2-dependencies-snapshot/BOOT-INF/lib/     && find ./unzipped/BOOT-INF/lib/ -type f -name '*-SNAPSHOT.jar' -exec mv {} /layers/2-dependencies-snapshot/BOOT-INF/lib/ ';'     && mv ./unzipped/ /layers/1-dependencies-release/     && tree /layers/
 /unzipped/
├── BOOT-INF
│   ├── classes
│   │   ├── application.properties
│   │   └── org
│   │       └── lukewpatterson
│   │           └── layers
│   │               └── blog
│   │                   └── app
│   │                       └── OurSpringBootApplication.class
│   └── lib
│       ├── classmate-1.3.4.jar
│       ├── hibernate-validator-6.0.12.Final.jar
│       ├── jackson-annotations-2.9.0.jar
│       ├── jackson-core-2.9.6.jar
│       ├── jackson-databind-2.9.6.jar
│       ├── jackson-datatype-jdk8-2.9.6.jar
│       ├── jackson-datatype-jsr310-2.9.6.jar
│       ├── jackson-module-parameter-names-2.9.6.jar
│       ├── javax.annotation-api-1.3.2.jar
│       ├── jboss-logging-3.3.2.Final.jar
│       ├── jul-to-slf4j-1.7.25.jar
│       ├── layers-blog-snapshot-dependency-1-SNAPSHOT.jar
│       ├── log4j-api-2.10.0.jar
│       ├── log4j-to-slf4j-2.10.0.jar
│       ├── logback-classic-1.2.3.jar
│       ├── logback-core-1.2.3.jar
│       ├── slf4j-api-1.7.25.jar
│       ├── snakeyaml-1.19.jar
│       ├── spring-aop-5.0.9.RELEASE.jar
│       ├── spring-beans-5.0.9.RELEASE.jar
│       ├── spring-boot-2.0.5.RELEASE.jar
│       ├── spring-boot-autoconfigure-2.0.5.RELEASE.jar
│       ├── spring-boot-starter-2.0.5.RELEASE.jar
│       ├── spring-boot-starter-json-2.0.5.RELEASE.jar
│       ├── spring-boot-starter-logging-2.0.5.RELEASE.jar
│       ├── spring-boot-starter-tomcat-2.0.5.RELEASE.jar
│       ├── spring-boot-starter-web-2.0.5.RELEASE.jar
│       ├── spring-context-5.0.9.RELEASE.jar
│       ├── spring-core-5.0.9.RELEASE.jar
│       ├── spring-expression-5.0.9.RELEASE.jar
│       ├── spring-jcl-5.0.9.RELEASE.jar
│       ├── spring-web-5.0.9.RELEASE.jar
│       ├── spring-webmvc-5.0.9.RELEASE.jar
│       ├── tomcat-embed-core-8.5.34.jar
│       ├── tomcat-embed-el-8.5.34.jar
│       ├── tomcat-embed-websocket-8.5.34.jar
│       └── validation-api-2.0.1.Final.jar
├── META-INF
│   ├── MANIFEST.MF
│   └── maven
│       └── org.lukewpatterson
│           └── layers-blog-app
│               ├── pom.properties
│               └── pom.xml
└── org
    └── springframework
        └── boot
            └── loader
                ├── ExecutableArchiveLauncher.class
                ├── JarLauncher.class
                ├── LaunchedURLClassLoader$UseFastConnectionExceptionsEnumeration.class
                ├── LaunchedURLClassLoader.class
                ├── Launcher.class
                ├── MainMethodRunner.class
                ├── PropertiesLauncher$1.class
                ├── PropertiesLauncher$ArchiveEntryFilter.class
                ├── PropertiesLauncher$PrefixMatchingArchiveFilter.class
                ├── PropertiesLauncher.class
                ├── WarLauncher.class
                ├── archive
                │   ├── Archive$Entry.class
                │   ├── Archive$EntryFilter.class
                │   ├── Archive.class
                │   ├── ExplodedArchive$1.class
                │   ├── ExplodedArchive$FileEntry.class
                │   ├── ExplodedArchive$FileEntryIterator$EntryComparator.class
                │   ├── ExplodedArchive$FileEntryIterator.class
                │   ├── ExplodedArchive.class
                │   ├── JarFileArchive$EntryIterator.class
                │   ├── JarFileArchive$JarFileEntry.class
                │   └── JarFileArchive.class
                ├── data
                │   ├── RandomAccessData.class
                │   ├── RandomAccessDataFile$1.class
                │   ├── RandomAccessDataFile$DataInputStream.class
                │   ├── RandomAccessDataFile$FileAccess.class
                │   └── RandomAccessDataFile.class
                ├── jar
                │   ├── AsciiBytes.class
                │   ├── Bytes.class
                │   ├── CentralDirectoryEndRecord.class
                │   ├── CentralDirectoryFileHeader.class
                │   ├── CentralDirectoryParser.class
                │   ├── CentralDirectoryVisitor.class
                │   ├── FileHeader.class
                │   ├── Handler.class
                │   ├── JarEntry.class
                │   ├── JarEntryFilter.class
                │   ├── JarFile$1.class
                │   ├── JarFile$2.class
                │   ├── JarFile$JarFileType.class
                │   ├── JarFile.class
                │   ├── JarFileEntries$1.class
                │   ├── JarFileEntries$EntryIterator.class
                │   ├── JarFileEntries.class
                │   ├── JarURLConnection$1.class
                │   ├── JarURLConnection$JarEntryName.class
                │   ├── JarURLConnection.class
                │   ├── StringSequence.class
                │   └── ZipInflaterInputStream.class
                └── util
                    └── SystemPropertyUtils.class

20 directories, 92 files
/layers/
├── 1-dependencies-release
│   ├── BOOT-INF
│   │   └── lib
│   │       ├── classmate-1.3.4.jar
│   │       ├── hibernate-validator-6.0.12.Final.jar
│   │       ├── jackson-annotations-2.9.0.jar
│   │       ├── jackson-core-2.9.6.jar
│   │       ├── jackson-databind-2.9.6.jar
│   │       ├── jackson-datatype-jdk8-2.9.6.jar
│   │       ├── jackson-datatype-jsr310-2.9.6.jar
│   │       ├── jackson-module-parameter-names-2.9.6.jar
│   │       ├── javax.annotation-api-1.3.2.jar
│   │       ├── jboss-logging-3.3.2.Final.jar
│   │       ├── jul-to-slf4j-1.7.25.jar
│   │       ├── log4j-api-2.10.0.jar
│   │       ├── log4j-to-slf4j-2.10.0.jar
│   │       ├── logback-classic-1.2.3.jar
│   │       ├── logback-core-1.2.3.jar
│   │       ├── slf4j-api-1.7.25.jar
│   │       ├── snakeyaml-1.19.jar
│   │       ├── spring-aop-5.0.9.RELEASE.jar
│   │       ├── spring-beans-5.0.9.RELEASE.jar
│   │       ├── spring-boot-2.0.5.RELEASE.jar
│   │       ├── spring-boot-autoconfigure-2.0.5.RELEASE.jar
│   │       ├── spring-boot-starter-2.0.5.RELEASE.jar
│   │       ├── spring-boot-starter-json-2.0.5.RELEASE.jar
│   │       ├── spring-boot-starter-logging-2.0.5.RELEASE.jar
│   │       ├── spring-boot-starter-tomcat-2.0.5.RELEASE.jar
│   │       ├── spring-boot-starter-web-2.0.5.RELEASE.jar
│   │       ├── spring-context-5.0.9.RELEASE.jar
│   │       ├── spring-core-5.0.9.RELEASE.jar
│   │       ├── spring-expression-5.0.9.RELEASE.jar
│   │       ├── spring-jcl-5.0.9.RELEASE.jar
│   │       ├── spring-web-5.0.9.RELEASE.jar
│   │       ├── spring-webmvc-5.0.9.RELEASE.jar
│   │       ├── tomcat-embed-core-8.5.34.jar
│   │       ├── tomcat-embed-el-8.5.34.jar
│   │       ├── tomcat-embed-websocket-8.5.34.jar
│   │       └── validation-api-2.0.1.Final.jar
│   └── org
│       └── springframework
│           └── boot
│               └── loader
│                   ├── ExecutableArchiveLauncher.class
│                   ├── JarLauncher.class
│                   ├── LaunchedURLClassLoader$UseFastConnectionExceptionsEnumeration.class
│                   ├── LaunchedURLClassLoader.class
│                   ├── Launcher.class
│                   ├── MainMethodRunner.class
│                   ├── PropertiesLauncher$1.class
│                   ├── PropertiesLauncher$ArchiveEntryFilter.class
│                   ├── PropertiesLauncher$PrefixMatchingArchiveFilter.class
│                   ├── PropertiesLauncher.class
│                   ├── WarLauncher.class
│                   ├── archive
│                   │   ├── Archive$Entry.class
│                   │   ├── Archive$EntryFilter.class
│                   │   ├── Archive.class
│                   │   ├── ExplodedArchive$1.class
│                   │   ├── ExplodedArchive$FileEntry.class
│                   │   ├── ExplodedArchive$FileEntryIterator$EntryComparator.class
│                   │   ├── ExplodedArchive$FileEntryIterator.class
│                   │   ├── ExplodedArchive.class
│                   │   ├── JarFileArchive$EntryIterator.class
│                   │   ├── JarFileArchive$JarFileEntry.class
│                   │   └── JarFileArchive.class
│                   ├── data
│                   │   ├── RandomAccessData.class
│                   │   ├── RandomAccessDataFile$1.class
│                   │   ├── RandomAccessDataFile$DataInputStream.class
│                   │   ├── RandomAccessDataFile$FileAccess.class
│                   │   └── RandomAccessDataFile.class
│                   ├── jar
│                   │   ├── AsciiBytes.class
│                   │   ├── Bytes.class
│                   │   ├── CentralDirectoryEndRecord.class
│                   │   ├── CentralDirectoryFileHeader.class
│                   │   ├── CentralDirectoryParser.class
│                   │   ├── CentralDirectoryVisitor.class
│                   │   ├── FileHeader.class
│                   │   ├── Handler.class
│                   │   ├── JarEntry.class
│                   │   ├── JarEntryFilter.class
│                   │   ├── JarFile$1.class
│                   │   ├── JarFile$2.class
│                   │   ├── JarFile$JarFileType.class
│                   │   ├── JarFile.class
│                   │   ├── JarFileEntries$1.class
│                   │   ├── JarFileEntries$EntryIterator.class
│                   │   ├── JarFileEntries.class
│                   │   ├── JarURLConnection$1.class
│                   │   ├── JarURLConnection$JarEntryName.class
│                   │   ├── JarURLConnection.class
│                   │   ├── StringSequence.class
│                   │   └── ZipInflaterInputStream.class
│                   └── util
│                       └── SystemPropertyUtils.class
├── 2-dependencies-snapshot
│   └── BOOT-INF
│       └── lib
│           └── layers-blog-snapshot-dependency-1-SNAPSHOT.jar
└── 3-app
    ├── BOOT-INF
    │   └── classes
    │       ├── application.properties
    │       └── org
    │           └── lukewpatterson
    │               └── layers
    │                   └── blog
    │                       └── app
    │                           └── OurSpringBootApplication.class
    └── META-INF
        ├── MANIFEST.MF
        └── maven
            └── org.lukewpatterson
                └── layers-blog-app
                    ├── pom.properties
                    └── pom.xml

26 directories, 92 files

...
Step 19/24 : WORKDIR /app/
 ---> e83ac4cda8f7
Step 20/24 : COPY --from=build /layers/1-dependencies-release/ ./
 ---> d158e97b92fe
Step 21/24 : COPY --from=build /layers/2-dependencies-snapshot/ ./
 ---> bb5e6342aa80
Step 22/24 : COPY --from=build /layers/3-app/ ./
 ---> e0395252c3b1
Step 23/24 : RUN tree
.
├── BOOT-INF
│   ├── classes
│   │   ├── application.properties
│   │   └── org
│   │       └── lukewpatterson
│   │           └── layers
│   │               └── blog
│   │                   └── app
│   │                       └── OurSpringBootApplication.class
│   └── lib
│       ├── classmate-1.3.4.jar
│       ├── hibernate-validator-6.0.12.Final.jar
│       ├── jackson-annotations-2.9.0.jar
│       ├── jackson-core-2.9.6.jar
│       ├── jackson-databind-2.9.6.jar
│       ├── jackson-datatype-jdk8-2.9.6.jar
│       ├── jackson-datatype-jsr310-2.9.6.jar
│       ├── jackson-module-parameter-names-2.9.6.jar
│       ├── javax.annotation-api-1.3.2.jar
│       ├── jboss-logging-3.3.2.Final.jar
│       ├── jul-to-slf4j-1.7.25.jar
│       ├── layers-blog-snapshot-dependency-1-SNAPSHOT.jar
│       ├── log4j-api-2.10.0.jar
│       ├── log4j-to-slf4j-2.10.0.jar
│       ├── logback-classic-1.2.3.jar
│       ├── logback-core-1.2.3.jar
│       ├── slf4j-api-1.7.25.jar
│       ├── snakeyaml-1.19.jar
│       ├── spring-aop-5.0.9.RELEASE.jar
│       ├── spring-beans-5.0.9.RELEASE.jar
│       ├── spring-boot-2.0.5.RELEASE.jar
│       ├── spring-boot-autoconfigure-2.0.5.RELEASE.jar
│       ├── spring-boot-starter-2.0.5.RELEASE.jar
│       ├── spring-boot-starter-json-2.0.5.RELEASE.jar
│       ├── spring-boot-starter-logging-2.0.5.RELEASE.jar
│       ├── spring-boot-starter-tomcat-2.0.5.RELEASE.jar
│       ├── spring-boot-starter-web-2.0.5.RELEASE.jar
│       ├── spring-context-5.0.9.RELEASE.jar
│       ├── spring-core-5.0.9.RELEASE.jar
│       ├── spring-expression-5.0.9.RELEASE.jar
│       ├── spring-jcl-5.0.9.RELEASE.jar
│       ├── spring-web-5.0.9.RELEASE.jar
│       ├── spring-webmvc-5.0.9.RELEASE.jar
│       ├── tomcat-embed-core-8.5.34.jar
│       ├── tomcat-embed-el-8.5.34.jar
│       ├── tomcat-embed-websocket-8.5.34.jar
│       └── validation-api-2.0.1.Final.jar
├── META-INF
│   ├── MANIFEST.MF
│   └── maven
│       └── org.lukewpatterson
│           └── layers-blog-app
│               ├── pom.properties
│               └── pom.xml
└── org
    └── springframework
        └── boot
            └── loader
                ├── ExecutableArchiveLauncher.class
                ├── JarLauncher.class
                ├── LaunchedURLClassLoader$UseFastConnectionExceptionsEnumeration.class
                ├── LaunchedURLClassLoader.class
                ├── Launcher.class
                ├── MainMethodRunner.class
                ├── PropertiesLauncher$1.class
                ├── PropertiesLauncher$ArchiveEntryFilter.class
                ├── PropertiesLauncher$PrefixMatchingArchiveFilter.class
                ├── PropertiesLauncher.class
                ├── WarLauncher.class
                ├── archive
                │   ├── Archive$Entry.class
                │   ├── Archive$EntryFilter.class
                │   ├── Archive.class
                │   ├── ExplodedArchive$1.class
                │   ├── ExplodedArchive$FileEntry.class
                │   ├── ExplodedArchive$FileEntryIterator$EntryComparator.class
                │   ├── ExplodedArchive$FileEntryIterator.class
                │   ├── ExplodedArchive.class
                │   ├── JarFileArchive$EntryIterator.class
                │   ├── JarFileArchive$JarFileEntry.class
                │   └── JarFileArchive.class
                ├── data
                │   ├── RandomAccessData.class
                │   ├── RandomAccessDataFile$1.class
                │   ├── RandomAccessDataFile$DataInputStream.class
                │   ├── RandomAccessDataFile$FileAccess.class
                │   └── RandomAccessDataFile.class
                ├── jar
                │   ├── AsciiBytes.class
                │   ├── Bytes.class
                │   ├── CentralDirectoryEndRecord.class
                │   ├── CentralDirectoryFileHeader.class
                │   ├── CentralDirectoryParser.class
                │   ├── CentralDirectoryVisitor.class
                │   ├── FileHeader.class
                │   ├── Handler.class
                │   ├── JarEntry.class
                │   ├── JarEntryFilter.class
                │   ├── JarFile$1.class
                │   ├── JarFile$2.class
                │   ├── JarFile$JarFileType.class
                │   ├── JarFile.class
                │   ├── JarFileEntries$1.class
                │   ├── JarFileEntries$EntryIterator.class
                │   ├── JarFileEntries.class
                │   ├── JarURLConnection$1.class
                │   ├── JarURLConnection$JarEntryName.class
                │   ├── JarURLConnection.class
                │   ├── StringSequence.class
                │   └── ZipInflaterInputStream.class
                └── util
                    └── SystemPropertyUtils.class

20 directories, 92 files
Step 24/24 : CMD ["java", "org.springframework.boot.loader.JarLauncher"]
 ---> ffcb1a7c41eb
Successfully built ffcb1a7c41eb
Successfully tagged layers-blog:step-0-initial-build
parent 4dd98fe4
FROM maven:3.5.4-jdk-8-slim as build
# ignore until next comment, use tricks and aspects of layers unrelated to this blog to help reduce repeated build times
RUN apt-get update -qq && apt-get install -qq --assume-yes tree
WORKDIR /layers-blog-modules/
COPY ./pom.xml ./pom.xml
COPY ./layers-blog-snapshot-dependency/pom.xml ./layers-blog-snapshot-dependency/pom.xml
COPY ./layers-blog-app/pom.xml ./layers-blog-app/pom.xml
# ignore errors for the following command
RUN mvn org.apache.maven.plugins:maven-dependency-plugin:3.1.1:go-offline -Dorg.slf4j.simpleLogger.defaultLogLevel=OFF --strict-checksums --batch-mode --fail-never
RUN mvn de.qaware.maven:go-offline-maven-plugin:1.0.0:resolve-dependencies --quiet --strict-checksums --batch-mode
#
# maven-build the snapshot and app modules
#
WORKDIR ./layers-blog-snapshot-dependency/
COPY ./layers-blog-snapshot-dependency/ ./
RUN mvn install --quiet --update-snapshots --strict-checksums --batch-mode
WORKDIR ../layers-blog-app/
COPY layers-blog-app ./
RUN mvn package --quiet --update-snapshots --strict-checksums --batch-mode
WORKDIR ./target/
#
# https://docs.spring.io/spring-boot/docs/2.0.5.RELEASE/reference/htmlsingle/#executable-jar-jar-file-structure
# https://docs.spring.io/spring-boot/docs/2.0.5.RELEASE/reference/htmlsingle/#executable-jar-exploded-archives
# unzip and pre-separate into layers
#
RUN unzip -q *.jar -d ./unzipped/ \
# display exploded jar structure
&& tree ./unzipped/ \
# layer 3 - app-layer classes, resources and meta
&& mkdir --parents /layers/3-app/BOOT-INF/ \
&& mv ./unzipped/BOOT-INF/classes/ /layers/3-app/BOOT-INF/ \
&& mv ./unzipped/META-INF/ /layers/3-app/ \
# layer 2 - snapshot dependencies
&& mkdir --parents /layers/2-dependencies-snapshot/BOOT-INF/lib/ \
&& find ./unzipped/BOOT-INF/lib/ -type f -name '*-SNAPSHOT.jar' -exec mv {} /layers/2-dependencies-snapshot/BOOT-INF/lib/ ';' \
# layer 1 - (everything else) release dependencies and jarlauncher, also any items not accounted for in other layers
&& mv ./unzipped/ /layers/1-dependencies-release/ \
# display exploded jar structure, separated into layers
&& tree /layers/
FROM openjdk:8u181-alpine3.8 as run
# ignore until next comment
RUN apk add tree
# reconstitute exploded jar structure
WORKDIR /app/
COPY --from=build /layers/1-dependencies-release/ ./
COPY --from=build /layers/2-dependencies-snapshot/ ./
COPY --from=build /layers/3-app/ ./
# display reconstituted exploded jar structure
RUN tree
# https://docs.spring.io/spring-boot/docs/2.0.5.RELEASE/reference/htmlsingle/#executable-jar-exploded-archives
CMD ["java", "org.springframework.boot.loader.JarLauncher"]
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath></relativePath>
</parent>
<groupId>org.lukewpatterson</groupId>
<artifactId>layers-blog-app</artifactId>
<version>1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.lukewpatterson</groupId>
<artifactId>layers-blog-snapshot-dependency</artifactId>
<version>1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>io.github.zlika</groupId>
<artifactId>reproducible-build-maven-plugin</artifactId>
<version>0.7</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>strip-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package org.lukewpatterson.layers.blog.app;
import org.lukewpatterson.layers.blog.snapshot.dependency.ClassFromSnapshotDependency;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class OurSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(OurSpringBootApplication.class, args);
}
@RequestMapping("/")
public String index() {
return String.format("Value from App is [%s]. Value from Snapshot Dependency is [%s]", //
"app-rev-1", //
ClassFromSnapshotDependency.SOME_VALUE //
);
}
}
somekey=somevalue
\ No newline at end of file
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.lukewpatterson</groupId>
<artifactId>layers-blog-snapshot-dependency</artifactId>
<version>1-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>io.github.zlika</groupId>
<artifactId>reproducible-build-maven-plugin</artifactId>
<version>0.7</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>strip-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package org.lukewpatterson.layers.blog.snapshot.dependency;
public class ClassFromSnapshotDependency {
public static String SOME_VALUE = "snapshot-rev-1";
}
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.lukewpatterson</groupId>
<artifactId>layers-blog-modules</artifactId>
<version>1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>layers-blog-app</module>
<module>layers-blog-snapshot-dependency</module>
</modules>
</project>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment