diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..2b75303a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 00000000..34dc27cb
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 00000000..79ee123c
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 00000000..7ac24c77
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 00000000..dfd2c799
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
new file mode 100644
index 00000000..7f68460d
--- /dev/null
+++ b/.idea/runConfigurations.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 00000000..796b96d1
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 00000000..e177897a
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,44 @@
+apply plugin: 'com.android.application'
+
+apply plugin: 'kotlin-android'
+
+apply plugin: 'kotlin-android-extensions'
+apply plugin: 'maven'
+
+android {
+ compileSdkVersion 28
+ defaultConfig {
+ applicationId "com.example.myapplication"
+ minSdkVersion 21
+ targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation 'com.android.support:appcompat-v7:28.0.0'
+ implementation 'com.android.support.constraint:constraint-layout:1.1.3'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'com.android.support.test:runner:1.0.2'
+ androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+ implementation 'com.google.android.gms:play-services-ads:17.1.1'
+ implementation "cz.msebera.android:httpclient:4.4.1.2"
+ compile 'info.guardianproject.netcipher:netcipher:2.0.0-alpha1'
+ compile 'info.guardianproject.netcipher:netcipher-okhttp3:2.0.0-alpha1'
+ compile 'com.squareup.okhttp3:okhttp:3.4.2'
+ compile 'org.apache.httpcomponents:httpcore:4.4.1'
+}
+
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 00000000..f1b42451
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/app/release/app-release.apk b/app/release/app-release.apk
new file mode 100644
index 00000000..dad6346e
Binary files /dev/null and b/app/release/app-release.apk differ
diff --git a/app/release/output.json b/app/release/output.json
new file mode 100644
index 00000000..9f0c9596
--- /dev/null
+++ b/app/release/output.json
@@ -0,0 +1 @@
+[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
\ No newline at end of file
diff --git a/app/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.kt
new file mode 100644
index 00000000..7a945382
--- /dev/null
+++ b/app/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.example.myapplication
+
+import android.support.test.InstrumentationRegistry
+import android.support.test.runner.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getTargetContext()
+ assertEquals("com.example.myapplication", appContext.packageName)
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..c324e7db
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/myapplication/SSLConnectionSocketFactory.java b/app/src/main/java/com/example/myapplication/SSLConnectionSocketFactory.java
new file mode 100644
index 00000000..2a36a26a
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/SSLConnectionSocketFactory.java
@@ -0,0 +1,490 @@
+package com.example.myapplication;
+
+import android.os.Build;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.security.auth.x500.X500Principal;
+
+import cz.msebera.android.httpclient.HttpHost;
+import cz.msebera.android.httpclient.conn.socket.LayeredConnectionSocketFactory;
+import cz.msebera.android.httpclient.conn.ssl.DefaultHostnameVerifier;
+import cz.msebera.android.httpclient.conn.ssl.SSLContexts;
+import cz.msebera.android.httpclient.conn.ssl.SSLInitializationException;
+import cz.msebera.android.httpclient.conn.ssl.X509HostnameVerifier;
+import cz.msebera.android.httpclient.conn.util.PublicSuffixMatcherLoader;
+import cz.msebera.android.httpclient.protocol.HttpContext;
+import cz.msebera.android.httpclient.util.Args;
+import cz.msebera.android.httpclient.util.TextUtils;
+
+/*
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.HttpHost;
+import org.apache.http.annotation.ThreadSafe;
+import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
+import org.apache.http.conn.util.PublicSuffixMatcherLoader;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.ssl.SSLContexts;
+import org.apache.http.util.Args;
+import org.apache.http.util.TextUtils;
+*/
+
+/**
+ * Layered socket factory for TLS/SSL connections.
+ *
+ * SSLSocketFactory can be used to validate the identity of the HTTPS server against a list of
+ * trusted certificates and to authenticate to the HTTPS server using a private key.
+ *
+ * SSLSocketFactory will enable server authentication when supplied with
+ * a {@link java.security.KeyStore trust-store} file containing one or several trusted certificates. The client
+ * secure socket will reject the connection during the SSL session handshake if the target HTTPS
+ * server attempts to authenticate itself with a non-trusted certificate.
+ *
+ * Use JDK keytool utility to import a trusted certificate and generate a trust-store file:
+ *
+ * keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
+ *
+ *
+ * In special cases the standard trust verification process can be bypassed by using a custom
+ * {@link org.apache.http.conn.ssl.TrustStrategy}. This interface is primarily intended for allowing self-signed
+ * certificates to be accepted as trusted without having to add them to the trust-store file.
+ *
+ * SSLSocketFactory will enable client authentication when supplied with
+ * a {@link java.security.KeyStore key-store} file containing a private key/public certificate
+ * pair. The client secure socket will use the private key to authenticate
+ * itself to the target HTTPS server during the SSL session handshake if
+ * requested to do so by the server.
+ * The target HTTPS server will in its turn verify the certificate presented
+ * by the client in order to establish client's authenticity.
+ *
+ * Use the following sequence of actions to generate a key-store file
+ *
+ *
+ *
+ *
+ * Use JDK keytool utility to generate a new key
+ *
+ * For simplicity use the same password for the key as that of the key-store
+ *
+ *
+ *
+ *
+ * Issue a certificate signing request (CSR)
+ *
+ *
keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore
+ *
+ *
+ *
+ * Send the certificate request to the trusted Certificate Authority for signature.
+ * One may choose to act as her own CA and sign the certificate request using a PKI
+ * tool, such as OpenSSL.
+ *
+ *
+ *
+ *
+ * Import the trusted CA root certificate
+ *
+ *
keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore
+ *
+ *
+ *
+ * Import the PKCS#7 file containing the complete certificate chain
+ *
+ *
keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore
+ *
+ *
+ *
+ * Verify the content of the resultant keystore file
+ *
+ *
keytool -list -v -keystore my.keystore
+ *
+ *
+ *
+ * @since 4.3
+ */
+// @ThreadSafe @SuppressWarnings("deprecation")
+public class SSLConnectionSocketFactory implements
+ LayeredConnectionSocketFactory {
+ private final static String TAG = "HttpClient";
+ public static final String TLS = "TLS";
+ public static final String SSL = "SSL";
+ public static final String SSLV2 = "SSLv2";
+
+/*
+ @Deprecated
+ public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER
+ = AllowAllHostnameVerifier.INSTANCE;
+ @Deprecated
+ public static final X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
+ = BrowserCompatHostnameVerifier.INSTANCE;
+ @Deprecated
+ public static final X509HostnameVerifier STRICT_HOSTNAME_VERIFIER
+ = StrictHostnameVerifier.INSTANCE;
+*/
+
+// private final Log log = LogFactory.getLog(getClass());
+
+ /**
+ * @since 4.4
+ */
+ public static HostnameVerifier getDefaultHostnameVerifier() {
+ return new DefaultHostnameVerifier(
+ PublicSuffixMatcherLoader.getDefault());
+ }
+
+ /**
+ * Obtains default SSL socket factory with an SSL context based on the standard JSSE
+ * trust material ({@code cacerts} file in the security properties directory).
+ * System properties are not taken into consideration.
+ *
+ * @return default SSL socket factory
+ */
+ public static SSLConnectionSocketFactory getSocketFactory() throws
+ SSLInitializationException {
+ return new SSLConnectionSocketFactory(
+ SSLContexts.createDefault(), getDefaultHostnameVerifier());
+ }
+
+ private static String[] split(final String s) {
+ if (TextUtils.isBlank(s)) {
+ return null;
+ }
+ return s.split(" *, *");
+ }
+
+ /**
+ * Obtains default SSL socket factory with an SSL context based on system properties
+ * as described in
+ *
+ * Java™ Secure Socket Extension (JSSE) Reference Guide.
+ *
+ * @return default system SSL socket factory
+ */
+ public static SSLConnectionSocketFactory getSystemSocketFactory() throws
+ SSLInitializationException {
+ return new SSLConnectionSocketFactory(
+ (javax.net.ssl.SSLSocketFactory) javax.net.ssl.SSLSocketFactory.getDefault(),
+ split(System.getProperty("https.protocols")),
+ split(System.getProperty("https.cipherSuites")),
+ getDefaultHostnameVerifier());
+ }
+
+ private final javax.net.ssl.SSLSocketFactory socketfactory;
+ private final HostnameVerifier hostnameVerifier;
+ private final String[] supportedProtocols;
+ private final String[] supportedCipherSuites;
+
+ public SSLConnectionSocketFactory(final SSLContext sslContext) {
+ this(sslContext, getDefaultHostnameVerifier());
+ }
+
+ /**
+ * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(SSLContext,
+ * HostnameVerifier)}
+ */
+ @Deprecated
+ public SSLConnectionSocketFactory(
+ final SSLContext sslContext, final X509HostnameVerifier hostnameVerifier) {
+ this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
+ null, null, hostnameVerifier);
+ }
+
+ /**
+ * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(SSLContext,
+ * String[], String[], HostnameVerifier)}
+ */
+ @Deprecated
+ public SSLConnectionSocketFactory(
+ final SSLContext sslContext,
+ final String[] supportedProtocols,
+ final String[] supportedCipherSuites,
+ final X509HostnameVerifier hostnameVerifier) {
+ this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
+ supportedProtocols, supportedCipherSuites, hostnameVerifier);
+ }
+
+ /**
+ * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(javax.net.ssl.SSLSocketFactory,
+ * HostnameVerifier)}
+ */
+ @Deprecated
+ public SSLConnectionSocketFactory(
+ final javax.net.ssl.SSLSocketFactory socketfactory,
+ final X509HostnameVerifier hostnameVerifier) {
+ this(socketfactory, null, null, hostnameVerifier);
+ }
+
+ /**
+ * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(javax.net.ssl.SSLSocketFactory,
+ * String[], String[], HostnameVerifier)}
+ */
+ @Deprecated
+ public SSLConnectionSocketFactory(
+ final javax.net.ssl.SSLSocketFactory socketfactory,
+ final String[] supportedProtocols,
+ final String[] supportedCipherSuites,
+ final X509HostnameVerifier hostnameVerifier) {
+ this(socketfactory, supportedProtocols, supportedCipherSuites, (HostnameVerifier) hostnameVerifier);
+ }
+
+ /**
+ * @since 4.4
+ */
+ public SSLConnectionSocketFactory(
+ final SSLContext sslContext, final HostnameVerifier hostnameVerifier) {
+ this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
+ null, null, hostnameVerifier);
+ }
+
+ /**
+ * @since 4.4
+ */
+ public SSLConnectionSocketFactory(
+ final SSLContext sslContext,
+ final String[] supportedProtocols,
+ final String[] supportedCipherSuites,
+ final HostnameVerifier hostnameVerifier) {
+ this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
+ supportedProtocols, supportedCipherSuites, hostnameVerifier);
+ }
+
+ /**
+ * @since 4.4
+ */
+ public SSLConnectionSocketFactory(
+ final javax.net.ssl.SSLSocketFactory socketfactory,
+ final HostnameVerifier hostnameVerifier) {
+ this(socketfactory, null, null, hostnameVerifier);
+ }
+
+ /**
+ * @since 4.4
+ */
+ public SSLConnectionSocketFactory(
+ final javax.net.ssl.SSLSocketFactory socketfactory,
+ final String[] supportedProtocols,
+ final String[] supportedCipherSuites,
+ final HostnameVerifier hostnameVerifier) {
+ this.socketfactory = Args.notNull(socketfactory, "SSL socket factory");
+ this.supportedProtocols = supportedProtocols;
+ this.supportedCipherSuites = supportedCipherSuites;
+ this.hostnameVerifier = hostnameVerifier != null ? hostnameVerifier : getDefaultHostnameVerifier();
+ }
+
+ /**
+ * Performs any custom initialization for a newly created SSLSocket
+ * (before the SSL handshake happens).
+ *
+ * The default implementation is a no-op, but could be overridden to, e.g.,
+ * call {@link SSLSocket#setEnabledCipherSuites(String[])}.
+ *
+ * @throws IOException may be thrown if overridden
+ */
+ protected void prepareSocket(final SSLSocket socket) throws IOException {
+ }
+
+ @Override
+ public Socket createSocket(final HttpContext context) throws IOException {
+ return SocketFactory.getDefault().createSocket();
+ }
+
+ @Override
+ public Socket connectSocket(
+ final int connectTimeout,
+ final Socket socket,
+ final HttpHost host,
+ final InetSocketAddress remoteAddress,
+ final InetSocketAddress localAddress,
+ final HttpContext context) throws IOException {
+ Args.notNull(host, "HTTP host");
+ Args.notNull(remoteAddress, "Remote address");
+ final Socket sock = socket != null ? socket : createSocket(context);
+ if (localAddress != null) {
+ sock.bind(localAddress);
+ }
+ try {
+ if (connectTimeout > 0 && sock.getSoTimeout() == 0) {
+ sock.setSoTimeout(connectTimeout);
+ }
+/*
+ if (this.log.isDebugEnabled()) {
+ this.log.debug("Connecting socket to " + remoteAddress + " with timeout " + connectTimeout);
+ }
+*/
+ sock.connect(remoteAddress, connectTimeout);
+ } catch (final IOException ex) {
+ try {
+ sock.close();
+ } catch (final IOException ignore) {
+ }
+ throw ex;
+ }
+ // Setup SSL layering if necessary
+ if (sock instanceof SSLSocket) {
+ final SSLSocket sslsock = (SSLSocket) sock;
+// this.log.debug("Starting handshake");
+ sslsock.startHandshake();
+ verifyHostname(sslsock, host.getHostName());
+ return sock;
+ } else {
+ return createLayeredSocket(sock, host.getHostName(), remoteAddress.getPort(), context);
+ }
+ }
+
+ @Override
+ public Socket createLayeredSocket(
+ final Socket socket,
+ final String target,
+ final int port,
+ final HttpContext context) throws IOException {
+ final SSLSocket sslsock = (SSLSocket) this.socketfactory.createSocket(
+ socket,
+ target,
+ port,
+ true);
+ if (supportedProtocols != null) {
+ sslsock.setEnabledProtocols(supportedProtocols);
+ } else {
+ // If supported protocols are not explicitly set, remove all SSL protocol versions
+ final String[] allProtocols = sslsock.getEnabledProtocols();
+ final List enabledProtocols = new ArrayList(allProtocols.length);
+ for (String protocol : allProtocols) {
+ if (!protocol.startsWith("SSL")) {
+ enabledProtocols.add(protocol);
+ }
+ }
+ if (!enabledProtocols.isEmpty()) {
+ sslsock.setEnabledProtocols(enabledProtocols.toArray(new String[enabledProtocols.size()]));
+ }
+ }
+ if (supportedCipherSuites != null) {
+ sslsock.setEnabledCipherSuites(supportedCipherSuites);
+ }
+
+/*
+ if (this.log.isDebugEnabled()) {
+ this.log.debug("Enabled protocols: " + Arrays.asList(sslsock.getEnabledProtocols()));
+ this.log.debug("Enabled cipher suites:" + Arrays.asList(sslsock.getEnabledCipherSuites()));
+ }
+*/
+
+ prepareSocket(sslsock);
+
+ // Android specific code to enable SNI
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Enabling SNI for " + target);
+ }
+ try {
+ Method method = sslsock.getClass().getMethod("setHostname", String.class);
+ method.invoke(sslsock, target);
+ } catch (Exception ex) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "SNI configuration failed", ex);
+ }
+ }
+ }
+ // End of Android specific code
+
+// this.log.debug("Starting handshake");
+ sslsock.startHandshake();
+ verifyHostname(sslsock, target);
+ return sslsock;
+ }
+
+ private void verifyHostname(final SSLSocket sslsock, final String hostname) throws IOException {
+ try {
+ SSLSession session = sslsock.getSession();
+ if (session == null) {
+ // In our experience this only happens under IBM 1.4.x when
+ // spurious (unrelated) certificates show up in the server'
+ // chain. Hopefully this will unearth the real problem:
+ final InputStream in = sslsock.getInputStream();
+ in.available();
+ // If ssl.getInputStream().available() didn't cause an
+ // exception, maybe at least now the session is available?
+ session = sslsock.getSession();
+ if (session == null) {
+ // If it's still null, probably a startHandshake() will
+ // unearth the real problem.
+ sslsock.startHandshake();
+ session = sslsock.getSession();
+ }
+ }
+ if (session == null) {
+ throw new SSLHandshakeException("SSL session not available");
+ }
+
+/*
+ if (this.log.isDebugEnabled()) {
+ this.log.debug("Secure session established");
+ this.log.debug(" negotiated protocol: " + session.getProtocol());
+ this.log.debug(" negotiated cipher suite: " + session.getCipherSuite());
+ try {
+ final Certificate[] certs = session.getPeerCertificates();
+ final X509Certificate x509 = (X509Certificate) certs[0];
+ final X500Principal peer = x509.getSubjectX500Principal();
+ this.log.debug(" peer principal: " + peer.toString());
+ final Collection> altNames1 = x509.getSubjectAlternativeNames();
+ if (altNames1 != null) {
+ final List altNames = new ArrayList();
+ for (final List> aC : altNames1) {
+ if (!aC.isEmpty()) {
+ altNames.add((String) aC.get(1));
+ }
+ }
+ this.log.debug(" peer alternative names: " + altNames);
+ }
+ final X500Principal issuer = x509.getIssuerX500Principal();
+ this.log.debug(" issuer principal: " + issuer.toString());
+ final Collection> altNames2 = x509.getIssuerAlternativeNames();
+ if (altNames2 != null) {
+ final List altNames = new ArrayList();
+ for (final List> aC : altNames2) {
+ if (!aC.isEmpty()) {
+ altNames.add((String) aC.get(1));
+ }
+ }
+ this.log.debug(" issuer alternative names: " + altNames);
+ }
+ } catch (Exception ignore) {
+ }
+ }
+*/
+
+ if (!this.hostnameVerifier.verify(hostname, session)) {
+ final Certificate[] certs = session.getPeerCertificates();
+ final X509Certificate x509 = (X509Certificate) certs[0];
+ final X500Principal x500Principal = x509.getSubjectX500Principal();
+ throw new SSLPeerUnverifiedException("Host name '" + hostname + "' does not match " +
+ "the certificate subject provided by the peer (" + x500Principal.toString() + ")");
+ }
+ // verifyHostName() didn't blowup - good!
+ } catch (final IOException iox) {
+ // close the socket before re-throwing the exception
+ try {
+ sslsock.close();
+ } catch (final Exception x) { /*ignore*/ }
+ throw iox;
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/myapplication/StrongBuild.java b/app/src/main/java/com/example/myapplication/StrongBuild.java
new file mode 100644
index 00000000..9c5b512e
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/StrongBuild.java
@@ -0,0 +1,85 @@
+package com.example.myapplication;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.Log;
+
+import javax.net.ssl.TrustManager;
+
+import android.webkit.WebView;
+import info.guardianproject.netcipher.client.StrongBuilder;
+import info.guardianproject.netcipher.client.StrongOkHttpClientBuilder;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
+public class StrongBuild implements StrongBuilder.Callback {
+
+ private static final StrongBuild ourInstance = new StrongBuild();
+
+ public static StrongBuild getInstance() {
+ return ourInstance;
+ }
+
+ public String url;
+ public String htmlCode;
+ public WebView view;
+
+ public void loadURL(String url, WebView view, Context applicationContext){
+ try{
+ this.url = url;
+ this.view = view;
+ StrongOkHttpClientBuilder.
+ forMaxSecurity(applicationContext).
+ withTorValidation().
+ withBestProxy().
+ build(StrongBuild.this);
+
+ }catch(Exception e){
+ e.printStackTrace();
+ Log.e("info", "ERROR");
+ }
+ }
+
+ @Override
+ public void onConnected(final OkHttpClient okHttpClient){
+ Log.e("info" , "CONNECTED Strong Builder");
+
+ view.loadDataWithBaseURL(null, "ASD", "text/html", "utf-8", null);
+ new Thread(new Runnable(){
+ @Override
+ public void run(){
+ try{
+ Request request = new Request.Builder().url(url).build();
+ Response response = okHttpClient.newCall(request).execute();
+
+ Log.e("info", "RESPONSE: "+response.toString());
+ Log.e("info", response.body().string());
+ htmlCode = response.body().string();
+
+ Log.d("LOADING : " ,"LOADING");
+ view.loadDataWithBaseURL(null, htmlCode, "text/html", "utf-8", null);
+
+ }catch(Exception e){
+ e.printStackTrace();
+ Log.e("info", "ERROR - ATTEMPTING CONNECTION TO ONION DOMAIN");
+ }
+ }
+ }).start();
+ }
+
+ @Override
+ public void onConnectionException(Exception e){
+ Log.e("info" , "Exception");
+ }
+
+ @Override
+ public void onTimeout(){
+ Log.e("info" , "Timeout");
+ }
+
+ @Override
+ public void onInvalid(){
+ Log.e("info" , "Invalid");
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/myapplication/admanager.java b/app/src/main/java/com/example/myapplication/admanager.java
new file mode 100644
index 00000000..81bc9b01
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/admanager.java
@@ -0,0 +1,64 @@
+package com.example.myapplication;
+
+import android.content.Context;
+import com.google.android.gms.ads.AdListener;
+import com.google.android.gms.ads.AdRequest;
+import com.google.android.gms.ads.InterstitialAd;
+import com.google.android.gms.ads.MobileAds;
+
+public class admanager {
+ private static final admanager ourInstance = new admanager();
+
+ public static admanager getInstance() {
+ return ourInstance;
+ }
+ private InterstitialAd mInterstitialAd;
+
+
+ private admanager() {
+ }
+
+ public void initialize(Context applicationContext)
+ {
+ MobileAds.initialize(applicationContext, "ca-app-pub-5074525529134731~2926711128");
+ mInterstitialAd = new InterstitialAd(applicationContext);
+ mInterstitialAd.setAdUnitId("ca-app-pub-3940256099942544/1033173712");
+ implementListeners();
+ mInterstitialAd.loadAd(new AdRequest.Builder().build());
+ }
+
+ public void implementListeners()
+ {
+ mInterstitialAd.setAdListener(new AdListener() {
+ @Override
+ public void onAdLoaded() {
+ // Code to be executed when an ad finishes loading.
+ }
+
+ @Override
+ public void onAdFailedToLoad(int errorCode) {
+ mInterstitialAd.loadAd(new AdRequest.Builder().build());
+ }
+
+ @Override
+ public void onAdOpened() {
+ }
+
+ @Override
+ public void onAdLeftApplication() {
+ // Code to be executed when the user has left the app.
+ }
+
+ @Override
+ public void onAdClosed() {
+ mInterstitialAd.loadAd(new AdRequest.Builder().build());
+ }
+ });
+ }
+
+ public void showAd()
+ {
+ mInterstitialAd.show();
+ }
+
+}
diff --git a/app/src/main/java/com/example/myapplication/applicationController.java b/app/src/main/java/com/example/myapplication/applicationController.java
new file mode 100644
index 00000000..0f90abb8
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/applicationController.java
@@ -0,0 +1,303 @@
+package com.example.myapplication;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Build;
+import android.support.constraint.ConstraintLayout;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.util.Log;
+import android.util.Patterns;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
+import android.webkit.*;
+import android.widget.*;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Stack;
+
+import static java.lang.Thread.sleep;
+
+public class applicationController extends AppCompatActivity
+{
+
+ /*View Objects*/
+ private WebView webView1;
+ private WebView webView2;
+ private ProgressBar progressBar;
+ private ConstraintLayout requestFailure;
+ private ConstraintLayout splashScreen;
+ private Button reloadButton;
+ private ImageButton homeButton;
+ private EditText searchbar;
+ private LinearLayout topbar;
+
+ /*helper Variables*/
+ String currentURL = "http://boogle.store/";
+ boolean isRequestError = false;
+ boolean hasApplicationLoaded = false;
+ Stack urlList = new Stack();
+ int scroll1y=0;
+ int scroll2y=0;
+
+ /*Initialization*/
+ @Override
+ protected void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_application_controller);
+ initializeView();
+ initializeProxy();
+ initializeAds();
+ }
+
+ public void initializeProxy()
+ {
+ //torProxyServer.getInstance().initialize(this,this);
+ }
+
+ public void initializeAds()
+ {
+
+ admanager.getInstance().initialize(this);
+ }
+
+ /*Initialization*/
+ public void initializeView()
+ {
+ webView1 = (WebView) findViewById(R.id.pageLoader1);
+ webView2 = (WebView) findViewById(R.id.pageLoader2);
+ progressBar = (ProgressBar) findViewById(R.id.progressBar);
+ requestFailure = (ConstraintLayout) findViewById(R.id.requestFailure);
+ splashScreen = (ConstraintLayout) findViewById(R.id.splashScreen);
+ reloadButton = (Button) findViewById(R.id.reloadButton);
+ homeButton = (ImageButton) findViewById(R.id.home);
+ searchbar = (EditText) findViewById(R.id.search);
+ topbar = (LinearLayout) findViewById(R.id.topbar);
+ webRequestHandler.getInstance().initialization(webView1,webView2,progressBar,searchbar,requestFailure);
+ webView1.bringToFront();
+
+ webView2.animate().setDuration(0).alpha(0f);
+ progressBar.setVisibility(View.INVISIBLE);
+ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+
+ webView1.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
+ webView1.setBackgroundColor(Color.WHITE);
+ webView1.setWebViewClient(loadWebViewClient());
+ webView1.getSettings().setJavaScriptEnabled(true);
+ webView1.loadUrl("http://boogle.store/");
+
+ webView2.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
+ webView2.setBackgroundColor(Color.WHITE);
+ webView2.setWebViewClient(loadWebViewClient());
+ webView2.getSettings().setJavaScriptEnabled(true);
+
+ requestFailure.animate().setDuration(0).alpha(0.0f);
+ initializeViewClients();
+
+ }
+
+ private void initializeViewClients()
+ {
+ homeButton.setOnClickListener(new View.OnClickListener(){
+
+ @Override
+ public void onClick(View v)
+ {
+ webRequestHandler.getInstance().loadURL("http://boogle.store/");
+ isRequestError = false;
+ }
+ });
+
+ searchbar.setOnEditorActionListener(new EditText.OnEditorActionListener()
+ {
+ @Override
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event)
+ {
+ try
+ {
+ String url = v.getText().toString();
+ if(!url.startsWith("www.")&& !url.startsWith("http://")){
+ url = "www."+url;
+ }
+ if(!url.startsWith("http://")){
+ url = "http://"+url;
+ }
+
+
+ boolean isUrlValid = Patterns.WEB_URL.matcher(url).matches();
+
+ URL host = new URL(url);
+ Log.i("SUPER WOW",host.getHost());
+ if(isUrlValid && host.getHost().replace("www.","").contains("."))
+ {
+ Log.i("WOW1","WOW1");
+ if(host.getHost().contains(".onion")||host.getHost().contains("boogle.store")||host.getHost().contains("genesis.store"))
+ {
+ webRequestHandler.getInstance().loadURL(v.getText().toString());
+ }
+ else
+ {
+ Toast.makeText(getApplicationContext(), "Only onion urls allowed", Toast.LENGTH_SHORT).show();
+ }
+ }
+ else
+ {
+ webRequestHandler.getInstance().loadURL("http://boogle.store/search?q="+v.getText().toString().replaceAll(" ","+")+"&p_num=1&s_type=all");
+ }
+ }
+ catch (IOException e)
+ {
+ webRequestHandler.getInstance().loadURL("http://boogle.store/search?q="+v.getText().toString().replaceAll(" ","+")+"&p_num=1&s_type=all");
+ e.printStackTrace();
+ }
+ return false;
+ }
+ });
+
+ Log.i("HELL1","HELL1");
+ reloadButton.setOnClickListener(new View.OnClickListener(){
+
+ @Override
+ public void onClick(View v)
+ {
+ Log.i("HELL2","HELL2");
+ webRequestHandler.getInstance().loadURL(currentURL);
+ isRequestError = false;
+ }
+ });
+
+ }
+
+ public static String getDomainName(String url) throws URISyntaxException
+ {
+ URI uri = new URI(url);
+ String domain = uri.getHost();
+ return domain.startsWith("www.") ? domain.substring(4) : domain;
+ }
+
+
+ @TargetApi(Build.VERSION_CODES.M)
+ private void onChromeClientProgressChanged(int newProgress)
+ {
+
+ }
+
+ @Override
+ public void onBackPressed()
+ {
+ if(urlList.size()>0)
+ {
+ boolean crul = !currentURL.equals("http://boogle.store/");
+ boolean peek = !urlList.peek().equals("http://boogle.store/");
+
+ Log.i("WOW",urlList.size() + "---" + urlList.peek() + "---" + currentURL + "---" + peek);
+ currentURL = urlList.peek().toString();
+
+ if(!currentURL.equals(urlList.peek()) && crul)
+ {
+ webRequestHandler.getInstance().loadURL("http://boogle.store/");
+ }
+ else
+ {
+ webRequestHandler.getInstance().loadURL(urlList.pop().toString());
+ }
+ }
+ }
+
+ private WebViewClient loadWebViewClient()
+ {
+ WebViewClient client = new WebViewClient()
+ {
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url)
+ {
+ Log.i("OVERRIDING URL 1 : ","SUCCESS : " + view);
+ System.out.println(url);
+ if(!currentURL.equals(url))
+ {
+ urlList.add(currentURL);
+ currentURL = url;
+ }
+ if(!url.toString().contains("boogle"))
+ {
+ Log.i("OVERRIDING URL 2 : ","SUCCESS : " + url);
+ //admanager.getInstance().showAd();
+ //StrongBuild.getInstance().loadURL("https://stackoverflow.com/questions/4543349/load-local-html-in-webview",view,getApplicationContext());
+ }
+ else
+ {
+ Log.i("OVERRIDING URL 3 : ","SUCCESS : " + url);
+ webRequestHandler.getInstance().loadURL(url);
+ return true;
+ }
+ return false;
+ }
+ @Override
+ public void onPageFinished(WebView view, String url)
+ {
+ Log.i("APPLIED : ","SUCCESS : APPLIED");
+ super.onPageFinished(view, url);
+ webView1.animate().setDuration(250).alpha(1f);
+ webView2.animate().setDuration(250).alpha(1f);
+
+ if(!hasApplicationLoaded)
+ {
+ try
+ {
+ sleep(2000);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ hasApplicationLoaded = true;
+ splashScreen.animate().alpha(0.0f).setDuration(500).setListener(null).withEndAction((new Runnable() {
+ @Override
+ public void run()
+ {
+ splashScreen.setVisibility(View.GONE);
+ }
+ }));
+ }
+ if(!isRequestError)
+ {
+ requestFailure.animate().alpha(0.0f).setDuration(500).setListener(null).withEndAction((new Runnable() {
+ @Override
+ public void run()
+ {
+ requestFailure.setVisibility(View.GONE);
+ //reloadButton.setEnabled(false);
+ }
+ }));
+ }
+ isRequestError = false;
+
+ InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(searchbar.getWindowToken(), 0);
+ }
+
+ @Override
+ public void onReceivedError(WebView view, int errorCode, String description, String failingUrl)
+ {
+ Log.i("SUPME3 : ","ERROR");
+ //reloadButton.setEnabled(true);
+ System.out.println("SUP2");
+ requestFailure.setVisibility(View.VISIBLE);
+ requestFailure.animate().alpha(1.0f);
+ isRequestError = true;
+
+ super.onReceivedError(view, errorCode, description, failingUrl);
+ }
+ };
+
+ return client;
+ }
+
+}
diff --git a/app/src/main/java/com/example/myapplication/torProxyServer.java b/app/src/main/java/com/example/myapplication/torProxyServer.java
new file mode 100644
index 00000000..ff99eab3
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/torProxyServer.java
@@ -0,0 +1,52 @@
+package com.example.myapplication;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import info.guardianproject.netcipher.NetCipher;
+import info.guardianproject.netcipher.proxy.OrbotHelper;
+import android.util.Log;
+import info.guardianproject.netcipher.proxy.StatusCallback;
+
+public class torProxyServer {
+ private static final torProxyServer ourInstance = new torProxyServer();
+
+ public static torProxyServer getInstance() {
+ return ourInstance;
+ }
+
+ private torProxyServer() {
+ }
+
+ public void initialize(Context applicationContext, final Activity activity)
+ {
+ if (OrbotHelper.isOrbotInstalled(activity))
+ {
+ NetCipher.useTor();
+ OrbotHelper.get(activity).statusTimeout(60000).addStatusCallback(new StatusCallback(){
+ @Override
+ public void onEnabled(Intent intent){ Log.d("Log Started","Log Started"); }
+
+ @Override
+ public void onStarting() { }
+
+ @Override
+ public void onStopping(){ }
+
+ @Override
+ public void onDisabled(){ }
+
+ @Override
+ public void onStatusTimeout(){ }
+
+ @Override
+ public void onNotYetInstalled(){ }
+ }).init();
+ }
+ else
+ {
+ Intent intent = OrbotHelper.getOrbotInstallIntent(activity);
+ activity.startActivityForResult(intent,0);
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/myapplication/webRequestHandler.java b/app/src/main/java/com/example/myapplication/webRequestHandler.java
new file mode 100644
index 00000000..e467c781
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/webRequestHandler.java
@@ -0,0 +1,184 @@
+package com.example.myapplication;
+
+import android.os.Message;
+import android.support.constraint.ConstraintLayout;
+import android.util.Log;
+import android.view.View;
+import android.webkit.WebView;
+import android.widget.EditText;
+import android.widget.ProgressBar;
+import cz.msebera.android.httpclient.HttpResponse;
+import cz.msebera.android.httpclient.client.HttpClient;
+import cz.msebera.android.httpclient.client.methods.HttpGet;
+import cz.msebera.android.httpclient.impl.client.DefaultHttpClient;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import android.os.Handler;
+
+public class webRequestHandler
+{
+ private static final webRequestHandler ourInstance = new webRequestHandler();
+ private WebView[] view = new WebView[2];;
+ private int viewIndex = 1;
+ private int currentViewIndex = 0;
+ private String html = "";
+ private String baseURL = "";
+ private Boolean isLoading = false;
+ private ProgressBar progressBar;
+ private EditText searchbar;
+ private HttpClient client = null;
+ private Thread clientThread = null;
+ private Boolean isRendering = false;
+ private ConstraintLayout requestFailure;
+
+ public static webRequestHandler getInstance() {
+ return ourInstance;
+ }
+
+ private webRequestHandler()
+ {
+ }
+
+ public void initialization(WebView view1,WebView view2,ProgressBar progressBar,EditText searchbar,ConstraintLayout requestFailure)
+ {
+ this.view[0] = view1;
+ this.view[1] = view2;
+ this.progressBar = progressBar;
+ this.searchbar = searchbar;
+ this.requestFailure = requestFailure;
+ createUpdateUiHandler();
+ }
+
+ public void loadURL(final String url)
+ {
+ try
+ {
+ progressBar.setVisibility(View.VISIBLE);
+ if(isRendering)
+ {
+ return;
+ }
+
+ if(!isLoading)
+ {
+ searchbar.setText(url.replace("http://boogle.store","http://genesis.onion"));
+ }
+ else if(client!=null)
+ {
+ client.getConnectionManager().shutdown();
+ isLoading = false;
+ }
+ if(clientThread!=null)
+ {
+ clientThread.interrupt();
+ }
+ client = new DefaultHttpClient();
+ }
+ catch (Exception ex)
+ {
+ Log.d("SUPER WOW1","SUPER WOW");
+ }
+ clientThread = new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+ try
+ {
+ isLoading = true;
+ HttpGet request = new HttpGet(url);
+ baseURL = url;
+ HttpResponse response = client.execute(request);
+ InputStream in = response.getEntity().getContent();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+ StringBuilder str = new StringBuilder();
+ String line = null;
+
+ while((line = reader.readLine()) != null)
+ {
+ if(!isLoading)
+ {
+ return;
+ }
+ str.append(line);
+ }
+ in.close();
+ html = str.toString();
+ Message message = new Message();
+ message.what = MESSAGE_UPDATE_TEXT_CHILD_THREAD;
+ updateUIHandler.sendMessage(message);
+ }
+ catch (Exception e)
+ {
+ Message message = new Message();
+ message.what = INTERNET_ERROR;
+ updateUIHandler.sendMessage(message);
+ Log.d("SUPER WOW2","SUPER WOW");
+ e.printStackTrace();
+ }
+ }
+ });
+ clientThread.start();
+ }
+
+ private Handler updateUIHandler = null;
+ private final static int MESSAGE_UPDATE_TEXT_CHILD_THREAD =1;
+ private final static int INTERNET_ERROR =2;
+
+ public WebView getView()
+ {
+ return view[currentViewIndex];
+ }
+
+ private void createUpdateUiHandler()
+ {
+
+ if(updateUIHandler == null)
+ {
+ updateUIHandler = new Handler()
+ {
+ @Override
+ public void handleMessage(Message msg) {
+ Log.i("APPLYING : ","SUCCESS : APPLYING");
+ if(msg.what == MESSAGE_UPDATE_TEXT_CHILD_THREAD && isLoading &&!isRendering)
+ {
+ isRendering = true;
+ view[viewIndex].animate().setDuration(0).alpha(0f);
+ view[viewIndex].bringToFront();
+ view[viewIndex].loadDataWithBaseURL(baseURL,html, "text/html", "utf-8", null);
+
+ if(viewIndex==1)
+ {
+ viewIndex = 0;
+ currentViewIndex =1;
+ }
+ else
+ {
+ viewIndex = 1;
+ currentViewIndex=0;
+ }
+ view[currentViewIndex].animate().setDuration(0).alpha(0f).withEndAction((new Runnable() {
+ @Override
+ public void run()
+ {
+ isLoading = false;
+ progressBar.setVisibility(View.INVISIBLE);
+ isRendering = false;
+ }
+ }));
+ }
+ else if (msg.what == INTERNET_ERROR)
+ {
+ isRendering = false;
+ isLoading = false;
+ progressBar.setVisibility(View.INVISIBLE);
+ requestFailure.setVisibility(View.VISIBLE);
+ requestFailure.animate().alpha(1f).setDuration(500);
+ }
+ }
+ };
+ }
+ }
+}
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 00000000..6348baae
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/backgradient.xml b/app/src/main/res/drawable/backgradient.xml
new file mode 100644
index 00000000..b08efe05
--- /dev/null
+++ b/app/src/main/res/drawable/backgradient.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/border.xml b/app/src/main/res/drawable/border.xml
new file mode 100644
index 00000000..f26d56cb
--- /dev/null
+++ b/app/src/main/res/drawable/border.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/cursorcolor.xml b/app/src/main/res/drawable/cursorcolor.xml
new file mode 100644
index 00000000..711a1507
--- /dev/null
+++ b/app/src/main/res/drawable/cursorcolor.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/homeicon.png b/app/src/main/res/drawable/homeicon.png
new file mode 100644
index 00000000..60f3721f
Binary files /dev/null and b/app/src/main/res/drawable/homeicon.png differ
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 00000000..8428ee45
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/interneticon.png b/app/src/main/res/drawable/interneticon.png
new file mode 100644
index 00000000..5a89c082
Binary files /dev/null and b/app/src/main/res/drawable/interneticon.png differ
diff --git a/app/src/main/res/drawable/logolarge.png b/app/src/main/res/drawable/logolarge.png
new file mode 100644
index 00000000..50585dfb
Binary files /dev/null and b/app/src/main/res/drawable/logolarge.png differ
diff --git a/app/src/main/res/drawable/pressedcolor.xml b/app/src/main/res/drawable/pressedcolor.xml
new file mode 100644
index 00000000..a829bc6a
--- /dev/null
+++ b/app/src/main/res/drawable/pressedcolor.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/progress_style.xml b/app/src/main/res/drawable/progress_style.xml
new file mode 100644
index 00000000..9b4949da
--- /dev/null
+++ b/app/src/main/res/drawable/progress_style.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/searchbar.xml b/app/src/main/res/drawable/searchbar.xml
new file mode 100644
index 00000000..1a9831bf
--- /dev/null
+++ b/app/src/main/res/drawable/searchbar.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/shadow.xml b/app/src/main/res/drawable/shadow.xml
new file mode 100644
index 00000000..f382569f
--- /dev/null
+++ b/app/src/main/res/drawable/shadow.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape.xml b/app/src/main/res/drawable/shape.xml
new file mode 100644
index 00000000..3adaf3de
--- /dev/null
+++ b/app/src/main/res/drawable/shape.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/topbar.xml b/app/src/main/res/drawable/topbar.xml
new file mode 100644
index 00000000..21ef3716
--- /dev/null
+++ b/app/src/main/res/drawable/topbar.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/touch_selector.xml b/app/src/main/res/drawable/touch_selector.xml
new file mode 100644
index 00000000..fdabe290
--- /dev/null
+++ b/app/src/main/res/drawable/touch_selector.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_application_controller.xml b/app/src/main/res/layout/activity_application_controller.xml
new file mode 100644
index 00000000..0bbdbf9d
--- /dev/null
+++ b/app/src/main/res/layout/activity_application_controller.xml
@@ -0,0 +1,199 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..1b4363dc
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/splash.xml b/app/src/main/res/layout/splash.xml
new file mode 100644
index 00000000..7524f5f0
--- /dev/null
+++ b/app/src/main/res/layout/splash.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/homeicon.png b/app/src/main/res/mipmap-anydpi-v26/homeicon.png
new file mode 100644
index 00000000..e8e2d57d
Binary files /dev/null and b/app/src/main/res/mipmap-anydpi-v26/homeicon.png differ
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 00000000..bbd3e021
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 00000000..bbd3e021
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/homeicon.png b/app/src/main/res/mipmap-hdpi/homeicon.png
new file mode 100644
index 00000000..e8e2d57d
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/homeicon.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round_v1.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round_v1.png
new file mode 100644
index 00000000..44ce853e
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round_v1.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_v1.png b/app/src/main/res/mipmap-hdpi/ic_launcher_v1.png
new file mode 100644
index 00000000..44ce853e
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_v1.png differ
diff --git a/app/src/main/res/mipmap-mdpi/homeicon.png b/app/src/main/res/mipmap-mdpi/homeicon.png
new file mode 100644
index 00000000..e8e2d57d
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/homeicon.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round_v1.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round_v1.png
new file mode 100644
index 00000000..44ce853e
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round_v1.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_v1.png b/app/src/main/res/mipmap-mdpi/ic_launcher_v1.png
new file mode 100644
index 00000000..44ce853e
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_v1.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/homeicon.png b/app/src/main/res/mipmap-xhdpi/homeicon.png
new file mode 100644
index 00000000..e8e2d57d
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/homeicon.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round_v1.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round_v1.png
new file mode 100644
index 00000000..44ce853e
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round_v1.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_v1.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_v1.png
new file mode 100644
index 00000000..44ce853e
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_v1.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/homeicon.png b/app/src/main/res/mipmap-xxhdpi/homeicon.png
new file mode 100644
index 00000000..e8e2d57d
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/homeicon.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round_v1.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round_v1.png
new file mode 100644
index 00000000..44ce853e
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round_v1.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_v1.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_v1.png
new file mode 100644
index 00000000..44ce853e
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_v1.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/homeicon.png b/app/src/main/res/mipmap-xxxhdpi/homeicon.png
new file mode 100644
index 00000000..e8e2d57d
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/homeicon.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round_v1.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round_v1.png
new file mode 100644
index 00000000..44ce853e
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round_v1.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_v1.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_v1.png
new file mode 100644
index 00000000..44ce853e
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_v1.png differ
diff --git a/app/src/main/res/values-v23/styles.xml b/app/src/main/res/values-v23/styles.xml
new file mode 100644
index 00000000..7f847b50
--- /dev/null
+++ b/app/src/main/res/values-v23/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 00000000..b8379b69
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,8 @@
+
+
+ #000000
+ #000000
+ #000000
+ #0066ff
+ #b3b3b3
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..eea21bd3
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ Genesis
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..24c67d15
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/app/src/test/java/com/example/myapplication/ExampleUnitTest.kt b/app/src/test/java/com/example/myapplication/ExampleUnitTest.kt
new file mode 100644
index 00000000..6ddef98f
--- /dev/null
+++ b/app/src/test/java/com/example/myapplication/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.example.myapplication
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 00000000..a65bf842
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,26 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ ext.kotlin_version = '1.3.20'
+ repositories {
+ google()
+ jcenter()
+ maven { url 'https://jitpack.io' }
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.3.1'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ maven { url 'https://jitpack.io' }
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 00000000..85be9ead
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,15 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..f6b961fd
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..981d2c42
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Sat Feb 23 18:52:38 PKT 2019
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
diff --git a/gradlew b/gradlew
new file mode 100644
index 00000000..cccdd3d5
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 00000000..f9553162
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 00000000..e7b4def4
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+include ':app'