diff --git a/.gitignore b/.gitignore
index 3622cd245b4976d460e4dc18c60ea895dfba32ce..7072e3190b74b3e07c5e0a8fb812a6a2e4ca8b74 100644
--- a/.gitignore
+++ b/.gitignore
@@ -67,3 +67,6 @@ build/
 
 ## iOS
 ios/robovm.properties
+
+## core
+core/gen
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index e9dad69e1bf1691da140766918e6f45d47a1072a..546fe3c7f33aa503501800a5c9e88f7873344fbf 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -7,6 +7,7 @@
     <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="21" />
 
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.INTERNET" />
 
     <application
         android:allowBackup="true"
diff --git a/android/assets/gfx/dialog_square_borderlines.9.png b/android/assets/gfx/dialog_square_borderlines.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..a41516c36eae47265b3a46da59cb53bd743f697d
Binary files /dev/null and b/android/assets/gfx/dialog_square_borderlines.9.png differ
diff --git a/android/assets/gfx/tablexiabutton_blank_blue_pressed.9.png b/android/assets/gfx/tablexiabutton_blank_blue_pressed.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..e543eec281f5155e2921ea83fa9f8fd6eac2449a
Binary files /dev/null and b/android/assets/gfx/tablexiabutton_blank_blue_pressed.9.png differ
diff --git a/android/assets/gfx/tablexiabutton_blank_blue_unpressed.9.png b/android/assets/gfx/tablexiabutton_blank_blue_unpressed.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..865dbe87982e2fd272faac8cdae581db4eaaac60
Binary files /dev/null and b/android/assets/gfx/tablexiabutton_blank_blue_unpressed.9.png differ
diff --git a/android/assets/gfx/tablexiabutton_blank_red_pressed.9.png b/android/assets/gfx/tablexiabutton_blank_red_pressed.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..6157c32a6353c81701cb3da4148fde24fd8544b3
Binary files /dev/null and b/android/assets/gfx/tablexiabutton_blank_red_pressed.9.png differ
diff --git a/android/assets/gfx/tablexiabutton_blank_red_unpressed.9.png b/android/assets/gfx/tablexiabutton_blank_red_unpressed.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..f770f4f0fde6b98d3072154e4f838a4945d9ecab
Binary files /dev/null and b/android/assets/gfx/tablexiabutton_blank_red_unpressed.9.png differ
diff --git a/android/assets/keystore/tablexiaTrustKeystore b/android/assets/keystore/tablexiaTrustKeystore
new file mode 100644
index 0000000000000000000000000000000000000000..c6fc6aa613a00d20a189b6bfcf97cdea8c8294f3
Binary files /dev/null and b/android/assets/keystore/tablexiaTrustKeystore differ
diff --git a/android/assets/text/application/application_cs.properties b/android/assets/text/application/application_cs.properties
index 095741916d6899b545f9b09cd664d333bf3724e3..75e1daab1450751ff5eb2efe90f2c96351d26cac 100644
--- a/android/assets/text/application/application_cs.properties
+++ b/android/assets/text/application/application_cs.properties
@@ -2,6 +2,11 @@ language_system=Systémový jazyk
 language_czech=Čeština
 language_slovak=Slovenština
 
+system_exit=Konec
+system_retry=Znovu
+
+zipassetloader_error=Chyba: Nemohu stáhnout dodatečná data! Zkontrolujte prosím připojení k internetu.
+
 mainmenu_games=Hry
 mainmenu_halloffame=Síň slávy
 mainmenu_statistics=Statistiky
diff --git a/android/assets/text/application/application_sk.properties b/android/assets/text/application/application_sk.properties
index ed092ed093b5b0a4f3ffe2c11c2ec8ea941ad0e4..93f5351b574f18a6b2f9f2d40ed993cf75824d08 100644
--- a/android/assets/text/application/application_sk.properties
+++ b/android/assets/text/application/application_sk.properties
@@ -2,6 +2,11 @@ language_system=Systémový jazyk
 language_czech=Čeština
 language_slovak=SlovenÄŤina
 
+system_exit=Koniec
+system_retry=Znovu
+
+zipassetloader_error=Chyba: Nemôžem stiahnuť dodatočná dáta! Skontrolujte prosím pripojenie k internetu.
+
 mainmenu_games=Hry
 mainmenu_halloffame=Sieň slávy
 mainmenu_statistics=Ĺ tatistiky
diff --git a/android/src/main/java/cz/nic/tablexia/android/AndroidLauncher.java b/android/src/main/java/cz/nic/tablexia/android/AndroidLauncher.java
index 2491f3a403b8b9cc55e9fb39d5bcdacef7757543..19741ef16cc00e57c8a617c54c6fc59d5e10b5af 100644
--- a/android/src/main/java/cz/nic/tablexia/android/AndroidLauncher.java
+++ b/android/src/main/java/cz/nic/tablexia/android/AndroidLauncher.java
@@ -14,7 +14,6 @@ import java.io.FileOutputStream;
 import cz.nic.tablexia.Tablexia;
 import cz.nic.tablexia.debug.BuildConfig;
 import cz.nic.tablexia.util.Log;
-import cz.nic.tablexia.util.Utility;
 
 public class AndroidLauncher extends AndroidApplication {
 
@@ -28,9 +27,7 @@ public class AndroidLauncher extends AndroidApplication {
         AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
         initialize(tablexia = new Tablexia(BuildConfig.BUILD_TYPE,
                                            getResources().getConfiguration().locale,
-                                           BuildConfig.VERSION_NAME,
                                            SQL_CONNECTION_TYPE,
-                                           Utility.createChecksumMapFromString(BuildConfig.ASSETS_CHECKSUMS),
                                            savedInstanceState == null), config);
     }
 
diff --git a/build.gradle b/build.gradle
index 549930ff26b380a9e07f65253ced24112d92e691..6281f1ab0c943aecd13059d679c3b87dc13ae3f0 100644
--- a/build.gradle
+++ b/build.gradle
@@ -21,9 +21,16 @@ final assetsDirName = "assets"
 final assetsSourceDirName = "src"
 final assetsDestinationDirName = "dest"
 
+final String ASSETS_DOWNLOAD_URL = "https://www.tablexia.cz/static/assets/"
+
+System.setProperty("javax.net.ssl.trustStore", new File("${project(":android").projectDir.absolutePath}/assets/keystore/tablexiaTrustKeystore").getAbsolutePath());
+System.setProperty("javax.net.ssl.trustStorePassword", "tablexia");
+
 ext {
     assetsChecksumPattern = "\"=======ASSETS_CHECKSUM=======\""
     assetsChecksum = [:]
+
+    assetsPackDir = new File("${rootProject.buildDir}/${assetsDirName}/pack/")
 }
 
 allprojects {
@@ -146,8 +153,8 @@ task zipAssets(dependsOn: [prepareSoundAssets, prepareGraphicAssets]) {
 
             if (!dir.name.equals('common')) {
                 task("${name}_${dir.name}", type: Zip) {
-                    archiveName = dir.getName() + ".zip"
-                    destinationDir = new File(project(":android").projectDir.absolutePath + "/${assetsDirName}")
+                    archiveName = dir.getName() + "_SNAPSHOT.zip"
+                    destinationDir = rootProject.ext.assetsPackDir
                     from "${buildDir}/${assetsDirName}/${assetsDestinationDirName}/${dir.name}"
                 }.execute()
             }
@@ -155,6 +162,35 @@ task zipAssets(dependsOn: [prepareSoundAssets, prepareGraphicAssets]) {
     }
 }
 
+task processAssets(dependsOn: [':util:checksum:runChecksum', ':util:checksum:runAssetsArchivesChecksum']) {
+    doLast {
+        if (project.hasProperty('TABLEXIA_ASSETS_SERVER_USER') && project.hasProperty('TABLEXIA_ASSETS_SERVER_URL')) {
+            def data = new URL(ASSETS_DOWNLOAD_URL).getText()
+            rootProject.ext.assetsPackDir.eachFile() { file ->
+                String fileName = file.getName()
+                String[] fileNameParts = fileName.split("_SNAPSHOT\\.");
+                String packageName = "${fileNameParts[0]}_${assetsChecksum[fileNameParts[0]]}.${fileNameParts[1]}";
+
+                boolean isProductionVersion = project.hasProperty('TABLEXIA_ASSETS_UPLOAD_PRODUCTION') && Boolean.valueOf(TABLEXIA_ASSETS_UPLOAD_PRODUCTION).booleanValue()
+                String uploadFileName = isProductionVersion ? packageName : fileName
+                if (!isProductionVersion || !data.contains(packageName)) {
+                    println "AssetsUploader: UPLOADING FILE: ${uploadFileName}"
+                    task ("${name}_${packageName}", type:Exec) {
+                        workingDir "${rootProject.projectDir}"
+                        commandLine 'scp', file.getAbsolutePath(), "${TABLEXIA_ASSETS_SERVER_USER}@${TABLEXIA_ASSETS_SERVER_URL}/${uploadFileName}"
+                        standardOutput = new ByteArrayOutputStream()
+                        ext.output = {
+                            return standardOutput.toString()
+                        }
+                    }.execute()
+                } else {
+                    println "AssetsUploader: FILE: ${packageName} EXISTS ON SERVER -> SKIPPING UPLOAD"
+                }
+            }
+        }
+    }
+}
+
 def getVersionNameFromGit() {
     def stdout = new ByteArrayOutputStream()
     exec {
@@ -264,7 +300,7 @@ project(":core") {
     apply plugin: "java"
 
     sourceSets.test.java.srcDirs = ["test/"]
-	tasks.processResources.dependsOn zipAssets
+	tasks.processResources.dependsOn processAssets
 
     dependencies {
         compile project(":util:checksum")
diff --git a/core/build.gradle b/core/build.gradle
index 03cd1bea21b97127a33a2662db7c063b93c0badd..c62a5d8b2c8fe48eea24830bbb931f986a815216 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -1,11 +1,44 @@
 apply plugin: "java"
 
+final String GEN_DIRECTORY = "gen/"
+final String TABLEXIA_PACKAGE_PATH = "${GEN_DIRECTORY}cz/nic/tablexia/"
+final String BUILD_CONFIG_FILE = "${TABLEXIA_PACKAGE_PATH}TablexiaBuildConfig.java"
+final String BUILD_CONFIG_FILE_ENCODING = "UTF-8"
+
 sourceCompatibility = 1.6
 [compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
 
-sourceSets.main.java.srcDirs = [ "src/" ]
+sourceSets.main.java.srcDirs = ["src/", "gen/"]
 
 
 eclipse.project {
     name = appName + "-core"
 }
+
+clean {
+    delete GEN_DIRECTORY
+}
+
+task writeTablexiaBuildConfig {
+    dependsOn(':util:checksum:runChecksum')
+    doLast {
+        File folder = file(TABLEXIA_PACKAGE_PATH)
+        if (!folder.exists()) {
+            folder.mkdirs()
+        }
+        File buildConfigFile = file(BUILD_CONFIG_FILE)
+        buildConfigFile.write("package cz.nic.tablexia;\n" +
+                "\n" +
+                "/**\n" +
+                " * Automatically generated file. Do not modify or add to repository!\n" +
+                " */\n" +
+                "public class TablexiaBuildConfig {\n" +
+                "\n" +
+                "    public final static String VERSION_NAME = \"${tablexiaVersionName}\";\n" +
+                "    public final static String ASSETS_CHECKSUM = \"${getMapConvertedToString(rootProject.ext.assetsChecksum)}\";\n" +
+                "\n" +
+                "}", BUILD_CONFIG_FILE_ENCODING)
+    }
+}
+
+compileJava.dependsOn writeTablexiaBuildConfig
diff --git a/core/src/cz/nic/tablexia/Tablexia.java b/core/src/cz/nic/tablexia/Tablexia.java
index 8fce48ad91537ca48365b0f7c7d99135b1580014..7f99a093b32d73f1d6436fc850d59ec11e129ce5 100644
--- a/core/src/cz/nic/tablexia/Tablexia.java
+++ b/core/src/cz/nic/tablexia/Tablexia.java
@@ -3,6 +3,11 @@ package cz.nic.tablexia;
 import com.badlogic.gdx.Application;
 import com.badlogic.gdx.Gdx;
 import com.badlogic.gdx.graphics.GL30;
+import com.badlogic.gdx.graphics.Texture;
+import com.badlogic.gdx.graphics.g2d.NinePatch;
+import com.badlogic.gdx.scenes.scene2d.InputEvent;
+import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
+import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable;
 
 import net.engio.mbassy.listener.Handler;
 
@@ -24,15 +29,28 @@ import cz.nic.tablexia.screen.AbstractTablexiaScreen;
 import cz.nic.tablexia.screen.loader.LoaderScreen;
 import cz.nic.tablexia.util.Log;
 import cz.nic.tablexia.util.Utility;
+import cz.nic.tablexia.util.ui.TablexiaButton;
+import cz.nic.tablexia.util.ui.dialog.AbstractButtonDialog;
+import cz.nic.tablexia.util.ui.dialog.text.DialogTextContent;
 
 public class Tablexia extends TablexiaApplication {
 
+    private static final String INTERNAL_GFX_ASSETS_PATH                = "gfx/";
+    public static final String  ERROR_DIALOG_BACKGROUND_INTERNAL        = INTERNAL_GFX_ASSETS_PATH + "dialog_square_borderlines.9.png";
+    public static final String  ERROR_BUTTON_BLUE_UNPRESSED_INTERNAL    = INTERNAL_GFX_ASSETS_PATH + "tablexiabutton_blank_blue_unpressed.9.png";
+    public static final String  ERROR_BUTTON_BLUE_PRESSED_INTERNAL      = INTERNAL_GFX_ASSETS_PATH + "tablexiabutton_blank_blue_pressed.9.png";
+    public static final String  ERROR_BUTTON_RED_UNPRESSED_INTERNAL     = INTERNAL_GFX_ASSETS_PATH + "tablexiabutton_blank_red_unpressed.9.png";
+    public static final String  ERROR_BUTTON_RED_PRESSED_INTERNAL       = INTERNAL_GFX_ASSETS_PATH + "tablexiabutton_blank_red_pressed.9.png";
+    public static final int     ERROR_DIALOG_WIDTH                      = 400;
+    public static final int     ERROR_DIALOG_HEIGHT                     = 250;
+
     private final SQLConnectionType     sqlConnectionType;
     private boolean                     loadingComplete = false;
     private MainMenuContainer           mainMenuContainer;
     private ZipAssetLoader              zipAssetLoader;
-    private Map<String, String>         buildChecksums;
     private boolean                     reset;
+    private boolean                     errorDialogShown = false;
+    private ScreenshotListener          screenshotListener;
 
     public static class SQLConnectionType {
 
@@ -53,12 +71,11 @@ public class Tablexia extends TablexiaApplication {
         }
     }
 
-    public Tablexia(String buildTypeKey, Locale systemLocale, String versionName, SQLConnectionType sqlConnectionType, Map<String, String> buildChecksums, boolean reset) {
+    public Tablexia(String buildType, Locale systemLocale, SQLConnectionType sqlConnectionType, boolean reset) {
         this.reset = reset;
-        this.buildChecksums = buildChecksums;
         this.sqlConnectionType = sqlConnectionType;
 
-        TablexiaSettings.init(buildTypeKey, systemLocale, versionName);
+        TablexiaSettings.init(buildType, systemLocale);
     }
 
     private void loadingComplete() {
@@ -100,7 +117,7 @@ public class Tablexia extends TablexiaApplication {
         ApplicationTextManager.getInstance().load(locale);
         // async zip extraction
         zipAssetLoader = new ZipAssetLoader();
-        zipAssetLoader.load(locale, buildChecksums);
+        zipAssetLoader.load(locale, Utility.createChecksumMapFromString(TablexiaBuildConfig.ASSETS_CHECKSUM));
         // async external assets loading
         ApplicationAtlasManager.getInstance().load();
         ApplicationSoundManager.getInstance().load();
@@ -182,8 +199,11 @@ public class Tablexia extends TablexiaApplication {
             // load internal assets
             if (!ApplicationFontManager.getInstance().update()) return;
             if (!ApplicationTextManager.getInstance().update()) return;
+
             // load external assets
             if (!zipAssetLoader.update()) return;
+            if (processLoaderError(zipAssetLoader.getError()))   return;
+
             if (!ApplicationAtlasManager.getInstance().update()) return;
             if (!ApplicationSoundManager.getInstance().update()) return;
 
@@ -192,8 +212,6 @@ public class Tablexia extends TablexiaApplication {
         }
     }
 
-    ScreenshotListener screenshotListener;
-
     /**
      * Queues request for screenshot with this listener, it is called after obtaining screenshot.
      *
@@ -237,7 +255,62 @@ public class Tablexia extends TablexiaApplication {
     }
 
 
-//////////////////////////// APPLICATION LOADING COMPLETE EVENT
+//////////////////////////// APPLICATION LOADERS
+
+    private class LoaderErrorDialog extends AbstractButtonDialog {
+
+        public LoaderErrorDialog(float width, float height, DialogTextContent dialogTextContent) {
+            super((Gdx.graphics.getWidth() / 2) - (width / 2),
+                    (Gdx.graphics.getHeight() / 2) - (height / 2),
+                    width,
+                    height,
+                    new NinePatchDrawable(new NinePatch(new Texture(Gdx.files.internal(ERROR_DIALOG_BACKGROUND_INTERNAL)))),
+                    dialogTextContent);
+
+            setModal(true);
+
+            createButton(ERROR_BUTTON_BLUE_UNPRESSED_INTERNAL,
+                         ERROR_BUTTON_BLUE_PRESSED_INTERNAL,
+                         ApplicationTextManager.SYSTEM_RETRY,
+                         new ClickListener() {
+
+                @Override
+                public void clicked(InputEvent event, float x, float y) {
+                    zipAssetLoader.reset();
+                    errorDialogShown = false;
+                    hide();
+                }
+            });
+
+            createButton(ERROR_BUTTON_RED_UNPRESSED_INTERNAL,
+                         ERROR_BUTTON_RED_PRESSED_INTERNAL,
+                         ApplicationTextManager.SYSTEM_EXIT,
+                         new ClickListener() {
+
+                @Override
+                public void clicked(InputEvent event, float x, float y) {
+                    Gdx.app.exit();
+                }
+            });
+        }
+
+        private void createButton(String unpressed, String pressed, String textKey, ClickListener clickListener) {
+            TablexiaButton button = new TablexiaButton(new NinePatchDrawable(new NinePatch(new Texture(Gdx.files.internal(unpressed)))),
+                                                       new NinePatchDrawable(new NinePatch(new Texture(Gdx.files.internal(pressed)))),
+                                                       null,
+                                                       ApplicationTextManager.getInstance().getText(textKey));
+
+            createButton(button, clickListener);
+        }
+    }
+
+    private boolean processLoaderError(String loaderError) {
+        if (loaderError != null && !errorDialogShown) {
+            new LoaderErrorDialog(ERROR_DIALOG_WIDTH, ERROR_DIALOG_HEIGHT, new DialogTextContent(loaderError)).show(getStage());
+            errorDialogShown = true;
+        }
+        return errorDialogShown;
+    }
 
     public static class ApplicationLoadingCompleteEvent implements ApplicationEvent {
     }
diff --git a/core/src/cz/nic/tablexia/TablexiaSettings.java b/core/src/cz/nic/tablexia/TablexiaSettings.java
index 1fd0e5349368409fb4aed9fb1e836a2cc7175087..a1be63b1432613913216c2e5bff90767f65ca861 100644
--- a/core/src/cz/nic/tablexia/TablexiaSettings.java
+++ b/core/src/cz/nic/tablexia/TablexiaSettings.java
@@ -29,11 +29,12 @@ public class TablexiaSettings {
     private static final String PREFERENCES_KEY    = "cz.nic.tablexia.";
     public static final  String LOCALE_KEY         = "locale";
 
-    private static final String IDE_BUILD_VERSION_NAME = "DEVEL";
+    private static final String IDE_BUILD_VERSION_NAME  = "DEVEL";
+    public  static final String DEV_VERSION_TYPE        = "-DEV-";
 
 
     private final BuildType BUILD_TYPE;
-    private final String    VERSION_NAME;
+    private final String    VERSION_NAME = TablexiaBuildConfig.VERSION_NAME;
 
     private Preferences      preferences;
     private LocaleDefinition systemLocale;
@@ -140,9 +141,8 @@ public class TablexiaSettings {
 
     private static TablexiaSettings instance;
 
-    private TablexiaSettings(BuildType buildType, Locale systemLocale, String versionName) {
+    private TablexiaSettings(BuildType buildType, Locale systemLocale) {
         BUILD_TYPE = buildType;
-        VERSION_NAME = versionName == null ? IDE_BUILD_VERSION_NAME : versionName;
         this.systemLocale = LocaleDefinition.getLocaleDefinitionForLocale(systemLocale);
     }
 
@@ -155,18 +155,18 @@ public class TablexiaSettings {
         return instance;
     }
 
-    static void init(String buildTypeKey, Locale systemLocale, String versionName) {
-        TablexiaSettings.init(BuildType.getBuildTypeForKey(buildTypeKey), systemLocale, versionName);
+    static void init(String buildTypeKey, Locale systemLocale) {
+        TablexiaSettings.init(BuildType.getBuildTypeForKey(buildTypeKey), systemLocale);
     }
 
-    static void init(BuildType buildType, Locale systemLocale, String versionName) {
+    static void init(BuildType buildType, Locale systemLocale) {
         if (instance != null) {
             String exceptionMessage = "Tablexia settings already initialized!";
             Log.err(TablexiaSettings.class, exceptionMessage);
             throw new IllegalStateException(exceptionMessage);
         }
 
-        instance = new TablexiaSettings(buildType, systemLocale, versionName);
+        instance = new TablexiaSettings(buildType, systemLocale);
     }
 
     void dispose() {
diff --git a/core/src/cz/nic/tablexia/loader/TablexiaAbstractFileManager.java b/core/src/cz/nic/tablexia/loader/TablexiaAbstractFileManager.java
index ec8ccc68c65fcf79b85101a0eb685904d04a89d4..028d1cdbbfb1d8d960144a634a10cfd74532134c 100644
--- a/core/src/cz/nic/tablexia/loader/TablexiaAbstractFileManager.java
+++ b/core/src/cz/nic/tablexia/loader/TablexiaAbstractFileManager.java
@@ -115,6 +115,54 @@ public abstract class TablexiaAbstractFileManager extends AssetManager {
         }
     }
 
+    public enum DownloadStorageType implements StorageType {
+
+        INTERNAL(RootStorageType.INTERNAL, DownloadStorageType.DOWNLOAD_DIRECTORY),
+        EXTERNAL(RootStorageType.EXTERNAL, DownloadStorageType.DOWNLOAD_DIRECTORY);
+
+        public static final String DOWNLOAD_DIRECTORY = "download/";
+
+        private String storagePath;
+        private FileHandleResolver resolver;
+
+        DownloadStorageType(RootStorageType rootStorageType, String assetsPath) {
+            this.storagePath = rootStorageType.getStoragePath() + assetsPath;
+            this.resolver = rootStorageType.getResolver();
+        }
+
+        public String getStoragePath() {
+            return storagePath;
+        }
+
+        public FileHandleResolver getResolver() {
+            return resolver;
+        }
+    }
+
+    public enum KeystoreStorageType implements StorageType {
+
+        INTERNAL(RootStorageType.INTERNAL, KeystoreStorageType.KEYSTORE_DIRECTORY),
+        EXTERNAL(RootStorageType.EXTERNAL, KeystoreStorageType.KEYSTORE_DIRECTORY);
+
+        public static final String KEYSTORE_DIRECTORY = "keystore/";
+
+        private String storagePath;
+        private FileHandleResolver resolver;
+
+        KeystoreStorageType(RootStorageType rootStorageType, String assetsPath) {
+            this.storagePath = rootStorageType.getStoragePath() + assetsPath;
+            this.resolver = rootStorageType.getResolver();
+        }
+
+        public String getStoragePath() {
+            return storagePath;
+        }
+
+        public FileHandleResolver getResolver() {
+            return resolver;
+        }
+    }
+
     public static FileHandle getFileStoragePathFileHandle(StorageType storageType, String additionalPath) {
         return storageType.getResolver().resolve(storageType.getStoragePath() + additionalPath);
     }
diff --git a/core/src/cz/nic/tablexia/loader/application/ApplicationTextManager.java b/core/src/cz/nic/tablexia/loader/application/ApplicationTextManager.java
index 493054d9c7216cb6ab4d804382ee145284fd089d..c98e7c08b204f868d9251cf7b8c2a8c85ac69ef9 100644
--- a/core/src/cz/nic/tablexia/loader/application/ApplicationTextManager.java
+++ b/core/src/cz/nic/tablexia/loader/application/ApplicationTextManager.java
@@ -25,9 +25,14 @@ public class ApplicationTextManager extends TablexiaDataManager<I18NBundle> impl
 	
 	private static final String APPLICATION_TEXT_RESOURCE_FILE = "text/application/application";
 
-    public static final String LANGUAGE_SYSTEM = "language_system";
-    public static final String LANGUAGE_CZECH  = "language_czech";
-    public static final String LANGUAGE_SLOVAK = "language_slovak";
+	public static final String SYSTEM_EXIT 			= "system_exit";
+	public static final String SYSTEM_RETRY			= "system_retry";
+
+	public static final String ZIPASSETLOADER_ERROR	= "zipassetloader_error";
+
+    public static final String LANGUAGE_SYSTEM 		= "language_system";
+    public static final String LANGUAGE_CZECH  		= "language_czech";
+    public static final String LANGUAGE_SLOVAK 		= "language_slovak";
 
 	private static class ApplicationTextLoader implements AsyncTask<I18NBundle> {
 
diff --git a/core/src/cz/nic/tablexia/loader/zip/ZipAssetLoader.java b/core/src/cz/nic/tablexia/loader/zip/ZipAssetLoader.java
index 8f2b68b726b8b7ae10733791f78d6b55044c8a9f..a5468a95288b8344d217900a33fd4331f85f4754 100644
--- a/core/src/cz/nic/tablexia/loader/zip/ZipAssetLoader.java
+++ b/core/src/cz/nic/tablexia/loader/zip/ZipAssetLoader.java
@@ -1,5 +1,7 @@
 package cz.nic.tablexia.loader.zip;
 
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.Net;
 import com.badlogic.gdx.files.FileHandle;
 import com.badlogic.gdx.utils.async.AsyncTask;
 
@@ -8,6 +10,8 @@ import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.security.NoSuchAlgorithmException;
 import java.util.Locale;
 import java.util.Map;
@@ -15,10 +19,13 @@ import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 
 import cz.nic.tablexia.TablexiaSettings;
+import cz.nic.tablexia.bus.ApplicationBus;
 import cz.nic.tablexia.checksum.Checksum;
 import cz.nic.tablexia.loader.IApplicationLoader;
 import cz.nic.tablexia.loader.TablexiaAbstractFileManager;
 import cz.nic.tablexia.loader.TablexiaDataManager;
+import cz.nic.tablexia.loader.application.ApplicationTextManager;
+import cz.nic.tablexia.screen.AbstractTablexiaScreen;
 import cz.nic.tablexia.util.Log;
 
 /**
@@ -29,8 +36,41 @@ import cz.nic.tablexia.util.Log;
  */
 public class ZipAssetLoader extends TablexiaDataManager<Void> implements IApplicationLoader {
 
-    public static final TablexiaAbstractFileManager.RootStorageType ZIP_FILES_STORAGE_TYPE         = TablexiaAbstractFileManager.RootStorageType.INTERNAL;
-    public static final String                                      ZIP_FILE_EXTENSION             = ".zip";
+    public static final TablexiaAbstractFileManager.StorageType     ZIP_FILES_STORAGE_TYPE              = TablexiaAbstractFileManager.DownloadStorageType.EXTERNAL;
+    public static final String                                      ZIP_FILE_EXTENSION                  = ".zip";
+    public static final String                                      CHECKSUM_FILE_EXTENSION             = ".checksum";
+    private static final String                                     TABLEXIA_ASSETS_DOWNLOAD_BASE_PATH  = "https://www.tablexia.cz/static/assets/";
+    private static final int                                        TABLEXIA_ASSETS_DOWNLOAD_TIMEOUT    = 2500;
+    private static final String                                     TABLEXIA_TRUST_KEYSTORE_NAME        = "tablexiaTrustKeystore";
+    private static final String                                     TABLEXIA_TRUST_KEYSTORE_PASSWORD    = "tablexia";
+    private static final String                                     SNAPSHOT_PACKAGE_NAME               = "SNAPSHOT";
+
+    public static final int                                         DOWNLOAD_TRY_COUNT                  = 3;
+    private static final Object                                     LOCK                                = new Object();
+
+
+    private static boolean                                          downloadResult                      = false;
+    private static boolean                                          downloadHasResult                   = false;
+    private static Long                                             startTime                           = null;
+    private static boolean                                          error                               = false;
+
+    private Locale                                                  locale;
+    private Map<String, String>                                     buildChecksum;
+
+    public void load(Locale locale, Map<String, String> buildChecksum) {
+        this.locale = locale;
+        this.buildChecksum = buildChecksum;
+        reset();
+    }
+
+    public void reset() {
+        error = false;
+        downloadResult = false;
+        downloadHasResult = false;
+        startTime = null;
+
+        setAsyncTask(new ZipAssetLoaderTask(locale, buildChecksum));
+    }
 
     private static class ZipAssetLoaderTask implements AsyncTask<Void> {
 
@@ -42,12 +82,89 @@ public class ZipAssetLoader extends TablexiaDataManager<Void> implements IApplic
             this.buildChecksums = buildChecksums;
         }
 
+		@Override
+		public Void call() throws Exception {
+            String language = locale.getLanguage();
+            String extractDestinationDirectory = TablexiaAbstractFileManager.getFileStoragePath(TablexiaAbstractFileManager.AssetsStorageType.EXTERNAL);
+
+            if (buildChecksums != null) {
+                String buildChecksum = buildChecksums.get(language);
+                if (buildChecksum != null) {
+
+                    // check current content
+                    Log.info(ZipAssetLoader.class, "Assets check started...");
+                    startTimer();
+                    boolean checksumResult = checkAssets((buildChecksum), extractDestinationDirectory);
+                    resultTimer("Assets check delay");
+                    if (checksumResult) {
+                        Log.info(ZipAssetLoader.class, "Assets check OK!");
+                        Log.info(ZipAssetLoader.class, "Continue to loading");
+                        return null;
+                    }
+                    Log.info(ZipAssetLoader.class, "Assets check FAILED!");
+
+
+                    String assetsPackageName = language + "_" + buildChecksum;
+                    String zipAssetsPackageName = assetsPackageName + ZIP_FILE_EXTENSION;
+                    FileHandle assetsPackageFileHandle = TablexiaAbstractFileManager.getFileStoragePathFileHandle(ZIP_FILES_STORAGE_TYPE, zipAssetsPackageName);
+
+                    // check current package file and download it if it is necessary
+                    boolean usedSnapshot = false;
+                    prepareKeyStore();
+                    if (TablexiaSettings.getInstance().getVersionName().contains(TablexiaSettings.DEV_VERSION_TYPE) || TablexiaSettings.getInstance().getBuildType() == TablexiaSettings.BuildType.DEVEL) {
+                        Log.info(ZipAssetLoader.class, "Devel mode --> try to use SNAPSHOT assets package");
+                        String snapshotAssetsPackageName = language + "_" + SNAPSHOT_PACKAGE_NAME;
+                        String snapshotZipAssetsPackageName = snapshotAssetsPackageName + ZIP_FILE_EXTENSION;
+                        if (checkAndDownload(snapshotAssetsPackageName)) {
+                            usedSnapshot = true;
+                            assetsPackageFileHandle = TablexiaAbstractFileManager.getFileStoragePathFileHandle(ZIP_FILES_STORAGE_TYPE, snapshotZipAssetsPackageName);
+                        } else {
+                            Log.err(getClass(), String.format("Cannot download assets package: %s", snapshotZipAssetsPackageName));
+                        }
+                    }
+                    if (!usedSnapshot && !checkAndDownload(assetsPackageName)) {
+                        error(getClass(), String.format("Cannot download assets package: %s", zipAssetsPackageName));
+                        return null;
+                    }
+
+
+                    // delete modified or old content
+                    File eddFile = new File(extractDestinationDirectory);
+                    if (eddFile.exists()) {
+                        Log.info(ZipAssetLoader.class, "Found invalid assets content!");
+                        Log.info(ZipAssetLoader.class, String.format("Deleting content under: %s", extractDestinationDirectory));
+                        startTimer();
+                        deleteDirectory(eddFile);
+                        resultTimer("Delete delay");
+                    }
+
+
+                    // extract new content
+                    Log.info(ZipAssetLoader.class, String.format("Extracting new content to: %s", extractDestinationDirectory));
+                    startTimer();
+                    // TODO check full disk situation
+                    unzip(assetsPackageFileHandle, extractDestinationDirectory);
+                    resultTimer("Extract delay");
+
+                } else {
+                    error(getClass(), "BUILD CHECKSUM: no build checksum specified for language " + language);
+                }
+            } else {
+                error(getClass(), "BUILD CHECKSUM: no build checksum specified");
+            }
+
+			return null;
+		}
+
+
+//////////////////////////// CHECK
+
         private boolean checkAssets(String buildChecksum, String extractDestinationDirectory) {
             File file = new File(extractDestinationDirectory);
             if (file.exists() && file.isDirectory()) {
                 try {
                     String runtimeChecksum = Checksum.getMd5OfDir(file);
-                    Log.debug(getClass(), "Comparing assets checksums: [BUILD: " + buildChecksum + "] - [RUNTIME: " + runtimeChecksum + "]");
+                    Log.debug(ZipAssetLoader.class, "Comparing assets checksums: [BUILD: " + buildChecksum + "] - [RUNTIME: " + runtimeChecksum + "]");
                     return runtimeChecksum.equals(buildChecksum);
                 } catch (NoSuchAlgorithmException e) {
                     Log.err(getClass(), "Cannot get checksum for assets!", e);
@@ -58,59 +175,150 @@ public class ZipAssetLoader extends TablexiaDataManager<Void> implements IApplic
             return false;
         }
 
-		@Override
-		public Void call() throws Exception {
-            String language = locale.getLanguage();
-            String extractDestinationDirectory = TablexiaAbstractFileManager.getFileStoragePath(TablexiaAbstractFileManager.AssetsStorageType.EXTERNAL);
-
-            Long startTime = null;
-            if (TablexiaSettings.getInstance().isDebug()) {
-                startTime = System.nanoTime();
+        private boolean checkAssetsPackage(FileHandle downloadedChecksum, FileHandle downloadedFile) {
+            if (downloadedFile.exists() && !downloadedFile.isDirectory()) {
+                try {
+                    String fileChecksum = Checksum.getMd5OfFile(downloadedFile.file());
+                    String controlChecksum = downloadedChecksum.readString();
+                    Log.debug(ZipAssetLoader.class, "Comparing assets package checksum: [PACKAGE: " + fileChecksum + "] - [CONTROL: " + controlChecksum + "]");
+                    return fileChecksum.equals(controlChecksum);
+                } catch (NoSuchAlgorithmException e) {
+                    Log.err(getClass(), "Cannot get checksum for assets package!", e);
+                } catch (IOException e) {
+                    Log.err(getClass(), "Cannot get checksum for assets package!", e);
+                }
             }
+            return false;
+        }
 
-            // check current content
-            if (buildChecksums != null) {
-                String buildChecksum = buildChecksums.get(language);
-                if (buildChecksum != null) {
-                    boolean checksumResult = checkAssets((buildChecksum), extractDestinationDirectory);
-                    if (startTime != null) {
-                        Log.debug(getClass(), String.format("Checksum delay: %05f s", (System.nanoTime() - startTime) / 1000000000.0));
-                    }
-                    if (checksumResult) {
-                        Log.info(getClass(), "Assets check OK! --> Continue to loading");
-                        return null;
+
+//////////////////////////// DOWNLOAD
+
+        private void prepareKeyStore() {
+            FileHandle keystoreExternal = TablexiaAbstractFileManager.getFileStoragePathFileHandle(TablexiaAbstractFileManager.KeystoreStorageType.EXTERNAL, TABLEXIA_TRUST_KEYSTORE_NAME);
+            FileHandle keystoreInternal = TablexiaAbstractFileManager.getFileStoragePathFileHandle(TablexiaAbstractFileManager.KeystoreStorageType.INTERNAL, TABLEXIA_TRUST_KEYSTORE_NAME);
+            keystoreExternal.write(keystoreInternal.read(), false);
+
+            System.setProperty("javax.net.ssl.trustStore", keystoreExternal.file().getAbsolutePath());
+            System.setProperty("javax.net.ssl.trustStorePassword", TABLEXIA_TRUST_KEYSTORE_PASSWORD);
+        }
+
+        private boolean checkAndDownload(final String fileName) {
+            int tryCounter = 0;
+            String zipFileName = fileName + ZIP_FILE_EXTENSION;
+            String checksumFileName = fileName + CHECKSUM_FILE_EXTENSION;
+
+            // load checksum and package file
+            FileHandle zipFileHandle = TablexiaAbstractFileManager.getFileStoragePathFileHandle(TablexiaAbstractFileManager.DownloadStorageType.EXTERNAL, zipFileName);
+            FileHandle checksumFileHandle = TablexiaAbstractFileManager.getFileStoragePathFileHandle(TablexiaAbstractFileManager.DownloadStorageType.EXTERNAL, checksumFileName);
+
+            while (true) {
+                // check if checksum and package file exists
+                if (checksumFileHandle.exists() && zipFileHandle.exists()) {
+                    if (checkAssetsPackage(checksumFileHandle, zipFileHandle)) {
+                        Log.info(ZipAssetLoader.class, String.format("Valid assets package file: %s", zipFileName));
+                        return true;
+                    } else {
+                        Log.info(ZipAssetLoader.class, String.format("Malformed assets package file: %s", zipFileName));
                     }
                 } else {
-                    Log.err(getClass(), "BUILD CHECKSUM: no build checksum specified for language " + language);
+                    Log.info(ZipAssetLoader.class, String.format("Checksum or assets package file not found!", zipFileName));
+                }
+
+                if (tryCounter >= DOWNLOAD_TRY_COUNT) {
+                    return false;
                 }
-            } else {
-                Log.err(getClass(), "BUILD CHECKSUM: no build checksum specified");
-            }
 
-            if (TablexiaSettings.getInstance().isDebug()) {
-                startTime = System.nanoTime();
+                // download assets package checksum
+                Log.info(ZipAssetLoader.class, String.format("Downloading checksum file: %s try %d/%d", checksumFileName, tryCounter + 1, DOWNLOAD_TRY_COUNT));
+                startTimer();
+                downloadToOutputStream(fileName + CHECKSUM_FILE_EXTENSION, checksumFileHandle.write(false));
+                resultTimer("Download delay of " + checksumFileName);
+                // download assets package file
+                Log.info(ZipAssetLoader.class, String.format("Downloading assets package file: %s try %d/%d", zipFileName, tryCounter + 1, DOWNLOAD_TRY_COUNT));
+                startTimer();
+                downloadToOutputStream(fileName + ZIP_FILE_EXTENSION, zipFileHandle.write(false));
+                resultTimer("Download delay of " + zipFileName);
+
+                tryCounter++;
             }
+        }
+
+        private boolean downloadToOutputStream(final String fileName, final OutputStream os) {
+            downloadHasResult = false;
+
+            Net.HttpRequest request = new Net.HttpRequest(Net.HttpMethods.GET);
+            request.setTimeOut(TABLEXIA_ASSETS_DOWNLOAD_TIMEOUT);
+            request.setUrl(TABLEXIA_ASSETS_DOWNLOAD_BASE_PATH + fileName);
+
+            Gdx.net.sendHttpRequest(request, new Net.HttpResponseListener() {
+
+                @Override
+                public void handleHttpResponse(Net.HttpResponse httpResponse) {
+                    long length = Long.parseLong(httpResponse.getHeader("Content-Length"));
+
+                    InputStream is = httpResponse.getResultAsStream();
+
+                    byte[] bytes = new byte[1024];
+                    int count = -1;
+                    long read = 0;
+                    try {
+                        while ((count = is.read(bytes, 0, bytes.length)) != -1) {
+                            os.write(bytes, 0, count);
+                            read += count;
+
+                            final int progress = ((int) (((double) read / (double) length) * 100));
+                            ApplicationBus.getInstance().post(new AbstractTablexiaScreen.ScreenInfoEvent("Downloading: ", fileName + " [ " + progress + "% ]")).asynchronously();
+                        }
+
+                        downloadResult = true;
+                    } catch (IOException e) {
+                        Log.err(ZipAssetLoader.class, "Cannot download file: " + fileName + " !", e);
+                        downloadResult = false;
+                    }
+                    notifyDownload();
+                }
+
+                @Override
+                public void failed(Throwable t) {
+                    Log.err(ZipAssetLoader.class, "Downloading of file: " + fileName + " Failed!", t);
+                    downloadResult = false;
+                    notifyDownload();
+                }
+
+                @Override
+                public void cancelled() {
+                    Log.info(ZipAssetLoader.class, "Downloading of file: " + fileName + " Canceled!");
+                    downloadResult = false;
+                    notifyDownload();
+                }
+            });
 
-            // delete modified or old content
-            File eddFile = new File(extractDestinationDirectory);
-            if (eddFile.exists()) {
-                Log.info(getClass(), "Assets check FAILED! --> Deleting content under: " + extractDestinationDirectory);
-                deleteDirectory(eddFile);
+            // wait to download complete
+            synchronized (LOCK) {
+                if (!downloadHasResult) {
+                    try {
+                        LOCK.wait();
+                    } catch (InterruptedException e) {
+                        Log.err(ZipAssetLoader.class, "Cannot wait to download end!", e);
+                    }
+                }
             }
 
-            // extract new content
-            Log.info(getClass(), "Assets check FAILED! --> Extracting new assets to: " + extractDestinationDirectory);
-            String localisedZipFile = language + ZIP_FILE_EXTENSION;
-            unzip(ZIP_FILES_STORAGE_TYPE.getResolver().resolve(ZIP_FILES_STORAGE_TYPE.getStoragePath() + localisedZipFile), extractDestinationDirectory);
+            return downloadResult;
+        }
 
-            if (startTime != null) {
-                Log.debug(getClass(), String.format("Unzip delay: %05f s", (System.nanoTime() - startTime) / 1000000000.0));
+        private void notifyDownload() {
+            synchronized (LOCK) {
+                downloadHasResult = true;
+                LOCK.notify();
             }
+        }
 
-			return null;
-		}
 
-        public static void unzip(FileHandle zipFile, String extractDestinationDirectory) throws IOException {
+//////////////////////////// EXTRACT
+
+        private static void unzip(FileHandle zipFile, String extractDestinationDirectory) throws IOException {
             ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(zipFile.read()));
             try {
                 ZipEntry zipEntry;
@@ -145,7 +353,7 @@ public class ZipAssetLoader extends TablexiaDataManager<Void> implements IApplic
             }
         }
 
-        public static boolean deleteDirectory(File directory) {
+        private static boolean deleteDirectory(File directory) {
             if(directory.exists()) {
                 File[] files = directory.listFiles();
 
@@ -162,9 +370,32 @@ public class ZipAssetLoader extends TablexiaDataManager<Void> implements IApplic
             return(directory.delete());
         }
 	}
-	
-	public void load(Locale locale, Map<String, String> buildChecksum) {
-        setAsyncTask(new ZipAssetLoaderTask(locale, buildChecksum));
-	}
+
+
+//////////////////////////// TIMER
+
+    private static void startTimer() {
+        if (TablexiaSettings.getInstance().isDebug()) {
+            startTime = System.nanoTime();
+        }
+    }
+
+    private static void resultTimer(String message) {
+        if (startTime != null) {
+            Log.debug(ZipAssetLoader.class, String.format("%s: %05f s", message, (System.nanoTime() - startTime) / 1000000000.0));
+        }
+    }
+
+//////////////////////////// ERROR
+
+    private static void error(Class clazz, String message) {
+        Log.err(clazz, message);
+        ApplicationBus.getInstance().post(new AbstractTablexiaScreen.ScreenInfoEvent("Downloading: ", "ERROR")).asynchronously();
+        error = true;
+    }
+
+    public String getError() {
+        return error ? ApplicationTextManager.getInstance().getText(ApplicationTextManager.ZIPASSETLOADER_ERROR) : null;
+    }
 	
 }
\ No newline at end of file
diff --git a/core/src/cz/nic/tablexia/util/ui/TablexiaButton.java b/core/src/cz/nic/tablexia/util/ui/TablexiaButton.java
index 7f6fcfb83e1f692e2dfbe2e8ab35c0933aad60d2..4a45cc6574df993f19f50d2c745e04240ef68708 100644
--- a/core/src/cz/nic/tablexia/util/ui/TablexiaButton.java
+++ b/core/src/cz/nic/tablexia/util/ui/TablexiaButton.java
@@ -17,9 +17,9 @@ public class TablexiaButton extends TextButton {
     private static final String DEFAULT_BUTTON_TEXT_FONT = ApplicationFontManager.APPLICATION_DEFAULT_FONT_REGULAR;
 
     public enum ButtonType{
-        BLUE(ApplicationAtlasManager.BUTTON_BLUE_PRESSED, ApplicationAtlasManager.BUTTON_BLUE_UNPRESSED),
-        GREEN(ApplicationAtlasManager.BUTTON_GREEN_PRESSED, ApplicationAtlasManager.BUTTON_GREEN_UNPRESSED),
-        RED(ApplicationAtlasManager.BUTTON_RED_PRESSED, ApplicationAtlasManager.BUTTON_RED_UNPRESSED);
+        BLUE            (ApplicationAtlasManager.BUTTON_BLUE_PRESSED,   ApplicationAtlasManager.BUTTON_BLUE_UNPRESSED),
+        GREEN           (ApplicationAtlasManager.BUTTON_GREEN_PRESSED,  ApplicationAtlasManager.BUTTON_GREEN_UNPRESSED),
+        RED             (ApplicationAtlasManager.BUTTON_RED_PRESSED,    ApplicationAtlasManager.BUTTON_RED_UNPRESSED);
 
         public static final String BUTTON_DISABLED = ApplicationAtlasManager.BUTTON_DISABLED;
 
@@ -31,26 +31,28 @@ public class TablexiaButton extends TextButton {
             this.buttonUnpressedResourceName = buttonUnpressedResourceName;
         }
 
-        public String getButtonPressedResourceName(){
-            return buttonPressedResourceName;
+        public NinePatch getUnpressedDrawable() {
+            return getNinePatchForName(buttonUnpressedResourceName);
         }
 
-        public String getButtonUnpressedResourceName() {
-            return buttonUnpressedResourceName;
+        public NinePatch getPressedDrawable() {
+            return getNinePatchForName(buttonPressedResourceName);
+        }
+
+        private NinePatch getNinePatchForName(String name) {
+            return ApplicationAtlasManager.getInstance().getPatch(name);
         }
     }
 
     public TablexiaButton(String buttonText, ButtonType buttonType) {
-        super(buttonText, new TextButton.TextButtonStyle(null, null, null, ApplicationFontManager.getInstance().getFont(DEFAULT_BUTTON_TEXT_FONT)));
-
-        NinePatch up = ApplicationAtlasManager.getInstance().getPatch(buttonType.getButtonUnpressedResourceName());
-        NinePatchDrawable npdUp = new NinePatchDrawable(up);
-
-        NinePatch down = ApplicationAtlasManager.getInstance().getPatch(buttonType.getButtonPressedResourceName());
-        NinePatchDrawable npdDown = new NinePatchDrawable(down);
+        this(new NinePatchDrawable(buttonType.getUnpressedDrawable()),
+             new NinePatchDrawable(buttonType.getPressedDrawable()),
+             new NinePatchDrawable(ApplicationAtlasManager.getInstance().getPatch(buttonType.BUTTON_DISABLED)),
+             buttonText);
+    }
 
-        NinePatch dis = ApplicationAtlasManager.getInstance().getPatch(buttonType.BUTTON_DISABLED);
-        NinePatchDrawable npdDis = new NinePatchDrawable(dis);
+    public TablexiaButton(NinePatchDrawable npdUp, NinePatchDrawable npdDown, NinePatchDrawable npdDis, String buttonText) {
+        super(buttonText, new TextButton.TextButtonStyle(null, null, null, ApplicationFontManager.getInstance().getFont(DEFAULT_BUTTON_TEXT_FONT)));
 
         TextButton.TextButtonStyle textButtonStyle = new TextButton.TextButtonStyle(npdUp, npdDown, npdDis, ApplicationFontManager.getInstance().getFont(DEFAULT_BUTTON_TEXT_FONT));
         textButtonStyle.fontColor = DEFAULT_BUTTON_TEXT_COLOR;
diff --git a/core/src/cz/nic/tablexia/util/ui/dialog/AbstractButtonDialog.java b/core/src/cz/nic/tablexia/util/ui/dialog/AbstractButtonDialog.java
index 1b9e216ed747f1db4fdfab34f73f56e3f009cf0c..56c100a96360bd389b37c2b973cfa372ca2ef362 100644
--- a/core/src/cz/nic/tablexia/util/ui/dialog/AbstractButtonDialog.java
+++ b/core/src/cz/nic/tablexia/util/ui/dialog/AbstractButtonDialog.java
@@ -1,6 +1,8 @@
 package cz.nic.tablexia.util.ui.dialog;
 
+import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
 import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
+import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable;
 
 import cz.nic.tablexia.util.ui.TablexiaButton;
 import cz.nic.tablexia.util.ui.dialog.text.DialogTextContent;
@@ -9,17 +11,24 @@ import cz.nic.tablexia.util.ui.dialog.text.DialogTextContent;
  * Created by Václav Tarantík on 9.4.15.
  */
 public abstract class AbstractButtonDialog extends TextDialog {
-    private static final float BUTTON_WIDTH_RATIO_TO_DIALOG_WIDTH = 0.27f;
-    private static final float BUTTON_HEIGHT_RATIO = 0.5f;
+
+    public static final float BUTTON_WIDTH_RATIO_TO_DIALOG_WIDTH = 0.27f;
+    public static final float BUTTON_HEIGHT_RATIO = 0.5f;
 
     public AbstractButtonDialog(float x, float y, float width, float height, BackGroundType backGroundType, DialogTextContent dialogTextContent) {
         super(x, y, width, height, backGroundType, dialogTextContent);
     }
 
-    public void createButton(String buttonText,TablexiaButton.ButtonType buttonType, ClickListener clickListener){
-        if(buttonType!=null){
+    public AbstractButtonDialog(float x, float y, float width, float height, NinePatchDrawable backGroundTypeDrawable, DialogTextContent dialogTextContent) {
+        super(x, y, width, height, backGroundTypeDrawable, dialogTextContent);
+    }
+
+    public void createButton(String buttonText, TablexiaButton.ButtonType buttonType, ClickListener clickListener){
+        createButton(new TablexiaButton(buttonText, buttonType), clickListener);
+    }
 
-            TablexiaButton textButton = new TablexiaButton(buttonText,buttonType);
+    public void createButton(TextButton textButton, ClickListener clickListener){
+        if(textButton != null){
 
             textButton.addListener(clickListener);
 
diff --git a/core/src/cz/nic/tablexia/util/ui/dialog/TablexiaDialog.java b/core/src/cz/nic/tablexia/util/ui/dialog/TablexiaDialog.java
index b1e667d41c159f830f475acb5802a3078d980325..227a0456c5e6936f679e147ade94e990b8b282fe 100644
--- a/core/src/cz/nic/tablexia/util/ui/dialog/TablexiaDialog.java
+++ b/core/src/cz/nic/tablexia/util/ui/dialog/TablexiaDialog.java
@@ -26,25 +26,37 @@ public class TablexiaDialog extends Dialog {
     private boolean hideOnOutsideClick = true;
 
     public enum BackGroundType {
-        BUBBLE_CLASSIC(ApplicationAtlasManager.DIALOG_BUBBLE_CLASSIC),
-        BUBBLE_ARROW_DOWN(ApplicationAtlasManager.DIALOG_BUBBLE_ARROW_DOWN),
-        BUBBLE_ARROW_LEFT(ApplicationAtlasManager.DIALOG_BUBBLE_ARROW_LEFT),
-        BUBBLE_CLASSIC_CONTINUE_BUTTON(ApplicationAtlasManager.DIALOG_BUBBLE_CLASSIC_CONTINUE_BUTTON),
-        DIALOG_RECTANGLE(ApplicationAtlasManager.DIALOG_RECTANGLE),
-        DIALOG_SQUARE(ApplicationAtlasManager.DIALOG_SQUARE),
-        DIALOG_SQUARE_BORDERLINES(ApplicationAtlasManager.DIALOG_SQUARE_BORDER_LINES);
+        BUBBLE_CLASSIC                  (ApplicationAtlasManager.DIALOG_BUBBLE_CLASSIC),
+        BUBBLE_ARROW_DOWN               (ApplicationAtlasManager.DIALOG_BUBBLE_ARROW_DOWN),
+        BUBBLE_ARROW_LEFT               (ApplicationAtlasManager.DIALOG_BUBBLE_ARROW_LEFT),
+        BUBBLE_CLASSIC_CONTINUE_BUTTON  (ApplicationAtlasManager.DIALOG_BUBBLE_CLASSIC_CONTINUE_BUTTON),
+        DIALOG_RECTANGLE                (ApplicationAtlasManager.DIALOG_RECTANGLE),
+        DIALOG_SQUARE                   (ApplicationAtlasManager.DIALOG_SQUARE),
+        DIALOG_SQUARE_BORDERLINES       (ApplicationAtlasManager.DIALOG_SQUARE_BORDER_LINES);
 
         private String dialogBackgroundTextureName;
 
         BackGroundType(String dialogBackgroundTextureName) {
             this.dialogBackgroundTextureName = dialogBackgroundTextureName;
         }
+
+        public NinePatchDrawable getDrawable() {
+            return new NinePatchDrawable(ApplicationAtlasManager.getInstance().getPatch(dialogBackgroundTextureName));
+        }
     }
 
     public TablexiaDialog(float x, float y, float width, float height, BackGroundType backGroundType) {
-        super("", new DialogStyle(ApplicationFontManager.getInstance().getDefaultApplicationRegularFont(),
-                Color.BLACK,
-                new NinePatchDrawable(ApplicationAtlasManager.getInstance().getPatch(backGroundType.dialogBackgroundTextureName)), new SpriteDrawable(new Sprite(ApplicationAtlasManager.getInstance().getColorTexture(ApplicationAtlasManager.COLOR_OVERLAY)))));
+        this(x, y, width, height, backGroundType.getDrawable());
+    }
+
+    public TablexiaDialog(float x, float y, float width, float height, NinePatchDrawable backgroundTypeDrawable) {
+        super("",
+              new DialogStyle(ApplicationFontManager.getInstance().getDefaultApplicationRegularFont(),
+              Color.BLACK,
+              backgroundTypeDrawable,
+              new SpriteDrawable(new Sprite(ApplicationAtlasManager.getInstance().getColorTexture(ApplicationAtlasManager.COLOR_OVERLAY)))));
+
+        //TODO MODAL DONT WORK
         setModal(true);
         setMovable(false);
         setResizable(false);
diff --git a/core/src/cz/nic/tablexia/util/ui/dialog/TextDialog.java b/core/src/cz/nic/tablexia/util/ui/dialog/TextDialog.java
index b0c1919d4494f91e3983df4f4505e06299864320..e054caefde8e48cbabaab3616d539ab043f77d73 100644
--- a/core/src/cz/nic/tablexia/util/ui/dialog/TextDialog.java
+++ b/core/src/cz/nic/tablexia/util/ui/dialog/TextDialog.java
@@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Color;
 import com.badlogic.gdx.graphics.g2d.BitmapFont;
 import com.badlogic.gdx.scenes.scene2d.ui.Cell;
 import com.badlogic.gdx.scenes.scene2d.ui.Label;
+import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable;
 import com.badlogic.gdx.utils.Align;
 
 import cz.nic.tablexia.loader.application.ApplicationFontManager;
@@ -19,7 +20,11 @@ public class TextDialog extends TablexiaDialog {
     private DialogTextContent dialogTextContent;
 
     public TextDialog(float x, float y, float width, float height, BackGroundType backGroundType, DialogTextContent dialogTextContent) {
-        super(x, y, width, height, backGroundType);
+        this(x, y, width, height, backGroundType.getDrawable(), dialogTextContent);
+    }
+
+    public TextDialog(float x, float y, float width, float height, NinePatchDrawable backgroundTypeDrawable, DialogTextContent dialogTextContent) {
+        super(x, y, width, height, backgroundTypeDrawable);
         this.dialogTextContent = dialogTextContent;
     }
 
diff --git a/desktop/build.gradle b/desktop/build.gradle
index 6d9aa731a0acdeda09e416d72706c55b541f915b..1cfd2b2107bf5af32edf32313261665a7d2df641 100644
--- a/desktop/build.gradle
+++ b/desktop/build.gradle
@@ -48,16 +48,14 @@ task releaseJar(type: Jar) {
     }
 }
 
-artifacts {
-    archives releaseJar, debugJar
-}
-jar.enabled = false
-
 debugJar.dependsOn classes
 debugJar.dependsOn(':util:checksum:runChecksum')
 releaseJar.dependsOn classes
 releaseJar.dependsOn(':util:checksum:runChecksum')
 
+build.dependsOn([debugJar, releaseJar])
+jar.enabled = false
+
 eclipse {
     project {
         name = appName + "-desktop"
diff --git a/desktop/src/cz/nic/tablexia/desktop/DesktopLauncher.java b/desktop/src/cz/nic/tablexia/desktop/DesktopLauncher.java
index cc54dcaa48c3a9c098e7544c9bcb5579212cd8b3..3d76fb587de8c7e43bf93b02f34ca0dc4340a5b5 100644
--- a/desktop/src/cz/nic/tablexia/desktop/DesktopLauncher.java
+++ b/desktop/src/cz/nic/tablexia/desktop/DesktopLauncher.java
@@ -1,6 +1,5 @@
 package cz.nic.tablexia.desktop;
 
-import com.badlogic.gdx.Gdx;
 import com.badlogic.gdx.Files;
 import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
 import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
@@ -10,13 +9,10 @@ import java.util.Locale;
 
 import cz.nic.tablexia.Tablexia;
 import cz.nic.tablexia.TablexiaSettings;
-import cz.nic.tablexia.util.Utility;
 
 public class DesktopLauncher {
 
     private static final String BUILD_VARIANT_MANIFEST_ATTRIBUTE     = "Build-Type";
-    private static final String VERSION_NAME_MANIFEST_ATTRIBUTE      = "Version-Name";
-    private static final String ASSETS_CHECKSUMS_MANIFEST_ATTRIBUTE  = "Assets-Cheksums";
 
     private static final String DESKTOP_ICON_PATH                    = "icon/";
     private static final String DESKTOP_ICON_16                      = DESKTOP_ICON_PATH + "desktop_icon_16.png";
@@ -33,9 +29,7 @@ public class DesktopLauncher {
 
     public static void main(String[] arg) {
 
-        String buildType = loadAttributeFromManifest(BUILD_VARIANT_MANIFEST_ATTRIBUTE);
-        String versionName = loadAttributeFromManifest(VERSION_NAME_MANIFEST_ATTRIBUTE);
-        String checksums = loadAttributeFromManifest(ASSETS_CHECKSUMS_MANIFEST_ATTRIBUTE);
+        String buildType = loadAttributeFromManifest(BUILD_VARIANT_MANIFEST_ATTRIBUTE, TablexiaSettings.BuildType.DEVEL.getKey());
 
 	    LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
 	    config.resizable = buildType == null || buildType.equals(TablexiaSettings.BuildType.DEVEL.getKey());
@@ -56,18 +50,13 @@ public class DesktopLauncher {
             config.addIcon(DESKTOP_ICON_128, Files.FileType.Internal);
         }
 
-	    new LwjglApplication(new Tablexia(buildType,
-                                          Locale.getDefault(),
-                                          versionName,
-                                          SQL_CONNECTION_TYPE,
-                                          Utility.createChecksumMapFromString(checksums),
-                                          true), config);
+	    new LwjglApplication(new Tablexia(buildType, Locale.getDefault(), SQL_CONNECTION_TYPE, true), config);
     }
 
-    private static String loadAttributeFromManifest(String attributeName) {
+    private static String loadAttributeFromManifest(String attributeName, String defaultValue) {
         if (Manifests.exists(attributeName)) {
             return Manifests.read(attributeName);
         }
-        return null;
+        return defaultValue;
     }
 }
diff --git a/ios/Info.plist.xml b/ios/Info.plist.xml
index 1542ac955d28c0d58b6c0986a61e16f5dbf5fcdb..fbe480ed333133bfb6797a815bda628129f43bd3 100644
--- a/ios/Info.plist.xml
+++ b/ios/Info.plist.xml
@@ -24,8 +24,6 @@
     <string>${app.build}</string>
     <key>cz.nic.tablexia.BuildType</key>
     <string>${app.buildtype}</string>
-    <key>cz.nic.tablexia.AssetsChecksums</key>
-    <string>${app.assetschecksums}</string>
     <key>LSRequiresIPhoneOS</key>
     <true/>
     <key>UIViewControllerBasedStatusBarAppearance</key>
diff --git a/ios/build.gradle b/ios/build.gradle
index 2cd53550a48721306ff4e0061ce89acc2e11fd44..c0de588a8bd2dc89d22fa15190eb46c1d6843ff1 100644
--- a/ios/build.gradle
+++ b/ios/build.gradle
@@ -29,7 +29,6 @@ def updateRoboVMProperties(String buildType, String applicationId, String iconNa
     props.setProperty('app.version', tablexiaVersionName)
     props.setProperty('app.buildtype', buildType)
     props.setProperty('app.build', '' + tablexiaVersionCode)
-    props.setProperty('app.assetschecksums', getMapConvertedToString(rootProject.ext.assetsChecksum))
     props.setProperty('app.executable', appName + '-' + buildType + '-' + tablexiaVersionName)
 
     props.store(propsFile.newDataOutputStream(), '')
diff --git a/ios/robovm.properties b/ios/robovm.properties
index fc7595766ac7bac652f90ff8af3cd0b7a1cfbb22..d70017fa371d6b595d2b26faf154c94e4061009d 100644
--- a/ios/robovm.properties
+++ b/ios/robovm.properties
@@ -1,6 +1,10 @@
-app.version=1.0
-app.id=cz.nic.tablexia.IOSLauncher
+#
+#Tue Jul 28 10:13:55 CEST 2015
+app.icon=Icon_devel
+app.id=cz.nic.tablexia.devel
+app.version=55b5a3f
 app.mainclass=cz.nic.tablexia.IOSLauncher
-app.executable=IOSLauncher
-app.build=1
-app.name=Tablexia-libGDX
+app.executable=Tablexia-devel-55b5a3f
+app.build=1438069145
+app.buildtype=devel
+app.name=Tablexia
diff --git a/ios/src/cz/nic/tablexia/IOSLauncher.java b/ios/src/cz/nic/tablexia/IOSLauncher.java
index c13c819330875ad22bd888fd1419df9cdb7bd66a..399a4f3026a8917800e788395b102cfb6167c379 100644
--- a/ios/src/cz/nic/tablexia/IOSLauncher.java
+++ b/ios/src/cz/nic/tablexia/IOSLauncher.java
@@ -11,8 +11,6 @@ import org.robovm.apple.uikit.UIApplication;
 
 import java.util.Locale;
 
-import cz.nic.tablexia.util.Utility;
-
 public class IOSLauncher extends IOSApplication.Delegate {
 
     public static final Tablexia.SQLConnectionType SQL_CONNECTION_TYPE = new Tablexia.SQLConnectionType("SQLite.JDBCDriver", "jdbc:sqlite:");
@@ -23,14 +21,10 @@ public class IOSLauncher extends IOSApplication.Delegate {
 
         NSDictionary infoDictionary = NSBundle.getMainBundle().getInfoDictionary();
         String buildType = infoDictionary.get(new NSString("cz.nic.tablexia.BuildType")).toString();
-        String versionName = infoDictionary.get(new NSString("CFBundleShortVersionString")).toString();
-        String checksums = infoDictionary.get(new NSString("cz.nic.tablexia.AssetsChecksums")).toString();
 
         return new IOSApplication(new Tablexia(buildType,
                                                Locale.getDefault(),
-                                               versionName,
                                                SQL_CONNECTION_TYPE,
-                                               Utility.createChecksumMapFromString(checksums),
                                                false), config);
     }
 
diff --git a/util/checksum/build.gradle b/util/checksum/build.gradle
index cdb5da13ce863502356b116e8a66168ab799ca3d..a5498f48f6ffb1c428c6db00831d374b8c0a3443 100644
--- a/util/checksum/build.gradle
+++ b/util/checksum/build.gradle
@@ -24,3 +24,25 @@ task runChecksum(dependsOn: [classes, rootProject.tasks.prepareSoundAssets, root
         }
     }
 }
+
+task runAssetsArchivesChecksum(dependsOn: [classes, rootProject.tasks.zipAssets]) {
+    doLast {
+        rootProject.ext.assetsPackDir.eachFile() { file ->
+            String fileName = file.getName()
+            if (fileName.endsWith(".zip")) {
+                task ("${name}_${fileName}", type: JavaExec) {
+                    main = MAIN_CLASS
+                    args = [file]
+                    classpath sourceSets.main.output.classesDir
+                    classpath += sourceSets.main.runtimeClasspath
+                    def stdout = new ByteArrayOutputStream()
+                    standardOutput = stdout
+
+                    doLast {
+                        (new File("${assetsPackDir.getAbsolutePath()}/${fileName.split("\\.")[0]}.checksum")).write(stdout.toString().trim());
+                    }
+                }.execute()
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/util/checksum/src/cz/nic/tablexia/checksum/Checksum.java b/util/checksum/src/cz/nic/tablexia/checksum/Checksum.java
index 8ae5417d79d11de155a1b505784cd9d60cf1500f..8f65208a232cbaa9429740794d0f861be8738381 100644
--- a/util/checksum/src/cz/nic/tablexia/checksum/Checksum.java
+++ b/util/checksum/src/cz/nic/tablexia/checksum/Checksum.java
@@ -15,24 +15,24 @@ public class Checksum {
         System.out.println(getMd5OfDir(new File(args[0])));
     }
 
-    public static String getMd5OfDir(File dir) throws NoSuchAlgorithmException, IOException {
-        StringBuilder checksumBuilder = new StringBuilder();
-        File[] files = dir.listFiles();
-        Arrays.sort(files,
+    public static String getMd5OfDir(File file) throws NoSuchAlgorithmException, IOException {
+        if (file.isDirectory()) {
+            StringBuilder checksumBuilder = new StringBuilder();
+            File[] files = file.listFiles();
+            Arrays.sort(files,
                     new Comparator<File>() {
                         public int compare(File a, File b) {
                             return a.getName().compareTo(b.getName());
                         }
                     });
 
-        for (int i = 0; i < files.length; i++) {
-            if (files[i].isDirectory()) {
+            for (int i = 0; i < files.length; i++) {
                 checksumBuilder.append(getMd5OfDir(files[i]));
-            } else {
-                checksumBuilder.append(getMd5OfFile(files[i]));
             }
+            return getMD5OfString(checksumBuilder.toString());
+        } else {
+            return getMd5OfFile(file);
         }
-        return getMD5OfString(checksumBuilder.toString());
     }
 
     public static String getMd5OfFile(File file) throws IOException, NoSuchAlgorithmException {