基础版本
diff --git a/platforms/android/.gitignore b/platforms/android/.gitignore
new file mode 100644
index 0000000..427a160
--- /dev/null
+++ b/platforms/android/.gitignore
@@ -0,0 +1,21 @@
+# Non-project-specific build files:
+build.xml
+local.properties
+/gradlew
+/gradlew.bat
+/gradle
+# Ant builds
+ant-build
+ant-gen
+# Eclipse builds
+gen
+out
+# Gradle build artifacts
+.gradle
+.gradletasknamecache
+/build
+/CordovaLib/build
+/app/build
+gradle-app.setting
+# Android Studio
+.idea
diff --git a/platforms/android/CordovaLib/AndroidManifest.xml b/platforms/android/CordovaLib/AndroidManifest.xml
new file mode 100755
index 0000000..1625b89
--- /dev/null
+++ b/platforms/android/CordovaLib/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="org.apache.cordova" android:versionName="1.0" android:versionCode="1">
+    <uses-sdk android:minSdkVersion="19" />
+</manifest>
diff --git a/platforms/android/CordovaLib/build.gradle b/platforms/android/CordovaLib/build.gradle
new file mode 100644
index 0000000..b92c9a3
--- /dev/null
+++ b/platforms/android/CordovaLib/build.gradle
@@ -0,0 +1,136 @@
+/* Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+*/
+
+ext {
+    apply from: 'cordova.gradle'
+    cdvCompileSdkVersion = privateHelpers.getProjectTarget()
+    cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools()
+}
+
+buildscript {
+    repositories {
+        google()
+        jcenter()
+    }
+
+    dependencies {
+        // The gradle plugin and the maven plugin have to be updated after each version of Android
+        // studio comes out
+        classpath 'com.android.tools.build:gradle:3.3.0'
+        classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
+        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
+    }
+}
+
+apply plugin: 'com.android.library'
+apply plugin: 'com.github.dcendents.android-maven'
+apply plugin: 'com.jfrog.bintray'
+
+group = 'org.apache.cordova'
+version = '8.0.0'
+
+android {
+    compileSdkVersion cdvCompileSdkVersion
+    buildToolsVersion cdvBuildToolsVersion
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+
+    sourceSets {
+        main {
+            manifest.srcFile 'AndroidManifest.xml'
+            java.srcDirs = ['src']
+            resources.srcDirs = ['src']
+            aidl.srcDirs = ['src']
+            renderscript.srcDirs = ['src']
+            res.srcDirs = ['res']
+            assets.srcDirs = ['assets']
+        }
+    }
+
+    packagingOptions {
+        exclude 'META-INF/LICENSE'
+        exclude 'META-INF/LICENSE.txt'
+        exclude 'META-INF/DEPENDENCIES'
+        exclude 'META-INF/NOTICE'
+    }
+}
+
+install {
+    repositories.mavenInstaller {
+        pom {
+            project {
+                packaging 'aar'
+                name 'Cordova'
+                url 'https://cordova.apache.org'
+                licenses {
+                    license {
+                        name 'The Apache Software License, Version 2.0'
+                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+                    }
+                }
+                developers {
+                    developer {
+                        id 'stevengill'
+                        name 'Steve Gill'
+                    }
+                }
+                scm {
+                    connection 'scm:git:https://github.com/apache/cordova-android.git'
+                    developerConnection 'scm:git:git@github.com:apache/cordova-android.git'
+                    url 'https://github.com/apache/cordova-android'
+
+                }
+            }
+        }
+    }
+}
+
+task sourcesJar(type: Jar) {
+    from android.sourceSets.main.java.srcDirs
+    classifier = 'sources'
+}
+
+artifacts {
+    archives sourcesJar
+}
+
+bintray {
+    user = System.getenv('BINTRAY_USER')
+    key = System.getenv('BINTRAY_KEY')
+    configurations = ['archives']
+    pkg {
+        repo = 'maven'
+        name = 'cordova-android'
+        userOrg = 'cordova'
+        licenses = ['Apache-2.0']
+        vcsUrl = 'https://github.com/apache/cordova-android'
+        websiteUrl = 'https://cordova.apache.org'
+        issueTrackerUrl = 'https://github.com/apache/cordova-android/issues'
+        publicDownloadNumbers = true
+        licenses = ['Apache-2.0']
+        labels = ['android', 'cordova', 'phonegap']
+        version {
+            name = '8.0.0'
+            released  = new Date()
+            vcsTag = '8.0.0'
+        }
+    }
+}
diff --git a/platforms/android/CordovaLib/cordova.gradle b/platforms/android/CordovaLib/cordova.gradle
new file mode 100644
index 0000000..6c6819a
--- /dev/null
+++ b/platforms/android/CordovaLib/cordova.gradle
@@ -0,0 +1,205 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+import java.util.regex.Pattern
+import groovy.swing.SwingBuilder
+
+String doEnsureValueExists(filePath, props, key) {
+    if (props.get(key) == null) {
+        throw new GradleException(filePath + ': Missing key required "' + key + '"')
+    }
+    return props.get(key)
+}
+
+String doGetProjectTarget() {
+    def props = new Properties()
+    def propertiesFile = 'project.properties';
+    if(!(file(propertiesFile).exists())) {
+      propertiesFile = '../project.properties';
+    }
+    file(propertiesFile).withReader { reader ->
+        props.load(reader)
+    }
+    return doEnsureValueExists('project.properties', props, 'target')
+}
+
+String[] getAvailableBuildTools() {
+    def buildToolsDir = new File(getAndroidSdkDir(), "build-tools")
+    buildToolsDir.list()
+        .findAll { it ==~ /[0-9.]+/ }
+        .sort { a, b -> compareVersions(b, a) }
+}
+
+String doFindLatestInstalledBuildTools(String minBuildToolsVersion) {
+    def availableBuildToolsVersions
+    try {
+        availableBuildToolsVersions = getAvailableBuildTools()
+    } catch (e) {
+        println "An exception occurred while trying to find the Android build tools."
+        throw e
+    }
+    if (availableBuildToolsVersions.length > 0) {
+        def highestBuildToolsVersion = availableBuildToolsVersions[0]
+        if (compareVersions(highestBuildToolsVersion, minBuildToolsVersion) < 0) {
+            throw new RuntimeException(
+                "No usable Android build tools found. Highest installed version is " +
+                highestBuildToolsVersion + "; minimum version required is " +
+                minBuildToolsVersion + ".")
+        }
+        highestBuildToolsVersion
+    } else {
+        throw new RuntimeException(
+            "No installed build tools found. Install the Android build tools version " +
+            minBuildToolsVersion + " or higher.")
+    }
+}
+
+// Return the first non-zero result of subtracting version list elements
+// pairwise. If they are all identical, return the difference in length of
+// the two lists.
+int compareVersionList(Collection aParts, Collection bParts) {
+    def pairs = ([aParts, bParts]).transpose()
+    pairs.findResult(aParts.size()-bParts.size()) {it[0] - it[1] != 0 ? it[0] - it[1] : null}
+}
+
+// Compare two version strings, such as "19.0.0" and "18.1.1.0". If all matched
+// elements are identical, the longer version is the largest by this method.
+// Examples:
+//   "19.0.0" > "19"
+//   "19.0.1" > "19.0.0"
+//   "19.1.0" > "19.0.1"
+//   "19" > "18.999.999"
+int compareVersions(String a, String b) {
+    def aParts = a.tokenize('.').collect {it.toInteger()}
+    def bParts = b.tokenize('.').collect {it.toInteger()}
+    compareVersionList(aParts, bParts)
+}
+
+String getAndroidSdkDir() {
+    def rootDir = project.rootDir
+    def androidSdkDir = null
+    String envVar = System.getenv("ANDROID_HOME")
+    def localProperties = new File(rootDir, 'local.properties')
+    String systemProperty = System.getProperty("android.home")
+    if (envVar != null) {
+        androidSdkDir = envVar
+    } else if (localProperties.exists()) {
+        Properties properties = new Properties()
+        localProperties.withInputStream { instr ->
+            properties.load(instr)
+        }
+        def sdkDirProp = properties.getProperty('sdk.dir')
+        if (sdkDirProp != null) {
+            androidSdkDir = sdkDirProp
+        } else {
+            sdkDirProp = properties.getProperty('android.dir')
+            if (sdkDirProp != null) {
+                androidSdkDir = (new File(rootDir, sdkDirProp)).getAbsolutePath()
+            }
+        }
+    }
+    if (androidSdkDir == null && systemProperty != null) {
+        androidSdkDir = systemProperty
+    }
+    if (androidSdkDir == null) {
+        throw new RuntimeException(
+            "Unable to determine Android SDK directory.")
+    }
+    androidSdkDir
+}
+
+def doExtractIntFromManifest(name) {
+    def manifestFile = file(android.sourceSets.main.manifest.srcFile)
+    def pattern = Pattern.compile(name + "=\"(\\d+)\"")
+    def matcher = pattern.matcher(manifestFile.getText())
+    matcher.find()
+    return new BigInteger(matcher.group(1))
+}
+
+def doExtractStringFromManifest(name) {
+    def manifestFile = file(android.sourceSets.main.manifest.srcFile)
+    def pattern = Pattern.compile(name + "=\"(\\S+)\"")
+    def matcher = pattern.matcher(manifestFile.getText())
+    matcher.find()
+    return matcher.group(1)
+}
+
+def doPromptForPassword(msg) {
+    if (System.console() == null) {
+        def ret = null
+        new SwingBuilder().edt {
+            dialog(modal: true, title: 'Enter password', alwaysOnTop: true, resizable: false, locationRelativeTo: null, pack: true, show: true) {
+                vbox {
+                    label(text: msg)
+                    def input = passwordField()
+                    button(defaultButton: true, text: 'OK', actionPerformed: {
+                        ret = input.password;
+                        dispose();
+                    })
+                }
+            }
+        }
+        if (!ret) {
+            throw new GradleException('User canceled build')
+        }
+        return new String(ret)
+    } else {
+        return System.console().readPassword('\n' + msg);
+    }
+}
+
+def doGetConfigXml() {
+    def xml = file("src/main/res/xml/config.xml").getText()
+    // Disable namespace awareness since Cordova doesn't use them properly
+    return new XmlParser(false, false).parseText(xml)
+}
+
+def doGetConfigPreference(name, defaultValue) {
+    name = name.toLowerCase()
+    def root = doGetConfigXml()
+
+    def ret = defaultValue
+    root.preference.each { it ->
+        def attrName = it.attribute("name")
+        if (attrName && attrName.toLowerCase() == name) {
+            ret = it.attribute("value")
+        }
+    }
+    return ret
+}
+
+// Properties exported here are visible to all plugins.
+ext {
+    // These helpers are shared, but are not guaranteed to be stable / unchanged.
+    privateHelpers = {}
+    privateHelpers.getProjectTarget = { doGetProjectTarget() }
+    privateHelpers.findLatestInstalledBuildTools = { doFindLatestInstalledBuildTools('19.1.0') }
+    privateHelpers.extractIntFromManifest = { name -> doExtractIntFromManifest(name) }
+    privateHelpers.extractStringFromManifest = { name -> doExtractStringFromManifest(name) }
+    privateHelpers.promptForPassword = { msg -> doPromptForPassword(msg) }
+    privateHelpers.ensureValueExists = { filePath, props, key -> doEnsureValueExists(filePath, props, key) }
+
+    // These helpers can be used by plugins / projects and will not change.
+    cdvHelpers = {}
+    // Returns a XmlParser for the config.xml. Added in 4.1.0.
+    cdvHelpers.getConfigXml = { doGetConfigXml() }
+    // Returns the value for the desired <preference>. Added in 4.1.0.
+    cdvHelpers.getConfigPreference = { name, defaultValue -> doGetConfigPreference(name, defaultValue) }
+}
+
diff --git a/platforms/android/CordovaLib/project.properties b/platforms/android/CordovaLib/project.properties
new file mode 100644
index 0000000..cbb644c
--- /dev/null
+++ b/platforms/android/CordovaLib/project.properties
@@ -0,0 +1,11 @@
+# This file was originally created by the Android Tools, but is now
+# used by cordova-android to manage the project configuration.
+
+# Indicates whether an apk should be generated for each density.
+split.density=false
+
+# Project target.
+target=android-28
+apk-configurations=
+renderscript.opt.level=O0
+android.library=true
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/AuthenticationToken.java b/platforms/android/CordovaLib/src/org/apache/cordova/AuthenticationToken.java
new file mode 100644
index 0000000..d3a231a
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/AuthenticationToken.java
@@ -0,0 +1,69 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+/**
+ * The Class AuthenticationToken defines the userName and password to be used for authenticating a web resource
+ */
+public class AuthenticationToken {
+    private String userName;
+    private String password;
+
+    /**
+     * Gets the user name.
+     *
+     * @return the user name
+     */
+    public String getUserName() {
+        return userName;
+    }
+
+    /**
+     * Sets the user name.
+     *
+     * @param userName
+     *            the new user name
+     */
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    /**
+     * Gets the password.
+     *
+     * @return the password
+     */
+    public String getPassword() {
+        return password;
+    }
+
+    /**
+     * Sets the password.
+     *
+     * @param password
+     *            the new password
+     */
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+
+
+
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/BuildHelper.java b/platforms/android/CordovaLib/src/org/apache/cordova/BuildHelper.java
new file mode 100644
index 0000000..6d9daa4
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/BuildHelper.java
@@ -0,0 +1,70 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova;
+
+/*
+ * This is a utility class that allows us to get the BuildConfig variable, which is required
+ * for the use of different providers.  This is not guaranteed to work, and it's better for this
+ * to be set in the build step in config.xml
+ *
+ */
+
+import android.app.Activity;
+import android.content.Context;
+
+import java.lang.reflect.Field;
+
+
+public class BuildHelper {
+
+
+    private static String TAG="BuildHelper";
+
+    /*
+     * This needs to be implemented if you wish to use the Camera Plugin or other plugins
+     * that read the Build Configuration.
+     *
+     * Thanks to Phil@Medtronic and Graham Borland for finding the answer and posting it to
+     * StackOverflow.  This is annoying as hell!  However, this method does not work with
+     * ProGuard, and you should use the config.xml to define the application_id
+     *
+     */
+
+    public static Object getBuildConfigValue(Context ctx, String key)
+    {
+        try
+        {
+            Class<?> clazz = Class.forName(ctx.getPackageName() + ".BuildConfig");
+            Field field = clazz.getField(key);
+            return field.get(null);
+        } catch (ClassNotFoundException e) {
+            LOG.d(TAG, "Unable to get the BuildConfig, is this built with ANT?");
+            e.printStackTrace();
+        } catch (NoSuchFieldException e) {
+            LOG.d(TAG, key + " is not a valid field. Check your build.gradle");
+        } catch (IllegalAccessException e) {
+            LOG.d(TAG, "Illegal Access Exception: Let's print a stack trace.");
+            e.printStackTrace();
+        }
+
+        return null;
+    }
+
+}
\ No newline at end of file
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CallbackContext.java b/platforms/android/CordovaLib/src/org/apache/cordova/CallbackContext.java
new file mode 100644
index 0000000..4336386
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/CallbackContext.java
@@ -0,0 +1,142 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import org.json.JSONArray;
+
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.PluginResult;
+import org.json.JSONObject;
+
+public class CallbackContext {
+    private static final String LOG_TAG = "CordovaPlugin";
+
+    private String callbackId;
+    private CordovaWebView webView;
+    protected boolean finished;
+    private int changingThreads;
+
+    public CallbackContext(String callbackId, CordovaWebView webView) {
+        this.callbackId = callbackId;
+        this.webView = webView;
+    }
+
+    public boolean isFinished() {
+        return finished;
+    }
+
+    public boolean isChangingThreads() {
+        return changingThreads > 0;
+    }
+
+    public String getCallbackId() {
+        return callbackId;
+    }
+
+    public void sendPluginResult(PluginResult pluginResult) {
+        synchronized (this) {
+            if (finished) {
+                LOG.w(LOG_TAG, "Attempted to send a second callback for ID: " + callbackId + "\nResult was: " + pluginResult.getMessage());
+                return;
+            } else {
+                finished = !pluginResult.getKeepCallback();
+            }
+        }
+        webView.sendPluginResult(pluginResult, callbackId);
+    }
+
+    /**
+     * Helper for success callbacks that just returns the Status.OK by default
+     *
+     * @param message           The message to add to the success result.
+     */
+    public void success(JSONObject message) {
+        sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
+    }
+
+    /**
+     * Helper for success callbacks that just returns the Status.OK by default
+     *
+     * @param message           The message to add to the success result.
+     */
+    public void success(String message) {
+        sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
+    }
+
+    /**
+     * Helper for success callbacks that just returns the Status.OK by default
+     *
+     * @param message           The message to add to the success result.
+     */
+    public void success(JSONArray message) {
+        sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
+    }
+
+    /**
+     * Helper for success callbacks that just returns the Status.OK by default
+     *
+     * @param message           The message to add to the success result.
+     */
+    public void success(byte[] message) {
+        sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
+    }
+
+    /**
+     * Helper for success callbacks that just returns the Status.OK by default
+     *
+     * @param message           The message to add to the success result.
+     */
+    public void success(int message) {
+        sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
+    }
+
+    /**
+     * Helper for success callbacks that just returns the Status.OK by default
+     */
+    public void success() {
+        sendPluginResult(new PluginResult(PluginResult.Status.OK));
+    }
+
+    /**
+     * Helper for error callbacks that just returns the Status.ERROR by default
+     *
+     * @param message           The message to add to the error result.
+     */
+    public void error(JSONObject message) {
+        sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message));
+    }
+
+    /**
+     * Helper for error callbacks that just returns the Status.ERROR by default
+     *
+     * @param message           The message to add to the error result.
+     */
+    public void error(String message) {
+        sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message));
+    }
+
+    /**
+     * Helper for error callbacks that just returns the Status.ERROR by default
+     *
+     * @param message           The message to add to the error result.
+     */
+    public void error(int message) {
+        sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message));
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CallbackMap.java b/platforms/android/CordovaLib/src/org/apache/cordova/CallbackMap.java
new file mode 100644
index 0000000..050daa0
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/CallbackMap.java
@@ -0,0 +1,65 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import android.util.Pair;
+import android.util.SparseArray;
+
+/**
+ * Provides a collection that maps unique request codes to CordovaPlugins and Integers.
+ * Used to ensure that when plugins make requests for runtime permissions, those requests do not
+ * collide with requests from other plugins that use the same request code value.
+ */
+public class CallbackMap {
+    private int currentCallbackId = 0;
+    private SparseArray<Pair<CordovaPlugin, Integer>> callbacks;
+
+    public CallbackMap() {
+        this.callbacks = new SparseArray<Pair<CordovaPlugin, Integer>>();
+    }
+
+    /**
+     * Stores a CordovaPlugin and request code and returns a new unique request code to use
+     * in a permission request.
+     *
+     * @param receiver      The plugin that is making the request
+     * @param requestCode   The original request code used by the plugin
+     * @return              A unique request code that can be used to retrieve this callback
+     *                      with getAndRemoveCallback()
+     */
+    public synchronized int registerCallback(CordovaPlugin receiver, int requestCode) {
+        int mappedId = this.currentCallbackId++;
+        callbacks.put(mappedId, new Pair<CordovaPlugin, Integer>(receiver, requestCode));
+        return mappedId;
+    }
+
+    /**
+     * Retrieves and removes a callback stored in the map using the mapped request code
+     * obtained from registerCallback()
+     *
+     * @param mappedId      The request code obtained from registerCallback()
+     * @return              The CordovaPlugin and orignal request code that correspond to the
+     *                      given mappedCode
+     */
+    public synchronized Pair<CordovaPlugin, Integer> getAndRemoveCallback(int mappedId) {
+        Pair<CordovaPlugin, Integer> callback = callbacks.get(mappedId);
+        callbacks.remove(mappedId);
+        return callback;
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/Config.java b/platforms/android/CordovaLib/src/org/apache/cordova/Config.java
new file mode 100644
index 0000000..0739795
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/Config.java
@@ -0,0 +1,71 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova;
+
+import java.util.List;
+
+import android.app.Activity;
+
+@Deprecated // Use Whitelist, CordovaPrefences, etc. directly.
+public class Config {
+    private static final String TAG = "Config";
+
+    static ConfigXmlParser parser;
+
+    private Config() {
+    }
+
+    public static void init(Activity action) {
+        parser = new ConfigXmlParser();
+        parser.parse(action);
+        //TODO: Add feature to bring this back.  Some preferences should be overridden by intents, but not all
+        parser.getPreferences().setPreferencesBundle(action.getIntent().getExtras());
+    }
+
+    // Intended to be used for testing only; creates an empty configuration.
+    public static void init() {
+        if (parser == null) {
+            parser = new ConfigXmlParser();
+        }
+    }
+
+    public static String getStartUrl() {
+        if (parser == null) {
+            return "file:///android_asset/www/index.html";
+        }
+        return parser.getLaunchUrl();
+    }
+
+    public static String getErrorUrl() {
+        return parser.getPreferences().getString("errorurl", null);
+    }
+
+    public static List<PluginEntry> getPluginEntries() {
+        return parser.getPluginEntries();
+    }
+
+    public static CordovaPreferences getPreferences() {
+        return parser.getPreferences();
+    }
+
+    public static boolean isInitialized() {
+        return parser != null;
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/ConfigXmlParser.java b/platforms/android/CordovaLib/src/org/apache/cordova/ConfigXmlParser.java
new file mode 100644
index 0000000..01a97f2
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/ConfigXmlParser.java
@@ -0,0 +1,145 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+
+public class ConfigXmlParser {
+    private static String TAG = "ConfigXmlParser";
+
+    private String launchUrl = "file:///android_asset/www/index.html";
+    private CordovaPreferences prefs = new CordovaPreferences();
+    private ArrayList<PluginEntry> pluginEntries = new ArrayList<PluginEntry>(20);
+
+    public CordovaPreferences getPreferences() {
+        return prefs;
+    }
+
+    public ArrayList<PluginEntry> getPluginEntries() {
+        return pluginEntries;
+    }
+
+    public String getLaunchUrl() {
+        return launchUrl;
+    }
+
+    public void parse(Context action) {
+        // First checking the class namespace for config.xml
+        int id = action.getResources().getIdentifier("config", "xml", action.getClass().getPackage().getName());
+        if (id == 0) {
+            // If we couldn't find config.xml there, we'll look in the namespace from AndroidManifest.xml
+            id = action.getResources().getIdentifier("config", "xml", action.getPackageName());
+            if (id == 0) {
+                LOG.e(TAG, "res/xml/config.xml is missing!");
+                return;
+            }
+        }
+        parse(action.getResources().getXml(id));
+    }
+
+    boolean insideFeature = false;
+    String service = "", pluginClass = "", paramType = "";
+    boolean onload = false;
+
+    public void parse(XmlPullParser xml) {
+        int eventType = -1;
+
+        while (eventType != XmlPullParser.END_DOCUMENT) {
+            if (eventType == XmlPullParser.START_TAG) {
+                handleStartTag(xml);
+            }
+            else if (eventType == XmlPullParser.END_TAG)
+            {
+                handleEndTag(xml);
+            }
+            try {
+                eventType = xml.next();
+            } catch (XmlPullParserException e) {
+                e.printStackTrace();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public void handleStartTag(XmlPullParser xml) {
+        String strNode = xml.getName();
+        if (strNode.equals("feature")) {
+            //Check for supported feature sets  aka. plugins (Accelerometer, Geolocation, etc)
+            //Set the bit for reading params
+            insideFeature = true;
+            service = xml.getAttributeValue(null, "name");
+        }
+        else if (insideFeature && strNode.equals("param")) {
+            paramType = xml.getAttributeValue(null, "name");
+            if (paramType.equals("service")) // check if it is using the older service param
+                service = xml.getAttributeValue(null, "value");
+            else if (paramType.equals("package") || paramType.equals("android-package"))
+                pluginClass = xml.getAttributeValue(null,"value");
+            else if (paramType.equals("onload"))
+                onload = "true".equals(xml.getAttributeValue(null, "value"));
+        }
+        else if (strNode.equals("preference")) {
+            String name = xml.getAttributeValue(null, "name").toLowerCase(Locale.ENGLISH);
+            String value = xml.getAttributeValue(null, "value");
+            prefs.set(name, value);
+        }
+        else if (strNode.equals("content")) {
+            String src = xml.getAttributeValue(null, "src");
+            if (src != null) {
+                setStartUrl(src);
+            }
+        }
+    }
+
+    public void handleEndTag(XmlPullParser xml) {
+        String strNode = xml.getName();
+        if (strNode.equals("feature")) {
+            pluginEntries.add(new PluginEntry(service, pluginClass, onload));
+
+            service = "";
+            pluginClass = "";
+            insideFeature = false;
+            onload = false;
+        }
+    }
+
+    private void setStartUrl(String src) {
+        Pattern schemeRegex = Pattern.compile("^[a-z-]+://");
+        Matcher matcher = schemeRegex.matcher(src);
+        if (matcher.find()) {
+            launchUrl = src;
+        } else {
+            if (src.charAt(0) == '/') {
+                src = src.substring(1);
+            }
+            launchUrl = "file:///android_asset/www/" + src;
+        }
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaActivity.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaActivity.java
new file mode 100755
index 0000000..dbbb48f
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaActivity.java
@@ -0,0 +1,519 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.annotation.SuppressLint;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.graphics.Color;
+import android.media.AudioManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.webkit.WebViewClient;
+import android.widget.FrameLayout;
+
+/**
+ * This class is the main Android activity that represents the Cordova
+ * application. It should be extended by the user to load the specific
+ * html file that contains the application.
+ *
+ * As an example:
+ *
+ * <pre>
+ *     package org.apache.cordova.examples;
+ *
+ *     import android.os.Bundle;
+ *     import org.apache.cordova.*;
+ *
+ *     public class Example extends CordovaActivity {
+ *       &#64;Override
+ *       public void onCreate(Bundle savedInstanceState) {
+ *         super.onCreate(savedInstanceState);
+ *         super.init();
+ *         // Load your application
+ *         loadUrl(launchUrl);
+ *       }
+ *     }
+ * </pre>
+ *
+ * Cordova xml configuration: Cordova uses a configuration file at
+ * res/xml/config.xml to specify its settings. See "The config.xml File"
+ * guide in cordova-docs at http://cordova.apache.org/docs for the documentation
+ * for the configuration. The use of the set*Property() methods is
+ * deprecated in favor of the config.xml file.
+ *
+ */
+public class CordovaActivity extends Activity {
+    public static String TAG = "CordovaActivity";
+
+    // The webview for our app
+    protected CordovaWebView appView;
+
+    private static int ACTIVITY_STARTING = 0;
+    private static int ACTIVITY_RUNNING = 1;
+    private static int ACTIVITY_EXITING = 2;
+
+    // Keep app running when pause is received. (default = true)
+    // If true, then the JavaScript and native code continue to run in the background
+    // when another application (activity) is started.
+    protected boolean keepRunning = true;
+
+    // Flag to keep immersive mode if set to fullscreen
+    protected boolean immersiveMode;
+
+    // Read from config.xml:
+    protected CordovaPreferences preferences;
+    protected String launchUrl;
+    protected ArrayList<PluginEntry> pluginEntries;
+    protected CordovaInterfaceImpl cordovaInterface;
+
+    /**
+     * Called when the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        // need to activate preferences before super.onCreate to avoid "requestFeature() must be called before adding content" exception
+        loadConfig();
+
+        String logLevel = preferences.getString("loglevel", "ERROR");
+        LOG.setLogLevel(logLevel);
+
+        LOG.i(TAG, "Apache Cordova native platform version " + CordovaWebView.CORDOVA_VERSION + " is starting");
+        LOG.d(TAG, "CordovaActivity.onCreate()");
+
+        if (!preferences.getBoolean("ShowTitle", false)) {
+            getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+        }
+
+        if (preferences.getBoolean("SetFullscreen", false)) {
+            LOG.d(TAG, "The SetFullscreen configuration is deprecated in favor of Fullscreen, and will be removed in a future version.");
+            preferences.set("Fullscreen", true);
+        }
+        if (preferences.getBoolean("Fullscreen", false)) {
+            // NOTE: use the FullscreenNotImmersive configuration key to set the activity in a REAL full screen
+            // (as was the case in previous cordova versions)
+            if (!preferences.getBoolean("FullscreenNotImmersive", false)) {
+                immersiveMode = true;
+            } else {
+                getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+                        WindowManager.LayoutParams.FLAG_FULLSCREEN);
+            }
+        } else {
+            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
+                    WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+        }
+
+        super.onCreate(savedInstanceState);
+
+        cordovaInterface = makeCordovaInterface();
+        if (savedInstanceState != null) {
+            cordovaInterface.restoreInstanceState(savedInstanceState);
+        }
+    }
+
+    protected void init() {
+        appView = makeWebView();
+        createViews();
+        if (!appView.isInitialized()) {
+            appView.init(cordovaInterface, pluginEntries, preferences);
+        }
+        cordovaInterface.onCordovaInit(appView.getPluginManager());
+
+        // Wire the hardware volume controls to control media if desired.
+        String volumePref = preferences.getString("DefaultVolumeStream", "");
+        if ("media".equals(volumePref.toLowerCase(Locale.ENGLISH))) {
+            setVolumeControlStream(AudioManager.STREAM_MUSIC);
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    protected void loadConfig() {
+        ConfigXmlParser parser = new ConfigXmlParser();
+        parser.parse(this);
+        preferences = parser.getPreferences();
+        preferences.setPreferencesBundle(getIntent().getExtras());
+        launchUrl = parser.getLaunchUrl();
+        pluginEntries = parser.getPluginEntries();
+        Config.parser = parser;
+    }
+
+    //Suppressing warnings in AndroidStudio
+    @SuppressWarnings({"deprecation", "ResourceType"})
+    protected void createViews() {
+        //Why are we setting a constant as the ID? This should be investigated
+        appView.getView().setId(100);
+        appView.getView().setLayoutParams(new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT));
+
+        setContentView(appView.getView());
+
+        if (preferences.contains("BackgroundColor")) {
+            try {
+                int backgroundColor = preferences.getInteger("BackgroundColor", Color.BLACK);
+                // Background of activity:
+                appView.getView().setBackgroundColor(backgroundColor);
+            }
+            catch (NumberFormatException e){
+                e.printStackTrace();
+            }
+        }
+
+        appView.getView().requestFocusFromTouch();
+    }
+
+    /**
+     * Construct the default web view object.
+     * <p/>
+     * Override this to customize the webview that is used.
+     */
+    protected CordovaWebView makeWebView() {
+        return new CordovaWebViewImpl(makeWebViewEngine());
+    }
+
+    protected CordovaWebViewEngine makeWebViewEngine() {
+        return CordovaWebViewImpl.createEngine(this, preferences);
+    }
+
+    protected CordovaInterfaceImpl makeCordovaInterface() {
+        return new CordovaInterfaceImpl(this) {
+            @Override
+            public Object onMessage(String id, Object data) {
+                // Plumb this to CordovaActivity.onMessage for backwards compatibility
+                return CordovaActivity.this.onMessage(id, data);
+            }
+        };
+    }
+
+    /**
+     * Load the url into the webview.
+     */
+    public void loadUrl(String url) {
+        if (appView == null) {
+            init();
+        }
+
+        // If keepRunning
+        this.keepRunning = preferences.getBoolean("KeepRunning", true);
+
+        appView.loadUrlIntoView(url, true);
+    }
+
+    /**
+     * Called when the system is about to start resuming a previous activity.
+     */
+    @Override
+    protected void onPause() {
+        super.onPause();
+        LOG.d(TAG, "Paused the activity.");
+
+        if (this.appView != null) {
+            // CB-9382 If there is an activity that started for result and main activity is waiting for callback
+            // result, we shoudn't stop WebView Javascript timers, as activity for result might be using them
+            boolean keepRunning = this.keepRunning || this.cordovaInterface.activityResultCallback != null;
+            this.appView.handlePause(keepRunning);
+        }
+    }
+
+    /**
+     * Called when the activity receives a new intent
+     */
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        //Forward to plugins
+        if (this.appView != null)
+            this.appView.onNewIntent(intent);
+    }
+
+    /**
+     * Called when the activity will start interacting with the user.
+     */
+    @Override
+    protected void onResume() {
+        super.onResume();
+        LOG.d(TAG, "Resumed the activity.");
+
+        if (this.appView == null) {
+            return;
+        }
+        // Force window to have focus, so application always
+        // receive user input. Workaround for some devices (Samsung Galaxy Note 3 at least)
+        this.getWindow().getDecorView().requestFocus();
+
+        this.appView.handleResume(this.keepRunning);
+    }
+
+    /**
+     * Called when the activity is no longer visible to the user.
+     */
+    @Override
+    protected void onStop() {
+        super.onStop();
+        LOG.d(TAG, "Stopped the activity.");
+
+        if (this.appView == null) {
+            return;
+        }
+        this.appView.handleStop();
+    }
+
+    /**
+     * Called when the activity is becoming visible to the user.
+     */
+    @Override
+    protected void onStart() {
+        super.onStart();
+        LOG.d(TAG, "Started the activity.");
+
+        if (this.appView == null) {
+            return;
+        }
+        this.appView.handleStart();
+    }
+
+    /**
+     * The final call you receive before your activity is destroyed.
+     */
+    @Override
+    public void onDestroy() {
+        LOG.d(TAG, "CordovaActivity.onDestroy()");
+        super.onDestroy();
+
+        if (this.appView != null) {
+            appView.handleDestroy();
+        }
+    }
+
+    /**
+     * Called when view focus is changed
+     */
+    @SuppressLint("InlinedApi")
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        if (hasFocus && immersiveMode) {
+            final int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+
+            getWindow().getDecorView().setSystemUiVisibility(uiOptions);
+        }
+    }
+
+    @SuppressLint("NewApi")
+    @Override
+    public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
+        // Capture requestCode here so that it is captured in the setActivityResultCallback() case.
+        cordovaInterface.setActivityResultRequestCode(requestCode);
+        super.startActivityForResult(intent, requestCode, options);
+    }
+
+    /**
+     * Called when an activity you launched exits, giving you the requestCode you started it with,
+     * the resultCode it returned, and any additional data from it.
+     *
+     * @param requestCode The request code originally supplied to startActivityForResult(),
+     *                    allowing you to identify who this result came from.
+     * @param resultCode  The integer result code returned by the child activity through its setResult().
+     * @param intent      An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
+     */
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
+        LOG.d(TAG, "Incoming Result. Request code = " + requestCode);
+        super.onActivityResult(requestCode, resultCode, intent);
+        cordovaInterface.onActivityResult(requestCode, resultCode, intent);
+    }
+
+    /**
+     * Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable).
+     * The errorCode parameter corresponds to one of the ERROR_* constants.
+     *
+     * @param errorCode   The error code corresponding to an ERROR_* value.
+     * @param description A String describing the error.
+     * @param failingUrl  The url that failed to load.
+     */
+    public void onReceivedError(final int errorCode, final String description, final String failingUrl) {
+        final CordovaActivity me = this;
+
+        // If errorUrl specified, then load it
+        final String errorUrl = preferences.getString("errorUrl", null);
+        if ((errorUrl != null) && (!failingUrl.equals(errorUrl)) && (appView != null)) {
+            // Load URL on UI thread
+            me.runOnUiThread(new Runnable() {
+                public void run() {
+                    me.appView.showWebPage(errorUrl, false, true, null);
+                }
+            });
+        }
+        // If not, then display error dialog
+        else {
+            final boolean exit = !(errorCode == WebViewClient.ERROR_HOST_LOOKUP);
+            me.runOnUiThread(new Runnable() {
+                public void run() {
+                    if (exit) {
+                        me.appView.getView().setVisibility(View.GONE);
+                        me.displayError("Application Error", description + " (" + failingUrl + ")", "OK", exit);
+                    }
+                }
+            });
+        }
+    }
+
+    /**
+     * Display an error dialog and optionally exit application.
+     */
+    public void displayError(final String title, final String message, final String button, final boolean exit) {
+        final CordovaActivity me = this;
+        me.runOnUiThread(new Runnable() {
+            public void run() {
+                try {
+                    AlertDialog.Builder dlg = new AlertDialog.Builder(me);
+                    dlg.setMessage(message);
+                    dlg.setTitle(title);
+                    dlg.setCancelable(false);
+                    dlg.setPositiveButton(button,
+                            new AlertDialog.OnClickListener() {
+                                public void onClick(DialogInterface dialog, int which) {
+                                    dialog.dismiss();
+                                    if (exit) {
+                                        finish();
+                                    }
+                                }
+                            });
+                    dlg.create();
+                    dlg.show();
+                } catch (Exception e) {
+                    finish();
+                }
+            }
+        });
+    }
+
+    /*
+     * Hook in Cordova for menu plugins
+     */
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        if (appView != null) {
+            appView.getPluginManager().postMessage("onCreateOptionsMenu", menu);
+        }
+        return super.onCreateOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        if (appView != null) {
+            appView.getPluginManager().postMessage("onPrepareOptionsMenu", menu);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (appView != null) {
+            appView.getPluginManager().postMessage("onOptionsItemSelected", item);
+        }
+        return true;
+    }
+
+    /**
+     * Called when a message is sent to plugin.
+     *
+     * @param id   The message id
+     * @param data The message data
+     * @return Object or null
+     */
+    public Object onMessage(String id, Object data) {
+        if ("onReceivedError".equals(id)) {
+            JSONObject d = (JSONObject) data;
+            try {
+                this.onReceivedError(d.getInt("errorCode"), d.getString("description"), d.getString("url"));
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+        } else if ("exit".equals(id)) {
+            finish();
+        }
+        return null;
+    }
+
+    protected void onSaveInstanceState(Bundle outState) {
+        cordovaInterface.onSaveInstanceState(outState);
+        super.onSaveInstanceState(outState);
+    }
+
+    /**
+     * Called by the system when the device configuration changes while your activity is running.
+     *
+     * @param newConfig The new device configuration
+     */
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        if (this.appView == null) {
+            return;
+        }
+        PluginManager pm = this.appView.getPluginManager();
+        if (pm != null) {
+            pm.onConfigurationChanged(newConfig);
+        }
+    }
+
+    /**
+     * Called by the system when the user grants permissions
+     *
+     * @param requestCode
+     * @param permissions
+     * @param grantResults
+     */
+    @Override
+    public void onRequestPermissionsResult(int requestCode, String permissions[],
+                                           int[] grantResults) {
+        try
+        {
+            cordovaInterface.onRequestPermissionResult(requestCode, permissions, grantResults);
+        }
+        catch (JSONException e)
+        {
+            LOG.d(TAG, "JSONException: Parameters fed into the method are not valid");
+            e.printStackTrace();
+        }
+
+    }
+
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaArgs.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaArgs.java
new file mode 100644
index 0000000..d40d26e
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaArgs.java
@@ -0,0 +1,113 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.util.Base64;
+
+public class CordovaArgs {
+    private JSONArray baseArgs;
+
+    public CordovaArgs(JSONArray args) {
+        this.baseArgs = args;
+    }
+
+
+    // Pass through the basics to the base args.
+    public Object get(int index) throws JSONException {
+        return baseArgs.get(index);
+    }
+
+    public boolean getBoolean(int index) throws JSONException {
+        return baseArgs.getBoolean(index);
+    }
+
+    public double getDouble(int index) throws JSONException {
+        return baseArgs.getDouble(index);
+    }
+
+    public int getInt(int index) throws JSONException {
+        return baseArgs.getInt(index);
+    }
+
+    public JSONArray getJSONArray(int index) throws JSONException {
+        return baseArgs.getJSONArray(index);
+    }
+
+    public JSONObject getJSONObject(int index) throws JSONException {
+        return baseArgs.getJSONObject(index);
+    }
+
+    public long getLong(int index) throws JSONException {
+        return baseArgs.getLong(index);
+    }
+
+    public String getString(int index) throws JSONException {
+        return baseArgs.getString(index);
+    }
+
+
+    public Object opt(int index) {
+        return baseArgs.opt(index);
+    }
+
+    public boolean optBoolean(int index) {
+        return baseArgs.optBoolean(index);
+    }
+
+    public double optDouble(int index) {
+        return baseArgs.optDouble(index);
+    }
+
+    public int optInt(int index) {
+        return baseArgs.optInt(index);
+    }
+
+    public JSONArray optJSONArray(int index) {
+        return baseArgs.optJSONArray(index);
+    }
+
+    public JSONObject optJSONObject(int index) {
+        return baseArgs.optJSONObject(index);
+    }
+
+    public long optLong(int index) {
+        return baseArgs.optLong(index);
+    }
+
+    public String optString(int index) {
+        return baseArgs.optString(index);
+    }
+
+    public boolean isNull(int index) {
+        return baseArgs.isNull(index);
+    }
+
+
+    // The interesting custom helpers.
+    public byte[] getArrayBuffer(int index) throws JSONException {
+        String encoded = baseArgs.getString(index);
+        return Base64.decode(encoded, Base64.DEFAULT);
+    }
+}
+
+
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaBridge.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaBridge.java
new file mode 100644
index 0000000..28c407f
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaBridge.java
@@ -0,0 +1,187 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import android.annotation.SuppressLint;
+
+import java.security.SecureRandom;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+
+/**
+ * Contains APIs that the JS can call. All functions in here should also have
+ * an equivalent entry in CordovaChromeClient.java, and be added to
+ * cordova-js/lib/android/plugin/android/promptbasednativeapi.js
+ */
+public class CordovaBridge {
+    private static final String LOG_TAG = "CordovaBridge";
+    private PluginManager pluginManager;
+    private NativeToJsMessageQueue jsMessageQueue;
+    private volatile int expectedBridgeSecret = -1; // written by UI thread, read by JS thread.
+
+    public CordovaBridge(PluginManager pluginManager, NativeToJsMessageQueue jsMessageQueue) {
+        this.pluginManager = pluginManager;
+        this.jsMessageQueue = jsMessageQueue;
+    }
+
+    public String jsExec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException {
+        if (!verifySecret("exec()", bridgeSecret)) {
+            return null;
+        }
+        // If the arguments weren't received, send a message back to JS.  It will switch bridge modes and try again.  See CB-2666.
+        // We send a message meant specifically for this case.  It starts with "@" so no other message can be encoded into the same string.
+        if (arguments == null) {
+            return "@Null arguments.";
+        }
+
+        jsMessageQueue.setPaused(true);
+        try {
+            // Tell the resourceApi what thread the JS is running on.
+            CordovaResourceApi.jsThread = Thread.currentThread();
+
+            pluginManager.exec(service, action, callbackId, arguments);
+            String ret = null;
+            if (!NativeToJsMessageQueue.DISABLE_EXEC_CHAINING) {
+                ret = jsMessageQueue.popAndEncode(false);
+            }
+            return ret;
+        } catch (Throwable e) {
+            e.printStackTrace();
+            return "";
+        } finally {
+            jsMessageQueue.setPaused(false);
+        }
+    }
+
+    public void jsSetNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException {
+        if (!verifySecret("setNativeToJsBridgeMode()", bridgeSecret)) {
+            return;
+        }
+        jsMessageQueue.setBridgeMode(value);
+    }
+
+    public String jsRetrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException {
+        if (!verifySecret("retrieveJsMessages()", bridgeSecret)) {
+            return null;
+        }
+        return jsMessageQueue.popAndEncode(fromOnlineEvent);
+    }
+
+    private boolean verifySecret(String action, int bridgeSecret) throws IllegalAccessException {
+        if (!jsMessageQueue.isBridgeEnabled()) {
+            if (bridgeSecret == -1) {
+                LOG.d(LOG_TAG, action + " call made before bridge was enabled.");
+            } else {
+                LOG.d(LOG_TAG, "Ignoring " + action + " from previous page load.");
+            }
+            return false;
+        }
+        // Bridge secret wrong and bridge not due to it being from the previous page.
+        if (expectedBridgeSecret < 0 || bridgeSecret != expectedBridgeSecret) {
+            LOG.e(LOG_TAG, "Bridge access attempt with wrong secret token, possibly from malicious code. Disabling exec() bridge!");
+            clearBridgeSecret();
+            throw new IllegalAccessException();
+        }
+        return true;
+    }
+
+    /** Called on page transitions */
+    void clearBridgeSecret() {
+        expectedBridgeSecret = -1;
+    }
+
+    public boolean isSecretEstablished() {
+        return expectedBridgeSecret != -1;
+    }
+
+    /** Called by cordova.js to initialize the bridge. */
+    //On old Androids SecureRandom isn't really secure, this is the least of your problems if
+    //you're running Android 4.3 and below in 2017
+    @SuppressLint("TrulyRandom")
+    int generateBridgeSecret() {
+        SecureRandom randGen = new SecureRandom();
+        expectedBridgeSecret = randGen.nextInt(Integer.MAX_VALUE);
+        return expectedBridgeSecret;
+    }
+
+    public void reset() {
+        jsMessageQueue.reset();
+        clearBridgeSecret();
+    }
+
+    public String promptOnJsPrompt(String origin, String message, String defaultValue) {
+        if (defaultValue != null && defaultValue.length() > 3 && defaultValue.startsWith("gap:")) {
+            JSONArray array;
+            try {
+                array = new JSONArray(defaultValue.substring(4));
+                int bridgeSecret = array.getInt(0);
+                String service = array.getString(1);
+                String action = array.getString(2);
+                String callbackId = array.getString(3);
+                String r = jsExec(bridgeSecret, service, action, callbackId, message);
+                return r == null ? "" : r;
+            } catch (JSONException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+            return "";
+        }
+        // Sets the native->JS bridge mode.
+        else if (defaultValue != null && defaultValue.startsWith("gap_bridge_mode:")) {
+            try {
+                int bridgeSecret = Integer.parseInt(defaultValue.substring(16));
+                jsSetNativeToJsBridgeMode(bridgeSecret, Integer.parseInt(message));
+            } catch (NumberFormatException e){
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+            return "";
+        }
+        // Polling for JavaScript messages
+        else if (defaultValue != null && defaultValue.startsWith("gap_poll:")) {
+            int bridgeSecret = Integer.parseInt(defaultValue.substring(9));
+            try {
+                String r = jsRetrieveJsMessages(bridgeSecret, "1".equals(message));
+                return r == null ? "" : r;
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+            return "";
+        }
+        else if (defaultValue != null && defaultValue.startsWith("gap_init:")) {
+            // Protect against random iframes being able to talk through the bridge.
+            // Trust only pages which the app would have been allowed to navigate to anyway.
+            if (pluginManager.shouldAllowBridgeAccess(origin)) {
+                // Enable the bridge
+                int bridgeMode = Integer.parseInt(defaultValue.substring(9));
+                jsMessageQueue.setBridgeMode(bridgeMode);
+                // Tell JS the bridge secret.
+                int secret = generateBridgeSecret();
+                return ""+secret;
+            } else {
+                LOG.e(LOG_TAG, "gap_init called from restricted origin: " + origin);
+            }
+            return "";
+        }
+        return null;
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaClientCertRequest.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaClientCertRequest.java
new file mode 100644
index 0000000..ccda027
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaClientCertRequest.java
@@ -0,0 +1,105 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+import android.annotation.SuppressLint;
+import android.webkit.ClientCertRequest;
+
+/**
+ * Implementation of the ICordovaClientCertRequest for Android WebView.
+ *
+ */
+public class CordovaClientCertRequest implements ICordovaClientCertRequest {
+
+    private final ClientCertRequest request;
+
+    public CordovaClientCertRequest(ClientCertRequest request) {
+        this.request = request;
+    }
+    
+    /**
+     * Cancel this request
+     */
+    @SuppressLint("NewApi")
+    public void cancel()
+    {
+        request.cancel();
+    }
+    
+    /*
+     * Returns the host name of the server requesting the certificate.
+     */
+    @SuppressLint("NewApi")
+    public String getHost()
+    {
+        return request.getHost();
+    }
+    
+    /*
+     * Returns the acceptable types of asymmetric keys (can be null).
+     */
+    @SuppressLint("NewApi")
+    public String[] getKeyTypes()
+    {
+        return request.getKeyTypes();
+    }
+    
+    /*
+     * Returns the port number of the server requesting the certificate.
+     */
+    @SuppressLint("NewApi")
+    public int getPort()
+    {
+        return request.getPort();
+    }
+    
+    /*
+     * Returns the acceptable certificate issuers for the certificate matching the private key (can be null).
+     */
+    @SuppressLint("NewApi")
+    public Principal[] getPrincipals()
+    {
+        return request.getPrincipals();
+    }
+    
+    /*
+     * Ignore the request for now. Do not remember user's choice.
+     */
+    @SuppressLint("NewApi")
+    public void ignore()
+    {
+        request.ignore();
+    }
+    
+    /*
+     * Proceed with the specified private key and client certificate chain. Remember the user's positive choice and use it for future requests.
+     * 
+     * @param privateKey The privateKey
+     * @param chain The certificate chain 
+     */
+    @SuppressLint("NewApi")
+    public void proceed(PrivateKey privateKey, X509Certificate[] chain)
+    {
+        request.proceed(privateKey, chain);
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaDialogsHelper.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaDialogsHelper.java
new file mode 100644
index 0000000..a219c99
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaDialogsHelper.java
@@ -0,0 +1,152 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.view.KeyEvent;
+import android.widget.EditText;
+
+/**
+ * Helper class for WebViews to implement prompt(), alert(), confirm() dialogs.
+ */
+public class CordovaDialogsHelper {
+    private final Context context;
+    private AlertDialog lastHandledDialog;
+
+    public CordovaDialogsHelper(Context context) {
+        this.context = context;
+    }
+
+    public void showAlert(String message, final Result result) {
+        AlertDialog.Builder dlg = new AlertDialog.Builder(context);
+        dlg.setMessage(message);
+        dlg.setTitle("Alert");
+        //Don't let alerts break the back button
+        dlg.setCancelable(true);
+        dlg.setPositiveButton(android.R.string.ok,
+                new AlertDialog.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int which) {
+                        result.gotResult(true, null);
+                    }
+                });
+        dlg.setOnCancelListener(
+                new DialogInterface.OnCancelListener() {
+                    public void onCancel(DialogInterface dialog) {
+                        result.gotResult(false, null);
+                    }
+                });
+        dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
+            //DO NOTHING
+            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
+                if (keyCode == KeyEvent.KEYCODE_BACK)
+                {
+                    result.gotResult(true, null);
+                    return false;
+                }
+                else
+                    return true;
+            }
+        });
+        lastHandledDialog = dlg.show();
+    }
+
+    public void showConfirm(String message, final Result result) {
+        AlertDialog.Builder dlg = new AlertDialog.Builder(context);
+        dlg.setMessage(message);
+        dlg.setTitle("Confirm");
+        dlg.setCancelable(true);
+        dlg.setPositiveButton(android.R.string.ok,
+                new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int which) {
+                        result.gotResult(true, null);
+                    }
+                });
+        dlg.setNegativeButton(android.R.string.cancel,
+                new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int which) {
+                        result.gotResult(false, null);
+                    }
+                });
+        dlg.setOnCancelListener(
+                new DialogInterface.OnCancelListener() {
+                    public void onCancel(DialogInterface dialog) {
+                        result.gotResult(false, null);
+                    }
+                });
+        dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
+            //DO NOTHING
+            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
+                if (keyCode == KeyEvent.KEYCODE_BACK)
+                {
+                    result.gotResult(false, null);
+                    return false;
+                }
+                else
+                    return true;
+            }
+        });
+        lastHandledDialog = dlg.show();
+    }
+
+    /**
+     * Tell the client to display a prompt dialog to the user.
+     * If the client returns true, WebView will assume that the client will
+     * handle the prompt dialog and call the appropriate JsPromptResult method.
+     *
+     * Since we are hacking prompts for our own purposes, we should not be using them for
+     * this purpose, perhaps we should hack console.log to do this instead!
+     */
+    public void showPrompt(String message, String defaultValue, final Result result) {
+        // Returning false would also show a dialog, but the default one shows the origin (ugly).
+        AlertDialog.Builder dlg = new AlertDialog.Builder(context);
+        dlg.setMessage(message);
+        final EditText input = new EditText(context);
+        if (defaultValue != null) {
+            input.setText(defaultValue);
+        }
+        dlg.setView(input);
+        dlg.setCancelable(false);
+        dlg.setPositiveButton(android.R.string.ok,
+                new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int which) {
+                        String userText = input.getText().toString();
+                        result.gotResult(true, userText);
+                    }
+                });
+        dlg.setNegativeButton(android.R.string.cancel,
+                new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int which) {
+                        result.gotResult(false, null);
+                    }
+                });
+        lastHandledDialog = dlg.show();
+    }
+
+    public void destroyLastDialog(){
+        if (lastHandledDialog != null){
+            lastHandledDialog.cancel();
+        }
+    }
+
+    public interface Result {
+        public void gotResult(boolean success, String value);
+    }
+}
\ No newline at end of file
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaHttpAuthHandler.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaHttpAuthHandler.java
new file mode 100644
index 0000000..724381e
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaHttpAuthHandler.java
@@ -0,0 +1,51 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import android.webkit.HttpAuthHandler;
+
+/**
+ * Specifies interface for HTTP auth handler object which is used to handle auth requests and
+ * specifying user credentials.
+ */
+public class CordovaHttpAuthHandler implements ICordovaHttpAuthHandler {
+
+    private final HttpAuthHandler handler;
+
+    public CordovaHttpAuthHandler(HttpAuthHandler handler) {
+        this.handler = handler;
+    }
+    
+    /**
+     * Instructs the WebView to cancel the authentication request.
+     */
+    public void cancel () {
+        this.handler.cancel();
+    }
+    
+    /**
+     * Instructs the WebView to proceed with the authentication with the given credentials.
+     * 
+     * @param username
+     * @param password
+     */
+    public void proceed (String username, String password) {
+        this.handler.proceed(username, password);
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterface.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterface.java
new file mode 100755
index 0000000..ff90683
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterface.java
@@ -0,0 +1,97 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+
+import org.apache.cordova.CordovaPlugin;
+
+import java.util.concurrent.ExecutorService;
+
+/**
+ * The Activity interface that is implemented by CordovaActivity.
+ * It is used to isolate plugin development, and remove dependency on entire Cordova library.
+ */
+public interface CordovaInterface {
+
+    /**
+     * Launch an activity for which you would like a result when it finished. When this activity exits,
+     * your onActivityResult() method will be called.
+     *
+     * @param command     The command object
+     * @param intent      The intent to start
+     * @param requestCode   The request code that is passed to callback to identify the activity
+     */
+    abstract public void startActivityForResult(CordovaPlugin command, Intent intent, int requestCode);
+
+    /**
+     * Set the plugin to be called when a sub-activity exits.
+     *
+     * @param plugin      The plugin on which onActivityResult is to be called
+     */
+    abstract public void setActivityResultCallback(CordovaPlugin plugin);
+
+    /**
+     * Get the Android activity.
+     *
+     * If a custom engine lives outside of the Activity's lifecycle the return value may be null.
+     *
+     * @return the Activity
+     */
+    public abstract Activity getActivity();
+
+    /**
+     * Get the Android context.
+     *
+     * @return the Context
+     */
+    public Context getContext();
+
+    /**
+     * Called when a message is sent to plugin.
+     *
+     * @param id            The message id
+     * @param data          The message data
+     * @return              Object or null
+     */
+    public Object onMessage(String id, Object data);
+    
+    /**
+     * Returns a shared thread pool that can be used for background tasks.
+     */
+    public ExecutorService getThreadPool();
+
+    /**
+     * Sends a permission request to the activity for one permission.
+     */
+    public void requestPermission(CordovaPlugin plugin, int requestCode, String permission);
+
+    /**
+     * Sends a permission request to the activity for a group of permissions
+     */
+    public void requestPermissions(CordovaPlugin plugin, int requestCode, String [] permissions);
+
+    /**
+     * Check for a permission.  Returns true if the permission is granted, false otherwise.
+     */
+    public boolean hasPermission(String permission);
+
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterfaceImpl.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterfaceImpl.java
new file mode 100644
index 0000000..9a6e924
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterfaceImpl.java
@@ -0,0 +1,249 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.Pair;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * Default implementation of CordovaInterface.
+ */
+public class CordovaInterfaceImpl implements CordovaInterface {
+    private static final String TAG = "CordovaInterfaceImpl";
+    protected Activity activity;
+    protected ExecutorService threadPool;
+    protected PluginManager pluginManager;
+
+    protected ActivityResultHolder savedResult;
+    protected CallbackMap permissionResultCallbacks;
+    protected CordovaPlugin activityResultCallback;
+    protected String initCallbackService;
+    protected int activityResultRequestCode;
+    protected boolean activityWasDestroyed = false;
+    protected Bundle savedPluginState;
+
+    public CordovaInterfaceImpl(Activity activity) {
+        this(activity, Executors.newCachedThreadPool());
+    }
+
+    public CordovaInterfaceImpl(Activity activity, ExecutorService threadPool) {
+        this.activity = activity;
+        this.threadPool = threadPool;
+        this.permissionResultCallbacks = new CallbackMap();
+    }
+
+    @Override
+    public void startActivityForResult(CordovaPlugin command, Intent intent, int requestCode) {
+        setActivityResultCallback(command);
+        try {
+            activity.startActivityForResult(intent, requestCode);
+        } catch (RuntimeException e) { // E.g.: ActivityNotFoundException
+            activityResultCallback = null;
+            throw e;
+        }
+    }
+
+    @Override
+    public void setActivityResultCallback(CordovaPlugin plugin) {
+        // Cancel any previously pending activity.
+        if (activityResultCallback != null) {
+            activityResultCallback.onActivityResult(activityResultRequestCode, Activity.RESULT_CANCELED, null);
+        }
+        activityResultCallback = plugin;
+    }
+
+    @Override
+    public Activity getActivity() {
+        return activity;
+    }
+
+    @Override
+    public Context getContext() {
+        return activity;
+    }
+
+    @Override
+    public Object onMessage(String id, Object data) {
+        if ("exit".equals(id)) {
+            activity.finish();
+        }
+        return null;
+    }
+
+    @Override
+    public ExecutorService getThreadPool() {
+        return threadPool;
+    }
+
+    /**
+     * Dispatches any pending onActivityResult callbacks and sends the resume event if the
+     * Activity was destroyed by the OS.
+     */
+    public void onCordovaInit(PluginManager pluginManager) {
+        this.pluginManager = pluginManager;
+        if (savedResult != null) {
+            onActivityResult(savedResult.requestCode, savedResult.resultCode, savedResult.intent);
+        } else if(activityWasDestroyed) {
+            // If there was no Activity result, we still need to send out the resume event if the
+            // Activity was destroyed by the OS
+            activityWasDestroyed = false;
+            if(pluginManager != null)
+            {
+                CoreAndroid appPlugin = (CoreAndroid) pluginManager.getPlugin(CoreAndroid.PLUGIN_NAME);
+                if(appPlugin != null) {
+                    JSONObject obj = new JSONObject();
+                    try {
+                        obj.put("action", "resume");
+                    } catch (JSONException e) {
+                        LOG.e(TAG, "Failed to create event message", e);
+                    }
+                    appPlugin.sendResumeEvent(new PluginResult(PluginResult.Status.OK, obj));
+                }
+            }
+
+        }
+    }
+
+    /**
+     * Routes the result to the awaiting plugin. Returns false if no plugin was waiting.
+     */
+    public boolean onActivityResult(int requestCode, int resultCode, Intent intent) {
+        CordovaPlugin callback = activityResultCallback;
+        if(callback == null && initCallbackService != null) {
+            // The application was restarted, but had defined an initial callback
+            // before being shut down.
+            savedResult = new ActivityResultHolder(requestCode, resultCode, intent);
+            if (pluginManager != null) {
+                callback = pluginManager.getPlugin(initCallbackService);
+                if(callback != null) {
+                    callback.onRestoreStateForActivityResult(savedPluginState.getBundle(callback.getServiceName()),
+                            new ResumeCallback(callback.getServiceName(), pluginManager));
+                }
+            }
+        }
+        activityResultCallback = null;
+
+        if (callback != null) {
+            LOG.d(TAG, "Sending activity result to plugin");
+            initCallbackService = null;
+            savedResult = null;
+            callback.onActivityResult(requestCode, resultCode, intent);
+            return true;
+        }
+        LOG.w(TAG, "Got an activity result, but no plugin was registered to receive it" + (savedResult != null ? " yet!" : "."));
+        return false;
+    }
+
+    /**
+     * Call this from your startActivityForResult() overload. This is required to catch the case
+     * where plugins use Activity.startActivityForResult() + CordovaInterface.setActivityResultCallback()
+     * rather than CordovaInterface.startActivityForResult().
+     */
+    public void setActivityResultRequestCode(int requestCode) {
+        activityResultRequestCode = requestCode;
+    }
+
+    /**
+     * Saves parameters for startActivityForResult().
+     */
+    public void onSaveInstanceState(Bundle outState) {
+        if (activityResultCallback != null) {
+            String serviceName = activityResultCallback.getServiceName();
+            outState.putString("callbackService", serviceName);
+        }
+        if(pluginManager != null){
+            outState.putBundle("plugin", pluginManager.onSaveInstanceState());
+        }
+
+    }
+
+    /**
+     * Call this from onCreate() so that any saved startActivityForResult parameters will be restored.
+     */
+    public void restoreInstanceState(Bundle savedInstanceState) {
+        initCallbackService = savedInstanceState.getString("callbackService");
+        savedPluginState = savedInstanceState.getBundle("plugin");
+        activityWasDestroyed = true;
+    }
+
+    private static class ActivityResultHolder {
+        private int requestCode;
+        private int resultCode;
+        private Intent intent;
+
+        public ActivityResultHolder(int requestCode, int resultCode, Intent intent) {
+            this.requestCode = requestCode;
+            this.resultCode = resultCode;
+            this.intent = intent;
+        }
+    }
+
+    /**
+     * Called by the system when the user grants permissions
+     *
+     * @param requestCode
+     * @param permissions
+     * @param grantResults
+     */
+    public void onRequestPermissionResult(int requestCode, String[] permissions,
+                                          int[] grantResults) throws JSONException {
+        Pair<CordovaPlugin, Integer> callback = permissionResultCallbacks.getAndRemoveCallback(requestCode);
+        if(callback != null) {
+            callback.first.onRequestPermissionResult(callback.second, permissions, grantResults);
+        }
+    }
+
+    public void requestPermission(CordovaPlugin plugin, int requestCode, String permission) {
+        String[] permissions = new String [1];
+        permissions[0] = permission;
+        requestPermissions(plugin, requestCode, permissions);
+    }
+
+        @SuppressLint("NewApi")
+    public void requestPermissions(CordovaPlugin plugin, int requestCode, String [] permissions) {
+        int mappedRequestCode = permissionResultCallbacks.registerCallback(plugin, requestCode);
+        getActivity().requestPermissions(permissions, mappedRequestCode);
+    }
+
+    public boolean hasPermission(String permission)
+    {
+        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
+        {
+            int result = activity.checkSelfPermission(permission);
+            return PackageManager.PERMISSION_GRANTED == result;
+        }
+        else
+        {
+            return true;
+        }
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPlugin.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPlugin.java
new file mode 100644
index 0000000..41af1db
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPlugin.java
@@ -0,0 +1,422 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import org.apache.cordova.CordovaArgs;
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CallbackContext;
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+/**
+ * Plugins must extend this class and override one of the execute methods.
+ */
+public class CordovaPlugin {
+    public CordovaWebView webView;
+    public CordovaInterface cordova;
+    protected CordovaPreferences preferences;
+    private String serviceName;
+
+    /**
+     * Call this after constructing to initialize the plugin.
+     * Final because we want to be able to change args without breaking plugins.
+     */
+    public final void privateInitialize(String serviceName, CordovaInterface cordova, CordovaWebView webView, CordovaPreferences preferences) {
+        assert this.cordova == null;
+        this.serviceName = serviceName;
+        this.cordova = cordova;
+        this.webView = webView;
+        this.preferences = preferences;
+        initialize(cordova, webView);
+        pluginInitialize();
+    }
+
+    /**
+     * Called after plugin construction and fields have been initialized.
+     * Prefer to use pluginInitialize instead since there is no value in
+     * having parameters on the initialize() function.
+     */
+    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
+    }
+
+    /**
+     * Called after plugin construction and fields have been initialized.
+     */
+    protected void pluginInitialize() {
+    }
+
+    /**
+     * Returns the plugin's service name (what you'd use when calling pluginManger.getPlugin())
+     */
+    public String getServiceName() {
+        return serviceName;
+    }
+
+    /**
+     * Executes the request.
+     *
+     * This method is called from the WebView thread. To do a non-trivial amount of work, use:
+     *     cordova.getThreadPool().execute(runnable);
+     *
+     * To run on the UI thread, use:
+     *     cordova.getActivity().runOnUiThread(runnable);
+     *
+     * @param action          The action to execute.
+     * @param rawArgs         The exec() arguments in JSON form.
+     * @param callbackContext The callback context used when calling back into JavaScript.
+     * @return                Whether the action was valid.
+     */
+    public boolean execute(String action, String rawArgs, CallbackContext callbackContext) throws JSONException {
+        JSONArray args = new JSONArray(rawArgs);
+        return execute(action, args, callbackContext);
+    }
+
+    /**
+     * Executes the request.
+     *
+     * This method is called from the WebView thread. To do a non-trivial amount of work, use:
+     *     cordova.getThreadPool().execute(runnable);
+     *
+     * To run on the UI thread, use:
+     *     cordova.getActivity().runOnUiThread(runnable);
+     *
+     * @param action          The action to execute.
+     * @param args            The exec() arguments.
+     * @param callbackContext The callback context used when calling back into JavaScript.
+     * @return                Whether the action was valid.
+     */
+    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
+        CordovaArgs cordovaArgs = new CordovaArgs(args);
+        return execute(action, cordovaArgs, callbackContext);
+    }
+
+    /**
+     * Executes the request.
+     *
+     * This method is called from the WebView thread. To do a non-trivial amount of work, use:
+     *     cordova.getThreadPool().execute(runnable);
+     *
+     * To run on the UI thread, use:
+     *     cordova.getActivity().runOnUiThread(runnable);
+     *
+     * @param action          The action to execute.
+     * @param args            The exec() arguments, wrapped with some Cordova helpers.
+     * @param callbackContext The callback context used when calling back into JavaScript.
+     * @return                Whether the action was valid.
+     */
+    public boolean execute(String action, CordovaArgs args, CallbackContext callbackContext) throws JSONException {
+        return false;
+    }
+
+    /**
+     * Called when the system is about to start resuming a previous activity.
+     *
+     * @param multitasking		Flag indicating if multitasking is turned on for app
+     */
+    public void onPause(boolean multitasking) {
+    }
+
+    /**
+     * Called when the activity will start interacting with the user.
+     *
+     * @param multitasking		Flag indicating if multitasking is turned on for app
+     */
+    public void onResume(boolean multitasking) {
+    }
+
+    /**
+     * Called when the activity is becoming visible to the user.
+     */
+    public void onStart() {
+    }
+
+    /**
+     * Called when the activity is no longer visible to the user.
+     */
+    public void onStop() {
+    }
+
+    /**
+     * Called when the activity receives a new intent.
+     */
+    public void onNewIntent(Intent intent) {
+    }
+
+    /**
+     * The final call you receive before your activity is destroyed.
+     */
+    public void onDestroy() {
+    }
+
+    /**
+     * Called when the Activity is being destroyed (e.g. if a plugin calls out to an external
+     * Activity and the OS kills the CordovaActivity in the background). The plugin should save its
+     * state in this method only if it is awaiting the result of an external Activity and needs
+     * to preserve some information so as to handle that result; onRestoreStateForActivityResult()
+     * will only be called if the plugin is the recipient of an Activity result
+     *
+     * @return  Bundle containing the state of the plugin or null if state does not need to be saved
+     */
+    public Bundle onSaveInstanceState() {
+        return null;
+    }
+
+    /**
+     * Called when a plugin is the recipient of an Activity result after the CordovaActivity has
+     * been destroyed. The Bundle will be the same as the one the plugin returned in
+     * onSaveInstanceState()
+     *
+     * @param state             Bundle containing the state of the plugin
+     * @param callbackContext   Replacement Context to return the plugin result to
+     */
+    public void onRestoreStateForActivityResult(Bundle state, CallbackContext callbackContext) {}
+
+    /**
+     * Called when a message is sent to plugin.
+     *
+     * @param id            The message id
+     * @param data          The message data
+     * @return              Object to stop propagation or null
+     */
+    public Object onMessage(String id, Object data) {
+        return null;
+    }
+
+    /**
+     * Called when an activity you launched exits, giving you the requestCode you started it with,
+     * the resultCode it returned, and any additional data from it.
+     *
+     * @param requestCode   The request code originally supplied to startActivityForResult(),
+     *                      allowing you to identify who this result came from.
+     * @param resultCode    The integer result code returned by the child activity through its setResult().
+     * @param intent        An Intent, which can return result data to the caller (various data can be
+     *                      attached to Intent "extras").
+     */
+    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+    }
+
+    /**
+     * Hook for blocking the loading of external resources.
+     *
+     * This will be called when the WebView's shouldInterceptRequest wants to
+     * know whether to open a connection to an external resource. Return false
+     * to block the request: if any plugin returns false, Cordova will block
+     * the request. If all plugins return null, the default policy will be
+     * enforced. If at least one plugin returns true, and no plugins return
+     * false, then the request will proceed.
+     *
+     * Note that this only affects resource requests which are routed through
+     * WebViewClient.shouldInterceptRequest, such as XMLHttpRequest requests and
+     * img tag loads. WebSockets and media requests (such as <video> and <audio>
+     * tags) are not affected by this method. Use CSP headers to control access
+     * to such resources.
+     */
+    public Boolean shouldAllowRequest(String url) {
+        return null;
+    }
+
+    /**
+     * Hook for blocking navigation by the Cordova WebView. This applies both to top-level and
+     * iframe navigations.
+     *
+     * This will be called when the WebView's needs to know whether to navigate
+     * to a new page. Return false to block the navigation: if any plugin
+     * returns false, Cordova will block the navigation. If all plugins return
+     * null, the default policy will be enforced. It at least one plugin returns
+     * true, and no plugins return false, then the navigation will proceed.
+     */
+    public Boolean shouldAllowNavigation(String url) {
+        return null;
+    }
+
+    /**
+     * Hook for allowing page to call exec(). By default, this returns the result of
+     * shouldAllowNavigation(). It's generally unsafe to allow untrusted content to be loaded
+     * into a CordovaWebView, even within an iframe, so it's best not to touch this.
+     */
+    public Boolean shouldAllowBridgeAccess(String url) {
+        return shouldAllowNavigation(url);
+    }
+
+    /**
+     * Hook for blocking the launching of Intents by the Cordova application.
+     *
+     * This will be called when the WebView will not navigate to a page, but
+     * could launch an intent to handle the URL. Return false to block this: if
+     * any plugin returns false, Cordova will block the navigation. If all
+     * plugins return null, the default policy will be enforced. If at least one
+     * plugin returns true, and no plugins return false, then the URL will be
+     * opened.
+     */
+    public Boolean shouldOpenExternalUrl(String url) {
+        return null;
+    }
+
+    /**
+     * Allows plugins to handle a link being clicked. Return true here to cancel the navigation.
+     *
+     * @param url           The URL that is trying to be loaded in the Cordova webview.
+     * @return              Return true to prevent the URL from loading. Default is false.
+     */
+    public boolean onOverrideUrlLoading(String url) {
+        return false;
+    }
+
+    /**
+     * Hook for redirecting requests. Applies to WebView requests as well as requests made by plugins.
+     * To handle the request directly, return a URI in the form:
+     *
+     *    cdvplugin://pluginId/...
+     *
+     * And implement handleOpenForRead().
+     * To make this easier, use the toPluginUri() and fromPluginUri() helpers:
+     *
+     *     public Uri remapUri(Uri uri) { return toPluginUri(uri); }
+     *
+     *     public CordovaResourceApi.OpenForReadResult handleOpenForRead(Uri uri) throws IOException {
+     *         Uri origUri = fromPluginUri(uri);
+     *         ...
+     *     }
+     */
+    public Uri remapUri(Uri uri) {
+        return null;
+    }
+
+    /**
+     * Called to handle CordovaResourceApi.openForRead() calls for a cdvplugin://pluginId/ URL.
+     * Should never return null.
+     * Added in cordova-android@4.0.0
+     */
+    public CordovaResourceApi.OpenForReadResult handleOpenForRead(Uri uri) throws IOException {
+        throw new FileNotFoundException("Plugin can't handle uri: " + uri);
+    }
+
+    /**
+     * Refer to remapUri()
+     * Added in cordova-android@4.0.0
+     */
+    protected Uri toPluginUri(Uri origUri) {
+        return new Uri.Builder()
+            .scheme(CordovaResourceApi.PLUGIN_URI_SCHEME)
+            .authority(serviceName)
+            .appendQueryParameter("origUri", origUri.toString())
+            .build();
+    }
+
+    /**
+     * Refer to remapUri()
+     * Added in cordova-android@4.0.0
+     */
+    protected Uri fromPluginUri(Uri pluginUri) {
+        return Uri.parse(pluginUri.getQueryParameter("origUri"));
+    }
+
+    /**
+     * Called when the WebView does a top-level navigation or refreshes.
+     *
+     * Plugins should stop any long-running processes and clean up internal state.
+     *
+     * Does nothing by default.
+     */
+    public void onReset() {
+    }
+
+    /**
+     * Called when the system received an HTTP authentication request. Plugin can use
+     * the supplied HttpAuthHandler to process this auth challenge.
+     *
+     * @param view              The WebView that is initiating the callback
+     * @param handler           The HttpAuthHandler used to set the WebView's response
+     * @param host              The host requiring authentication
+     * @param realm             The realm for which authentication is required
+     *
+     * @return                  Returns True if plugin will resolve this auth challenge, otherwise False
+     *
+     */
+    public boolean onReceivedHttpAuthRequest(CordovaWebView view, ICordovaHttpAuthHandler handler, String host, String realm) {
+        return false;
+    }
+
+    /**
+     * Called when he system received an SSL client certificate request.  Plugin can use
+     * the supplied ClientCertRequest to process this certificate challenge.
+     *
+     * @param view              The WebView that is initiating the callback
+     * @param request           The client certificate request
+     *
+     * @return                  Returns True if plugin will resolve this auth challenge, otherwise False
+     *
+     */
+    public boolean onReceivedClientCertRequest(CordovaWebView view, ICordovaClientCertRequest request) {
+        return false;
+    }
+
+    /**
+     * Called by the system when the device configuration changes while your activity is running.
+     *
+     * @param newConfig		The new device configuration
+     */
+    public void onConfigurationChanged(Configuration newConfig) {
+    }
+
+    /**
+     * Called by the Plugin Manager when we need to actually request permissions
+     *
+     * @param requestCode   Passed to the activity to track the request
+     *
+     * @return              Returns the permission that was stored in the plugin
+     */
+
+    public void requestPermissions(int requestCode) {
+    }
+
+    /*
+     * Called by the WebView implementation to check for geolocation permissions, can be used
+     * by other Java methods in the event that a plugin is using this as a dependency.
+     *
+     * @return          Returns true if the plugin has all the permissions it needs to operate.
+     */
+
+    public boolean hasPermisssion() {
+        return true;
+    }
+
+    /**
+     * Called by the system when the user grants permissions
+     *
+     * @param requestCode
+     * @param permissions
+     * @param grantResults
+     */
+    public void onRequestPermissionResult(int requestCode, String[] permissions,
+                                          int[] grantResults) throws JSONException {
+
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPreferences.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPreferences.java
new file mode 100644
index 0000000..4dbc93e
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPreferences.java
@@ -0,0 +1,101 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.cordova.LOG;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class CordovaPreferences {
+    private HashMap<String, String> prefs = new HashMap<String, String>(20);
+    private Bundle preferencesBundleExtras;
+
+    public void setPreferencesBundle(Bundle extras) {
+        preferencesBundleExtras = extras;
+    }
+
+    public void set(String name, String value) {
+        prefs.put(name.toLowerCase(Locale.ENGLISH), value);
+    }
+
+    public void set(String name, boolean value) {
+        set(name, "" + value);
+    }
+
+    public void set(String name, int value) {
+        set(name, "" + value);
+    }
+    
+    public void set(String name, double value) {
+        set(name, "" + value);
+    }
+    
+    public Map<String, String> getAll() {
+        return prefs;
+    }
+
+    public boolean getBoolean(String name, boolean defaultValue) {
+        name = name.toLowerCase(Locale.ENGLISH);
+        String value = prefs.get(name);
+        if (value != null) {
+            return Boolean.parseBoolean(value);
+        }
+        return defaultValue;
+    }
+
+    // Added in 4.0.0
+    public boolean contains(String name) {
+        return getString(name, null) != null;
+    }
+
+    public int getInteger(String name, int defaultValue) {
+        name = name.toLowerCase(Locale.ENGLISH);
+        String value = prefs.get(name);
+        if (value != null) {
+            // Use Integer.decode() can't handle it if the highest bit is set.
+            return (int)(long)Long.decode(value);
+        }
+        return defaultValue;
+    }
+
+    public double getDouble(String name, double defaultValue) {
+        name = name.toLowerCase(Locale.ENGLISH);
+        String value = prefs.get(name);
+        if (value != null) {
+            return Double.valueOf(value);
+        }
+        return defaultValue;
+    }
+
+    public String getString(String name, String defaultValue) {
+        name = name.toLowerCase(Locale.ENGLISH);
+        String value = prefs.get(name);
+        if (value != null) {
+            return value;
+        }
+        return defaultValue;
+    }
+
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaResourceApi.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaResourceApi.java
new file mode 100644
index 0000000..3c438e2
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaResourceApi.java
@@ -0,0 +1,472 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+ */
+package org.apache.cordova;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Looper;
+import android.util.Base64;
+import android.webkit.MimeTypeMap;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.channels.FileChannel;
+import java.util.Locale;
+
+/**
+ * What this class provides:
+ * 1. Helpers for reading & writing to URLs.
+ *   - E.g. handles assets, resources, content providers, files, data URIs, http[s]
+ *   - E.g. Can be used to query for mime-type & content length.
+ *
+ * 2. To allow plugins to redirect URLs (via remapUrl).
+ *   - All plugins should call remapUrl() on URLs they receive from JS *before*
+ *     passing the URL onto other utility functions in this class.
+ *   - For an example usage of this, refer to the org.apache.cordova.file plugin.
+ *
+ * Future Work:
+ *   - Consider using a Cursor to query content URLs for their size (like the file plugin does).
+ *   - Allow plugins to remapUri to "cdv-plugin://plugin-name/foo", which CordovaResourceApi
+ *     would then delegate to pluginManager.getPlugin(plugin-name).openForRead(url)
+ *     - Currently, plugins *can* do this by remapping to a data: URL, but it's inefficient
+ *       for large payloads.
+ */
+public class CordovaResourceApi {
+    @SuppressWarnings("unused")
+    private static final String LOG_TAG = "CordovaResourceApi";
+
+    public static final int URI_TYPE_FILE = 0;
+    public static final int URI_TYPE_ASSET = 1;
+    public static final int URI_TYPE_CONTENT = 2;
+    public static final int URI_TYPE_RESOURCE = 3;
+    public static final int URI_TYPE_DATA = 4;
+    public static final int URI_TYPE_HTTP = 5;
+    public static final int URI_TYPE_HTTPS = 6;
+    public static final int URI_TYPE_PLUGIN = 7;
+    public static final int URI_TYPE_UNKNOWN = -1;
+
+    public static final String PLUGIN_URI_SCHEME = "cdvplugin";
+
+    private static final String[] LOCAL_FILE_PROJECTION = { "_data" };
+    
+    public static Thread jsThread;
+
+    private final AssetManager assetManager;
+    private final ContentResolver contentResolver;
+    private final PluginManager pluginManager;
+    private boolean threadCheckingEnabled = true;
+
+
+    public CordovaResourceApi(Context context, PluginManager pluginManager) {
+        this.contentResolver = context.getContentResolver();
+        this.assetManager = context.getAssets();
+        this.pluginManager = pluginManager;
+    }
+    
+    public void setThreadCheckingEnabled(boolean value) {
+        threadCheckingEnabled = value;
+    }
+
+    public boolean isThreadCheckingEnabled() {
+        return threadCheckingEnabled;
+    }
+    
+    
+    public static int getUriType(Uri uri) {
+        assertNonRelative(uri);
+        String scheme = uri.getScheme();
+        if (ContentResolver.SCHEME_CONTENT.equalsIgnoreCase(scheme)) {
+            return URI_TYPE_CONTENT;
+        }
+        if (ContentResolver.SCHEME_ANDROID_RESOURCE.equalsIgnoreCase(scheme)) {
+            return URI_TYPE_RESOURCE;
+        }
+        if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(scheme)) {
+            if (uri.getPath().startsWith("/android_asset/")) {
+                return URI_TYPE_ASSET;
+            }
+            return URI_TYPE_FILE;
+        }
+        if ("data".equalsIgnoreCase(scheme)) {
+            return URI_TYPE_DATA;
+        }
+        if ("http".equalsIgnoreCase(scheme)) {
+            return URI_TYPE_HTTP;
+        }
+        if ("https".equalsIgnoreCase(scheme)) {
+            return URI_TYPE_HTTPS;
+        }
+        if (PLUGIN_URI_SCHEME.equalsIgnoreCase(scheme)) {
+            return URI_TYPE_PLUGIN;
+        }
+        return URI_TYPE_UNKNOWN;
+    }
+    
+    public Uri remapUri(Uri uri) {
+        assertNonRelative(uri);
+        Uri pluginUri = pluginManager.remapUri(uri);
+        return pluginUri != null ? pluginUri : uri;
+    }
+
+    public String remapPath(String path) {
+        return remapUri(Uri.fromFile(new File(path))).getPath();
+    }
+    
+    /**
+     * Returns a File that points to the resource, or null if the resource
+     * is not on the local filesystem.
+     */
+    public File mapUriToFile(Uri uri) {
+        assertBackgroundThread();
+        switch (getUriType(uri)) {
+            case URI_TYPE_FILE:
+                return new File(uri.getPath());
+            case URI_TYPE_CONTENT: {
+                Cursor cursor = contentResolver.query(uri, LOCAL_FILE_PROJECTION, null, null, null);
+                if (cursor != null) {
+                    try {
+                        int columnIndex = cursor.getColumnIndex(LOCAL_FILE_PROJECTION[0]);
+                        if (columnIndex != -1 && cursor.getCount() > 0) {
+                            cursor.moveToFirst();
+                            String realPath = cursor.getString(columnIndex);
+                            if (realPath != null) {
+                                return new File(realPath);
+                            }
+                        }
+                    } finally {
+                        cursor.close();
+                    }
+                }
+            }
+        }
+        return null;
+    }
+    
+    public String getMimeType(Uri uri) {
+        switch (getUriType(uri)) {
+            case URI_TYPE_FILE:
+            case URI_TYPE_ASSET:
+                return getMimeTypeFromPath(uri.getPath());
+            case URI_TYPE_CONTENT:
+            case URI_TYPE_RESOURCE:
+                return contentResolver.getType(uri);
+            case URI_TYPE_DATA: {
+                return getDataUriMimeType(uri);
+            }
+            case URI_TYPE_HTTP:
+            case URI_TYPE_HTTPS: {
+                try {
+                    HttpURLConnection conn = (HttpURLConnection)new URL(uri.toString()).openConnection();
+                    conn.setDoInput(false);
+                    conn.setRequestMethod("HEAD");
+                    String mimeType = conn.getHeaderField("Content-Type");
+                    if (mimeType != null) {
+                        mimeType = mimeType.split(";")[0];
+                    }
+                    return mimeType;
+                } catch (IOException e) {
+                }
+            }
+        }
+        
+        return null;
+    }
+    
+    
+    //This already exists
+    private String getMimeTypeFromPath(String path) {
+        String extension = path;
+        int lastDot = extension.lastIndexOf('.');
+        if (lastDot != -1) {
+            extension = extension.substring(lastDot + 1);
+        }
+        // Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
+        extension = extension.toLowerCase(Locale.getDefault());
+        if (extension.equals("3ga")) {
+            return "audio/3gpp";
+        } else if (extension.equals("js")) {
+            // Missing from the map :(.
+            return "text/javascript";
+        }
+        return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+    }
+    
+    /**
+     * Opens a stream to the given URI, also providing the MIME type & length.
+     * @return Never returns null.
+     * @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be
+     *     resolved before being passed into this function.
+     * @throws Throws an IOException if the URI cannot be opened.
+     * @throws Throws an IllegalStateException if called on a foreground thread.
+     */
+    public OpenForReadResult openForRead(Uri uri) throws IOException {
+        return openForRead(uri, false);
+    }
+
+    /**
+     * Opens a stream to the given URI, also providing the MIME type & length.
+     * @return Never returns null.
+     * @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be
+     *     resolved before being passed into this function.
+     * @throws Throws an IOException if the URI cannot be opened.
+     * @throws Throws an IllegalStateException if called on a foreground thread and skipThreadCheck is false.
+     */
+    public OpenForReadResult openForRead(Uri uri, boolean skipThreadCheck) throws IOException {
+        if (!skipThreadCheck) {
+            assertBackgroundThread();
+        }
+        switch (getUriType(uri)) {
+            case URI_TYPE_FILE: {
+                FileInputStream inputStream = new FileInputStream(uri.getPath());
+                String mimeType = getMimeTypeFromPath(uri.getPath());
+                long length = inputStream.getChannel().size();
+                return new OpenForReadResult(uri, inputStream, mimeType, length, null);
+            }
+            case URI_TYPE_ASSET: {
+                String assetPath = uri.getPath().substring(15);
+                AssetFileDescriptor assetFd = null;
+                InputStream inputStream;
+                long length = -1;
+                try {
+                    assetFd = assetManager.openFd(assetPath);
+                    inputStream = assetFd.createInputStream();
+                    length = assetFd.getLength();
+                } catch (FileNotFoundException e) {
+                    // Will occur if the file is compressed.
+                    inputStream = assetManager.open(assetPath);
+                    length = inputStream.available();
+                }
+                String mimeType = getMimeTypeFromPath(assetPath);
+                return new OpenForReadResult(uri, inputStream, mimeType, length, assetFd);
+            }
+            case URI_TYPE_CONTENT:
+            case URI_TYPE_RESOURCE: {
+                String mimeType = contentResolver.getType(uri);
+                AssetFileDescriptor assetFd = contentResolver.openAssetFileDescriptor(uri, "r");
+                InputStream inputStream = assetFd.createInputStream();
+                long length = assetFd.getLength();
+                return new OpenForReadResult(uri, inputStream, mimeType, length, assetFd);
+            }
+            case URI_TYPE_DATA: {
+                OpenForReadResult ret = readDataUri(uri);
+                if (ret == null) {
+                    break;
+                }
+                return ret;
+            }
+            case URI_TYPE_HTTP:
+            case URI_TYPE_HTTPS: {
+                HttpURLConnection conn = (HttpURLConnection)new URL(uri.toString()).openConnection();
+                conn.setDoInput(true);
+                String mimeType = conn.getHeaderField("Content-Type");
+                if (mimeType != null) {
+                    mimeType = mimeType.split(";")[0];
+                }
+                int length = conn.getContentLength();
+                InputStream inputStream = conn.getInputStream();
+                return new OpenForReadResult(uri, inputStream, mimeType, length, null);
+            }
+            case URI_TYPE_PLUGIN: {
+                String pluginId = uri.getHost();
+                CordovaPlugin plugin = pluginManager.getPlugin(pluginId);
+                if (plugin == null) {
+                    throw new FileNotFoundException("Invalid plugin ID in URI: " + uri);
+                }
+                return plugin.handleOpenForRead(uri);
+            }
+        }
+        throw new FileNotFoundException("URI not supported by CordovaResourceApi: " + uri);
+    }
+
+    public OutputStream openOutputStream(Uri uri) throws IOException {
+        return openOutputStream(uri, false);
+    }
+
+    /**
+     * Opens a stream to the given URI.
+     * @return Never returns null.
+     * @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be
+     *     resolved before being passed into this function.
+     * @throws Throws an IOException if the URI cannot be opened.
+     */
+    public OutputStream openOutputStream(Uri uri, boolean append) throws IOException {
+        assertBackgroundThread();
+        switch (getUriType(uri)) {
+            case URI_TYPE_FILE: {
+                File localFile = new File(uri.getPath());
+                File parent = localFile.getParentFile();
+                if (parent != null) {
+                    parent.mkdirs();
+                }
+                return new FileOutputStream(localFile, append);
+            }
+            case URI_TYPE_CONTENT:
+            case URI_TYPE_RESOURCE: {
+                AssetFileDescriptor assetFd = contentResolver.openAssetFileDescriptor(uri, append ? "wa" : "w");
+                return assetFd.createOutputStream();
+            }
+        }
+        throw new FileNotFoundException("URI not supported by CordovaResourceApi: " + uri);
+    }
+
+    public HttpURLConnection createHttpConnection(Uri uri) throws IOException {
+        assertBackgroundThread();
+        return (HttpURLConnection)new URL(uri.toString()).openConnection();
+    }
+    
+    // Copies the input to the output in the most efficient manner possible.
+    // Closes both streams.
+    public void copyResource(OpenForReadResult input, OutputStream outputStream) throws IOException {
+        assertBackgroundThread();
+        try {
+            InputStream inputStream = input.inputStream;
+            if (inputStream instanceof FileInputStream && outputStream instanceof FileOutputStream) {
+                FileChannel inChannel = ((FileInputStream)input.inputStream).getChannel();
+                FileChannel outChannel = ((FileOutputStream)outputStream).getChannel();
+                long offset = 0;
+                long length = input.length;
+                if (input.assetFd != null) {
+                    offset = input.assetFd.getStartOffset();
+                }
+                // transferFrom()'s 2nd arg is a relative position. Need to set the absolute
+                // position first.
+                inChannel.position(offset);
+                outChannel.transferFrom(inChannel, 0, length);
+            } else {
+                final int BUFFER_SIZE = 8192;
+                byte[] buffer = new byte[BUFFER_SIZE];
+                
+                for (;;) {
+                    int bytesRead = inputStream.read(buffer, 0, BUFFER_SIZE);
+                    
+                    if (bytesRead <= 0) {
+                        break;
+                    }
+                    outputStream.write(buffer, 0, bytesRead);
+                }
+            }            
+        } finally {
+            input.inputStream.close();
+            if (outputStream != null) {
+                outputStream.close();
+            }
+        }
+    }
+
+    public void copyResource(Uri sourceUri, OutputStream outputStream) throws IOException {
+        copyResource(openForRead(sourceUri), outputStream);
+    }
+
+    // Added in 3.5.0.
+    public void copyResource(Uri sourceUri, Uri dstUri) throws IOException {
+        copyResource(openForRead(sourceUri), openOutputStream(dstUri));
+    }
+    
+    private void assertBackgroundThread() {
+        if (threadCheckingEnabled) {
+            Thread curThread = Thread.currentThread();
+            if (curThread == Looper.getMainLooper().getThread()) {
+                throw new IllegalStateException("Do not perform IO operations on the UI thread. Use CordovaInterface.getThreadPool() instead.");
+            }
+            if (curThread == jsThread) {
+                throw new IllegalStateException("Tried to perform an IO operation on the WebCore thread. Use CordovaInterface.getThreadPool() instead.");
+            }
+        }
+    }
+    
+    private String getDataUriMimeType(Uri uri) {
+        String uriAsString = uri.getSchemeSpecificPart();
+        int commaPos = uriAsString.indexOf(',');
+        if (commaPos == -1) {
+            return null;
+        }
+        String[] mimeParts = uriAsString.substring(0, commaPos).split(";");
+        if (mimeParts.length > 0) {
+            return mimeParts[0];
+        }
+        return null;
+    }
+
+    private OpenForReadResult readDataUri(Uri uri) {
+        String uriAsString = uri.getSchemeSpecificPart();
+        int commaPos = uriAsString.indexOf(',');
+        if (commaPos == -1) {
+            return null;
+        }
+        String[] mimeParts = uriAsString.substring(0, commaPos).split(";");
+        String contentType = null;
+        boolean base64 = false;
+        if (mimeParts.length > 0) {
+            contentType = mimeParts[0];
+        }
+        for (int i = 1; i < mimeParts.length; ++i) {
+            if ("base64".equalsIgnoreCase(mimeParts[i])) {
+                base64 = true;
+            }
+        }
+        String dataPartAsString = uriAsString.substring(commaPos + 1);
+        byte[] data;
+        if (base64) {
+            data = Base64.decode(dataPartAsString, Base64.DEFAULT);
+        } else {
+            try {
+                data = dataPartAsString.getBytes("UTF-8");
+            } catch (UnsupportedEncodingException e) {
+                data = dataPartAsString.getBytes();
+            }
+        }
+        InputStream inputStream = new ByteArrayInputStream(data);
+        return new OpenForReadResult(uri, inputStream, contentType, data.length, null);
+    }
+    
+    private static void assertNonRelative(Uri uri) {
+        if (!uri.isAbsolute()) {
+            throw new IllegalArgumentException("Relative URIs are not supported.");
+        }
+    }
+    
+    public static final class OpenForReadResult {
+        public final Uri uri;
+        public final InputStream inputStream;
+        public final String mimeType;
+        public final long length;
+        public final AssetFileDescriptor assetFd;
+        
+        public OpenForReadResult(Uri uri, InputStream inputStream, String mimeType, long length, AssetFileDescriptor assetFd) {
+            this.uri = uri;
+            this.inputStream = inputStream;
+            this.mimeType = mimeType;
+            this.length = length;
+            this.assetFd = assetFd;
+        }
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebView.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebView.java
new file mode 100644
index 0000000..20aea80
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebView.java
@@ -0,0 +1,142 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+         http://www.apache.org/licenses/LICENSE-2.0
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import java.util.List;
+import java.util.Map;
+
+import android.content.Context;
+import android.content.Intent;
+import android.view.View;
+import android.webkit.WebChromeClient.CustomViewCallback;
+
+/**
+ * Main interface for interacting with a Cordova webview - implemented by CordovaWebViewImpl.
+ * This is an interface so that it can be easily mocked in tests.
+ * Methods may be added to this interface without a major version bump, as plugins & embedders
+ * are not expected to implement it.
+ */
+public interface CordovaWebView {
+    public static final String CORDOVA_VERSION = "8.0.0";
+
+    void init(CordovaInterface cordova, List<PluginEntry> pluginEntries, CordovaPreferences preferences);
+
+    boolean isInitialized();
+
+    View getView();
+
+    void loadUrlIntoView(String url, boolean recreatePlugins);
+
+    void stopLoading();
+
+    boolean canGoBack();
+
+    void clearCache();
+
+    /** Use parameter-less overload */
+    @Deprecated
+    void clearCache(boolean b);
+
+    void clearHistory();
+
+    boolean backHistory();
+
+    void handlePause(boolean keepRunning);
+
+    void onNewIntent(Intent intent);
+
+    void handleResume(boolean keepRunning);
+
+    void handleStart();
+
+    void handleStop();
+
+    void handleDestroy();
+
+    /**
+     * Send JavaScript statement back to JavaScript.
+     *
+     * Deprecated (https://issues.apache.org/jira/browse/CB-6851)
+     * Instead of executing snippets of JS, you should use the exec bridge
+     * to create a Java->JS communication channel.
+     * To do this:
+     * 1. Within plugin.xml (to have your JS run before deviceready):
+     *    <js-module><runs/></js-module>
+     * 2. Within your .js (call exec on start-up):
+     *    require('cordova/channel').onCordovaReady.subscribe(function() {
+     *      require('cordova/exec')(win, null, 'Plugin', 'method', []);
+     *      function win(message) {
+     *        ... process message from java here ...
+     *      }
+     *    });
+     * 3. Within your .java:
+     *    PluginResult dataResult = new PluginResult(PluginResult.Status.OK, CODE);
+     *    dataResult.setKeepCallback(true);
+     *    savedCallbackContext.sendPluginResult(dataResult);
+     */
+    @Deprecated
+    void sendJavascript(String statememt);
+
+    /**
+     * Load the specified URL in the Cordova webview or a new browser instance.
+     *
+     * NOTE: If openExternal is false, only whitelisted URLs can be loaded.
+     *
+     * @param url           The url to load.
+     * @param openExternal  Load url in browser instead of Cordova webview.
+     * @param clearHistory  Clear the history stack, so new page becomes top of history
+     * @param params        Parameters for new app
+     */
+    void showWebPage(String url, boolean openExternal, boolean clearHistory, Map<String, Object> params);
+
+    /**
+     * Deprecated in 4.0.0. Use your own View-toggling logic.
+     */
+    @Deprecated
+    boolean isCustomViewShowing();
+
+    /**
+     * Deprecated in 4.0.0. Use your own View-toggling logic.
+     */
+    @Deprecated
+    void showCustomView(View view, CustomViewCallback callback);
+
+    /**
+     * Deprecated in 4.0.0. Use your own View-toggling logic.
+     */
+    @Deprecated
+    void hideCustomView();
+
+    CordovaResourceApi getResourceApi();
+
+    void setButtonPlumbedToJs(int keyCode, boolean override);
+    boolean isButtonPlumbedToJs(int keyCode);
+
+    void sendPluginResult(PluginResult cr, String callbackId);
+
+    PluginManager getPluginManager();
+    CordovaWebViewEngine getEngine();
+    CordovaPreferences getPreferences();
+    ICordovaCookieManager getCookieManager();
+
+    String getUrl();
+
+    // TODO: Work on deleting these by removing refs from plugins.
+    Context getContext();
+    void loadUrl(String url);
+    Object postMessage(String id, Object data);
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewEngine.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewEngine.java
new file mode 100644
index 0000000..c8e5a55
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewEngine.java
@@ -0,0 +1,85 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import android.view.KeyEvent;
+import android.view.View;
+import android.webkit.ValueCallback;
+
+/**
+ * Interface for all Cordova engines.
+ * No methods will be added to this class (in order to be compatible with existing engines).
+ * Instead, we will create a new interface: e.g. CordovaWebViewEngineV2
+ */
+public interface CordovaWebViewEngine {
+    void init(CordovaWebView parentWebView, CordovaInterface cordova, Client client,
+              CordovaResourceApi resourceApi, PluginManager pluginManager,
+              NativeToJsMessageQueue nativeToJsMessageQueue);
+
+    CordovaWebView getCordovaWebView();
+    ICordovaCookieManager getCookieManager();
+    View getView();
+
+    void loadUrl(String url, boolean clearNavigationStack);
+
+    void stopLoading();
+
+    /** Return the currently loaded URL */
+    String getUrl();
+
+    void clearCache();
+
+    /** After calling clearHistory(), canGoBack() should be false. */
+    void clearHistory();
+
+    boolean canGoBack();
+
+    /** Returns whether a navigation occurred */
+    boolean goBack();
+
+    /** Pauses / resumes the WebView's event loop. */
+    void setPaused(boolean value);
+
+    /** Clean up all resources associated with the WebView. */
+    void destroy();
+
+    /** Add the evaulate Javascript method **/
+    void evaluateJavascript(String js, ValueCallback<String> callback);
+
+    /**
+     * Used to retrieve the associated CordovaWebView given a View without knowing the type of Engine.
+     * E.g. ((CordovaWebView.EngineView)activity.findViewById(android.R.id.webView)).getCordovaWebView();
+     */
+    public interface EngineView {
+        CordovaWebView getCordovaWebView();
+    }
+
+    /**
+     * Contains methods that an engine uses to communicate with the parent CordovaWebView.
+     * Methods may be added in future cordova versions, but never removed.
+     */
+    public interface Client {
+        Boolean onDispatchKeyEvent(KeyEvent event);
+        void clearLoadTimeoutTimer();
+        void onPageStarted(String newUrl);
+        void onReceivedError(int errorCode, String description, String failingUrl);
+        void onPageFinishedLoading(String url);
+        boolean onNavigationAttempt(String url);
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewImpl.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewImpl.java
new file mode 100644
index 0000000..1db2e95
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewImpl.java
@@ -0,0 +1,617 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebChromeClient;
+import android.widget.FrameLayout;
+
+import org.apache.cordova.engine.SystemWebViewEngine;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Main class for interacting with a Cordova webview. Manages plugins, events, and a CordovaWebViewEngine.
+ * Class uses two-phase initialization. You must call init() before calling any other methods.
+ */
+public class CordovaWebViewImpl implements CordovaWebView {
+
+    public static final String TAG = "CordovaWebViewImpl";
+
+    private PluginManager pluginManager;
+
+    protected final CordovaWebViewEngine engine;
+    private CordovaInterface cordova;
+
+    // Flag to track that a loadUrl timeout occurred
+    private int loadUrlTimeout = 0;
+
+    private CordovaResourceApi resourceApi;
+    private CordovaPreferences preferences;
+    private CoreAndroid appPlugin;
+    private NativeToJsMessageQueue nativeToJsMessageQueue;
+    private EngineClient engineClient = new EngineClient();
+    private boolean hasPausedEver;
+
+    // The URL passed to loadUrl(), not necessarily the URL of the current page.
+    String loadedUrl;
+
+    /** custom view created by the browser (a video player for example) */
+    private View mCustomView;
+    private WebChromeClient.CustomViewCallback mCustomViewCallback;
+
+    private Set<Integer> boundKeyCodes = new HashSet<Integer>();
+
+    public static CordovaWebViewEngine createEngine(Context context, CordovaPreferences preferences) {
+        String className = preferences.getString("webview", SystemWebViewEngine.class.getCanonicalName());
+        try {
+            Class<?> webViewClass = Class.forName(className);
+            Constructor<?> constructor = webViewClass.getConstructor(Context.class, CordovaPreferences.class);
+            return (CordovaWebViewEngine) constructor.newInstance(context, preferences);
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to create webview. ", e);
+        }
+    }
+
+    public CordovaWebViewImpl(CordovaWebViewEngine cordovaWebViewEngine) {
+        this.engine = cordovaWebViewEngine;
+    }
+
+    // Convenience method for when creating programmatically (not from Config.xml).
+    public void init(CordovaInterface cordova) {
+        init(cordova, new ArrayList<PluginEntry>(), new CordovaPreferences());
+    }
+
+    @SuppressLint("Assert")
+    @Override
+    public void init(CordovaInterface cordova, List<PluginEntry> pluginEntries, CordovaPreferences preferences) {
+        if (this.cordova != null) {
+            throw new IllegalStateException();
+        }
+        this.cordova = cordova;
+        this.preferences = preferences;
+        pluginManager = new PluginManager(this, this.cordova, pluginEntries);
+        resourceApi = new CordovaResourceApi(engine.getView().getContext(), pluginManager);
+        nativeToJsMessageQueue = new NativeToJsMessageQueue();
+        nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.NoOpBridgeMode());
+        nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.LoadUrlBridgeMode(engine, cordova));
+
+        if (preferences.getBoolean("DisallowOverscroll", false)) {
+            engine.getView().setOverScrollMode(View.OVER_SCROLL_NEVER);
+        }
+        engine.init(this, cordova, engineClient, resourceApi, pluginManager, nativeToJsMessageQueue);
+        // This isn't enforced by the compiler, so assert here.
+        assert engine.getView() instanceof CordovaWebViewEngine.EngineView;
+
+        pluginManager.addService(CoreAndroid.PLUGIN_NAME, "org.apache.cordova.CoreAndroid");
+        pluginManager.init();
+
+    }
+
+    @Override
+    public boolean isInitialized() {
+        return cordova != null;
+    }
+
+    @Override
+    public void loadUrlIntoView(final String url, boolean recreatePlugins) {
+        LOG.d(TAG, ">>> loadUrl(" + url + ")");
+        if (url.equals("about:blank") || url.startsWith("javascript:")) {
+            engine.loadUrl(url, false);
+            return;
+        }
+
+        recreatePlugins = recreatePlugins || (loadedUrl == null);
+
+        if (recreatePlugins) {
+            // Don't re-initialize on first load.
+            if (loadedUrl != null) {
+                appPlugin = null;
+                pluginManager.init();
+            }
+            loadedUrl = url;
+        }
+
+        // Create a timeout timer for loadUrl
+        final int currentLoadUrlTimeout = loadUrlTimeout;
+        final int loadUrlTimeoutValue = preferences.getInteger("LoadUrlTimeoutValue", 20000);
+
+        // Timeout error method
+        final Runnable loadError = new Runnable() {
+            public void run() {
+                stopLoading();
+                LOG.e(TAG, "CordovaWebView: TIMEOUT ERROR!");
+
+                // Handle other errors by passing them to the webview in JS
+                JSONObject data = new JSONObject();
+                try {
+                    data.put("errorCode", -6);
+                    data.put("description", "The connection to the server was unsuccessful.");
+                    data.put("url", url);
+                } catch (JSONException e) {
+                    // Will never happen.
+                }
+                pluginManager.postMessage("onReceivedError", data);
+            }
+        };
+
+        // Timeout timer method
+        final Runnable timeoutCheck = new Runnable() {
+            public void run() {
+                try {
+                    synchronized (this) {
+                        wait(loadUrlTimeoutValue);
+                    }
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+
+                // If timeout, then stop loading and handle error
+                if (loadUrlTimeout == currentLoadUrlTimeout) {
+                    cordova.getActivity().runOnUiThread(loadError);
+                }
+            }
+        };
+
+        final boolean _recreatePlugins = recreatePlugins;
+        cordova.getActivity().runOnUiThread(new Runnable() {
+            public void run() {
+                if (loadUrlTimeoutValue > 0) {
+                    cordova.getThreadPool().execute(timeoutCheck);
+                }
+                engine.loadUrl(url, _recreatePlugins);
+            }
+        });
+    }
+
+
+    @Override
+    public void loadUrl(String url) {
+        loadUrlIntoView(url, true);
+    }
+
+    @Override
+    public void showWebPage(String url, boolean openExternal, boolean clearHistory, Map<String, Object> params) {
+        LOG.d(TAG, "showWebPage(%s, %b, %b, HashMap)", url, openExternal, clearHistory);
+
+        // If clearing history
+        if (clearHistory) {
+            engine.clearHistory();
+        }
+
+        // If loading into our webview
+        if (!openExternal) {
+            // Make sure url is in whitelist
+            if (pluginManager.shouldAllowNavigation(url)) {
+                // TODO: What about params?
+                // Load new URL
+                loadUrlIntoView(url, true);
+                return;
+            } else {
+                LOG.w(TAG, "showWebPage: Refusing to load URL into webview since it is not in the <allow-navigation> whitelist. URL=" + url);
+                return;
+            }
+        }
+        if (!pluginManager.shouldOpenExternalUrl(url)) {
+            LOG.w(TAG, "showWebPage: Refusing to send intent for URL since it is not in the <allow-intent> whitelist. URL=" + url);
+            return;
+        }
+        try {
+            Intent intent = new Intent(Intent.ACTION_VIEW);
+            // To send an intent without CATEGORY_BROWSER, a custom plugin should be used.
+            intent.addCategory(Intent.CATEGORY_BROWSABLE);
+            Uri uri = Uri.parse(url);
+            // Omitting the MIME type for file: URLs causes "No Activity found to handle Intent".
+            // Adding the MIME type to http: URLs causes them to not be handled by the downloader.
+            if ("file".equals(uri.getScheme())) {
+                intent.setDataAndType(uri, resourceApi.getMimeType(uri));
+            } else {
+                intent.setData(uri);
+            }
+            cordova.getActivity().startActivity(intent);
+        } catch (android.content.ActivityNotFoundException e) {
+            LOG.e(TAG, "Error loading url " + url, e);
+        }
+    }
+
+    @Override
+    @Deprecated
+    public void showCustomView(View view, WebChromeClient.CustomViewCallback callback) {
+        // This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0
+        LOG.d(TAG, "showing Custom View");
+        // if a view already exists then immediately terminate the new one
+        if (mCustomView != null) {
+            callback.onCustomViewHidden();
+            return;
+        }
+
+        // Store the view and its callback for later (to kill it properly)
+        mCustomView = view;
+        mCustomViewCallback = callback;
+
+        // Add the custom view to its container.
+        ViewGroup parent = (ViewGroup) engine.getView().getParent();
+        parent.addView(view, new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                Gravity.CENTER));
+
+        // Hide the content view.
+        engine.getView().setVisibility(View.GONE);
+
+        // Finally show the custom view container.
+        parent.setVisibility(View.VISIBLE);
+        parent.bringToFront();
+    }
+
+    @Override
+    @Deprecated
+    public void hideCustomView() {
+        // This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0
+        if (mCustomView == null) return;
+        LOG.d(TAG, "Hiding Custom View");
+
+        // Hide the custom view.
+        mCustomView.setVisibility(View.GONE);
+
+        // Remove the custom view from its container.
+        ViewGroup parent = (ViewGroup) engine.getView().getParent();
+        parent.removeView(mCustomView);
+        mCustomView = null;
+        mCustomViewCallback.onCustomViewHidden();
+
+        // Show the content view.
+        engine.getView().setVisibility(View.VISIBLE);
+    }
+
+    @Override
+    @Deprecated
+    public boolean isCustomViewShowing() {
+        return mCustomView != null;
+    }
+
+    @Override
+    @Deprecated
+    public void sendJavascript(String statement) {
+        nativeToJsMessageQueue.addJavaScript(statement);
+    }
+
+    @Override
+    public void sendPluginResult(PluginResult cr, String callbackId) {
+        nativeToJsMessageQueue.addPluginResult(cr, callbackId);
+    }
+
+    @Override
+    public PluginManager getPluginManager() {
+        return pluginManager;
+    }
+    @Override
+    public CordovaPreferences getPreferences() {
+        return preferences;
+    }
+    @Override
+    public ICordovaCookieManager getCookieManager() {
+        return engine.getCookieManager();
+    }
+    @Override
+    public CordovaResourceApi getResourceApi() {
+        return resourceApi;
+    }
+    @Override
+    public CordovaWebViewEngine getEngine() {
+        return engine;
+    }
+    @Override
+    public View getView() {
+        return engine.getView();
+    }
+    @Override
+    public Context getContext() {
+        return engine.getView().getContext();
+    }
+
+    private void sendJavascriptEvent(String event) {
+        if (appPlugin == null) {
+            appPlugin = (CoreAndroid)pluginManager.getPlugin(CoreAndroid.PLUGIN_NAME);
+        }
+
+        if (appPlugin == null) {
+            LOG.w(TAG, "Unable to fire event without existing plugin");
+            return;
+        }
+        appPlugin.fireJavascriptEvent(event);
+    }
+
+    @Override
+    public void setButtonPlumbedToJs(int keyCode, boolean override) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_VOLUME_DOWN:
+            case KeyEvent.KEYCODE_VOLUME_UP:
+            case KeyEvent.KEYCODE_BACK:
+            case KeyEvent.KEYCODE_MENU:
+                // TODO: Why are search and menu buttons handled separately?
+                if (override) {
+                    boundKeyCodes.add(keyCode);
+                } else {
+                    boundKeyCodes.remove(keyCode);
+                }
+                return;
+            default:
+                throw new IllegalArgumentException("Unsupported keycode: " + keyCode);
+        }
+    }
+
+    @Override
+    public boolean isButtonPlumbedToJs(int keyCode) {
+        return boundKeyCodes.contains(keyCode);
+    }
+
+    @Override
+    public Object postMessage(String id, Object data) {
+        return pluginManager.postMessage(id, data);
+    }
+
+    // Engine method proxies:
+    @Override
+    public String getUrl() {
+        return engine.getUrl();
+    }
+
+    @Override
+    public void stopLoading() {
+        // Clear timeout flag
+        loadUrlTimeout++;
+    }
+
+    @Override
+    public boolean canGoBack() {
+        return engine.canGoBack();
+    }
+
+    @Override
+    public void clearCache() {
+        engine.clearCache();
+    }
+
+    @Override
+    @Deprecated
+    public void clearCache(boolean b) {
+        engine.clearCache();
+    }
+
+    @Override
+    public void clearHistory() {
+        engine.clearHistory();
+    }
+
+    @Override
+    public boolean backHistory() {
+        return engine.goBack();
+    }
+
+    /////// LifeCycle methods ///////
+    @Override
+    public void onNewIntent(Intent intent) {
+        if (this.pluginManager != null) {
+            this.pluginManager.onNewIntent(intent);
+        }
+    }
+    @Override
+    public void handlePause(boolean keepRunning) {
+        if (!isInitialized()) {
+            return;
+        }
+        hasPausedEver = true;
+        pluginManager.onPause(keepRunning);
+        sendJavascriptEvent("pause");
+
+        // If app doesn't want to run in background
+        if (!keepRunning) {
+            // Pause JavaScript timers. This affects all webviews within the app!
+            engine.setPaused(true);
+        }
+    }
+    @Override
+    public void handleResume(boolean keepRunning) {
+        if (!isInitialized()) {
+            return;
+        }
+
+        // Resume JavaScript timers. This affects all webviews within the app!
+        engine.setPaused(false);
+        this.pluginManager.onResume(keepRunning);
+
+        // In order to match the behavior of the other platforms, we only send onResume after an
+        // onPause has occurred. The resume event might still be sent if the Activity was killed
+        // while waiting for the result of an external Activity once the result is obtained
+        if (hasPausedEver) {
+            sendJavascriptEvent("resume");
+        }
+    }
+    @Override
+    public void handleStart() {
+        if (!isInitialized()) {
+            return;
+        }
+        pluginManager.onStart();
+    }
+    @Override
+    public void handleStop() {
+        if (!isInitialized()) {
+            return;
+        }
+        pluginManager.onStop();
+    }
+    @Override
+    public void handleDestroy() {
+        if (!isInitialized()) {
+            return;
+        }
+        // Cancel pending timeout timer.
+        loadUrlTimeout++;
+
+        // Forward to plugins
+        this.pluginManager.onDestroy();
+
+        // TODO: about:blank is a bit special (and the default URL for new frames)
+        // We should use a blank data: url instead so it's more obvious
+        this.loadUrl("about:blank");
+
+        // TODO: Should not destroy webview until after about:blank is done loading.
+        engine.destroy();
+        hideCustomView();
+    }
+
+    protected class EngineClient implements CordovaWebViewEngine.Client {
+        @Override
+        public void clearLoadTimeoutTimer() {
+            loadUrlTimeout++;
+        }
+
+        @Override
+        public void onPageStarted(String newUrl) {
+            LOG.d(TAG, "onPageDidNavigate(" + newUrl + ")");
+            boundKeyCodes.clear();
+            pluginManager.onReset();
+            pluginManager.postMessage("onPageStarted", newUrl);
+        }
+
+        @Override
+        public void onReceivedError(int errorCode, String description, String failingUrl) {
+            clearLoadTimeoutTimer();
+            JSONObject data = new JSONObject();
+            try {
+                data.put("errorCode", errorCode);
+                data.put("description", description);
+                data.put("url", failingUrl);
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+            pluginManager.postMessage("onReceivedError", data);
+        }
+
+        @Override
+        public void onPageFinishedLoading(String url) {
+            LOG.d(TAG, "onPageFinished(" + url + ")");
+
+            clearLoadTimeoutTimer();
+
+            // Broadcast message that page has loaded
+            pluginManager.postMessage("onPageFinished", url);
+
+            // Make app visible after 2 sec in case there was a JS error and Cordova JS never initialized correctly
+            if (engine.getView().getVisibility() != View.VISIBLE) {
+                Thread t = new Thread(new Runnable() {
+                    public void run() {
+                        try {
+                            Thread.sleep(2000);
+                            cordova.getActivity().runOnUiThread(new Runnable() {
+                                public void run() {
+                                    pluginManager.postMessage("spinner", "stop");
+                                }
+                            });
+                        } catch (InterruptedException e) {
+                        }
+                    }
+                });
+                t.start();
+            }
+
+            // Shutdown if blank loaded
+            if (url.equals("about:blank")) {
+                pluginManager.postMessage("exit", null);
+            }
+        }
+
+        @Override
+        public Boolean onDispatchKeyEvent(KeyEvent event) {
+            int keyCode = event.getKeyCode();
+            boolean isBackButton = keyCode == KeyEvent.KEYCODE_BACK;
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                if (isBackButton && mCustomView != null) {
+                    return true;
+                } else if (boundKeyCodes.contains(keyCode)) {
+                    return true;
+                } else if (isBackButton) {
+                    return engine.canGoBack();
+                }
+            } else if (event.getAction() == KeyEvent.ACTION_UP) {
+                if (isBackButton && mCustomView != null) {
+                    hideCustomView();
+                    return true;
+                } else if (boundKeyCodes.contains(keyCode)) {
+                    String eventName = null;
+                    switch (keyCode) {
+                        case KeyEvent.KEYCODE_VOLUME_DOWN:
+                            eventName = "volumedownbutton";
+                            break;
+                        case KeyEvent.KEYCODE_VOLUME_UP:
+                            eventName = "volumeupbutton";
+                            break;
+                        case KeyEvent.KEYCODE_SEARCH:
+                            eventName = "searchbutton";
+                            break;
+                        case KeyEvent.KEYCODE_MENU:
+                            eventName = "menubutton";
+                            break;
+                        case KeyEvent.KEYCODE_BACK:
+                            eventName = "backbutton";
+                            break;
+                    }
+                    if (eventName != null) {
+                        sendJavascriptEvent(eventName);
+                        return true;
+                    }
+                } else if (isBackButton) {
+                    return engine.goBack();
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public boolean onNavigationAttempt(String url) {
+            // Give plugins the chance to handle the url
+            if (pluginManager.onOverrideUrlLoading(url)) {
+                return true;
+            } else if (pluginManager.shouldAllowNavigation(url)) {
+                return false;
+            } else if (pluginManager.shouldOpenExternalUrl(url)) {
+                showWebPage(url, true, false, null);
+                return true;
+            }
+            LOG.w(TAG, "Blocked (possibly sub-frame) navigation to non-allowed URL: " + url);
+            return true;
+        }
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CoreAndroid.java b/platforms/android/CordovaLib/src/org/apache/cordova/CoreAndroid.java
new file mode 100755
index 0000000..3945cdd
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/CoreAndroid.java
@@ -0,0 +1,407 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.telephony.TelephonyManager;
+import android.view.KeyEvent;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+
+/**
+ * This class exposes methods in Cordova that can be called from JavaScript.
+ */
+public class CoreAndroid extends CordovaPlugin {
+
+    public static final String PLUGIN_NAME = "CoreAndroid";
+    protected static final String TAG = "CordovaApp";
+    private BroadcastReceiver telephonyReceiver;
+    private CallbackContext messageChannel;
+    private PluginResult pendingResume;
+    private PluginResult pendingPause;
+    private final Object messageChannelLock = new Object();
+
+    /**
+     * Send an event to be fired on the Javascript side.
+     *
+     * @param action The name of the event to be fired
+     */
+    public void fireJavascriptEvent(String action) {
+        sendEventMessage(action);
+    }
+
+    /**
+     * Sets the context of the Command. This can then be used to do things like
+     * get file paths associated with the Activity.
+     */
+    @Override
+    public void pluginInitialize() {
+        this.initTelephonyReceiver();
+    }
+
+    /**
+     * Executes the request and returns PluginResult.
+     *
+     * @param action            The action to execute.
+     * @param args              JSONArry of arguments for the plugin.
+     * @param callbackContext   The callback context from which we were invoked.
+     * @return                  A PluginResult object with a status and message.
+     */
+    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
+        PluginResult.Status status = PluginResult.Status.OK;
+        String result = "";
+
+        try {
+            if (action.equals("clearCache")) {
+                this.clearCache();
+            }
+            else if (action.equals("show")) {
+                // This gets called from JavaScript onCordovaReady to show the webview.
+                // I recommend we change the name of the Message as spinner/stop is not
+                // indicative of what this actually does (shows the webview).
+                cordova.getActivity().runOnUiThread(new Runnable() {
+                    public void run() {
+                        webView.getPluginManager().postMessage("spinner", "stop");
+                    }
+                });
+            }
+            else if (action.equals("loadUrl")) {
+                this.loadUrl(args.getString(0), args.optJSONObject(1));
+            }
+            else if (action.equals("cancelLoadUrl")) {
+                //this.cancelLoadUrl();
+            }
+            else if (action.equals("clearHistory")) {
+                this.clearHistory();
+            }
+            else if (action.equals("backHistory")) {
+                this.backHistory();
+            }
+            else if (action.equals("overrideButton")) {
+                this.overrideButton(args.getString(0), args.getBoolean(1));
+            }
+            else if (action.equals("overrideBackbutton")) {
+                this.overrideBackbutton(args.getBoolean(0));
+            }
+            else if (action.equals("exitApp")) {
+                this.exitApp();
+            }
+			else if (action.equals("messageChannel")) {
+                synchronized(messageChannelLock) {
+                    messageChannel = callbackContext;
+                    if (pendingPause != null) {
+                        sendEventMessage(pendingPause);
+                        pendingPause = null;
+                    }
+                    if (pendingResume != null) {
+                        sendEventMessage(pendingResume);
+                        pendingResume = null;
+                    }
+                }
+                return true;
+            }
+
+            callbackContext.sendPluginResult(new PluginResult(status, result));
+            return true;
+        } catch (JSONException e) {
+            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+            return false;
+        }
+    }
+
+    //--------------------------------------------------------------------------
+    // LOCAL METHODS
+    //--------------------------------------------------------------------------
+
+    /**
+     * Clear the resource cache.
+     */
+    public void clearCache() {
+        cordova.getActivity().runOnUiThread(new Runnable() {
+            public void run() {
+                webView.clearCache();
+            }
+        });
+    }
+
+    /**
+     * Load the url into the webview.
+     *
+     * @param url
+     * @param props			Properties that can be passed in to the Cordova activity (i.e. loadingDialog, wait, ...)
+     * @throws JSONException
+     */
+    public void loadUrl(String url, JSONObject props) throws JSONException {
+        LOG.d("App", "App.loadUrl("+url+","+props+")");
+        int wait = 0;
+        boolean openExternal = false;
+        boolean clearHistory = false;
+
+        // If there are properties, then set them on the Activity
+        HashMap<String, Object> params = new HashMap<String, Object>();
+        if (props != null) {
+            JSONArray keys = props.names();
+            for (int i = 0; i < keys.length(); i++) {
+                String key = keys.getString(i);
+                if (key.equals("wait")) {
+                    wait = props.getInt(key);
+                }
+                else if (key.equalsIgnoreCase("openexternal")) {
+                    openExternal = props.getBoolean(key);
+                }
+                else if (key.equalsIgnoreCase("clearhistory")) {
+                    clearHistory = props.getBoolean(key);
+                }
+                else {
+                    Object value = props.get(key);
+                    if (value == null) {
+
+                    }
+                    else if (value.getClass().equals(String.class)) {
+                        params.put(key, (String)value);
+                    }
+                    else if (value.getClass().equals(Boolean.class)) {
+                        params.put(key, (Boolean)value);
+                    }
+                    else if (value.getClass().equals(Integer.class)) {
+                        params.put(key, (Integer)value);
+                    }
+                }
+            }
+        }
+
+        // If wait property, then delay loading
+
+        if (wait > 0) {
+            try {
+                synchronized(this) {
+                    this.wait(wait);
+                }
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+        this.webView.showWebPage(url, openExternal, clearHistory, params);
+    }
+
+    /**
+     * Clear page history for the app.
+     */
+    public void clearHistory() {
+        cordova.getActivity().runOnUiThread(new Runnable() {
+            public void run() {
+                webView.clearHistory();
+            }
+        });
+    }
+
+    /**
+     * Go to previous page displayed.
+     * This is the same as pressing the backbutton on Android device.
+     */
+    public void backHistory() {
+        cordova.getActivity().runOnUiThread(new Runnable() {
+            public void run() {
+                webView.backHistory();
+            }
+        });
+    }
+
+    /**
+     * Override the default behavior of the Android back button.
+     * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
+     *
+     * @param override		T=override, F=cancel override
+     */
+    public void overrideBackbutton(boolean override) {
+        LOG.i("App", "WARNING: Back Button Default Behavior will be overridden.  The backbutton event will be fired!");
+        webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_BACK, override);
+    }
+
+    /**
+     * Override the default behavior of the Android volume buttons.
+     * If overridden, when the volume button is pressed, the "volume[up|down]button" JavaScript event will be fired.
+     *
+     * @param button        volumeup, volumedown
+     * @param override      T=override, F=cancel override
+     */
+    public void overrideButton(String button, boolean override) {
+        LOG.i("App", "WARNING: Volume Button Default Behavior will be overridden.  The volume event will be fired!");
+        if (button.equals("volumeup")) {
+            webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_UP, override);
+        }
+        else if (button.equals("volumedown")) {
+            webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_DOWN, override);
+        }
+        else if (button.equals("menubutton")) {
+            webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_MENU, override);
+        }
+    }
+
+    /**
+     * Return whether the Android back button is overridden by the user.
+     *
+     * @return boolean
+     */
+    public boolean isBackbuttonOverridden() {
+        return webView.isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK);
+    }
+
+    /**
+     * Exit the Android application.
+     */
+    public void exitApp() {
+        this.webView.getPluginManager().postMessage("exit", null);
+    }
+
+
+    /**
+     * Listen for telephony events: RINGING, OFFHOOK and IDLE
+     * Send these events to all plugins using
+     *      CordovaActivity.onMessage("telephone", "ringing" | "offhook" | "idle")
+     */
+    private void initTelephonyReceiver() {
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
+        //final CordovaInterface mycordova = this.cordova;
+        this.telephonyReceiver = new BroadcastReceiver() {
+
+            @Override
+            public void onReceive(Context context, Intent intent) {
+
+                // If state has changed
+                if ((intent != null) && intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
+                    if (intent.hasExtra(TelephonyManager.EXTRA_STATE)) {
+                        String extraData = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
+                        if (extraData.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
+                            LOG.i(TAG, "Telephone RINGING");
+                            webView.getPluginManager().postMessage("telephone", "ringing");
+                        }
+                        else if (extraData.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
+                            LOG.i(TAG, "Telephone OFFHOOK");
+                            webView.getPluginManager().postMessage("telephone", "offhook");
+                        }
+                        else if (extraData.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
+                            LOG.i(TAG, "Telephone IDLE");
+                            webView.getPluginManager().postMessage("telephone", "idle");
+                        }
+                    }
+                }
+            }
+        };
+
+        // Register the receiver
+        webView.getContext().registerReceiver(this.telephonyReceiver, intentFilter);
+    }
+
+    private void sendEventMessage(String action) {
+        JSONObject obj = new JSONObject();
+        try {
+            obj.put("action", action);
+        } catch (JSONException e) {
+            LOG.e(TAG, "Failed to create event message", e);
+        }
+        PluginResult result = new PluginResult(PluginResult.Status.OK, obj);
+
+        if (messageChannel == null) {
+            LOG.i(TAG, "Request to send event before messageChannel initialised: " + action);
+            if ("pause".equals(action)) {
+                pendingPause = result;
+            } else if ("resume".equals(action)) {
+                // When starting normally onPause then onResume is called
+                pendingPause = null;
+            }
+        } else {
+            sendEventMessage(result);
+        }
+    }
+
+    private void sendEventMessage(PluginResult payload) {
+        payload.setKeepCallback(true);
+        if (messageChannel != null) {
+            messageChannel.sendPluginResult(payload);
+        }
+    }
+
+    /*
+     * Unregister the receiver
+     *
+     */
+    public void onDestroy()
+    {
+        webView.getContext().unregisterReceiver(this.telephonyReceiver);
+    }
+
+    /**
+     * Used to send the resume event in the case that the Activity is destroyed by the OS
+     *
+     * @param resumeEvent PluginResult containing the payload for the resume event to be fired
+     */
+    public void sendResumeEvent(PluginResult resumeEvent) {
+        // This operation must be synchronized because plugin results that trigger resume
+        // events can be processed asynchronously
+        synchronized(messageChannelLock) {
+            if (messageChannel != null) {
+                sendEventMessage(resumeEvent);
+            } else {
+                // Might get called before the page loads, so we need to store it until the
+                // messageChannel gets created
+                this.pendingResume = resumeEvent;
+            }
+        }
+    }
+
+      /*
+     * This needs to be implemented if you wish to use the Camera Plugin or other plugins
+     * that read the Build Configuration.
+     *
+     * Thanks to Phil@Medtronic and Graham Borland for finding the answer and posting it to
+     * StackOverflow.  This is annoying as hell!
+     *
+     */
+
+    public static Object getBuildConfigValue(Context ctx, String key)
+    {
+        try
+        {
+            Class<?> clazz = Class.forName(ctx.getPackageName() + ".BuildConfig");
+            Field field = clazz.getField(key);
+            return field.get(null);
+        } catch (ClassNotFoundException e) {
+            LOG.d(TAG, "Unable to get the BuildConfig, is this built with ANT?");
+            e.printStackTrace();
+        } catch (NoSuchFieldException e) {
+            LOG.d(TAG, key + " is not a valid field. Check your build.gradle");
+        } catch (IllegalAccessException e) {
+            LOG.d(TAG, "Illegal Access Exception: Let's print a stack trace.");
+            e.printStackTrace();
+        }
+
+        return null;
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/ExposedJsApi.java b/platforms/android/CordovaLib/src/org/apache/cordova/ExposedJsApi.java
new file mode 100644
index 0000000..acc65c6
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/ExposedJsApi.java
@@ -0,0 +1,31 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova;
+
+import org.json.JSONException;
+
+/*
+ * Any exposed Javascript API MUST implement these three things!
+ */
+public interface ExposedJsApi {
+    public String exec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException;
+    public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException;
+    public String retrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException;
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaClientCertRequest.java b/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaClientCertRequest.java
new file mode 100644
index 0000000..455d2f9
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaClientCertRequest.java
@@ -0,0 +1,66 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+/**
+ * Specifies interface for handling certificate requests.
+ */
+public interface ICordovaClientCertRequest {
+    /**
+     * Cancel this request
+     */
+    public void cancel();
+    
+    /*
+     * Returns the host name of the server requesting the certificate.
+     */
+    public String getHost();
+    
+    /*
+     * Returns the acceptable types of asymmetric keys (can be null).
+     */
+    public String[] getKeyTypes();
+    
+    /*
+     * Returns the port number of the server requesting the certificate.
+     */
+    public int getPort();
+    
+    /*
+     * Returns the acceptable certificate issuers for the certificate matching the private key (can be null).
+     */
+    public Principal[] getPrincipals();
+    
+    /*
+     * Ignore the request for now. Do not remember user's choice.
+     */
+    public void ignore();
+    
+    /*
+     * Proceed with the specified private key and client certificate chain. Remember the user's positive choice and use it for future requests.
+     * 
+     * @param privateKey The privateKey
+     * @param chain The certificate chain 
+     */
+    public void proceed(PrivateKey privateKey, X509Certificate[] chain);
+}
\ No newline at end of file
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaCookieManager.java b/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaCookieManager.java
new file mode 100644
index 0000000..e776194
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaCookieManager.java
@@ -0,0 +1,33 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova;
+
+public interface ICordovaCookieManager {
+
+    public void setCookiesEnabled(boolean accept);
+
+    public void setCookie(final String url, final String value);
+
+    public String getCookie(final String url);
+
+    public void clearCookies();
+
+    public void flush();
+};
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaHttpAuthHandler.java b/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaHttpAuthHandler.java
new file mode 100644
index 0000000..c55818a
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaHttpAuthHandler.java
@@ -0,0 +1,38 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+/**
+ * Specifies interface for HTTP auth handler object which is used to handle auth requests and
+ * specifying user credentials.
+ */
+ public interface ICordovaHttpAuthHandler {
+    /**
+     * Instructs the WebView to cancel the authentication request.
+     */
+    public void cancel ();
+    
+    /**
+     * Instructs the WebView to proceed with the authentication with the given credentials.
+     * 
+     * @param username The user name
+     * @param password The password
+     */
+    public void proceed (String username, String password);
+}
\ No newline at end of file
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/LOG.java b/platforms/android/CordovaLib/src/org/apache/cordova/LOG.java
new file mode 100755
index 0000000..9fe7a7d
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/LOG.java
@@ -0,0 +1,244 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import android.util.Log;
+
+/**
+ * Log to Android logging system.
+ *
+ * Log message can be a string or a printf formatted string with arguments.
+ * See http://developer.android.com/reference/java/util/Formatter.html
+ */
+public class LOG {
+
+    public static final int VERBOSE = Log.VERBOSE;
+    public static final int DEBUG = Log.DEBUG;
+    public static final int INFO = Log.INFO;
+    public static final int WARN = Log.WARN;
+    public static final int ERROR = Log.ERROR;
+
+    // Current log level
+    public static int LOGLEVEL = Log.ERROR;
+
+    /**
+     * Set the current log level.
+     *
+     * @param logLevel
+     */
+    public static void setLogLevel(int logLevel) {
+        LOGLEVEL = logLevel;
+        Log.i("CordovaLog", "Changing log level to " + logLevel);
+    }
+
+    /**
+     * Set the current log level.
+     *
+     * @param logLevel
+     */
+    public static void setLogLevel(String logLevel) {
+        if ("VERBOSE".equals(logLevel)) LOGLEVEL = VERBOSE;
+        else if ("DEBUG".equals(logLevel)) LOGLEVEL = DEBUG;
+        else if ("INFO".equals(logLevel)) LOGLEVEL = INFO;
+        else if ("WARN".equals(logLevel)) LOGLEVEL = WARN;
+        else if ("ERROR".equals(logLevel)) LOGLEVEL = ERROR;
+        Log.i("CordovaLog", "Changing log level to " + logLevel + "(" + LOGLEVEL + ")");
+    }
+
+    /**
+     * Determine if log level will be logged
+     *
+     * @param logLevel
+     * @return true if the parameter passed in is greater than or equal to the current log level
+     */
+    public static boolean isLoggable(int logLevel) {
+        return (logLevel >= LOGLEVEL);
+    }
+
+    /**
+     * Verbose log message.
+     *
+     * @param tag
+     * @param s
+     */
+    public static void v(String tag, String s) {
+        if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, s);
+    }
+
+    /**
+     * Debug log message.
+     *
+     * @param tag
+     * @param s
+     */
+    public static void d(String tag, String s) {
+        if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, s);
+    }
+
+    /**
+     * Info log message.
+     *
+     * @param tag
+     * @param s
+     */
+    public static void i(String tag, String s) {
+        if (LOG.INFO >= LOGLEVEL) Log.i(tag, s);
+    }
+
+    /**
+     * Warning log message.
+     *
+     * @param tag
+     * @param s
+     */
+    public static void w(String tag, String s) {
+        if (LOG.WARN >= LOGLEVEL) Log.w(tag, s);
+    }
+
+    /**
+     * Error log message.
+     *
+     * @param tag
+     * @param s
+     */
+    public static void e(String tag, String s) {
+        if (LOG.ERROR >= LOGLEVEL) Log.e(tag, s);
+    }
+
+    /**
+     * Verbose log message.
+     *
+     * @param tag
+     * @param s
+     * @param e
+     */
+    public static void v(String tag, String s, Throwable e) {
+        if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, s, e);
+    }
+
+    /**
+     * Debug log message.
+     *
+     * @param tag
+     * @param s
+     * @param e
+     */
+    public static void d(String tag, String s, Throwable e) {
+        if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, s, e);
+    }
+
+    /**
+     * Info log message.
+     *
+     * @param tag
+     * @param s
+     * @param e
+     */
+    public static void i(String tag, String s, Throwable e) {
+        if (LOG.INFO >= LOGLEVEL) Log.i(tag, s, e);
+    }
+
+    /**
+     * Warning log message.
+     *
+     * @param tag
+     * @param e
+     */
+    public static void w(String tag, Throwable e) {
+        if (LOG.WARN >= LOGLEVEL) Log.w(tag, e);
+    }
+
+    /**
+     * Warning log message.
+     *
+     * @param tag
+     * @param s
+     * @param e
+     */
+    public static void w(String tag, String s, Throwable e) {
+        if (LOG.WARN >= LOGLEVEL) Log.w(tag, s, e);
+    }
+
+    /**
+     * Error log message.
+     *
+     * @param tag
+     * @param s
+     * @param e
+     */
+    public static void e(String tag, String s, Throwable e) {
+        if (LOG.ERROR >= LOGLEVEL) Log.e(tag, s, e);
+    }
+
+    /**
+     * Verbose log message with printf formatting.
+     *
+     * @param tag
+     * @param s
+     * @param args
+     */
+    public static void v(String tag, String s, Object... args) {
+        if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, String.format(s, args));
+    }
+
+    /**
+     * Debug log message with printf formatting.
+     *
+     * @param tag
+     * @param s
+     * @param args
+     */
+    public static void d(String tag, String s, Object... args) {
+        if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, String.format(s, args));
+    }
+
+    /**
+     * Info log message with printf formatting.
+     *
+     * @param tag
+     * @param s
+     * @param args
+     */
+    public static void i(String tag, String s, Object... args) {
+        if (LOG.INFO >= LOGLEVEL) Log.i(tag, String.format(s, args));
+    }
+
+    /**
+     * Warning log message with printf formatting.
+     *
+     * @param tag
+     * @param s
+     * @param args
+     */
+    public static void w(String tag, String s, Object... args) {
+        if (LOG.WARN >= LOGLEVEL) Log.w(tag, String.format(s, args));
+    }
+
+    /**
+     * Error log message with printf formatting.
+     *
+     * @param tag
+     * @param s
+     * @param args
+     */
+    public static void e(String tag, String s, Object... args) {
+        if (LOG.ERROR >= LOGLEVEL) Log.e(tag, String.format(s, args));
+    }
+
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/NativeToJsMessageQueue.java b/platforms/android/CordovaLib/src/org/apache/cordova/NativeToJsMessageQueue.java
new file mode 100755
index 0000000..d17b1c4
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/NativeToJsMessageQueue.java
@@ -0,0 +1,542 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+/**
+ * Holds the list of messages to be sent to the WebView.
+ */
+public class NativeToJsMessageQueue {
+    private static final String LOG_TAG = "JsMessageQueue";
+
+    // Set this to true to force plugin results to be encoding as
+    // JS instead of the custom format (useful for benchmarking).
+    // Doesn't work for multipart messages.
+    private static final boolean FORCE_ENCODE_USING_EVAL = false;
+
+    // Disable sending back native->JS messages during an exec() when the active
+    // exec() is asynchronous. Set this to true when running bridge benchmarks.
+    static final boolean DISABLE_EXEC_CHAINING = false;
+
+    // Arbitrarily chosen upper limit for how much data to send to JS in one shot.
+    // This currently only chops up on message boundaries. It may be useful
+    // to allow it to break up messages.
+    private static int MAX_PAYLOAD_SIZE = 50 * 1024 * 10240;
+
+    /**
+     * When true, the active listener is not fired upon enqueue. When set to false,
+     * the active listener will be fired if the queue is non-empty.
+     */
+    private boolean paused;
+
+    /**
+     * The list of JavaScript statements to be sent to JavaScript.
+     */
+    private final LinkedList<JsMessage> queue = new LinkedList<JsMessage>();
+
+    /**
+     * The array of listeners that can be used to send messages to JS.
+     */
+    private ArrayList<BridgeMode> bridgeModes = new ArrayList<BridgeMode>();
+
+    /**
+     * When null, the bridge is disabled. This occurs during page transitions.
+     * When disabled, all callbacks are dropped since they are assumed to be
+     * relevant to the previous page.
+     */
+    private BridgeMode activeBridgeMode;
+
+    public void addBridgeMode(BridgeMode bridgeMode) {
+        bridgeModes.add(bridgeMode);
+    }
+
+    public boolean isBridgeEnabled() {
+        return activeBridgeMode != null;
+    }
+
+    public boolean isEmpty() {
+        return queue.isEmpty();
+    }
+
+    /**
+     * Changes the bridge mode.
+     */
+    public void setBridgeMode(int value) {
+        if (value < -1 || value >= bridgeModes.size()) {
+            LOG.d(LOG_TAG, "Invalid NativeToJsBridgeMode: " + value);
+        } else {
+            BridgeMode newMode = value < 0 ? null : bridgeModes.get(value);
+            if (newMode != activeBridgeMode) {
+                LOG.d(LOG_TAG, "Set native->JS mode to " + (newMode == null ? "null" : newMode.getClass().getSimpleName()));
+                synchronized (this) {
+                    activeBridgeMode = newMode;
+                    if (newMode != null) {
+                        newMode.reset();
+                        if (!paused && !queue.isEmpty()) {
+                            newMode.onNativeToJsMessageAvailable(this);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Clears all messages and resets to the default bridge mode.
+     */
+    public void reset() {
+        synchronized (this) {
+            queue.clear();
+            setBridgeMode(-1);
+        }
+    }
+
+    private int calculatePackedMessageLength(JsMessage message) {
+        int messageLen = message.calculateEncodedLength();
+        String messageLenStr = String.valueOf(messageLen);
+        return messageLenStr.length() + messageLen + 1;
+    }
+
+    private void packMessage(JsMessage message, StringBuilder sb) {
+        int len = message.calculateEncodedLength();
+        sb.append(len)
+          .append(' ');
+        message.encodeAsMessage(sb);
+    }
+
+    /**
+     * Combines and returns queued messages combined into a single string.
+     * Combines as many messages as possible, while staying under MAX_PAYLOAD_SIZE.
+     * Returns null if the queue is empty.
+     */
+    public String popAndEncode(boolean fromOnlineEvent) {
+        synchronized (this) {
+            if (activeBridgeMode == null) {
+                return null;
+            }
+            activeBridgeMode.notifyOfFlush(this, fromOnlineEvent);
+            if (queue.isEmpty()) {
+                return null;
+            }
+            int totalPayloadLen = 0;
+            int numMessagesToSend = 0;
+            for (JsMessage message : queue) {
+                int messageSize = calculatePackedMessageLength(message);
+                if (numMessagesToSend > 0 && totalPayloadLen + messageSize > MAX_PAYLOAD_SIZE && MAX_PAYLOAD_SIZE > 0) {
+                    break;
+                }
+                totalPayloadLen += messageSize;
+                numMessagesToSend += 1;
+            }
+
+            StringBuilder sb = new StringBuilder(totalPayloadLen);
+            for (int i = 0; i < numMessagesToSend; ++i) {
+                JsMessage message = queue.removeFirst();
+                packMessage(message, sb);
+            }
+
+            if (!queue.isEmpty()) {
+                // Attach a char to indicate that there are more messages pending.
+                sb.append('*');
+            }
+            String ret = sb.toString();
+            return ret;
+        }
+    }
+
+    /**
+     * Same as popAndEncode(), except encodes in a form that can be executed as JS.
+     */
+    public String popAndEncodeAsJs() {
+        synchronized (this) {
+            int length = queue.size();
+            if (length == 0) {
+                return null;
+            }
+            int totalPayloadLen = 0;
+            int numMessagesToSend = 0;
+            for (JsMessage message : queue) {
+                int messageSize = message.calculateEncodedLength() + 50; // overestimate.
+                if (numMessagesToSend > 0 && totalPayloadLen + messageSize > MAX_PAYLOAD_SIZE && MAX_PAYLOAD_SIZE > 0) {
+                    break;
+                }
+                totalPayloadLen += messageSize;
+                numMessagesToSend += 1;
+            }
+            boolean willSendAllMessages = numMessagesToSend == queue.size();
+            StringBuilder sb = new StringBuilder(totalPayloadLen + (willSendAllMessages ? 0 : 100));
+            // Wrap each statement in a try/finally so that if one throws it does
+            // not affect the next.
+            for (int i = 0; i < numMessagesToSend; ++i) {
+                JsMessage message = queue.removeFirst();
+                if (willSendAllMessages && (i + 1 == numMessagesToSend)) {
+                    message.encodeAsJsMessage(sb);
+                } else {
+                    sb.append("try{");
+                    message.encodeAsJsMessage(sb);
+                    sb.append("}finally{");
+                }
+            }
+            if (!willSendAllMessages) {
+                sb.append("window.setTimeout(function(){cordova.require('cordova/plugin/android/polling').pollOnce();},0);");
+            }
+            for (int i = willSendAllMessages ? 1 : 0; i < numMessagesToSend; ++i) {
+                sb.append('}');
+            }
+            String ret = sb.toString();
+            return ret;
+        }
+    }
+
+    /**
+     * Add a JavaScript statement to the list.
+     */
+    public void addJavaScript(String statement) {
+        enqueueMessage(new JsMessage(statement));
+    }
+
+    /**
+     * Add a JavaScript statement to the list.
+     */
+    public void addPluginResult(PluginResult result, String callbackId) {
+        if (callbackId == null) {
+            LOG.e(LOG_TAG, "Got plugin result with no callbackId", new Throwable());
+            return;
+        }
+        // Don't send anything if there is no result and there is no need to
+        // clear the callbacks.
+        boolean noResult = result.getStatus() == PluginResult.Status.NO_RESULT.ordinal();
+        boolean keepCallback = result.getKeepCallback();
+        if (noResult && keepCallback) {
+            return;
+        }
+        JsMessage message = new JsMessage(result, callbackId);
+        if (FORCE_ENCODE_USING_EVAL) {
+            StringBuilder sb = new StringBuilder(message.calculateEncodedLength() + 50);
+            message.encodeAsJsMessage(sb);
+            message = new JsMessage(sb.toString());
+        }
+
+        enqueueMessage(message);
+    }
+
+    private void enqueueMessage(JsMessage message) {
+        synchronized (this) {
+            if (activeBridgeMode == null) {
+                LOG.d(LOG_TAG, "Dropping Native->JS message due to disabled bridge");
+                return;
+            }
+            queue.add(message);
+            if (!paused) {
+                activeBridgeMode.onNativeToJsMessageAvailable(this);
+            }
+        }
+    }
+
+    public void setPaused(boolean value) {
+        if (paused && value) {
+            // This should never happen. If a use-case for it comes up, we should
+            // change pause to be a counter.
+            LOG.e(LOG_TAG, "nested call to setPaused detected.", new Throwable());
+        }
+        paused = value;
+        if (!value) {
+            synchronized (this) {
+                if (!queue.isEmpty() && activeBridgeMode != null) {
+                    activeBridgeMode.onNativeToJsMessageAvailable(this);
+                }
+            }
+        }
+    }
+
+    public static abstract class BridgeMode {
+        public abstract void onNativeToJsMessageAvailable(NativeToJsMessageQueue queue);
+        public void notifyOfFlush(NativeToJsMessageQueue queue, boolean fromOnlineEvent) {}
+        public void reset() {}
+    }
+
+    /** Uses JS polls for messages on a timer.. */
+    public static class NoOpBridgeMode extends BridgeMode {
+        @Override public void onNativeToJsMessageAvailable(NativeToJsMessageQueue queue) {
+        }
+    }
+
+    /** Uses webView.loadUrl("javascript:") to execute messages. */
+    public static class LoadUrlBridgeMode extends BridgeMode {
+        private final CordovaWebViewEngine engine;
+        private final CordovaInterface cordova;
+
+        public LoadUrlBridgeMode(CordovaWebViewEngine engine, CordovaInterface cordova) {
+            this.engine = engine;
+            this.cordova = cordova;
+        }
+
+        @Override
+        public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {
+            cordova.getActivity().runOnUiThread(new Runnable() {
+                public void run() {
+                    String js = queue.popAndEncodeAsJs();
+                    if (js != null) {
+                        engine.loadUrl("javascript:" + js, false);
+                    }
+                }
+            });
+        }
+    }
+
+    /** Uses online/offline events to tell the JS when to poll for messages. */
+    public static class OnlineEventsBridgeMode extends BridgeMode {
+        private final OnlineEventsBridgeModeDelegate delegate;
+        private boolean online;
+        private boolean ignoreNextFlush;
+
+        public interface OnlineEventsBridgeModeDelegate {
+            void setNetworkAvailable(boolean value);
+            void runOnUiThread(Runnable r);
+        }
+
+        public OnlineEventsBridgeMode(OnlineEventsBridgeModeDelegate delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public void reset() {
+            delegate.runOnUiThread(new Runnable() {
+                public void run() {
+                    online = false;
+                    // If the following call triggers a notifyOfFlush, then ignore it.
+                    ignoreNextFlush = true;
+                    delegate.setNetworkAvailable(true);
+                }
+            });
+        }
+
+        @Override
+        public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {
+            delegate.runOnUiThread(new Runnable() {
+                public void run() {
+                    if (!queue.isEmpty()) {
+                        ignoreNextFlush = false;
+                        delegate.setNetworkAvailable(online);
+                    }
+                }
+            });
+        }
+        // Track when online/offline events are fired so that we don't fire excess events.
+        @Override
+        public void notifyOfFlush(final NativeToJsMessageQueue queue, boolean fromOnlineEvent) {
+            if (fromOnlineEvent && !ignoreNextFlush) {
+                online = !online;
+            }
+        }
+    }
+
+    /** Uses webView.evaluateJavascript to execute messages. */
+    public static class EvalBridgeMode extends BridgeMode {
+        private final CordovaWebViewEngine engine;
+        private final CordovaInterface cordova;
+
+        public EvalBridgeMode(CordovaWebViewEngine engine, CordovaInterface cordova) {
+            this.engine = engine;
+            this.cordova = cordova;
+        }
+
+        @Override
+        public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {
+            cordova.getActivity().runOnUiThread(new Runnable() {
+                public void run() {
+                    String js = queue.popAndEncodeAsJs();
+                    if (js != null) {
+                        engine.evaluateJavascript(js, null);
+                    }
+                }
+            });
+        }
+    }
+
+
+
+    private static class JsMessage {
+        final String jsPayloadOrCallbackId;
+        final PluginResult pluginResult;
+        JsMessage(String js) {
+            if (js == null) {
+                throw new NullPointerException();
+            }
+            jsPayloadOrCallbackId = js;
+            pluginResult = null;
+        }
+        JsMessage(PluginResult pluginResult, String callbackId) {
+            if (callbackId == null || pluginResult == null) {
+                throw new NullPointerException();
+            }
+            jsPayloadOrCallbackId = callbackId;
+            this.pluginResult = pluginResult;
+        }
+
+        static int calculateEncodedLengthHelper(PluginResult pluginResult) {
+            switch (pluginResult.getMessageType()) {
+                case PluginResult.MESSAGE_TYPE_BOOLEAN: // f or t
+                case PluginResult.MESSAGE_TYPE_NULL: // N
+                    return 1;
+                case PluginResult.MESSAGE_TYPE_NUMBER: // n
+                    return 1 + pluginResult.getMessage().length();
+                case PluginResult.MESSAGE_TYPE_STRING: // s
+                    return 1 + pluginResult.getStrMessage().length();
+                case PluginResult.MESSAGE_TYPE_BINARYSTRING:
+                    return 1 + pluginResult.getMessage().length();
+                case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
+                    return 1 + pluginResult.getMessage().length();
+                case PluginResult.MESSAGE_TYPE_MULTIPART:
+                    int ret = 1;
+                    for (int i = 0; i < pluginResult.getMultipartMessagesSize(); i++) {
+                        int length = calculateEncodedLengthHelper(pluginResult.getMultipartMessage(i));
+                        int argLength = String.valueOf(length).length();
+                        ret += argLength + 1 + length;
+                    }
+                    return ret;
+                case PluginResult.MESSAGE_TYPE_JSON:
+                default:
+                    return pluginResult.getMessage().length();
+            }
+        }
+
+        int calculateEncodedLength() {
+            if (pluginResult == null) {
+                return jsPayloadOrCallbackId.length() + 1;
+            }
+            int statusLen = String.valueOf(pluginResult.getStatus()).length();
+            int ret = 2 + statusLen + 1 + jsPayloadOrCallbackId.length() + 1;
+            return ret + calculateEncodedLengthHelper(pluginResult);
+            }
+
+        static void encodeAsMessageHelper(StringBuilder sb, PluginResult pluginResult) {
+            switch (pluginResult.getMessageType()) {
+                case PluginResult.MESSAGE_TYPE_BOOLEAN:
+                    sb.append(pluginResult.getMessage().charAt(0)); // t or f.
+                    break;
+                case PluginResult.MESSAGE_TYPE_NULL: // N
+                    sb.append('N');
+                    break;
+                case PluginResult.MESSAGE_TYPE_NUMBER: // n
+                    sb.append('n')
+                      .append(pluginResult.getMessage());
+                    break;
+                case PluginResult.MESSAGE_TYPE_STRING: // s
+                    sb.append('s');
+                    sb.append(pluginResult.getStrMessage());
+                    break;
+                case PluginResult.MESSAGE_TYPE_BINARYSTRING: // S
+                    sb.append('S');
+                    sb.append(pluginResult.getMessage());
+                    break;
+                case PluginResult.MESSAGE_TYPE_ARRAYBUFFER: // A
+                    sb.append('A');
+                    sb.append(pluginResult.getMessage());
+                    break;
+                case PluginResult.MESSAGE_TYPE_MULTIPART:
+                    sb.append('M');
+                    for (int i = 0; i < pluginResult.getMultipartMessagesSize(); i++) {
+                        PluginResult multipartMessage = pluginResult.getMultipartMessage(i);
+                        sb.append(String.valueOf(calculateEncodedLengthHelper(multipartMessage)));
+                        sb.append(' ');
+                        encodeAsMessageHelper(sb, multipartMessage);
+                    }
+                    break;
+                case PluginResult.MESSAGE_TYPE_JSON:
+                default:
+                    sb.append(pluginResult.getMessage()); // [ or {
+            }
+        }
+
+        void encodeAsMessage(StringBuilder sb) {
+            if (pluginResult == null) {
+                sb.append('J')
+                  .append(jsPayloadOrCallbackId);
+                return;
+            }
+            int status = pluginResult.getStatus();
+            boolean noResult = status == PluginResult.Status.NO_RESULT.ordinal();
+            boolean resultOk = status == PluginResult.Status.OK.ordinal();
+            boolean keepCallback = pluginResult.getKeepCallback();
+
+            sb.append((noResult || resultOk) ? 'S' : 'F')
+              .append(keepCallback ? '1' : '0')
+              .append(status)
+              .append(' ')
+              .append(jsPayloadOrCallbackId)
+              .append(' ');
+
+            encodeAsMessageHelper(sb, pluginResult);
+        }
+
+        void buildJsMessage(StringBuilder sb) {
+            switch (pluginResult.getMessageType()) {
+                case PluginResult.MESSAGE_TYPE_MULTIPART:
+                    int size = pluginResult.getMultipartMessagesSize();
+                    for (int i=0; i<size; i++) {
+                        PluginResult subresult = pluginResult.getMultipartMessage(i);
+                        JsMessage submessage = new JsMessage(subresult, jsPayloadOrCallbackId);
+                        submessage.buildJsMessage(sb);
+                        if (i < (size-1)) {
+                            sb.append(",");
+                        }
+                    }
+                    break;
+                case PluginResult.MESSAGE_TYPE_BINARYSTRING:
+                    sb.append("atob('")
+                            .append(pluginResult.getMessage())
+                            .append("')");
+                    break;
+                case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
+                    sb.append("cordova.require('cordova/base64').toArrayBuffer('")
+                            .append(pluginResult.getMessage())
+                            .append("')");
+                    break;
+                case PluginResult.MESSAGE_TYPE_NULL:
+                    sb.append("null");
+                    break;
+                default:
+                    sb.append(pluginResult.getMessage());
+            }
+        }
+
+        void encodeAsJsMessage(StringBuilder sb) {
+            if (pluginResult == null) {
+                sb.append(jsPayloadOrCallbackId);
+            } else {
+                int status = pluginResult.getStatus();
+                boolean success = (status == PluginResult.Status.OK.ordinal()) || (status == PluginResult.Status.NO_RESULT.ordinal());
+                sb.append("cordova.callbackFromNative('")
+                        .append(jsPayloadOrCallbackId)
+                        .append("',")
+                        .append(success)
+                        .append(",")
+                        .append(status)
+                        .append(",[");
+                buildJsMessage(sb);
+                sb.append("],")
+                        .append(pluginResult.getKeepCallback())
+                        .append(");");
+            }
+        }
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/PermissionHelper.java b/platforms/android/CordovaLib/src/org/apache/cordova/PermissionHelper.java
new file mode 100644
index 0000000..52f6e14
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/PermissionHelper.java
@@ -0,0 +1,87 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import java.util.Arrays;
+
+import org.json.JSONException;
+
+import android.content.pm.PackageManager;
+
+/**
+ * This class provides reflective methods for permission requesting and checking so that plugins
+ * written for cordova-android 5.0.0+ can still compile with earlier cordova-android versions.
+ */
+public class PermissionHelper {
+    private static final String LOG_TAG = "CordovaPermissionHelper";
+
+    /**
+     * Requests a "dangerous" permission for the application at runtime. This is a helper method
+     * alternative to cordovaInterface.requestPermission() that does not require the project to be
+     * built with cordova-android 5.0.0+
+     *
+     * @param plugin        The plugin the permission is being requested for
+     * @param requestCode   A requestCode to be passed to the plugin's onRequestPermissionResult()
+     *                      along with the result of the permission request
+     * @param permission    The permission to be requested
+     */
+    public static void requestPermission(CordovaPlugin plugin, int requestCode, String permission) {
+        PermissionHelper.requestPermissions(plugin, requestCode, new String[] {permission});
+    }
+
+    /**
+     * Requests "dangerous" permissions for the application at runtime. This is a helper method
+     * alternative to cordovaInterface.requestPermissions() that does not require the project to be
+     * built with cordova-android 5.0.0+
+     *
+     * @param plugin        The plugin the permissions are being requested for
+     * @param requestCode   A requestCode to be passed to the plugin's onRequestPermissionResult()
+     *                      along with the result of the permissions request
+     * @param permissions   The permissions to be requested
+     */
+    public static void requestPermissions(CordovaPlugin plugin, int requestCode, String[] permissions) {
+        plugin.cordova.requestPermissions(plugin, requestCode, permissions);
+    }
+
+    /**
+     * Checks at runtime to see if the application has been granted a permission. This is a helper
+     * method alternative to cordovaInterface.hasPermission() that does not require the project to
+     * be built with cordova-android 5.0.0+
+     *
+     * @param plugin        The plugin the permission is being checked against
+     * @param permission    The permission to be checked
+     *
+     * @return              True if the permission has already been granted and false otherwise
+     */
+    public static boolean hasPermission(CordovaPlugin plugin, String permission) {
+        return plugin.cordova.hasPermission(permission);
+    }
+
+    private static void deliverPermissionResult(CordovaPlugin plugin, int requestCode, String[] permissions) {
+        // Generate the request results
+        int[] requestResults = new int[permissions.length];
+        Arrays.fill(requestResults, PackageManager.PERMISSION_GRANTED);
+
+        try {
+            plugin.onRequestPermissionResult(requestCode, permissions, requestResults);
+        } catch (JSONException e) {
+            LOG.e(LOG_TAG, "JSONException when delivering permissions results", e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/PluginEntry.java b/platforms/android/CordovaLib/src/org/apache/cordova/PluginEntry.java
new file mode 100755
index 0000000..c56c453
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/PluginEntry.java
@@ -0,0 +1,70 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+ */
+package org.apache.cordova;
+
+import org.apache.cordova.CordovaPlugin;
+
+/**
+ * This class represents a service entry object.
+ */
+public final class PluginEntry {
+
+    /**
+     * The name of the service that this plugin implements
+     */
+    public final String service;
+
+    /**
+     * The plugin class name that implements the service.
+     */
+    public final String pluginClass;
+
+    /**
+     * The pre-instantiated plugin to use for this entry.
+     */
+    public final CordovaPlugin plugin;
+
+    /**
+     * Flag that indicates the plugin object should be created when PluginManager is initialized.
+     */
+    public final boolean onload;
+
+    /**
+     * Constructs with a CordovaPlugin already instantiated.
+     */
+    public PluginEntry(String service, CordovaPlugin plugin) {
+        this(service, plugin.getClass().getName(), true, plugin);
+    }
+
+    /**
+     * @param service               The name of the service
+     * @param pluginClass           The plugin class name
+     * @param onload                Create plugin object when HTML page is loaded
+     */
+    public PluginEntry(String service, String pluginClass, boolean onload) {
+        this(service, pluginClass, onload, null);
+    }
+
+    private PluginEntry(String service, String pluginClass, boolean onload, CordovaPlugin plugin) {
+        this.service = service;
+        this.pluginClass = pluginClass;
+        this.onload = onload;
+        this.plugin = plugin;
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/PluginManager.java b/platforms/android/CordovaLib/src/org/apache/cordova/PluginManager.java
new file mode 100755
index 0000000..c9576a6
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/PluginManager.java
@@ -0,0 +1,526 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+ */
+package org.apache.cordova;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+
+import org.json.JSONException;
+
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Debug;
+
+/**
+ * PluginManager is exposed to JavaScript in the Cordova WebView.
+ *
+ * Calling native plugin code can be done by calling PluginManager.exec(...)
+ * from JavaScript.
+ */
+public class PluginManager {
+    private static String TAG = "PluginManager";
+    private static final int SLOW_EXEC_WARNING_THRESHOLD = Debug.isDebuggerConnected() ? 60 : 16;
+
+    // List of service entries
+    private final LinkedHashMap<String, CordovaPlugin> pluginMap = new LinkedHashMap<String, CordovaPlugin>();
+    private final LinkedHashMap<String, PluginEntry> entryMap = new LinkedHashMap<String, PluginEntry>();
+
+    private final CordovaInterface ctx;
+    private final CordovaWebView app;
+    private boolean isInitialized;
+
+    private CordovaPlugin permissionRequester;
+
+    public PluginManager(CordovaWebView cordovaWebView, CordovaInterface cordova, Collection<PluginEntry> pluginEntries) {
+        this.ctx = cordova;
+        this.app = cordovaWebView;
+        setPluginEntries(pluginEntries);
+    }
+
+    public Collection<PluginEntry> getPluginEntries() {
+        return entryMap.values();
+    }
+
+    public void setPluginEntries(Collection<PluginEntry> pluginEntries) {
+        if (isInitialized) {
+            this.onPause(false);
+            this.onDestroy();
+            pluginMap.clear();
+            entryMap.clear();
+        }
+        for (PluginEntry entry : pluginEntries) {
+            addService(entry);
+        }
+        if (isInitialized) {
+            startupPlugins();
+        }
+    }
+
+    /**
+     * Init when loading a new HTML page into webview.
+     */
+    public void init() {
+        LOG.d(TAG, "init()");
+        isInitialized = true;
+        this.onPause(false);
+        this.onDestroy();
+        pluginMap.clear();
+        this.startupPlugins();
+    }
+
+    /**
+     * Create plugins objects that have onload set.
+     */
+    private void startupPlugins() {
+        for (PluginEntry entry : entryMap.values()) {
+            // Add a null entry to for each non-startup plugin to avoid ConcurrentModificationException
+            // When iterating plugins.
+            if (entry.onload) {
+                getPlugin(entry.service);
+            } else {
+                pluginMap.put(entry.service, null);
+            }
+        }
+    }
+
+    /**
+     * Receives a request for execution and fulfills it by finding the appropriate
+     * Java class and calling it's execute method.
+     *
+     * PluginManager.exec can be used either synchronously or async. In either case, a JSON encoded
+     * string is returned that will indicate if any errors have occurred when trying to find
+     * or execute the class denoted by the clazz argument.
+     *
+     * @param service       String containing the service to run
+     * @param action        String containing the action that the class is supposed to perform. This is
+     *                      passed to the plugin execute method and it is up to the plugin developer
+     *                      how to deal with it.
+     * @param callbackId    String containing the id of the callback that is execute in JavaScript if
+     *                      this is an async plugin call.
+     * @param rawArgs       An Array literal string containing any arguments needed in the
+     *                      plugin execute method.
+     */
+    public void exec(final String service, final String action, final String callbackId, final String rawArgs) {
+        CordovaPlugin plugin = getPlugin(service);
+        if (plugin == null) {
+            LOG.d(TAG, "exec() call to unknown plugin: " + service);
+            PluginResult cr = new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION);
+            app.sendPluginResult(cr, callbackId);
+            return;
+        }
+        CallbackContext callbackContext = new CallbackContext(callbackId, app);
+        try {
+            long pluginStartTime = System.currentTimeMillis();
+            boolean wasValidAction = plugin.execute(action, rawArgs, callbackContext);
+            long duration = System.currentTimeMillis() - pluginStartTime;
+
+            if (duration > SLOW_EXEC_WARNING_THRESHOLD) {
+                LOG.w(TAG, "THREAD WARNING: exec() call to " + service + "." + action + " blocked the main thread for " + duration + "ms. Plugin should use CordovaInterface.getThreadPool().");
+            }
+            if (!wasValidAction) {
+                PluginResult cr = new PluginResult(PluginResult.Status.INVALID_ACTION);
+                callbackContext.sendPluginResult(cr);
+            }
+        } catch (JSONException e) {
+            PluginResult cr = new PluginResult(PluginResult.Status.JSON_EXCEPTION);
+            callbackContext.sendPluginResult(cr);
+        } catch (Exception e) {
+            LOG.e(TAG, "Uncaught exception from plugin", e);
+            callbackContext.error(e.getMessage());
+        }
+    }
+
+    /**
+     * Get the plugin object that implements the service.
+     * If the plugin object does not already exist, then create it.
+     * If the service doesn't exist, then return null.
+     *
+     * @param service       The name of the service.
+     * @return              CordovaPlugin or null
+     */
+    public CordovaPlugin getPlugin(String service) {
+        CordovaPlugin ret = pluginMap.get(service);
+        if (ret == null) {
+            PluginEntry pe = entryMap.get(service);
+            if (pe == null) {
+                return null;
+            }
+            if (pe.plugin != null) {
+                ret = pe.plugin;
+            } else {
+                ret = instantiatePlugin(pe.pluginClass);
+            }
+            ret.privateInitialize(service, ctx, app, app.getPreferences());
+            pluginMap.put(service, ret);
+        }
+        return ret;
+    }
+
+    /**
+     * Add a plugin class that implements a service to the service entry table.
+     * This does not create the plugin object instance.
+     *
+     * @param service           The service name
+     * @param className         The plugin class name
+     */
+    public void addService(String service, String className) {
+        PluginEntry entry = new PluginEntry(service, className, false);
+        this.addService(entry);
+    }
+
+    /**
+     * Add a plugin class that implements a service to the service entry table.
+     * This does not create the plugin object instance.
+     *
+     * @param entry             The plugin entry
+     */
+    public void addService(PluginEntry entry) {
+        this.entryMap.put(entry.service, entry);
+        if (entry.plugin != null) {
+            entry.plugin.privateInitialize(entry.service, ctx, app, app.getPreferences());
+            pluginMap.put(entry.service, entry.plugin);
+        }
+    }
+
+    /**
+     * Called when the system is about to start resuming a previous activity.
+     *
+     * @param multitasking      Flag indicating if multitasking is turned on for app
+     */
+    public void onPause(boolean multitasking) {
+        for (CordovaPlugin plugin : this.pluginMap.values()) {
+            if (plugin != null) {
+                plugin.onPause(multitasking);
+            }
+        }
+    }
+
+    /**
+     * Called when the system received an HTTP authentication request. Plugins can use
+     * the supplied HttpAuthHandler to process this auth challenge.
+     *
+     * @param view              The WebView that is initiating the callback
+     * @param handler           The HttpAuthHandler used to set the WebView's response
+     * @param host              The host requiring authentication
+     * @param realm             The realm for which authentication is required
+     *
+     * @return                  Returns True if there is a plugin which will resolve this auth challenge, otherwise False
+     *
+     */
+    public boolean onReceivedHttpAuthRequest(CordovaWebView view, ICordovaHttpAuthHandler handler, String host, String realm) {
+        for (CordovaPlugin plugin : this.pluginMap.values()) {
+            if (plugin != null && plugin.onReceivedHttpAuthRequest(app, handler, host, realm)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called when he system received an SSL client certificate request.  Plugin can use
+     * the supplied ClientCertRequest to process this certificate challenge.
+     *
+     * @param view              The WebView that is initiating the callback
+     * @param request           The client certificate request
+     *
+     * @return                  Returns True if plugin will resolve this auth challenge, otherwise False
+     *
+     */
+    public boolean onReceivedClientCertRequest(CordovaWebView view, ICordovaClientCertRequest request) {
+        for (CordovaPlugin plugin : this.pluginMap.values()) {
+            if (plugin != null && plugin.onReceivedClientCertRequest(app, request)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called when the activity will start interacting with the user.
+     *
+     * @param multitasking      Flag indicating if multitasking is turned on for app
+     */
+    public void onResume(boolean multitasking) {
+        for (CordovaPlugin plugin : this.pluginMap.values()) {
+            if (plugin != null) {
+                plugin.onResume(multitasking);
+            }
+        }
+    }
+
+    /**
+     * Called when the activity is becoming visible to the user.
+     */
+    public void onStart() {
+        for (CordovaPlugin plugin : this.pluginMap.values()) {
+            if (plugin != null) {
+                plugin.onStart();
+            }
+        }
+    }
+
+    /**
+     * Called when the activity is no longer visible to the user.
+     */
+    public void onStop() {
+        for (CordovaPlugin plugin : this.pluginMap.values()) {
+            if (plugin != null) {
+                plugin.onStop();
+            }
+        }
+    }
+
+    /**
+     * The final call you receive before your activity is destroyed.
+     */
+    public void onDestroy() {
+        for (CordovaPlugin plugin : this.pluginMap.values()) {
+            if (plugin != null) {
+                plugin.onDestroy();
+            }
+        }
+    }
+
+    /**
+     * Send a message to all plugins.
+     *
+     * @param id                The message id
+     * @param data              The message data
+     * @return                  Object to stop propagation or null
+     */
+    public Object postMessage(String id, Object data) {
+        for (CordovaPlugin plugin : this.pluginMap.values()) {
+            if (plugin != null) {
+                Object obj = plugin.onMessage(id, data);
+                if (obj != null) {
+                    return obj;
+                }
+            }
+        }
+        return ctx.onMessage(id, data);
+    }
+
+    /**
+     * Called when the activity receives a new intent.
+     */
+    public void onNewIntent(Intent intent) {
+        for (CordovaPlugin plugin : this.pluginMap.values()) {
+            if (plugin != null) {
+                plugin.onNewIntent(intent);
+            }
+        }
+    }
+
+    /**
+     * Called when the webview is going to request an external resource.
+     *
+     * This delegates to the installed plugins, and returns true/false for the
+     * first plugin to provide a non-null result.  If no plugins respond, then
+     * the default policy is applied.
+     *
+     * @param url       The URL that is being requested.
+     * @return          Returns true to allow the resource to load,
+     *                  false to block the resource.
+     */
+    public boolean shouldAllowRequest(String url) {
+        for (PluginEntry entry : this.entryMap.values()) {
+            CordovaPlugin plugin = pluginMap.get(entry.service);
+            if (plugin != null) {
+                Boolean result = plugin.shouldAllowRequest(url);
+                if (result != null) {
+                    return result;
+                }
+            }
+        }
+
+        // Default policy:
+        if (url.startsWith("blob:") || url.startsWith("data:") || url.startsWith("about:blank")) {
+            return true;
+        }
+        // TalkBack requires this, so allow it by default.
+        if (url.startsWith("https://ssl.gstatic.com/accessibility/javascript/android/")) {
+            return true;
+        }
+        if (url.startsWith("file://")) {
+            //This directory on WebKit/Blink based webviews contains SQLite databases!
+            //DON'T CHANGE THIS UNLESS YOU KNOW WHAT YOU'RE DOING!
+            return !url.contains("/app_webview/");
+        }
+        return false;
+    }
+
+    /**
+     * Called when the webview is going to change the URL of the loaded content.
+     *
+     * This delegates to the installed plugins, and returns true/false for the
+     * first plugin to provide a non-null result.  If no plugins respond, then
+     * the default policy is applied.
+     *
+     * @param url       The URL that is being requested.
+     * @return          Returns true to allow the navigation,
+     *                  false to block the navigation.
+     */
+    public boolean shouldAllowNavigation(String url) {
+        for (PluginEntry entry : this.entryMap.values()) {
+            CordovaPlugin plugin = pluginMap.get(entry.service);
+            if (plugin != null) {
+                Boolean result = plugin.shouldAllowNavigation(url);
+                if (result != null) {
+                    return result;
+                }
+            }
+        }
+
+        // Default policy:
+        return url.startsWith("file://") || url.startsWith("about:blank");
+    }
+
+
+    /**
+     * Called when the webview is requesting the exec() bridge be enabled.
+     */
+    public boolean shouldAllowBridgeAccess(String url) {
+        for (PluginEntry entry : this.entryMap.values()) {
+            CordovaPlugin plugin = pluginMap.get(entry.service);
+            if (plugin != null) {
+                Boolean result = plugin.shouldAllowBridgeAccess(url);
+                if (result != null) {
+                    return result;
+                }
+            }
+        }
+
+        // Default policy:
+        return url.startsWith("file://");
+    }
+
+    /**
+     * Called when the webview is going not going to navigate, but may launch
+     * an Intent for an URL.
+     *
+     * This delegates to the installed plugins, and returns true/false for the
+     * first plugin to provide a non-null result.  If no plugins respond, then
+     * the default policy is applied.
+     *
+     * @param url       The URL that is being requested.
+     * @return          Returns true to allow the URL to launch an intent,
+     *                  false to block the intent.
+     */
+    public Boolean shouldOpenExternalUrl(String url) {
+        for (PluginEntry entry : this.entryMap.values()) {
+            CordovaPlugin plugin = pluginMap.get(entry.service);
+            if (plugin != null) {
+                Boolean result = plugin.shouldOpenExternalUrl(url);
+                if (result != null) {
+                    return result;
+                }
+            }
+        }
+        // Default policy:
+        // External URLs are not allowed
+        return false;
+    }
+
+    /**
+     * Called when the URL of the webview changes.
+     *
+     * @param url               The URL that is being changed to.
+     * @return                  Return false to allow the URL to load, return true to prevent the URL from loading.
+     */
+    public boolean onOverrideUrlLoading(String url) {
+        for (PluginEntry entry : this.entryMap.values()) {
+            CordovaPlugin plugin = pluginMap.get(entry.service);
+            if (plugin != null && plugin.onOverrideUrlLoading(url)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called when the app navigates or refreshes.
+     */
+    public void onReset() {
+        for (CordovaPlugin plugin : this.pluginMap.values()) {
+            if (plugin != null) {
+                plugin.onReset();
+            }
+        }
+    }
+
+    Uri remapUri(Uri uri) {
+        for (CordovaPlugin plugin : this.pluginMap.values()) {
+            if (plugin != null) {
+                Uri ret = plugin.remapUri(uri);
+                if (ret != null) {
+                    return ret;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Create a plugin based on class name.
+     */
+    private CordovaPlugin instantiatePlugin(String className) {
+        CordovaPlugin ret = null;
+        try {
+            Class<?> c = null;
+            if ((className != null) && !("".equals(className))) {
+                c = Class.forName(className);
+            }
+            if (c != null & CordovaPlugin.class.isAssignableFrom(c)) {
+                ret = (CordovaPlugin) c.newInstance();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            System.out.println("Error adding plugin " + className + ".");
+        }
+        return ret;
+    }
+
+    /**
+     * Called by the system when the device configuration changes while your activity is running.
+     *
+     * @param newConfig		The new device configuration
+     */
+    public void onConfigurationChanged(Configuration newConfig) {
+        for (CordovaPlugin plugin : this.pluginMap.values()) {
+            if (plugin != null) {
+                plugin.onConfigurationChanged(newConfig);
+            }
+        }
+    }
+
+    public Bundle onSaveInstanceState() {
+        Bundle state = new Bundle();
+        for (CordovaPlugin plugin : this.pluginMap.values()) {
+            if (plugin != null) {
+                Bundle pluginState = plugin.onSaveInstanceState();
+                if(pluginState != null) {
+                    state.putBundle(plugin.getServiceName(), pluginState);
+                }
+            }
+        }
+        return state;
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/PluginResult.java b/platforms/android/CordovaLib/src/org/apache/cordova/PluginResult.java
new file mode 100644
index 0000000..2b3ac72
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/PluginResult.java
@@ -0,0 +1,198 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import java.util.List;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import android.util.Base64;
+
+public class PluginResult {
+    private final int status;
+    private final int messageType;
+    private boolean keepCallback = false;
+    private String strMessage;
+    private String encodedMessage;
+    private List<PluginResult> multipartMessages;
+
+    public PluginResult(Status status) {
+        this(status, PluginResult.StatusMessages[status.ordinal()]);
+    }
+
+    public PluginResult(Status status, String message) {
+        this.status = status.ordinal();
+        this.messageType = message == null ? MESSAGE_TYPE_NULL : MESSAGE_TYPE_STRING;
+        this.strMessage = message;
+    }
+
+    public PluginResult(Status status, JSONArray message) {
+        this.status = status.ordinal();
+        this.messageType = MESSAGE_TYPE_JSON;
+        encodedMessage = message.toString();
+    }
+
+    public PluginResult(Status status, JSONObject message) {
+        this.status = status.ordinal();
+        this.messageType = MESSAGE_TYPE_JSON;
+        encodedMessage = message.toString();
+    }
+
+    public PluginResult(Status status, int i) {
+        this.status = status.ordinal();
+        this.messageType = MESSAGE_TYPE_NUMBER;
+        this.encodedMessage = ""+i;
+    }
+
+    public PluginResult(Status status, float f) {
+        this.status = status.ordinal();
+        this.messageType = MESSAGE_TYPE_NUMBER;
+        this.encodedMessage = ""+f;
+    }
+
+    public PluginResult(Status status, boolean b) {
+        this.status = status.ordinal();
+        this.messageType = MESSAGE_TYPE_BOOLEAN;
+        this.encodedMessage = Boolean.toString(b);
+    }
+
+    public PluginResult(Status status, byte[] data) {
+        this(status, data, false);
+    }
+
+    public PluginResult(Status status, byte[] data, boolean binaryString) {
+        this.status = status.ordinal();
+        this.messageType = binaryString ? MESSAGE_TYPE_BINARYSTRING : MESSAGE_TYPE_ARRAYBUFFER;
+        this.encodedMessage = Base64.encodeToString(data, Base64.NO_WRAP);
+    }
+    
+    // The keepCallback and status of multipartMessages are ignored.
+    public PluginResult(Status status, List<PluginResult> multipartMessages) {
+        this.status = status.ordinal();
+        this.messageType = MESSAGE_TYPE_MULTIPART;
+        this.multipartMessages = multipartMessages;
+    }
+
+    public void setKeepCallback(boolean b) {
+        this.keepCallback = b;
+    }
+
+    public int getStatus() {
+        return status;
+    }
+
+    public int getMessageType() {
+        return messageType;
+    }
+
+    public String getMessage() {
+        if (encodedMessage == null) {
+            encodedMessage = JSONObject.quote(strMessage);
+        }
+        return encodedMessage;
+    }
+
+    public int getMultipartMessagesSize() {
+        return multipartMessages.size();
+    }
+
+    public PluginResult getMultipartMessage(int index) {
+        return multipartMessages.get(index);
+    }
+
+    /**
+     * If messageType == MESSAGE_TYPE_STRING, then returns the message string.
+     * Otherwise, returns null.
+     */
+    public String getStrMessage() {
+        return strMessage;
+    }
+
+    public boolean getKeepCallback() {
+        return this.keepCallback;
+    }
+
+    @Deprecated // Use sendPluginResult instead of sendJavascript.
+    public String getJSONString() {
+        return "{\"status\":" + this.status + ",\"message\":" + this.getMessage() + ",\"keepCallback\":" + this.keepCallback + "}";
+    }
+
+    @Deprecated // Use sendPluginResult instead of sendJavascript.
+    public String toCallbackString(String callbackId) {
+        // If no result to be sent and keeping callback, then no need to sent back to JavaScript
+        if ((status == PluginResult.Status.NO_RESULT.ordinal()) && keepCallback) {
+        	return null;
+        }
+
+        // Check the success (OK, NO_RESULT & !KEEP_CALLBACK)
+        if ((status == PluginResult.Status.OK.ordinal()) || (status == PluginResult.Status.NO_RESULT.ordinal())) {
+            return toSuccessCallbackString(callbackId);
+        }
+
+        return toErrorCallbackString(callbackId);
+    }
+
+    @Deprecated // Use sendPluginResult instead of sendJavascript.
+    public String toSuccessCallbackString(String callbackId) {
+        return "cordova.callbackSuccess('"+callbackId+"',"+this.getJSONString()+");";
+    }
+
+    @Deprecated // Use sendPluginResult instead of sendJavascript.
+    public String toErrorCallbackString(String callbackId) {
+        return "cordova.callbackError('"+callbackId+"', " + this.getJSONString()+ ");";
+    }
+
+    public static final int MESSAGE_TYPE_STRING = 1;
+    public static final int MESSAGE_TYPE_JSON = 2;
+    public static final int MESSAGE_TYPE_NUMBER = 3;
+    public static final int MESSAGE_TYPE_BOOLEAN = 4;
+    public static final int MESSAGE_TYPE_NULL = 5;
+    public static final int MESSAGE_TYPE_ARRAYBUFFER = 6;
+    // Use BINARYSTRING when your string may contain null characters.
+    // This is required to work around a bug in the platform :(.
+    public static final int MESSAGE_TYPE_BINARYSTRING = 7;
+    public static final int MESSAGE_TYPE_MULTIPART = 8;
+
+    public static String[] StatusMessages = new String[] {
+        "No result",
+        "OK",
+        "Class not found",
+        "Illegal access",
+        "Instantiation error",
+        "Malformed url",
+        "IO error",
+        "Invalid action",
+        "JSON error",
+        "Error"
+    };
+
+    public enum Status {
+        NO_RESULT,
+        OK,
+        CLASS_NOT_FOUND_EXCEPTION,
+        ILLEGAL_ACCESS_EXCEPTION,
+        INSTANTIATION_EXCEPTION,
+        MALFORMED_URL_EXCEPTION,
+        IO_EXCEPTION,
+        INVALID_ACTION,
+        JSON_EXCEPTION,
+        ERROR
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/ResumeCallback.java b/platforms/android/CordovaLib/src/org/apache/cordova/ResumeCallback.java
new file mode 100644
index 0000000..49a43b5
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/ResumeCallback.java
@@ -0,0 +1,76 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ResumeCallback extends CallbackContext {
+    private final String TAG = "CordovaResumeCallback";
+    private String serviceName;
+    private PluginManager pluginManager;
+
+    public ResumeCallback(String serviceName, PluginManager pluginManager) {
+        super("resumecallback", null);
+        this.serviceName = serviceName;
+        this.pluginManager = pluginManager;
+    }
+
+    @Override
+    public void sendPluginResult(PluginResult pluginResult) {
+        synchronized (this) {
+            if (finished) {
+                LOG.w(TAG, serviceName + " attempted to send a second callback to ResumeCallback\nResult was: " + pluginResult.getMessage());
+                return;
+            } else {
+                finished = true;
+            }
+        }
+
+        JSONObject event = new JSONObject();
+        JSONObject pluginResultObject = new JSONObject();
+
+        try {
+            pluginResultObject.put("pluginServiceName", this.serviceName);
+            pluginResultObject.put("pluginStatus", PluginResult.StatusMessages[pluginResult.getStatus()]);
+
+            event.put("action", "resume");
+            event.put("pendingResult", pluginResultObject);
+        } catch (JSONException e) {
+            LOG.e(TAG, "Unable to create resume object for Activity Result");
+        }
+
+        PluginResult eventResult = new PluginResult(PluginResult.Status.OK, event);
+
+        // We send a list of results to the js so that we don't have to decode
+        // the PluginResult passed to this CallbackContext into JSON twice.
+        // The results are combined into an event payload before the event is
+        // fired on the js side of things (see platform.js)
+        List<PluginResult> result = new ArrayList<PluginResult>();
+        result.add(eventResult);
+        result.add(pluginResult);
+
+        CoreAndroid appPlugin = (CoreAndroid) pluginManager.getPlugin(CoreAndroid.PLUGIN_NAME);
+        appPlugin.sendResumeEvent(new PluginResult(PluginResult.Status.OK, result));
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/Whitelist.java b/platforms/android/CordovaLib/src/org/apache/cordova/Whitelist.java
new file mode 100644
index 0000000..d0f823c
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/Whitelist.java
@@ -0,0 +1,170 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.cordova.LOG;
+
+import android.net.Uri;
+
+public class Whitelist {
+    private static class URLPattern {
+        public Pattern scheme;
+        public Pattern host;
+        public Integer port;
+        public Pattern path;
+
+        private String regexFromPattern(String pattern, boolean allowWildcards) {
+            final String toReplace = "\\.[]{}()^$?+|";
+            StringBuilder regex = new StringBuilder();
+            for (int i=0; i < pattern.length(); i++) {
+                char c = pattern.charAt(i);
+                if (c == '*' && allowWildcards) {
+                    regex.append(".");
+                } else if (toReplace.indexOf(c) > -1) {
+                    regex.append('\\');
+                }
+                regex.append(c);
+            }
+            return regex.toString();
+        }
+
+        public URLPattern(String scheme, String host, String port, String path) throws MalformedURLException {
+            try {
+                if (scheme == null || "*".equals(scheme)) {
+                    this.scheme = null;
+                } else {
+                    this.scheme = Pattern.compile(regexFromPattern(scheme, false), Pattern.CASE_INSENSITIVE);
+                }
+                if ("*".equals(host)) {
+                    this.host = null;
+                } else if (host.startsWith("*.")) {
+                    this.host = Pattern.compile("([a-z0-9.-]*\\.)?" + regexFromPattern(host.substring(2), false), Pattern.CASE_INSENSITIVE);
+                } else {
+                    this.host = Pattern.compile(regexFromPattern(host, false), Pattern.CASE_INSENSITIVE);
+                }
+                if (port == null || "*".equals(port)) {
+                    this.port = null;
+                } else {
+                    this.port = Integer.parseInt(port,10);
+                }
+                if (path == null || "/*".equals(path)) {
+                    this.path = null;
+                } else {
+                    this.path = Pattern.compile(regexFromPattern(path, true));
+                }
+            } catch (NumberFormatException e) {
+                throw new MalformedURLException("Port must be a number");
+            }
+        }
+
+        public boolean matches(Uri uri) {
+            try {
+                return ((scheme == null || scheme.matcher(uri.getScheme()).matches()) &&
+                        (host == null || host.matcher(uri.getHost()).matches()) &&
+                        (port == null || port.equals(uri.getPort())) &&
+                        (path == null || path.matcher(uri.getPath()).matches()));
+            } catch (Exception e) {
+                LOG.d(TAG, e.toString());
+                return false;
+            }
+        }
+    }
+
+    private ArrayList<URLPattern> whiteList;
+
+    public static final String TAG = "Whitelist";
+
+    public Whitelist() {
+        this.whiteList = new ArrayList<URLPattern>();
+    }
+
+    /* Match patterns (from http://developer.chrome.com/extensions/match_patterns.html)
+     *
+     * <url-pattern> := <scheme>://<host><path>
+     * <scheme> := '*' | 'http' | 'https' | 'file' | 'ftp' | 'chrome-extension'
+     * <host> := '*' | '*.' <any char except '/' and '*'>+
+     * <path> := '/' <any chars>
+     *
+     * We extend this to explicitly allow a port attached to the host, and we allow
+     * the scheme to be omitted for backwards compatibility. (Also host is not required
+     * to begin with a "*" or "*.".)
+     */
+    public void addWhiteListEntry(String origin, boolean subdomains) {
+        if (whiteList != null) {
+            try {
+                // Unlimited access to network resources
+                if (origin.compareTo("*") == 0) {
+                    LOG.d(TAG, "Unlimited access to network resources");
+                    whiteList = null;
+                }
+                else { // specific access
+                    Pattern parts = Pattern.compile("^((\\*|[A-Za-z-]+):(//)?)?(\\*|((\\*\\.)?[^*/:]+))?(:(\\d+))?(/.*)?");
+                    Matcher m = parts.matcher(origin);
+                    if (m.matches()) {
+                        String scheme = m.group(2);
+                        String host = m.group(4);
+                        // Special case for two urls which are allowed to have empty hosts
+                        if (("file".equals(scheme) || "content".equals(scheme)) && host == null) host = "*";
+                        String port = m.group(8);
+                        String path = m.group(9);
+                        if (scheme == null) {
+                            // XXX making it stupid friendly for people who forget to include protocol/SSL
+                            whiteList.add(new URLPattern("http", host, port, path));
+                            whiteList.add(new URLPattern("https", host, port, path));
+                        } else {
+                            whiteList.add(new URLPattern(scheme, host, port, path));
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                LOG.d(TAG, "Failed to add origin %s", origin);
+            }
+        }
+    }
+
+
+    /**
+     * Determine if URL is in approved list of URLs to load.
+     *
+     * @param uri
+     * @return true if wide open or whitelisted
+     */
+    public boolean isUrlWhiteListed(String uri) {
+        // If there is no whitelist, then it's wide open
+        if (whiteList == null) return true;
+
+        Uri parsedUri = Uri.parse(uri);
+        // Look for match in white list
+        Iterator<URLPattern> pit = whiteList.iterator();
+        while (pit.hasNext()) {
+            URLPattern p = pit.next();
+            if (p.matches(parsedUri)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemCookieManager.java b/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemCookieManager.java
new file mode 100644
index 0000000..3e5df51
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemCookieManager.java
@@ -0,0 +1,73 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova.engine;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.webkit.CookieManager;
+import android.webkit.WebView;
+
+import org.apache.cordova.ICordovaCookieManager;
+
+class SystemCookieManager implements ICordovaCookieManager {
+
+    protected final WebView webView;
+    private final CookieManager cookieManager;
+
+    //Added because lint can't see the conditional RIGHT ABOVE this
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public SystemCookieManager(WebView webview) {
+        webView = webview;
+        cookieManager = CookieManager.getInstance();
+
+        //REALLY? Nobody has seen this UNTIL NOW?
+        cookieManager.setAcceptFileSchemeCookies(true);
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            cookieManager.setAcceptThirdPartyCookies(webView, true);
+        }
+    }
+
+    public void setCookiesEnabled(boolean accept) {
+        cookieManager.setAcceptCookie(accept);
+    }
+
+    public void setCookie(final String url, final String value) {
+        cookieManager.setCookie(url, value);
+    }
+
+    public String getCookie(final String url) {
+        return cookieManager.getCookie(url);
+    }
+
+    public void clearCookies() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            cookieManager.removeAllCookies(null);
+        } else {
+            cookieManager.removeAllCookie();
+        }
+    }
+
+    public void flush() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            cookieManager.flush();
+        }
+    }
+};
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemExposedJsApi.java b/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemExposedJsApi.java
new file mode 100755
index 0000000..94c3d93
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemExposedJsApi.java
@@ -0,0 +1,53 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.engine;
+
+import android.webkit.JavascriptInterface;
+
+import org.apache.cordova.CordovaBridge;
+import org.apache.cordova.ExposedJsApi;
+import org.json.JSONException;
+
+/**
+ * Contains APIs that the JS can call. All functions in here should also have
+ * an equivalent entry in CordovaChromeClient.java, and be added to
+ * cordova-js/lib/android/plugin/android/promptbasednativeapi.js
+ */
+class SystemExposedJsApi implements ExposedJsApi {
+    private final CordovaBridge bridge;
+
+    SystemExposedJsApi(CordovaBridge bridge) {
+        this.bridge = bridge;
+    }
+
+    @JavascriptInterface
+    public String exec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException {
+        return bridge.jsExec(bridgeSecret, service, action, callbackId, arguments);
+    }
+
+    @JavascriptInterface
+    public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException {
+        bridge.jsSetNativeToJsBridgeMode(bridgeSecret, value);
+    }
+
+    @JavascriptInterface
+    public String retrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException {
+        return bridge.jsRetrieveJsMessages(bridgeSecret, fromOnlineEvent);
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebChromeClient.java b/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebChromeClient.java
new file mode 100755
index 0000000..72846f0
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebChromeClient.java
@@ -0,0 +1,280 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.engine;
+
+import java.util.Arrays;
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.webkit.ConsoleMessage;
+import android.webkit.GeolocationPermissions.Callback;
+import android.webkit.JsPromptResult;
+import android.webkit.JsResult;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
+import android.webkit.WebStorage;
+import android.webkit.WebView;
+import android.webkit.PermissionRequest;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.RelativeLayout;
+
+import org.apache.cordova.CordovaDialogsHelper;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.LOG;
+
+/**
+ * This class is the WebChromeClient that implements callbacks for our web view.
+ * The kind of callbacks that happen here are on the chrome outside the document,
+ * such as onCreateWindow(), onConsoleMessage(), onProgressChanged(), etc. Related
+ * to but different than CordovaWebViewClient.
+ */
+public class SystemWebChromeClient extends WebChromeClient {
+
+    private static final int FILECHOOSER_RESULTCODE = 5173;
+    private static final String LOG_TAG = "SystemWebChromeClient";
+    private long MAX_QUOTA = 100 * 1024 * 1024;
+    protected final SystemWebViewEngine parentEngine;
+
+    // the video progress view
+    private View mVideoProgressView;
+
+    private CordovaDialogsHelper dialogsHelper;
+    private Context appContext;
+
+    private WebChromeClient.CustomViewCallback mCustomViewCallback;
+    private View mCustomView;
+
+    public SystemWebChromeClient(SystemWebViewEngine parentEngine) {
+        this.parentEngine = parentEngine;
+        appContext = parentEngine.webView.getContext();
+        dialogsHelper = new CordovaDialogsHelper(appContext);
+    }
+
+    /**
+     * Tell the client to display a javascript alert dialog.
+     */
+    @Override
+    public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
+        dialogsHelper.showAlert(message, new CordovaDialogsHelper.Result() {
+            @Override public void gotResult(boolean success, String value) {
+                if (success) {
+                    result.confirm();
+                } else {
+                    result.cancel();
+                }
+            }
+        });
+        return true;
+    }
+
+    /**
+     * Tell the client to display a confirm dialog to the user.
+     */
+    @Override
+    public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
+        dialogsHelper.showConfirm(message, new CordovaDialogsHelper.Result() {
+            @Override
+            public void gotResult(boolean success, String value) {
+                if (success) {
+                    result.confirm();
+                } else {
+                    result.cancel();
+                }
+            }
+        });
+        return true;
+    }
+
+    /**
+     * Tell the client to display a prompt dialog to the user.
+     * If the client returns true, WebView will assume that the client will
+     * handle the prompt dialog and call the appropriate JsPromptResult method.
+     *
+     * Since we are hacking prompts for our own purposes, we should not be using them for
+     * this purpose, perhaps we should hack console.log to do this instead!
+     */
+    @Override
+    public boolean onJsPrompt(WebView view, String origin, String message, String defaultValue, final JsPromptResult result) {
+        // Unlike the @JavascriptInterface bridge, this method is always called on the UI thread.
+        String handledRet = parentEngine.bridge.promptOnJsPrompt(origin, message, defaultValue);
+        if (handledRet != null) {
+            result.confirm(handledRet);
+        } else {
+            dialogsHelper.showPrompt(message, defaultValue, new CordovaDialogsHelper.Result() {
+                @Override
+                public void gotResult(boolean success, String value) {
+                    if (success) {
+                        result.confirm(value);
+                    } else {
+                        result.cancel();
+                    }
+                }
+            });
+        }
+        return true;
+    }
+
+    /**
+     * Handle database quota exceeded notification.
+     */
+    @Override
+    @SuppressWarnings("deprecation")
+    public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize,
+            long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater)
+    {
+        LOG.d(LOG_TAG, "onExceededDatabaseQuota estimatedSize: %d  currentQuota: %d  totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota);
+        quotaUpdater.updateQuota(MAX_QUOTA);
+    }
+
+    @Override
+    public boolean onConsoleMessage(ConsoleMessage consoleMessage)
+    {
+        if (consoleMessage.message() != null)
+            LOG.d(LOG_TAG, "%s: Line %d : %s" , consoleMessage.sourceId() , consoleMessage.lineNumber(), consoleMessage.message());
+         return super.onConsoleMessage(consoleMessage);
+    }
+
+    @Override
+    /**
+     * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin.
+     *
+     * This also checks for the Geolocation Plugin and requests permission from the application  to use Geolocation.
+     *
+     * @param origin
+     * @param callback
+     */
+    public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
+        super.onGeolocationPermissionsShowPrompt(origin, callback);
+        callback.invoke(origin, true, false);
+        //Get the plugin, it should be loaded
+        CordovaPlugin geolocation = parentEngine.pluginManager.getPlugin("Geolocation");
+        if(geolocation != null && !geolocation.hasPermisssion())
+        {
+            geolocation.requestPermissions(0);
+        }
+
+    }
+
+    // API level 7 is required for this, see if we could lower this using something else
+    @Override
+    @SuppressWarnings("deprecation")
+    public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback) {
+        parentEngine.getCordovaWebView().showCustomView(view, callback);
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    public void onHideCustomView() {
+        parentEngine.getCordovaWebView().hideCustomView();
+    }
+
+    @Override
+    /**
+     * Ask the host application for a custom progress view to show while
+     * a <video> is loading.
+     * @return View The progress view.
+     */
+    public View getVideoLoadingProgressView() {
+
+        if (mVideoProgressView == null) {
+            // Create a new Loading view programmatically.
+
+            // create the linear layout
+            LinearLayout layout = new LinearLayout(parentEngine.getView().getContext());
+            layout.setOrientation(LinearLayout.VERTICAL);
+            RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+            layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
+            layout.setLayoutParams(layoutParams);
+            // the proress bar
+            ProgressBar bar = new ProgressBar(parentEngine.getView().getContext());
+            LinearLayout.LayoutParams barLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+            barLayoutParams.gravity = Gravity.CENTER;
+            bar.setLayoutParams(barLayoutParams);
+            layout.addView(bar);
+
+            mVideoProgressView = layout;
+        }
+    return mVideoProgressView;
+    }
+
+    // <input type=file> support:
+    // openFileChooser() is for pre KitKat and in KitKat mr1 (it's known broken in KitKat).
+    // For Lollipop, we use onShowFileChooser().
+    public void openFileChooser(ValueCallback<Uri> uploadMsg) {
+        this.openFileChooser(uploadMsg, "*/*");
+    }
+
+    public void openFileChooser( ValueCallback<Uri> uploadMsg, String acceptType ) {
+        this.openFileChooser(uploadMsg, acceptType, null);
+    }
+
+    public void openFileChooser(final ValueCallback<Uri> uploadMsg, String acceptType, String capture)
+    {
+        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+        intent.addCategory(Intent.CATEGORY_OPENABLE);
+        intent.setType("*/*");
+        parentEngine.cordova.startActivityForResult(new CordovaPlugin() {
+            @Override
+            public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+                Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData();
+                LOG.d(LOG_TAG, "Receive file chooser URL: " + result);
+                uploadMsg.onReceiveValue(result);
+            }
+        }, intent, FILECHOOSER_RESULTCODE);
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    @Override
+    public boolean onShowFileChooser(WebView webView, final ValueCallback<Uri[]> filePathsCallback, final WebChromeClient.FileChooserParams fileChooserParams) {
+        Intent intent = fileChooserParams.createIntent();
+        try {
+            parentEngine.cordova.startActivityForResult(new CordovaPlugin() {
+                @Override
+                public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+                    Uri[] result = WebChromeClient.FileChooserParams.parseResult(resultCode, intent);
+                    LOG.d(LOG_TAG, "Receive file chooser URL: " + result);
+                    filePathsCallback.onReceiveValue(result);
+                }
+            }, intent, FILECHOOSER_RESULTCODE);
+        } catch (ActivityNotFoundException e) {
+            LOG.w("No activity found to handle file chooser intent.", e);
+            filePathsCallback.onReceiveValue(null);
+        }
+        return true;
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    @Override
+    public void onPermissionRequest(final PermissionRequest request) {
+        LOG.d(LOG_TAG, "onPermissionRequest: " + Arrays.toString(request.getResources()));
+        request.grant(request.getResources());
+    }
+
+    public void destroyLastDialog(){
+        dialogsHelper.destroyLastDialog();
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebView.java b/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebView.java
new file mode 100644
index 0000000..01c2f00
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebView.java
@@ -0,0 +1,88 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova.engine;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.webkit.WebChromeClient;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.CordovaWebViewEngine;
+
+/**
+ * Custom WebView subclass that enables us to capture events needed for Cordova.
+ */
+public class SystemWebView extends WebView implements CordovaWebViewEngine.EngineView {
+    private SystemWebViewClient viewClient;
+    SystemWebChromeClient chromeClient;
+    private SystemWebViewEngine parentEngine;
+    private CordovaInterface cordova;
+
+    public SystemWebView(Context context) {
+        this(context, null);
+    }
+
+    public SystemWebView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    // Package visibility to enforce that only SystemWebViewEngine should call this method.
+    void init(SystemWebViewEngine parentEngine, CordovaInterface cordova) {
+        this.cordova = cordova;
+        this.parentEngine = parentEngine;
+        if (this.viewClient == null) {
+            setWebViewClient(new SystemWebViewClient(parentEngine));
+        }
+
+        if (this.chromeClient == null) {
+            setWebChromeClient(new SystemWebChromeClient(parentEngine));
+        }
+    }
+
+    @Override
+    public CordovaWebView getCordovaWebView() {
+        return parentEngine != null ? parentEngine.getCordovaWebView() : null;
+    }
+
+    @Override
+    public void setWebViewClient(WebViewClient client) {
+        viewClient = (SystemWebViewClient)client;
+        super.setWebViewClient(client);
+    }
+
+    @Override
+    public void setWebChromeClient(WebChromeClient client) {
+        chromeClient = (SystemWebChromeClient)client;
+        super.setWebChromeClient(client);
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        Boolean ret = parentEngine.client.onDispatchKeyEvent(event);
+        if (ret != null) {
+            return ret.booleanValue();
+        }
+        return super.dispatchKeyEvent(event);
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewClient.java b/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewClient.java
new file mode 100755
index 0000000..616cef1
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewClient.java
@@ -0,0 +1,370 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.engine;
+
+import android.annotation.TargetApi;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.net.http.SslError;
+import android.os.Build;
+import android.webkit.ClientCertRequest;
+import android.webkit.HttpAuthHandler;
+import android.webkit.SslErrorHandler;
+import android.webkit.WebResourceResponse;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import org.apache.cordova.AuthenticationToken;
+import org.apache.cordova.CordovaClientCertRequest;
+import org.apache.cordova.CordovaHttpAuthHandler;
+import org.apache.cordova.CordovaResourceApi;
+import org.apache.cordova.LOG;
+import org.apache.cordova.PluginManager;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Hashtable;
+
+
+/**
+ * This class is the WebViewClient that implements callbacks for our web view.
+ * The kind of callbacks that happen here are regarding the rendering of the
+ * document instead of the chrome surrounding it, such as onPageStarted(), 
+ * shouldOverrideUrlLoading(), etc. Related to but different than
+ * CordovaChromeClient.
+ */
+public class SystemWebViewClient extends WebViewClient {
+
+    private static final String TAG = "SystemWebViewClient";
+    protected final SystemWebViewEngine parentEngine;
+    private boolean doClearHistory = false;
+    boolean isCurrentlyLoading;
+
+    /** The authorization tokens. */
+    private Hashtable<String, AuthenticationToken> authenticationTokens = new Hashtable<String, AuthenticationToken>();
+
+    public SystemWebViewClient(SystemWebViewEngine parentEngine) {
+        this.parentEngine = parentEngine;
+    }
+
+    /**
+     * Give the host application a chance to take over the control when a new url
+     * is about to be loaded in the current WebView.
+     *
+     * @param view          The WebView that is initiating the callback.
+     * @param url           The url to be loaded.
+     * @return              true to override, false for default behavior
+     */
+    @Override
+    @SuppressWarnings("deprecation")
+    public boolean shouldOverrideUrlLoading(WebView view, String url) {
+        return parentEngine.client.onNavigationAttempt(url);
+    }
+
+    /**
+     * On received http auth request.
+     * The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination
+     */
+    @Override
+    public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
+
+        // Get the authentication token (if specified)
+        AuthenticationToken token = this.getAuthenticationToken(host, realm);
+        if (token != null) {
+            handler.proceed(token.getUserName(), token.getPassword());
+            return;
+        }
+
+        // Check if there is some plugin which can resolve this auth challenge
+        PluginManager pluginManager = this.parentEngine.pluginManager;
+        if (pluginManager != null && pluginManager.onReceivedHttpAuthRequest(null, new CordovaHttpAuthHandler(handler), host, realm)) {
+            parentEngine.client.clearLoadTimeoutTimer();
+            return;
+        }
+
+        // By default handle 401 like we'd normally do!
+        super.onReceivedHttpAuthRequest(view, handler, host, realm);
+    }
+    
+    /**
+     * On received client cert request.
+     * The method forwards the request to any running plugins before using the default implementation.
+     *
+     * @param view
+     * @param request
+     */
+    @Override
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public void onReceivedClientCertRequest (WebView view, ClientCertRequest request)
+    {
+
+        // Check if there is some plugin which can resolve this certificate request
+        PluginManager pluginManager = this.parentEngine.pluginManager;
+        if (pluginManager != null && pluginManager.onReceivedClientCertRequest(null, new CordovaClientCertRequest(request))) {
+            parentEngine.client.clearLoadTimeoutTimer();
+            return;
+        }
+
+        // By default pass to WebViewClient
+        super.onReceivedClientCertRequest(view, request);
+    }
+
+    /**
+     * Notify the host application that a page has started loading.
+     * This method is called once for each main frame load so a page with iframes or framesets will call onPageStarted
+     * one time for the main frame. This also means that onPageStarted will not be called when the contents of an
+     * embedded frame changes, i.e. clicking a link whose target is an iframe.
+     *
+     * @param view          The webview initiating the callback.
+     * @param url           The url of the page.
+     */
+    @Override
+    public void onPageStarted(WebView view, String url, Bitmap favicon) {
+        super.onPageStarted(view, url, favicon);
+        isCurrentlyLoading = true;
+        // Flush stale messages & reset plugins.
+        parentEngine.bridge.reset();
+        parentEngine.client.onPageStarted(url);
+    }
+
+    /**
+     * Notify the host application that a page has finished loading.
+     * This method is called only for main frame. When onPageFinished() is called, the rendering picture may not be updated yet.
+     *
+     *
+     * @param view          The webview initiating the callback.
+     * @param url           The url of the page.
+     */
+    @Override
+    public void onPageFinished(WebView view, String url) {
+        super.onPageFinished(view, url);
+        // Ignore excessive calls, if url is not about:blank (CB-8317).
+        if (!isCurrentlyLoading && !url.startsWith("about:")) {
+            return;
+        }
+        isCurrentlyLoading = false;
+
+        /**
+         * Because of a timing issue we need to clear this history in onPageFinished as well as
+         * onPageStarted. However we only want to do this if the doClearHistory boolean is set to
+         * true. You see when you load a url with a # in it which is common in jQuery applications
+         * onPageStared is not called. Clearing the history at that point would break jQuery apps.
+         */
+        if (this.doClearHistory) {
+            view.clearHistory();
+            this.doClearHistory = false;
+        }
+        parentEngine.client.onPageFinishedLoading(url);
+
+    }
+
+    /**
+     * Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable).
+     * The errorCode parameter corresponds to one of the ERROR_* constants.
+     *
+     * @param view          The WebView that is initiating the callback.
+     * @param errorCode     The error code corresponding to an ERROR_* value.
+     * @param description   A String describing the error.
+     * @param failingUrl    The url that failed to load.
+     */
+    @Override
+    @SuppressWarnings("deprecation")
+    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+        // Ignore error due to stopLoading().
+        if (!isCurrentlyLoading) {
+            return;
+        }
+        LOG.d(TAG, "CordovaWebViewClient.onReceivedError: Error code=%s Description=%s URL=%s", errorCode, description, failingUrl);
+
+        // If this is a "Protocol Not Supported" error, then revert to the previous
+        // page. If there was no previous page, then punt. The application's config
+        // is likely incorrect (start page set to sms: or something like that)
+        if (errorCode == WebViewClient.ERROR_UNSUPPORTED_SCHEME) {
+            parentEngine.client.clearLoadTimeoutTimer();
+
+            if (view.canGoBack()) {
+                view.goBack();
+                return;
+            } else {
+                super.onReceivedError(view, errorCode, description, failingUrl);
+            }
+        }
+        parentEngine.client.onReceivedError(errorCode, description, failingUrl);
+    }
+
+    /**
+     * Notify the host application that an SSL error occurred while loading a resource.
+     * The host application must call either handler.cancel() or handler.proceed().
+     * Note that the decision may be retained for use in response to future SSL errors.
+     * The default behavior is to cancel the load.
+     *
+     * @param view          The WebView that is initiating the callback.
+     * @param handler       An SslErrorHandler object that will handle the user's response.
+     * @param error         The SSL error object.
+     */
+    @Override
+    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
+
+        final String packageName = parentEngine.cordova.getActivity().getPackageName();
+        final PackageManager pm = parentEngine.cordova.getActivity().getPackageManager();
+
+        ApplicationInfo appInfo;
+        try {
+            appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
+            if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+                // debug = true
+                handler.proceed();
+                return;
+            } else {
+                // debug = false
+                super.onReceivedSslError(view, handler, error);
+            }
+        } catch (NameNotFoundException e) {
+            // When it doubt, lock it out!
+            super.onReceivedSslError(view, handler, error);
+        }
+    }
+
+
+    /**
+     * Sets the authentication token.
+     *
+     * @param authenticationToken
+     * @param host
+     * @param realm
+     */
+    public void setAuthenticationToken(AuthenticationToken authenticationToken, String host, String realm) {
+        if (host == null) {
+            host = "";
+        }
+        if (realm == null) {
+            realm = "";
+        }
+        this.authenticationTokens.put(host.concat(realm), authenticationToken);
+    }
+
+    /**
+     * Removes the authentication token.
+     *
+     * @param host
+     * @param realm
+     *
+     * @return the authentication token or null if did not exist
+     */
+    public AuthenticationToken removeAuthenticationToken(String host, String realm) {
+        return this.authenticationTokens.remove(host.concat(realm));
+    }
+
+    /**
+     * Gets the authentication token.
+     *
+     * In order it tries:
+     * 1- host + realm
+     * 2- host
+     * 3- realm
+     * 4- no host, no realm
+     *
+     * @param host
+     * @param realm
+     *
+     * @return the authentication token
+     */
+    public AuthenticationToken getAuthenticationToken(String host, String realm) {
+        AuthenticationToken token = null;
+        token = this.authenticationTokens.get(host.concat(realm));
+
+        if (token == null) {
+            // try with just the host
+            token = this.authenticationTokens.get(host);
+
+            // Try the realm
+            if (token == null) {
+                token = this.authenticationTokens.get(realm);
+            }
+
+            // if no host found, just query for default
+            if (token == null) {
+                token = this.authenticationTokens.get("");
+            }
+        }
+
+        return token;
+    }
+
+    /**
+     * Clear all authentication tokens.
+     */
+    public void clearAuthenticationTokens() {
+        this.authenticationTokens.clear();
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
+        try {
+            // Check the against the whitelist and lock out access to the WebView directory
+            // Changing this will cause problems for your application
+            if (!parentEngine.pluginManager.shouldAllowRequest(url)) {
+                LOG.w(TAG, "URL blocked by whitelist: " + url);
+                // Results in a 404.
+                return new WebResourceResponse("text/plain", "UTF-8", null);
+            }
+
+            CordovaResourceApi resourceApi = parentEngine.resourceApi;
+            Uri origUri = Uri.parse(url);
+            // Allow plugins to intercept WebView requests.
+            Uri remappedUri = resourceApi.remapUri(origUri);
+
+            if (!origUri.equals(remappedUri) || needsSpecialsInAssetUrlFix(origUri) || needsKitKatContentUrlFix(origUri)) {
+                CordovaResourceApi.OpenForReadResult result = resourceApi.openForRead(remappedUri, true);
+                return new WebResourceResponse(result.mimeType, "UTF-8", result.inputStream);
+            }
+            // If we don't need to special-case the request, let the browser load it.
+            return null;
+        } catch (IOException e) {
+            if (!(e instanceof FileNotFoundException)) {
+                LOG.e(TAG, "Error occurred while loading a file (returning a 404).", e);
+            }
+            // Results in a 404.
+            return new WebResourceResponse("text/plain", "UTF-8", null);
+        }
+    }
+
+    private static boolean needsKitKatContentUrlFix(Uri uri) {
+        return "content".equals(uri.getScheme());
+    }
+
+    private static boolean needsSpecialsInAssetUrlFix(Uri uri) {
+        if (CordovaResourceApi.getUriType(uri) != CordovaResourceApi.URI_TYPE_ASSET) {
+            return false;
+        }
+        if (uri.getQuery() != null || uri.getFragment() != null) {
+            return true;
+        }
+
+        if (!uri.toString().contains("%")) {
+            return false;
+        }
+
+        return false;
+    }
+}
diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewEngine.java b/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewEngine.java
new file mode 100755
index 0000000..1cbd7f8
--- /dev/null
+++ b/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewEngine.java
@@ -0,0 +1,319 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova.engine;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.os.Build;
+import android.view.View;
+import android.webkit.ValueCallback;
+import android.webkit.WebSettings;
+import android.webkit.WebSettings.LayoutAlgorithm;
+import android.webkit.WebView;
+
+import org.apache.cordova.CordovaBridge;
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CordovaPreferences;
+import org.apache.cordova.CordovaResourceApi;
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.CordovaWebViewEngine;
+import org.apache.cordova.ICordovaCookieManager;
+import org.apache.cordova.LOG;
+import org.apache.cordova.NativeToJsMessageQueue;
+import org.apache.cordova.PluginManager;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+
+/**
+ * Glue class between CordovaWebView (main Cordova logic) and SystemWebView (the actual View).
+ * We make the Engine separate from the actual View so that:
+ *  A) We don't need to worry about WebView methods clashing with CordovaWebViewEngine methods
+ *     (e.g.: goBack() is void for WebView, and boolean for CordovaWebViewEngine)
+ *  B) Separating the actual View from the Engine makes API surfaces smaller.
+ * Class uses two-phase initialization. However, CordovaWebView is responsible for calling .init().
+ */
+public class SystemWebViewEngine implements CordovaWebViewEngine {
+    public static final String TAG = "SystemWebViewEngine";
+
+    protected final SystemWebView webView;
+    protected final SystemCookieManager cookieManager;
+    protected CordovaPreferences preferences;
+    protected CordovaBridge bridge;
+    protected CordovaWebViewEngine.Client client;
+    protected CordovaWebView parentWebView;
+    protected CordovaInterface cordova;
+    protected PluginManager pluginManager;
+    protected CordovaResourceApi resourceApi;
+    protected NativeToJsMessageQueue nativeToJsMessageQueue;
+    private BroadcastReceiver receiver;
+
+    /** Used when created via reflection. */
+    public SystemWebViewEngine(Context context, CordovaPreferences preferences) {
+        this(new SystemWebView(context), preferences);
+    }
+
+    public SystemWebViewEngine(SystemWebView webView) {
+        this(webView, null);
+    }
+
+    public SystemWebViewEngine(SystemWebView webView, CordovaPreferences preferences) {
+        this.preferences = preferences;
+        this.webView = webView;
+        cookieManager = new SystemCookieManager(webView);
+    }
+
+    @Override
+    public void init(CordovaWebView parentWebView, CordovaInterface cordova, CordovaWebViewEngine.Client client,
+              CordovaResourceApi resourceApi, PluginManager pluginManager,
+              NativeToJsMessageQueue nativeToJsMessageQueue) {
+        if (this.cordova != null) {
+            throw new IllegalStateException();
+        }
+        // Needed when prefs are not passed by the constructor
+        if (preferences == null) {
+            preferences = parentWebView.getPreferences();
+        }
+        this.parentWebView = parentWebView;
+        this.cordova = cordova;
+        this.client = client;
+        this.resourceApi = resourceApi;
+        this.pluginManager = pluginManager;
+        this.nativeToJsMessageQueue = nativeToJsMessageQueue;
+        webView.init(this, cordova);
+
+        initWebViewSettings();
+
+        nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode.OnlineEventsBridgeModeDelegate() {
+            @Override
+            public void setNetworkAvailable(boolean value) {
+                //sometimes this can be called after calling webview.destroy() on destroy()
+                //thus resulting in a NullPointerException
+                if(webView!=null) {
+                   webView.setNetworkAvailable(value); 
+                }
+            }
+            @Override
+            public void runOnUiThread(Runnable r) {
+                SystemWebViewEngine.this.cordova.getActivity().runOnUiThread(r);
+            }
+        }));
+        nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.EvalBridgeMode(this, cordova));
+        bridge = new CordovaBridge(pluginManager, nativeToJsMessageQueue);
+        exposeJsInterface(webView, bridge);
+    }
+
+    @Override
+    public CordovaWebView getCordovaWebView() {
+        return parentWebView;
+    }
+
+    @Override
+    public ICordovaCookieManager getCookieManager() {
+        return cookieManager;
+    }
+
+    @Override
+    public View getView() {
+        return webView;
+    }
+
+    @SuppressLint({"NewApi", "SetJavaScriptEnabled"})
+    @SuppressWarnings("deprecation")
+    private void initWebViewSettings() {
+        webView.setInitialScale(0);
+        webView.setVerticalScrollBarEnabled(false);
+        // Enable JavaScript
+        final WebSettings settings = webView.getSettings();
+        settings.setJavaScriptEnabled(true);
+        settings.setJavaScriptCanOpenWindowsAutomatically(true);
+        settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
+
+        String manufacturer = android.os.Build.MANUFACTURER;
+        LOG.d(TAG, "CordovaWebView is running on device made by: " + manufacturer);
+
+        //We don't save any form data in the application
+        settings.setSaveFormData(false);
+        settings.setSavePassword(false);
+
+        // Jellybean rightfully tried to lock this down. Too bad they didn't give us a whitelist
+        // while we do this
+        settings.setAllowUniversalAccessFromFileURLs(true);
+        settings.setMediaPlaybackRequiresUserGesture(false);
+
+        // Enable database
+        // We keep this disabled because we use or shim to get around DOM_EXCEPTION_ERROR_16
+        String databasePath = webView.getContext().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
+        settings.setDatabaseEnabled(true);
+        settings.setDatabasePath(databasePath);
+
+
+        //Determine whether we're in debug or release mode, and turn on Debugging!
+        ApplicationInfo appInfo = webView.getContext().getApplicationContext().getApplicationInfo();
+        if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+            enableRemoteDebugging();
+        }
+
+        settings.setGeolocationDatabasePath(databasePath);
+
+        // Enable DOM storage
+        settings.setDomStorageEnabled(true);
+
+        // Enable built-in geolocation
+        settings.setGeolocationEnabled(true);
+
+        // Enable AppCache
+        // Fix for CB-2282
+        settings.setAppCacheMaxSize(5 * 1048576);
+        settings.setAppCachePath(databasePath);
+        settings.setAppCacheEnabled(true);
+
+        // Fix for CB-1405
+        // Google issue 4641
+        String defaultUserAgent = settings.getUserAgentString();
+
+        // Fix for CB-3360
+        String overrideUserAgent = preferences.getString("OverrideUserAgent", null);
+        if (overrideUserAgent != null) {
+            settings.setUserAgentString(overrideUserAgent);
+        } else {
+            String appendUserAgent = preferences.getString("AppendUserAgent", null);
+            if (appendUserAgent != null) {
+                settings.setUserAgentString(defaultUserAgent + " " + appendUserAgent);
+            }
+        }
+        // End CB-3360
+
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+        if (this.receiver == null) {
+            this.receiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    settings.getUserAgentString();
+                }
+            };
+            webView.getContext().registerReceiver(this.receiver, intentFilter);
+        }
+        // end CB-1405
+    }
+
+    private void enableRemoteDebugging() {
+        try {
+            WebView.setWebContentsDebuggingEnabled(true);
+        } catch (IllegalArgumentException e) {
+            LOG.d(TAG, "You have one job! To turn on Remote Web Debugging! YOU HAVE FAILED! ");
+            e.printStackTrace();
+        }
+    }
+
+    // Yeah, we know. It'd be great if lint was just a little smarter.
+    @SuppressLint("AddJavascriptInterface")
+    private static void exposeJsInterface(WebView webView, CordovaBridge bridge) {
+        SystemExposedJsApi exposedJsApi = new SystemExposedJsApi(bridge);
+        webView.addJavascriptInterface(exposedJsApi, "_cordovaNative");
+    }
+
+
+    /**
+     * Load the url into the webview.
+     */
+    @Override
+    public void loadUrl(final String url, boolean clearNavigationStack) {
+        webView.loadUrl(url);
+    }
+
+    @Override
+    public String getUrl() {
+        return webView.getUrl();
+    }
+
+    @Override
+    public void stopLoading() {
+        webView.stopLoading();
+    }
+
+    @Override
+    public void clearCache() {
+        webView.clearCache(true);
+    }
+
+    @Override
+    public void clearHistory() {
+        webView.clearHistory();
+    }
+
+    @Override
+    public boolean canGoBack() {
+        return webView.canGoBack();
+    }
+
+    /**
+     * Go to previous page in history.  (We manage our own history)
+     *
+     * @return true if we went back, false if we are already at top
+     */
+    @Override
+    public boolean goBack() {
+        // Check webview first to see if there is a history
+        // This is needed to support curPage#diffLink, since they are added to parentEngine's history, but not our history url array (JQMobile behavior)
+        if (webView.canGoBack()) {
+            webView.goBack();
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void setPaused(boolean value) {
+        if (value) {
+            webView.onPause();
+            webView.pauseTimers();
+        } else {
+            webView.onResume();
+            webView.resumeTimers();
+        }
+    }
+
+    @Override
+    public void destroy() {
+        webView.chromeClient.destroyLastDialog();
+        webView.destroy();
+        // unregister the receiver
+        if (receiver != null) {
+            try {
+                webView.getContext().unregisterReceiver(receiver);
+            } catch (Exception e) {
+                LOG.e(TAG, "Error unregistering configuration receiver: " + e.getMessage(), e);
+            }
+        }
+    }
+
+    @Override
+    public void evaluateJavascript(String js, ValueCallback<String> callback) {
+        webView.evaluateJavascript(js, callback);
+    }
+}
diff --git a/platforms/android/android.json b/platforms/android/android.json
new file mode 100644
index 0000000..825de01
--- /dev/null
+++ b/platforms/android/android.json
@@ -0,0 +1,490 @@
+{
+  "prepare_queue": {
+    "installed": [],
+    "uninstalled": []
+  },
+  "config_munge": {
+    "files": {
+      "res/xml/config.xml": {
+        "parents": {
+          "/*": [
+            {
+              "xml": "<feature name=\"Fingerprint\"><param name=\"android-package\" value=\"de.niklasmerz.cordova.fingerprint.Fingerprint\" /></feature>",
+              "count": 1
+            },
+            {
+              "xml": "<feature name=\"Whitelist\"><param name=\"android-package\" value=\"org.apache.cordova.whitelist.WhitelistPlugin\" /><param name=\"onload\" value=\"true\" /></feature>",
+              "count": 1
+            },
+            {
+              "xml": "<feature name=\"File\"><param name=\"android-package\" value=\"org.apache.cordova.file.FileUtils\" /><param name=\"onload\" value=\"true\" /></feature>",
+              "count": 1
+            },
+            {
+              "xml": "<allow-navigation href=\"cdvfile:*\" />",
+              "count": 1
+            },
+            {
+              "xml": "<feature name=\"CordovaHttpPlugin\"><param name=\"android-package\" value=\"com.silkimen.cordovahttp.CordovaHttpPlugin\" /></feature>",
+              "count": 1
+            },
+            {
+              "xml": "<feature name=\"StatusBar\"><param name=\"android-package\" value=\"org.apache.cordova.statusbar.StatusBar\" /><param name=\"onload\" value=\"true\" /></feature>",
+              "count": 1
+            },
+            {
+              "xml": "<feature name=\"QRScanner\"><param name=\"android-package\" value=\"com.bitpay.cordova.qrscanner.QRScanner\" /></feature>",
+              "count": 1
+            },
+            {
+              "xml": "<feature name=\"Camera\"><param name=\"android-package\" value=\"org.apache.cordova.camera.CameraLauncher\" /></feature>",
+              "count": 1
+            },
+            {
+              "xml": "<feature name=\"InAppBrowser\"><param name=\"android-package\" value=\"org.apache.cordova.inappbrowser.InAppBrowser\" /></feature>",
+              "count": 1
+            },
+            {
+              "xml": "<feature name=\"Device\"><param name=\"android-package\" value=\"org.apache.cordova.device.Device\" /></feature>",
+              "count": 1
+            },
+            {
+              "xml": "<feature name=\"ThemeableBrowser\"><param name=\"android-package\" value=\"com.initialxy.cordova.themeablebrowser.ThemeableBrowser\" /></feature>",
+              "count": 1
+            }
+          ]
+        }
+      },
+      "AndroidManifest.xml": {
+        "parents": {
+          "/*": [
+            {
+              "xml": "<uses-permission android:name=\"android.permission.USE_FINGERPRINT\" />",
+              "count": 1
+            },
+            {
+              "xml": "<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />",
+              "count": 2
+            },
+            {
+              "xml": "<uses-permission android:name=\"android.permission.CAMERA\" android:required=\"false\" />",
+              "count": 1
+            },
+            {
+              "xml": "<uses-feature android:name=\"android.hardware.camera\" android:required=\"false\" />",
+              "count": 1
+            },
+            {
+              "xml": "<uses-feature android:name=\"android.hardware.camera.front\" android:required=\"false\" />",
+              "count": 1
+            }
+          ],
+          "/manifest": [
+            {
+              "xml": "<uses-permission android:name=\"android.permission.INTERNET\" />",
+              "count": 1
+            }
+          ],
+          "application": [
+            {
+              "xml": "<provider android:authorities=\"${applicationId}.provider\" android:exported=\"false\" android:grantUriPermissions=\"true\" android:name=\"org.apache.cordova.camera.FileProvider\"><meta-data android:name=\"android.support.FILE_PROVIDER_PATHS\" android:resource=\"@xml/camera_provider_paths\" /></provider>",
+              "count": 1
+            }
+          ]
+        }
+      },
+      "*-Info.plist": {
+        "parents": {
+          "NSCameraUsageDescription": [
+            {
+              "xml": "<string>APP需要使用您的相机权限,没有该权限将无法完成扫一扫功能</string>",
+              "count": 1,
+              "mode": "merge",
+              "id": "config.xml"
+            }
+          ]
+        }
+      }
+    }
+  },
+  "installed_plugins": {
+    "cordova-plugin-add-swift-support": {
+      "PACKAGE_NAME": "com.supwisdom.dlapp"
+    },
+    "cordova-plugin-fingerprint-aio": {
+      "PACKAGE_NAME": "com.supwisdom.dlapp"
+    },
+    "cordova-plugin-touch-id": {
+      "PACKAGE_NAME": "com.supwisdom.dlapp"
+    },
+    "cordova-plugin-whitelist": {
+      "PACKAGE_NAME": "com.supwisdom.dlapp"
+    },
+    "cordova-plugin-file": {
+      "PACKAGE_NAME": "com.supwisdom.dlapp"
+    },
+    "cordova-plugin-advanced-http": {
+      "OKHTTP_VERSION": "3.10.0",
+      "PACKAGE_NAME": "com.supwisdom.dlapp"
+    },
+    "cordova-plugin-statusbar": {
+      "PACKAGE_NAME": "com.supwisdom.dlapp"
+    },
+    "cordova-plugin-disable-ios11-statusbar": {
+      "PACKAGE_NAME": "com.supwisdom.dlapp"
+    },
+    "cordova-plugin-qrscanner": {
+      "PACKAGE_NAME": "com.supwisdom.dlapp"
+    },
+    "cordova-plugin-camera": {
+      "PACKAGE_NAME": "com.supwisdom.dlapp"
+    },
+    "cordova-plugin-inappbrowser": {
+      "PACKAGE_NAME": "com.supwisdom.dlapp"
+    },
+    "cordova-plugin-device": {
+      "PACKAGE_NAME": "com.supwisdom.dlapp"
+    },
+    "cordova-plugin-themeablebrowser": {
+      "PACKAGE_NAME": "com.supwisdom.dlapp"
+    }
+  },
+  "dependent_plugins": {},
+  "modules": [
+    {
+      "id": "cordova-plugin-fingerprint-aio.Fingerprint",
+      "file": "plugins/cordova-plugin-fingerprint-aio/www/Fingerprint.js",
+      "pluginId": "cordova-plugin-fingerprint-aio",
+      "clobbers": [
+        "Fingerprint"
+      ]
+    },
+    {
+      "id": "cordova-plugin-touch-id.TouchID",
+      "file": "plugins/cordova-plugin-touch-id/www/TouchID.js",
+      "pluginId": "cordova-plugin-touch-id",
+      "clobbers": [
+        "window.plugins.touchid"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.DirectoryEntry",
+      "file": "plugins/cordova-plugin-file/www/DirectoryEntry.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.DirectoryEntry"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.DirectoryReader",
+      "file": "plugins/cordova-plugin-file/www/DirectoryReader.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.DirectoryReader"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.Entry",
+      "file": "plugins/cordova-plugin-file/www/Entry.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.Entry"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.File",
+      "file": "plugins/cordova-plugin-file/www/File.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.File"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileEntry",
+      "file": "plugins/cordova-plugin-file/www/FileEntry.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileEntry"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileError",
+      "file": "plugins/cordova-plugin-file/www/FileError.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileError"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileReader",
+      "file": "plugins/cordova-plugin-file/www/FileReader.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileReader"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileSystem",
+      "file": "plugins/cordova-plugin-file/www/FileSystem.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileSystem"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileUploadOptions",
+      "file": "plugins/cordova-plugin-file/www/FileUploadOptions.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileUploadOptions"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileUploadResult",
+      "file": "plugins/cordova-plugin-file/www/FileUploadResult.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileUploadResult"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileWriter",
+      "file": "plugins/cordova-plugin-file/www/FileWriter.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileWriter"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.Flags",
+      "file": "plugins/cordova-plugin-file/www/Flags.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.Flags"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.LocalFileSystem",
+      "file": "plugins/cordova-plugin-file/www/LocalFileSystem.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.LocalFileSystem"
+      ],
+      "merges": [
+        "window"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.Metadata",
+      "file": "plugins/cordova-plugin-file/www/Metadata.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.Metadata"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.ProgressEvent",
+      "file": "plugins/cordova-plugin-file/www/ProgressEvent.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.ProgressEvent"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.fileSystems",
+      "file": "plugins/cordova-plugin-file/www/fileSystems.js",
+      "pluginId": "cordova-plugin-file"
+    },
+    {
+      "id": "cordova-plugin-file.requestFileSystem",
+      "file": "plugins/cordova-plugin-file/www/requestFileSystem.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.requestFileSystem"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.resolveLocalFileSystemURI",
+      "file": "plugins/cordova-plugin-file/www/resolveLocalFileSystemURI.js",
+      "pluginId": "cordova-plugin-file",
+      "merges": [
+        "window"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.isChrome",
+      "file": "plugins/cordova-plugin-file/www/browser/isChrome.js",
+      "pluginId": "cordova-plugin-file",
+      "runs": true
+    },
+    {
+      "id": "cordova-plugin-file.androidFileSystem",
+      "file": "plugins/cordova-plugin-file/www/android/FileSystem.js",
+      "pluginId": "cordova-plugin-file",
+      "merges": [
+        "FileSystem"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.fileSystems-roots",
+      "file": "plugins/cordova-plugin-file/www/fileSystems-roots.js",
+      "pluginId": "cordova-plugin-file",
+      "runs": true
+    },
+    {
+      "id": "cordova-plugin-file.fileSystemPaths",
+      "file": "plugins/cordova-plugin-file/www/fileSystemPaths.js",
+      "pluginId": "cordova-plugin-file",
+      "merges": [
+        "cordova"
+      ],
+      "runs": true
+    },
+    {
+      "id": "cordova-plugin-advanced-http.cookie-handler",
+      "file": "plugins/cordova-plugin-advanced-http/www/cookie-handler.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.global-configs",
+      "file": "plugins/cordova-plugin-advanced-http/www/global-configs.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.helpers",
+      "file": "plugins/cordova-plugin-advanced-http/www/helpers.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.js-util",
+      "file": "plugins/cordova-plugin-advanced-http/www/js-util.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.local-storage-store",
+      "file": "plugins/cordova-plugin-advanced-http/www/local-storage-store.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.lodash",
+      "file": "plugins/cordova-plugin-advanced-http/www/lodash.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.messages",
+      "file": "plugins/cordova-plugin-advanced-http/www/messages.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.public-interface",
+      "file": "plugins/cordova-plugin-advanced-http/www/public-interface.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.tough-cookie",
+      "file": "plugins/cordova-plugin-advanced-http/www/umd-tough-cookie.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.url-util",
+      "file": "plugins/cordova-plugin-advanced-http/www/url-util.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.http",
+      "file": "plugins/cordova-plugin-advanced-http/www/advanced-http.js",
+      "pluginId": "cordova-plugin-advanced-http",
+      "clobbers": [
+        "cordova.plugin.http"
+      ]
+    },
+    {
+      "id": "cordova-plugin-statusbar.statusbar",
+      "file": "plugins/cordova-plugin-statusbar/www/statusbar.js",
+      "pluginId": "cordova-plugin-statusbar",
+      "clobbers": [
+        "window.StatusBar"
+      ]
+    },
+    {
+      "id": "cordova-plugin-qrscanner.QRScanner",
+      "file": "plugins/cordova-plugin-qrscanner/www/www.min.js",
+      "pluginId": "cordova-plugin-qrscanner",
+      "clobbers": [
+        "QRScanner"
+      ]
+    },
+    {
+      "id": "cordova-plugin-camera.Camera",
+      "file": "plugins/cordova-plugin-camera/www/CameraConstants.js",
+      "pluginId": "cordova-plugin-camera",
+      "clobbers": [
+        "Camera"
+      ]
+    },
+    {
+      "id": "cordova-plugin-camera.CameraPopoverOptions",
+      "file": "plugins/cordova-plugin-camera/www/CameraPopoverOptions.js",
+      "pluginId": "cordova-plugin-camera",
+      "clobbers": [
+        "CameraPopoverOptions"
+      ]
+    },
+    {
+      "id": "cordova-plugin-camera.camera",
+      "file": "plugins/cordova-plugin-camera/www/Camera.js",
+      "pluginId": "cordova-plugin-camera",
+      "clobbers": [
+        "navigator.camera"
+      ]
+    },
+    {
+      "id": "cordova-plugin-camera.CameraPopoverHandle",
+      "file": "plugins/cordova-plugin-camera/www/CameraPopoverHandle.js",
+      "pluginId": "cordova-plugin-camera",
+      "clobbers": [
+        "CameraPopoverHandle"
+      ]
+    },
+    {
+      "id": "cordova-plugin-inappbrowser.inappbrowser",
+      "file": "plugins/cordova-plugin-inappbrowser/www/inappbrowser.js",
+      "pluginId": "cordova-plugin-inappbrowser",
+      "clobbers": [
+        "cordova.InAppBrowser.open",
+        "window.open"
+      ]
+    },
+    {
+      "id": "cordova-plugin-device.device",
+      "file": "plugins/cordova-plugin-device/www/device.js",
+      "pluginId": "cordova-plugin-device",
+      "clobbers": [
+        "device"
+      ]
+    },
+    {
+      "id": "cordova-plugin-themeablebrowser.themeablebrowser",
+      "file": "plugins/cordova-plugin-themeablebrowser/www/themeablebrowser.js",
+      "pluginId": "cordova-plugin-themeablebrowser",
+      "clobbers": [
+        "cordova.ThemeableBrowser"
+      ]
+    }
+  ],
+  "plugin_metadata": {
+    "cordova-plugin-add-swift-support": "2.0.2",
+    "cordova-plugin-fingerprint-aio": "1.7.0",
+    "cordova-plugin-touch-id": "3.3.1",
+    "cordova-plugin-whitelist": "1.3.3",
+    "cordova-plugin-file": "6.0.1",
+    "cordova-plugin-advanced-http": "2.1.1",
+    "cordova-plugin-statusbar": "2.4.2",
+    "cordova-plugin-disable-ios11-statusbar": "1.0.0",
+    "cordova-plugin-qrscanner": "3.0.1",
+    "cordova-plugin-camera": "4.0.3",
+    "cordova-plugin-inappbrowser": "3.0.0",
+    "cordova-plugin-device": "2.0.2",
+    "cordova-plugin-themeablebrowser": "0.2.17"
+  }
+}
diff --git a/platforms/android/app/build.gradle b/platforms/android/app/build.gradle
new file mode 100644
index 0000000..871aabb
--- /dev/null
+++ b/platforms/android/app/build.gradle
@@ -0,0 +1,333 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+apply plugin: 'com.android.application'
+
+buildscript {
+    repositories {
+        mavenCentral()
+        google()
+        jcenter()
+    }
+
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.3.0'
+    }
+}
+
+// Allow plugins to declare Maven dependencies via build-extras.gradle.
+allprojects {
+    repositories {
+        mavenCentral()
+        jcenter()
+    }
+}
+
+task wrapper(type: Wrapper) {
+    gradleVersion = '4.10.3'
+}
+
+// Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties.
+// Refer to: http://www.gradle.org/docs/current/userguide/tutorial_this_and_that.html
+ext {
+    apply from: '../CordovaLib/cordova.gradle'
+
+    // The value for android.compileSdkVersion.
+    if (!project.hasProperty('cdvCompileSdkVersion')) {
+        cdvCompileSdkVersion = null;
+    }
+    // The value for android.buildToolsVersion.
+    if (!project.hasProperty('cdvBuildToolsVersion')) {
+        cdvBuildToolsVersion = null;
+    }
+    // Sets the versionCode to the given value.
+    if (!project.hasProperty('cdvVersionCode')) {
+        cdvVersionCode = null
+    }
+    // Sets the minSdkVersion to the given value.
+    if (!project.hasProperty('cdvMinSdkVersion')) {
+        cdvMinSdkVersion = null
+    }
+    // Whether to build architecture-specific APKs.
+    if (!project.hasProperty('cdvBuildMultipleApks')) {
+        cdvBuildMultipleApks = null
+    }
+    // Whether to append a 0 "abi digit" to versionCode when only a single APK is build
+    if (!project.hasProperty('cdvVersionCodeForceAbiDigit')) {
+        cdvVersionCodeForceAbiDigit = null
+    }
+    // .properties files to use for release signing.
+    if (!project.hasProperty('cdvReleaseSigningPropertiesFile')) {
+        cdvReleaseSigningPropertiesFile = null
+    }
+    // .properties files to use for debug signing.
+    if (!project.hasProperty('cdvDebugSigningPropertiesFile')) {
+        cdvDebugSigningPropertiesFile = null
+    }
+    // Set by build.js script.
+    if (!project.hasProperty('cdvBuildArch')) {
+        cdvBuildArch = null
+    }
+
+    // Plugin gradle extensions can append to this to have code run at the end.
+    cdvPluginPostBuildExtras = []
+}
+
+// PLUGIN GRADLE EXTENSIONS START
+apply from: "../cordova-plugin-qrscanner/dlapp-qrscanner.gradle"
+// PLUGIN GRADLE EXTENSIONS END
+
+def hasBuildExtras1 = file('build-extras.gradle').exists()
+if (hasBuildExtras1) {
+    apply from: 'build-extras.gradle'
+}
+
+def hasBuildExtras2 = file('../build-extras.gradle').exists()
+if (hasBuildExtras2) {
+    apply from: '../build-extras.gradle'
+}
+
+// Set property defaults after extension .gradle files.
+if (ext.cdvCompileSdkVersion == null) {
+    ext.cdvCompileSdkVersion = privateHelpers.getProjectTarget()
+    //ext.cdvCompileSdkVersion = project.ext.defaultCompileSdkVersion
+}
+if (ext.cdvBuildToolsVersion == null) {
+    ext.cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools()
+    //ext.cdvBuildToolsVersion = project.ext.defaultBuildToolsVersion
+}
+if (ext.cdvDebugSigningPropertiesFile == null && file('../debug-signing.properties').exists()) {
+    ext.cdvDebugSigningPropertiesFile = '../debug-signing.properties'
+}
+if (ext.cdvReleaseSigningPropertiesFile == null && file('../release-signing.properties').exists()) {
+    ext.cdvReleaseSigningPropertiesFile = '../release-signing.properties'
+}
+
+// Cast to appropriate types.
+ext.cdvBuildMultipleApks = cdvBuildMultipleApks == null ? false : cdvBuildMultipleApks.toBoolean();
+ext.cdvVersionCodeForceAbiDigit = cdvVersionCodeForceAbiDigit == null ? false : cdvVersionCodeForceAbiDigit.toBoolean();
+ext.cdvMinSdkVersion = cdvMinSdkVersion == null ? defaultMinSdkVersion : Integer.parseInt('' + cdvMinSdkVersion)
+ext.cdvVersionCode = cdvVersionCode == null ? null : Integer.parseInt('' + cdvVersionCode)
+
+def computeBuildTargetName(debugBuild) {
+    def ret = 'assemble'
+    if (cdvBuildMultipleApks && cdvBuildArch) {
+        def arch = cdvBuildArch == 'arm' ? 'armv7' : cdvBuildArch
+        ret += '' + arch.toUpperCase().charAt(0) + arch.substring(1);
+    }
+    return ret + (debugBuild ? 'Debug' : 'Release')
+}
+
+// Make cdvBuild a task that depends on the debug/arch-sepecific task.
+task cdvBuildDebug
+cdvBuildDebug.dependsOn {
+    return computeBuildTargetName(true)
+}
+
+task cdvBuildRelease
+cdvBuildRelease.dependsOn {
+    return computeBuildTargetName(false)
+}
+
+task cdvPrintProps {
+    doLast {
+        println('cdvCompileSdkVersion=' + cdvCompileSdkVersion)
+        println('cdvBuildToolsVersion=' + cdvBuildToolsVersion)
+        println('cdvVersionCode=' + cdvVersionCode)
+        println('cdvVersionCodeForceAbiDigit=' + cdvVersionCodeForceAbiDigit)
+        println('cdvMinSdkVersion=' + cdvMinSdkVersion)
+        println('cdvBuildMultipleApks=' + cdvBuildMultipleApks)
+        println('cdvReleaseSigningPropertiesFile=' + cdvReleaseSigningPropertiesFile)
+        println('cdvDebugSigningPropertiesFile=' + cdvDebugSigningPropertiesFile)
+        println('cdvBuildArch=' + cdvBuildArch)
+        println('computedVersionCode=' + android.defaultConfig.versionCode)
+        android.productFlavors.each { flavor ->
+            println('computed' + flavor.name.capitalize() + 'VersionCode=' + flavor.versionCode)
+        }
+    }
+}
+
+android {
+    defaultConfig {
+        versionCode cdvVersionCode ?: new BigInteger("" + privateHelpers.extractIntFromManifest("versionCode"))
+        applicationId privateHelpers.extractStringFromManifest("package")
+
+        if (cdvMinSdkVersion != null) {
+            minSdkVersion cdvMinSdkVersion
+        }
+    }
+
+    lintOptions {
+      abortOnError false;
+    }
+
+    compileSdkVersion cdvCompileSdkVersion
+    buildToolsVersion cdvBuildToolsVersion
+
+    // This code exists for Crosswalk and other Native APIs.
+    // By default, we multiply the existing version code in the
+    // Android Manifest by 10 and add a number for each architecture.
+    // If you are not using Crosswalk or SQLite, you can
+    // ignore this chunk of code, and your version codes will be respected.
+
+    if (Boolean.valueOf(cdvBuildMultipleApks)) {
+        flavorDimensions "default"
+
+        productFlavors {
+            armeabi {
+                versionCode defaultConfig.versionCode*10 + 1
+                ndk {
+                    abiFilters = ["armeabi"]
+                }
+            }
+            armv7 {
+                versionCode defaultConfig.versionCode*10 + 2
+                ndk {
+                    abiFilters = ["armeabi-v7a"]
+                }
+            }
+            arm64 {
+                versionCode defaultConfig.versionCode*10 + 3
+                ndk {
+                    abiFilters = ["arm64-v8a"]
+                }
+            }
+            x86 {
+                versionCode defaultConfig.versionCode*10 + 4
+                ndk {
+                    abiFilters = ["x86"]
+                }
+            }
+            x86_64 {
+                versionCode defaultConfig.versionCode*10 + 5
+                ndk {
+                    abiFilters = ["x86_64"]
+                }
+            }
+        }
+    } else if (Boolean.valueOf(cdvVersionCodeForceAbiDigit)) {
+        // This provides compatibility to the default logic for versionCode before cordova-android 5.2.0
+        defaultConfig {
+            versionCode defaultConfig.versionCode*10
+        }
+    }
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+
+    if (cdvReleaseSigningPropertiesFile) {
+        signingConfigs {
+            release {
+                // These must be set or Gradle will complain (even if they are overridden).
+                keyAlias = ""
+                keyPassword = "__unset" // And these must be set to non-empty in order to have the signing step added to the task graph.
+                storeFile = null
+                storePassword = "__unset"
+            }
+        }
+        buildTypes {
+            release {
+                signingConfig signingConfigs.release
+            }
+        }
+        addSigningProps(cdvReleaseSigningPropertiesFile, signingConfigs.release)
+    }
+
+    if (cdvDebugSigningPropertiesFile) {
+        addSigningProps(cdvDebugSigningPropertiesFile, signingConfigs.debug)
+    }
+}
+
+/*
+ * WARNING: Cordova Lib and platform scripts do management inside of this code here,
+ * if you are adding the dependencies manually, do so outside the comments, otherwise
+ * the Cordova tools will overwrite them
+ */
+
+
+dependencies {
+    implementation fileTree(dir: 'libs', include: '*.jar')
+    // SUB-PROJECT DEPENDENCIES START
+    implementation(project(path: ":CordovaLib"))
+    implementation "com.squareup.okhttp3:okhttp-urlconnection:3.10.0"
+    implementation "com.android.support:support-v4:24.1.1+"
+    // SUB-PROJECT DEPENDENCIES END
+}
+
+def promptForReleaseKeyPassword() {
+    if (!cdvReleaseSigningPropertiesFile) {
+        return;
+    }
+    if ('__unset'.equals(android.signingConfigs.release.storePassword)) {
+        android.signingConfigs.release.storePassword = privateHelpers.promptForPassword('Enter key store password: ')
+    }
+    if ('__unset'.equals(android.signingConfigs.release.keyPassword)) {
+        android.signingConfigs.release.keyPassword = privateHelpers.promptForPassword('Enter key password: ');
+    }
+}
+
+gradle.taskGraph.whenReady { taskGraph ->
+    taskGraph.getAllTasks().each() { task ->
+      if(['validateReleaseSigning', 'validateSigningRelease', 'validateSigningArmv7Release', 'validateSigningX76Release'].contains(task.name)) {
+         promptForReleaseKeyPassword()
+      }
+    }
+}
+
+def addSigningProps(propsFilePath, signingConfig) {
+    def propsFile = file(propsFilePath)
+    def props = new Properties()
+    propsFile.withReader { reader ->
+        props.load(reader)
+    }
+
+    def storeFile = new File(props.get('key.store') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'storeFile'))
+    if (!storeFile.isAbsolute()) {
+        storeFile = RelativePath.parse(true, storeFile.toString()).getFile(propsFile.getParentFile())
+    }
+    if (!storeFile.exists()) {
+        throw new FileNotFoundException('Keystore file does not exist: ' + storeFile.getAbsolutePath())
+    }
+    signingConfig.keyAlias = props.get('key.alias') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'keyAlias')
+    signingConfig.keyPassword = props.get('keyPassword', props.get('key.alias.password', signingConfig.keyPassword))
+    signingConfig.storeFile = storeFile
+    signingConfig.storePassword = props.get('storePassword', props.get('key.store.password', signingConfig.storePassword))
+    def storeType = props.get('storeType', props.get('key.store.type', ''))
+    if (!storeType) {
+        def filename = storeFile.getName().toLowerCase();
+        if (filename.endsWith('.p12') || filename.endsWith('.pfx')) {
+            storeType = 'pkcs12'
+        } else {
+            storeType = signingConfig.storeType // "jks"
+        }
+    }
+    signingConfig.storeType = storeType
+}
+
+for (def func : cdvPluginPostBuildExtras) {
+    func()
+}
+
+// This can be defined within build-extras.gradle as:
+//     ext.postBuildExtras = { ... code here ... }
+if (hasProperty('postBuildExtras')) {
+    postBuildExtras()
+}
diff --git a/platforms/android/app/src/main/AndroidManifest.xml b/platforms/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..5a16756
--- /dev/null
+++ b/platforms/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version='1.0' encoding='utf-8'?>
+<manifest android:hardwareAccelerated="true" android:versionCode="10000" android:versionName="1.0.0" package="com.supwisdom.dlapp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <application android:hardwareAccelerated="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true">
+        <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/activity_name" android:launchMode="singleTop" android:name="MainActivity" android:screenOrientation="portrait" android:theme="@android:style/Theme.DeviceDefault.NoActionBar" android:windowSoftInputMode="adjustResize">
+            <intent-filter android:label="@string/launcher_name">
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <provider android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true" android:name="org.apache.cordova.camera.FileProvider">
+            <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/camera_provider_paths" />
+        </provider>
+    </application>
+    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="28" />
+    <uses-permission android:name="android.permission.USE_FINGERPRINT" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.CAMERA" android:required="false" />
+    <uses-feature android:name="android.hardware.camera" android:required="false" />
+    <uses-feature android:name="android.hardware.camera.front" android:required="false" />
+</manifest>
diff --git a/platforms/android/app/src/main/assets/www/bill.html b/platforms/android/app/src/main/assets/www/bill.html
new file mode 100644
index 0000000..e70285f
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/bill.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <link rel="stylesheet" type="text/css" href="mobileui/style.css">
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="viewport-fit=cover, initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <link rel="stylesheet" type="text/css" href="css/aui.css">
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <title>账单</title>
+</head>
+
+<body>
+    <header class="aui-bar aui-bar-nav" style="padding-top:25px;">
+        <a class="aui-pull-left" href="javascript:window.history.back()">
+            <span class="aui-iconfont aui-icon-left"></span>
+        </a>
+        <div class="aui-title">账单</div>
+    </header>
+    <div style="overflow: scroll;position: absolute;top:74px;bottom:0px;left: 0;right: 0">
+        <div class="aui-card-list" id="billcontent">
+            
+        </div>
+         <div class="aui-card-list-footer aui-text-center" id="loadNext" onclick="app.loadNext()" style="background:#fff;display: none;">
+            继续加载
+        </div>
+    </div>
+</body>
+</html>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/lib/jquery-weui.js"></script>
+<script type="text/javascript" src="js/lib/aui-dialog.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
+<script type="text/javascript" src="js/bill.js"></script>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/billdetail.html b/platforms/android/app/src/main/assets/www/billdetail.html
new file mode 100644
index 0000000..8bbde06
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/billdetail.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <link rel="stylesheet" type="text/css" href="mobileui/style.css">
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="viewport-fit=cover, initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
+    <link rel="stylesheet" type="text/css" href="css/aui.css">
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <title>账单详情</title>
+</head>
+
+<body>
+    <header class="aui-bar aui-bar-nav" style="padding-top:25px;">
+        <a class="aui-pull-left" href="javascript:window.history.back()">
+            <span class="aui-iconfont aui-icon-left"></span>
+        </a>
+        <div class="aui-title">账单详情</div>
+    </header>
+    <header class="demos-header">
+      <h1 class="demos-title" id="amount"></h1>
+      <h1 class="detail-title" id="status"></h1>
+    </header>
+    <div class="weui-form-preview">
+        <div class="weui-form-preview__hd" style="padding: 5px 10px;">
+            <label class="weui-form-preview__label">交易名称</label>
+            <em class="weui-form-preview__value" style="font-size: 1.1em;" id="tranddes">&nbsp;</em>
+        </div>
+        <div class="weui-form-preview__hd" style="padding: 5px 10px;">
+            <label class="weui-form-preview__label">交易时间</label>
+            <em class="weui-form-preview__value" style="font-size: 1.1em;" id="transtime">&nbsp;</em>
+        </div>
+        <div class="weui-form-preview__hd" style="padding: 5px 10px;">
+            <label class="weui-form-preview__label">订单编号</label>
+            <em class="weui-form-preview__value" style="font-size: 1.1em;" id="refno">&nbsp;</em>
+        </div>
+    </div>
+</body>
+
+</html>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/lib/jquery-weui.js"></script>
+<script type="text/javascript" src="js/lib/aui-dialog.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
+<script type="text/javascript" src="js/billdetail.js"></script>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/bindcard.html b/platforms/android/app/src/main/assets/www/bindcard.html
new file mode 100644
index 0000000..3ec9d26
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/bindcard.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <link rel="stylesheet" type="text/css" href="mobileui/style.css">
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="viewport-fit=cover, initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <link rel="stylesheet" type="text/css" href="css/aui.css">
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <title>绑定银行卡</title>
+</head>
+<body>
+    <header class="aui-bar aui-bar-nav" style="padding-top:25px;">
+        <a class="aui-pull-left" href="main.html">
+            <span class="aui-iconfont aui-icon-left"></span>
+        </a>
+        <div class="aui-title">绑定银行卡</div>
+    </header>
+    <div>
+        <div class="weui-cells__title">市民卡信息</div>
+        <div class="weui-cells weui-cells_form">
+            <div class="weui-cell" style="padding:0 10px; "> 
+                <div class="weui-cell__hd"><label class="weui-label" style="width: 80px;font-size: 14px;">姓名</label></div>
+                <div class="weui-cell__bd">
+                    <input class="weui-input" type="text" id="name" style="font-size: 14px;" placeholder="请输入您的真实姓名">
+                </div>
+            </div>
+            <div class="weui-cell" style="padding:0 10px; "> 
+                <div class="weui-cell__hd"><label class="weui-label" style="width: 80px;font-size: 14px;">银行卡号</label></div>
+                <div class="weui-cell__bd">
+                    <input class="weui-input" type="text" id="cardnum" style="font-size: 14px;" placeholder="市民卡对应的银行卡号">
+                </div>
+            </div>
+        </div>
+
+        <div class="weui-cells__title">短信验证市民卡预留的手机号</div>
+        <div class="weui-cells weui-cells_form">
+            <div class="weui-cell" style="padding:0 10px; "> 
+                <div class="weui-cell__hd"><label class="weui-label" style="width: 80px;font-size: 14px;">手机号</label></div>
+                <div class="weui-cell__bd">
+                    <input class="weui-input" type="tel" id="phone" style="font-size: 14px;" placeholder="请输入市民卡预留的手机号" disabled="disabled" >
+                </div>
+            </div>
+            <div class="weui-cell weui-cell_vcode" style="padding:0 10px; ">
+                <div class="weui-cell__hd">
+                    <label class="weui-label" style="width: 80px;font-size: 14px;">验证码</label>
+                </div>
+                <div class="weui-cell__bd">
+                    <input class="weui-input" type="number" id="code" style="font-size: 14px;" placeholder="请输入验证码" maxlength="6">
+                </div>
+                <div class="weui-cell__ft">
+                    <button class="weui-vcode-btn" onclick="app.getCode()" id="codebtn" style="width: 100px;height: 1rem;font-size: 14px;">获取验证码</button>
+                </div>
+            </div>
+        </div>
+
+        <section class="aui-content-padded" style="margin-top: 30px;">
+            <div class="aui-btn aui-btn-block aui-btn-info" tapmode onclick="app.doNext()">下一步</div>
+        </section>
+    </div>
+</body>
+
+</html>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/lib/jquery-weui.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
+<script type="text/javascript" src="js/bindcard.js"></script>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/card.html b/platforms/android/app/src/main/assets/www/card.html
new file mode 100644
index 0000000..3c48354
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/card.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <link rel="stylesheet" type="text/css" href="mobileui/style.css">
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="viewport-fit=cover, initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <link rel="stylesheet" type="text/css" href="css/aui.css">
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <title>市民卡挂失</title>
+</head>
+<body>
+    <header class="aui-bar aui-bar-nav" style="padding-top:25px;">
+        <a class="aui-pull-left" href="main.html">
+            <span class="aui-iconfont aui-icon-left"></span>
+        </a>
+        <div class="aui-title">市民卡挂失</div>
+    </header>
+    <div>
+        <div class="weui-cells weui-cells_form">
+            <div class="weui-cell">
+                <div class="weui-cell__hd"><label class="weui-label">支付密码</label></div>
+                <div class="weui-cell__bd">
+                    <input class="weui-input" type="password" id="pwd"  pattern="[0-9]*" placeholder="请输入支付密码" maxlength="6">
+                </div>
+            </div>
+        </div>
+        <div style="padding: 20px;">
+            <a href="javascript:app.doNext();" class="weui-btn weui-btn_primary">挂失</a>
+        </div>
+    </div>
+</body>
+</html>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/lib/jquery-weui.js"></script>
+<script type="text/javascript" src="js/lib/aui-dialog.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
+<script type="text/javascript" src="js/card.js"></script>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/cordova-js-src/android/nativeapiprovider.js b/platforms/android/app/src/main/assets/www/cordova-js-src/android/nativeapiprovider.js
new file mode 100644
index 0000000..2e9aa67
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/cordova-js-src/android/nativeapiprovider.js
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+*/
+
+/**
+ * Exports the ExposedJsApi.java object if available, otherwise exports the PromptBasedNativeApi.
+ */
+
+var nativeApi = this._cordovaNative || require('cordova/android/promptbasednativeapi');
+var currentApi = nativeApi;
+
+module.exports = {
+    get: function() { return currentApi; },
+    setPreferPrompt: function(value) {
+        currentApi = value ? require('cordova/android/promptbasednativeapi') : nativeApi;
+    },
+    // Used only by tests.
+    set: function(value) {
+        currentApi = value;
+    }
+};
diff --git a/platforms/android/app/src/main/assets/www/cordova-js-src/android/promptbasednativeapi.js b/platforms/android/app/src/main/assets/www/cordova-js-src/android/promptbasednativeapi.js
new file mode 100644
index 0000000..f7fb6bc
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/cordova-js-src/android/promptbasednativeapi.js
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+*/
+
+/**
+ * Implements the API of ExposedJsApi.java, but uses prompt() to communicate.
+ * This is used pre-JellyBean, where addJavascriptInterface() is disabled.
+ */
+
+module.exports = {
+    exec: function(bridgeSecret, service, action, callbackId, argsJson) {
+        return prompt(argsJson, 'gap:'+JSON.stringify([bridgeSecret, service, action, callbackId]));
+    },
+    setNativeToJsBridgeMode: function(bridgeSecret, value) {
+        prompt(value, 'gap_bridge_mode:' + bridgeSecret);
+    },
+    retrieveJsMessages: function(bridgeSecret, fromOnlineEvent) {
+        return prompt(+fromOnlineEvent, 'gap_poll:' + bridgeSecret);
+    }
+};
diff --git a/platforms/android/app/src/main/assets/www/cordova-js-src/exec.js b/platforms/android/app/src/main/assets/www/cordova-js-src/exec.js
new file mode 100644
index 0000000..39e8c97
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/cordova-js-src/exec.js
@@ -0,0 +1,286 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * Execute a cordova command.  It is up to the native side whether this action
+ * is synchronous or asynchronous.  The native side can return:
+ *      Synchronous: PluginResult object as a JSON string
+ *      Asynchronous: Empty string ""
+ * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
+ * depending upon the result of the action.
+ *
+ * @param {Function} success    The success callback
+ * @param {Function} fail       The fail callback
+ * @param {String} service      The name of the service to use
+ * @param {String} action       Action to be run in cordova
+ * @param {String[]} [args]     Zero or more arguments to pass to the method
+ */
+var cordova = require('cordova'),
+    nativeApiProvider = require('cordova/android/nativeapiprovider'),
+    utils = require('cordova/utils'),
+    base64 = require('cordova/base64'),
+    channel = require('cordova/channel'),
+    jsToNativeModes = {
+        PROMPT: 0,
+        JS_OBJECT: 1
+    },
+    nativeToJsModes = {
+        // Polls for messages using the JS->Native bridge.
+        POLLING: 0,
+        // For LOAD_URL to be viable, it would need to have a work-around for
+        // the bug where the soft-keyboard gets dismissed when a message is sent.
+        LOAD_URL: 1,
+        // For the ONLINE_EVENT to be viable, it would need to intercept all event
+        // listeners (both through addEventListener and window.ononline) as well
+        // as set the navigator property itself.
+        ONLINE_EVENT: 2,
+        EVAL_BRIDGE: 3
+    },
+    jsToNativeBridgeMode,  // Set lazily.
+    nativeToJsBridgeMode = nativeToJsModes.EVAL_BRIDGE,
+    pollEnabled = false,
+    bridgeSecret = -1;
+
+var messagesFromNative = [];
+var isProcessing = false;
+var resolvedPromise = typeof Promise == 'undefined' ? null : Promise.resolve();
+var nextTick = resolvedPromise ? function(fn) { resolvedPromise.then(fn); } : function(fn) { setTimeout(fn); };
+
+function androidExec(success, fail, service, action, args) {
+    if (bridgeSecret < 0) {
+        // If we ever catch this firing, we'll need to queue up exec()s
+        // and fire them once we get a secret. For now, I don't think
+        // it's possible for exec() to be called since plugins are parsed but
+        // not run until until after onNativeReady.
+        throw new Error('exec() called without bridgeSecret');
+    }
+    // Set default bridge modes if they have not already been set.
+    // By default, we use the failsafe, since addJavascriptInterface breaks too often
+    if (jsToNativeBridgeMode === undefined) {
+        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
+    }
+
+    // If args is not provided, default to an empty array
+    args = args || [];
+
+    // Process any ArrayBuffers in the args into a string.
+    for (var i = 0; i < args.length; i++) {
+        if (utils.typeName(args[i]) == 'ArrayBuffer') {
+            args[i] = base64.fromArrayBuffer(args[i]);
+        }
+    }
+
+    var callbackId = service + cordova.callbackId++,
+        argsJson = JSON.stringify(args);
+    if (success || fail) {
+        cordova.callbacks[callbackId] = {success:success, fail:fail};
+    }
+
+    var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);
+    // If argsJson was received by Java as null, try again with the PROMPT bridge mode.
+    // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2.  See CB-2666.
+    if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && msgs === "@Null arguments.") {
+        androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
+        androidExec(success, fail, service, action, args);
+        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
+    } else if (msgs) {
+        messagesFromNative.push(msgs);
+        // Always process async to avoid exceptions messing up stack.
+        nextTick(processMessages);
+    }
+}
+
+androidExec.init = function() {
+    bridgeSecret = +prompt('', 'gap_init:' + nativeToJsBridgeMode);
+    channel.onNativeReady.fire();
+};
+
+function pollOnceFromOnlineEvent() {
+    pollOnce(true);
+}
+
+function pollOnce(opt_fromOnlineEvent) {
+    if (bridgeSecret < 0) {
+        // This can happen when the NativeToJsMessageQueue resets the online state on page transitions.
+        // We know there's nothing to retrieve, so no need to poll.
+        return;
+    }
+    var msgs = nativeApiProvider.get().retrieveJsMessages(bridgeSecret, !!opt_fromOnlineEvent);
+    if (msgs) {
+        messagesFromNative.push(msgs);
+        // Process sync since we know we're already top-of-stack.
+        processMessages();
+    }
+}
+
+function pollingTimerFunc() {
+    if (pollEnabled) {
+        pollOnce();
+        setTimeout(pollingTimerFunc, 50);
+    }
+}
+
+function hookOnlineApis() {
+    function proxyEvent(e) {
+        cordova.fireWindowEvent(e.type);
+    }
+    // The network module takes care of firing online and offline events.
+    // It currently fires them only on document though, so we bridge them
+    // to window here (while first listening for exec()-releated online/offline
+    // events).
+    window.addEventListener('online', pollOnceFromOnlineEvent, false);
+    window.addEventListener('offline', pollOnceFromOnlineEvent, false);
+    cordova.addWindowEventHandler('online');
+    cordova.addWindowEventHandler('offline');
+    document.addEventListener('online', proxyEvent, false);
+    document.addEventListener('offline', proxyEvent, false);
+}
+
+hookOnlineApis();
+
+androidExec.jsToNativeModes = jsToNativeModes;
+androidExec.nativeToJsModes = nativeToJsModes;
+
+androidExec.setJsToNativeBridgeMode = function(mode) {
+    if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {
+        mode = jsToNativeModes.PROMPT;
+    }
+    nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);
+    jsToNativeBridgeMode = mode;
+};
+
+androidExec.setNativeToJsBridgeMode = function(mode) {
+    if (mode == nativeToJsBridgeMode) {
+        return;
+    }
+    if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {
+        pollEnabled = false;
+    }
+
+    nativeToJsBridgeMode = mode;
+    // Tell the native side to switch modes.
+    // Otherwise, it will be set by androidExec.init()
+    if (bridgeSecret >= 0) {
+        nativeApiProvider.get().setNativeToJsBridgeMode(bridgeSecret, mode);
+    }
+
+    if (mode == nativeToJsModes.POLLING) {
+        pollEnabled = true;
+        setTimeout(pollingTimerFunc, 1);
+    }
+};
+
+function buildPayload(payload, message) {
+    var payloadKind = message.charAt(0);
+    if (payloadKind == 's') {
+        payload.push(message.slice(1));
+    } else if (payloadKind == 't') {
+        payload.push(true);
+    } else if (payloadKind == 'f') {
+        payload.push(false);
+    } else if (payloadKind == 'N') {
+        payload.push(null);
+    } else if (payloadKind == 'n') {
+        payload.push(+message.slice(1));
+    } else if (payloadKind == 'A') {
+        var data = message.slice(1);
+        payload.push(base64.toArrayBuffer(data));
+    } else if (payloadKind == 'S') {
+        payload.push(window.atob(message.slice(1)));
+    } else if (payloadKind == 'M') {
+        var multipartMessages = message.slice(1);
+        while (multipartMessages !== "") {
+            var spaceIdx = multipartMessages.indexOf(' ');
+            var msgLen = +multipartMessages.slice(0, spaceIdx);
+            var multipartMessage = multipartMessages.substr(spaceIdx + 1, msgLen);
+            multipartMessages = multipartMessages.slice(spaceIdx + msgLen + 1);
+            buildPayload(payload, multipartMessage);
+        }
+    } else {
+        payload.push(JSON.parse(message));
+    }
+}
+
+// Processes a single message, as encoded by NativeToJsMessageQueue.java.
+function processMessage(message) {
+    var firstChar = message.charAt(0);
+    if (firstChar == 'J') {
+        // This is deprecated on the .java side. It doesn't work with CSP enabled.
+        eval(message.slice(1));
+    } else if (firstChar == 'S' || firstChar == 'F') {
+        var success = firstChar == 'S';
+        var keepCallback = message.charAt(1) == '1';
+        var spaceIdx = message.indexOf(' ', 2);
+        var status = +message.slice(2, spaceIdx);
+        var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);
+        var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);
+        var payloadMessage = message.slice(nextSpaceIdx + 1);
+        var payload = [];
+        buildPayload(payload, payloadMessage);
+        cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);
+    } else {
+        console.log("processMessage failed: invalid message: " + JSON.stringify(message));
+    }
+}
+
+function processMessages() {
+    // Check for the reentrant case.
+    if (isProcessing) {
+        return;
+    }
+    if (messagesFromNative.length === 0) {
+        return;
+    }
+    isProcessing = true;
+    try {
+        var msg = popMessageFromQueue();
+        // The Java side can send a * message to indicate that it
+        // still has messages waiting to be retrieved.
+        if (msg == '*' && messagesFromNative.length === 0) {
+            nextTick(pollOnce);
+            return;
+        }
+        processMessage(msg);
+    } finally {
+        isProcessing = false;
+        if (messagesFromNative.length > 0) {
+            nextTick(processMessages);
+        }
+    }
+}
+
+function popMessageFromQueue() {
+    var messageBatch = messagesFromNative.shift();
+    if (messageBatch == '*') {
+        return '*';
+    }
+
+    var spaceIdx = messageBatch.indexOf(' ');
+    var msgLen = +messageBatch.slice(0, spaceIdx);
+    var message = messageBatch.substr(spaceIdx + 1, msgLen);
+    messageBatch = messageBatch.slice(spaceIdx + msgLen + 1);
+    if (messageBatch) {
+        messagesFromNative.unshift(messageBatch);
+    }
+    return message;
+}
+
+module.exports = androidExec;
diff --git a/platforms/android/app/src/main/assets/www/cordova-js-src/platform.js b/platforms/android/app/src/main/assets/www/cordova-js-src/platform.js
new file mode 100644
index 0000000..2bfd024
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/cordova-js-src/platform.js
@@ -0,0 +1,125 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+// The last resume event that was received that had the result of a plugin call.
+var lastResumeEvent = null;
+
+module.exports = {
+    id: 'android',
+    bootstrap: function() {
+        var channel = require('cordova/channel'),
+            cordova = require('cordova'),
+            exec = require('cordova/exec'),
+            modulemapper = require('cordova/modulemapper');
+
+        // Get the shared secret needed to use the bridge.
+        exec.init();
+
+        // TODO: Extract this as a proper plugin.
+        modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');
+
+        var APP_PLUGIN_NAME = Number(cordova.platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';
+
+        // Inject a listener for the backbutton on the document.
+        var backButtonChannel = cordova.addDocumentEventHandler('backbutton');
+        backButtonChannel.onHasSubscribersChange = function() {
+            // If we just attached the first handler or detached the last handler,
+            // let native know we need to override the back button.
+            exec(null, null, APP_PLUGIN_NAME, "overrideBackbutton", [this.numHandlers == 1]);
+        };
+
+        // Add hardware MENU and SEARCH button handlers
+        cordova.addDocumentEventHandler('menubutton');
+        cordova.addDocumentEventHandler('searchbutton');
+
+        function bindButtonChannel(buttonName) {
+            // generic button bind used for volumeup/volumedown buttons
+            var volumeButtonChannel = cordova.addDocumentEventHandler(buttonName + 'button');
+            volumeButtonChannel.onHasSubscribersChange = function() {
+                exec(null, null, APP_PLUGIN_NAME, "overrideButton", [buttonName, this.numHandlers == 1]);
+            };
+        }
+        // Inject a listener for the volume buttons on the document.
+        bindButtonChannel('volumeup');
+        bindButtonChannel('volumedown');
+
+        // The resume event is not "sticky", but it is possible that the event
+        // will contain the result of a plugin call. We need to ensure that the
+        // plugin result is delivered even after the event is fired (CB-10498)
+        var cordovaAddEventListener = document.addEventListener;
+
+        document.addEventListener = function(evt, handler, capture) {
+            cordovaAddEventListener(evt, handler, capture);
+
+            if (evt === 'resume' && lastResumeEvent) {
+                handler(lastResumeEvent);
+            }
+        };
+
+        // Let native code know we are all done on the JS side.
+        // Native code will then un-hide the WebView.
+        channel.onCordovaReady.subscribe(function() {
+            exec(onMessageFromNative, null, APP_PLUGIN_NAME, 'messageChannel', []);
+            exec(null, null, APP_PLUGIN_NAME, "show", []);
+        });
+    }
+};
+
+function onMessageFromNative(msg) {
+    var cordova = require('cordova');
+    var action = msg.action;
+
+    switch (action)
+    {
+        // Button events
+        case 'backbutton':
+        case 'menubutton':
+        case 'searchbutton':
+        // App life cycle events
+        case 'pause':
+        // Volume events
+        case 'volumedownbutton':
+        case 'volumeupbutton':
+            cordova.fireDocumentEvent(action);
+            break;
+        case 'resume':
+            if(arguments.length > 1 && msg.pendingResult) {
+                if(arguments.length === 2) {
+                    msg.pendingResult.result = arguments[1];
+                } else {
+                    // The plugin returned a multipart message
+                    var res = [];
+                    for(var i = 1; i < arguments.length; i++) {
+                        res.push(arguments[i]);
+                    }
+                    msg.pendingResult.result = res;
+                }
+
+                // Save the plugin result so that it can be delivered to the js
+                // even if they miss the initial firing of the event
+                lastResumeEvent = msg;
+            }
+            cordova.fireDocumentEvent(action, msg);
+            break;
+        default:
+            throw new Error('Unknown event action ' + action);
+    }
+}
diff --git a/platforms/android/app/src/main/assets/www/cordova-js-src/plugin/android/app.js b/platforms/android/app/src/main/assets/www/cordova-js-src/plugin/android/app.js
new file mode 100644
index 0000000..22cf96e
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/cordova-js-src/plugin/android/app.js
@@ -0,0 +1,108 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var exec = require('cordova/exec');
+var APP_PLUGIN_NAME = Number(require('cordova').platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';
+
+module.exports = {
+    /**
+    * Clear the resource cache.
+    */
+    clearCache:function() {
+        exec(null, null, APP_PLUGIN_NAME, "clearCache", []);
+    },
+
+    /**
+    * Load the url into the webview or into new browser instance.
+    *
+    * @param url           The URL to load
+    * @param props         Properties that can be passed in to the activity:
+    *      wait: int                           => wait msec before loading URL
+    *      loadingDialog: "Title,Message"      => display a native loading dialog
+    *      loadUrlTimeoutValue: int            => time in msec to wait before triggering a timeout error
+    *      clearHistory: boolean              => clear webview history (default=false)
+    *      openExternal: boolean              => open in a new browser (default=false)
+    *
+    * Example:
+    *      navigator.app.loadUrl("http://server/myapp/index.html", {wait:2000, loadingDialog:"Wait,Loading App", loadUrlTimeoutValue: 60000});
+    */
+    loadUrl:function(url, props) {
+        exec(null, null, APP_PLUGIN_NAME, "loadUrl", [url, props]);
+    },
+
+    /**
+    * Cancel loadUrl that is waiting to be loaded.
+    */
+    cancelLoadUrl:function() {
+        exec(null, null, APP_PLUGIN_NAME, "cancelLoadUrl", []);
+    },
+
+    /**
+    * Clear web history in this web view.
+    * Instead of BACK button loading the previous web page, it will exit the app.
+    */
+    clearHistory:function() {
+        exec(null, null, APP_PLUGIN_NAME, "clearHistory", []);
+    },
+
+    /**
+    * Go to previous page displayed.
+    * This is the same as pressing the backbutton on Android device.
+    */
+    backHistory:function() {
+        exec(null, null, APP_PLUGIN_NAME, "backHistory", []);
+    },
+
+    /**
+    * Override the default behavior of the Android back button.
+    * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
+    *
+    * Note: The user should not have to call this method.  Instead, when the user
+    *       registers for the "backbutton" event, this is automatically done.
+    *
+    * @param override        T=override, F=cancel override
+    */
+    overrideBackbutton:function(override) {
+        exec(null, null, APP_PLUGIN_NAME, "overrideBackbutton", [override]);
+    },
+
+    /**
+    * Override the default behavior of the Android volume button.
+    * If overridden, when the volume button is pressed, the "volume[up|down]button"
+    * JavaScript event will be fired.
+    *
+    * Note: The user should not have to call this method.  Instead, when the user
+    *       registers for the "volume[up|down]button" event, this is automatically done.
+    *
+    * @param button          volumeup, volumedown
+    * @param override        T=override, F=cancel override
+    */
+    overrideButton:function(button, override) {
+        exec(null, null, APP_PLUGIN_NAME, "overrideButton", [button, override]);
+    },
+
+    /**
+    * Exit and terminate the application.
+    */
+    exitApp:function() {
+        return exec(null, null, APP_PLUGIN_NAME, "exitApp", []);
+    }
+};
diff --git a/platforms/android/app/src/main/assets/www/cordova.js b/platforms/android/app/src/main/assets/www/cordova.js
new file mode 100644
index 0000000..0f2d2e6
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/cordova.js
@@ -0,0 +1,1908 @@
+// Platform: android
+// 882658ab17740dbdece764e68c1f1f1f44fe3f9d
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+ 
+     http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+;(function() {
+var PLATFORM_VERSION_BUILD_LABEL = '8.0.0';
+// file: src/scripts/require.js
+
+var require;
+var define;
+
+(function () {
+    var modules = {};
+    // Stack of moduleIds currently being built.
+    var requireStack = [];
+    // Map of module ID -> index into requireStack of modules currently being built.
+    var inProgressModules = {};
+    var SEPARATOR = '.';
+
+    function build (module) {
+        var factory = module.factory;
+        var localRequire = function (id) {
+            var resultantId = id;
+            // Its a relative path, so lop off the last portion and add the id (minus "./")
+            if (id.charAt(0) === '.') {
+                resultantId = module.id.slice(0, module.id.lastIndexOf(SEPARATOR)) + SEPARATOR + id.slice(2);
+            }
+            return require(resultantId);
+        };
+        module.exports = {};
+        delete module.factory;
+        factory(localRequire, module.exports, module);
+        return module.exports;
+    }
+
+    require = function (id) {
+        if (!modules[id]) {
+            throw 'module ' + id + ' not found';
+        } else if (id in inProgressModules) {
+            var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
+            throw 'Cycle in require graph: ' + cycle;
+        }
+        if (modules[id].factory) {
+            try {
+                inProgressModules[id] = requireStack.length;
+                requireStack.push(id);
+                return build(modules[id]);
+            } finally {
+                delete inProgressModules[id];
+                requireStack.pop();
+            }
+        }
+        return modules[id].exports;
+    };
+
+    define = function (id, factory) {
+        if (modules[id]) {
+            throw 'module ' + id + ' already defined';
+        }
+
+        modules[id] = {
+            id: id,
+            factory: factory
+        };
+    };
+
+    define.remove = function (id) {
+        delete modules[id];
+    };
+
+    define.moduleMap = modules;
+})();
+
+// Export for use in node
+if (typeof module === 'object' && typeof require === 'function') {
+    module.exports.require = require;
+    module.exports.define = define;
+}
+
+// file: src/cordova.js
+define("cordova", function(require, exports, module) {
+
+// Workaround for Windows 10 in hosted environment case
+// http://www.w3.org/html/wg/drafts/html/master/browsers.html#named-access-on-the-window-object
+if (window.cordova && !(window.cordova instanceof HTMLElement)) { // eslint-disable-line no-undef
+    throw new Error('cordova already defined');
+}
+
+var channel = require('cordova/channel');
+var platform = require('cordova/platform');
+
+/**
+ * Intercept calls to addEventListener + removeEventListener and handle deviceready,
+ * resume, and pause events.
+ */
+var m_document_addEventListener = document.addEventListener;
+var m_document_removeEventListener = document.removeEventListener;
+var m_window_addEventListener = window.addEventListener;
+var m_window_removeEventListener = window.removeEventListener;
+
+/**
+ * Houses custom event handlers to intercept on document + window event listeners.
+ */
+var documentEventHandlers = {};
+var windowEventHandlers = {};
+
+document.addEventListener = function (evt, handler, capture) {
+    var e = evt.toLowerCase();
+    if (typeof documentEventHandlers[e] !== 'undefined') {
+        documentEventHandlers[e].subscribe(handler);
+    } else {
+        m_document_addEventListener.call(document, evt, handler, capture);
+    }
+};
+
+window.addEventListener = function (evt, handler, capture) {
+    var e = evt.toLowerCase();
+    if (typeof windowEventHandlers[e] !== 'undefined') {
+        windowEventHandlers[e].subscribe(handler);
+    } else {
+        m_window_addEventListener.call(window, evt, handler, capture);
+    }
+};
+
+document.removeEventListener = function (evt, handler, capture) {
+    var e = evt.toLowerCase();
+    // If unsubscribing from an event that is handled by a plugin
+    if (typeof documentEventHandlers[e] !== 'undefined') {
+        documentEventHandlers[e].unsubscribe(handler);
+    } else {
+        m_document_removeEventListener.call(document, evt, handler, capture);
+    }
+};
+
+window.removeEventListener = function (evt, handler, capture) {
+    var e = evt.toLowerCase();
+    // If unsubscribing from an event that is handled by a plugin
+    if (typeof windowEventHandlers[e] !== 'undefined') {
+        windowEventHandlers[e].unsubscribe(handler);
+    } else {
+        m_window_removeEventListener.call(window, evt, handler, capture);
+    }
+};
+
+function createEvent (type, data) {
+    var event = document.createEvent('Events');
+    event.initEvent(type, false, false);
+    if (data) {
+        for (var i in data) {
+            if (data.hasOwnProperty(i)) {
+                event[i] = data[i];
+            }
+        }
+    }
+    return event;
+}
+
+/* eslint-disable no-undef */
+var cordova = {
+    define: define,
+    require: require,
+    version: PLATFORM_VERSION_BUILD_LABEL,
+    platformVersion: PLATFORM_VERSION_BUILD_LABEL,
+    platformId: platform.id,
+
+    /* eslint-enable no-undef */
+
+    /**
+     * Methods to add/remove your own addEventListener hijacking on document + window.
+     */
+    addWindowEventHandler: function (event) {
+        return (windowEventHandlers[event] = channel.create(event));
+    },
+    addStickyDocumentEventHandler: function (event) {
+        return (documentEventHandlers[event] = channel.createSticky(event));
+    },
+    addDocumentEventHandler: function (event) {
+        return (documentEventHandlers[event] = channel.create(event));
+    },
+    removeWindowEventHandler: function (event) {
+        delete windowEventHandlers[event];
+    },
+    removeDocumentEventHandler: function (event) {
+        delete documentEventHandlers[event];
+    },
+    /**
+     * Retrieve original event handlers that were replaced by Cordova
+     *
+     * @return object
+     */
+    getOriginalHandlers: function () {
+        return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},
+            'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};
+    },
+    /**
+     * Method to fire event from native code
+     * bNoDetach is required for events which cause an exception which needs to be caught in native code
+     */
+    fireDocumentEvent: function (type, data, bNoDetach) {
+        var evt = createEvent(type, data);
+        if (typeof documentEventHandlers[type] !== 'undefined') {
+            if (bNoDetach) {
+                documentEventHandlers[type].fire(evt);
+            } else {
+                setTimeout(function () {
+                    // Fire deviceready on listeners that were registered before cordova.js was loaded.
+                    if (type === 'deviceready') {
+                        document.dispatchEvent(evt);
+                    }
+                    documentEventHandlers[type].fire(evt);
+                }, 0);
+            }
+        } else {
+            document.dispatchEvent(evt);
+        }
+    },
+    fireWindowEvent: function (type, data) {
+        var evt = createEvent(type, data);
+        if (typeof windowEventHandlers[type] !== 'undefined') {
+            setTimeout(function () {
+                windowEventHandlers[type].fire(evt);
+            }, 0);
+        } else {
+            window.dispatchEvent(evt);
+        }
+    },
+
+    /**
+     * Plugin callback mechanism.
+     */
+    // Randomize the starting callbackId to avoid collisions after refreshing or navigating.
+    // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.
+    callbackId: Math.floor(Math.random() * 2000000000),
+    callbacks: {},
+    callbackStatus: {
+        NO_RESULT: 0,
+        OK: 1,
+        CLASS_NOT_FOUND_EXCEPTION: 2,
+        ILLEGAL_ACCESS_EXCEPTION: 3,
+        INSTANTIATION_EXCEPTION: 4,
+        MALFORMED_URL_EXCEPTION: 5,
+        IO_EXCEPTION: 6,
+        INVALID_ACTION: 7,
+        JSON_EXCEPTION: 8,
+        ERROR: 9
+    },
+
+    /**
+     * Called by native code when returning successful result from an action.
+     */
+    callbackSuccess: function (callbackId, args) {
+        cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
+    },
+
+    /**
+     * Called by native code when returning error result from an action.
+     */
+    callbackError: function (callbackId, args) {
+        // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
+        // Derive success from status.
+        cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
+    },
+
+    /**
+     * Called by native code when returning the result from an action.
+     */
+    callbackFromNative: function (callbackId, isSuccess, status, args, keepCallback) {
+        try {
+            var callback = cordova.callbacks[callbackId];
+            if (callback) {
+                if (isSuccess && status === cordova.callbackStatus.OK) {
+                    callback.success && callback.success.apply(null, args);
+                } else if (!isSuccess) {
+                    callback.fail && callback.fail.apply(null, args);
+                }
+                /*
+                else
+                    Note, this case is intentionally not caught.
+                    this can happen if isSuccess is true, but callbackStatus is NO_RESULT
+                    which is used to remove a callback from the list without calling the callbacks
+                    typically keepCallback is false in this case
+                */
+                // Clear callback if not expecting any more results
+                if (!keepCallback) {
+                    delete cordova.callbacks[callbackId];
+                }
+            }
+        } catch (err) {
+            var msg = 'Error in ' + (isSuccess ? 'Success' : 'Error') + ' callbackId: ' + callbackId + ' : ' + err;
+            console && console.log && console.log(msg);
+            console && console.log && err.stack && console.log(err.stack);
+            cordova.fireWindowEvent('cordovacallbackerror', { 'message': msg });
+            throw err;
+        }
+    },
+    addConstructor: function (func) {
+        channel.onCordovaReady.subscribe(function () {
+            try {
+                func();
+            } catch (e) {
+                console.log('Failed to run constructor: ' + e);
+            }
+        });
+    }
+};
+
+module.exports = cordova;
+
+});
+
+// file: /Users/erisu/git/apache/cordova/cordova-android/cordova-js-src/android/nativeapiprovider.js
+define("cordova/android/nativeapiprovider", function(require, exports, module) {
+
+/**
+ * Exports the ExposedJsApi.java object if available, otherwise exports the PromptBasedNativeApi.
+ */
+
+var nativeApi = this._cordovaNative || require('cordova/android/promptbasednativeapi');
+var currentApi = nativeApi;
+
+module.exports = {
+    get: function() { return currentApi; },
+    setPreferPrompt: function(value) {
+        currentApi = value ? require('cordova/android/promptbasednativeapi') : nativeApi;
+    },
+    // Used only by tests.
+    set: function(value) {
+        currentApi = value;
+    }
+};
+
+});
+
+// file: /Users/erisu/git/apache/cordova/cordova-android/cordova-js-src/android/promptbasednativeapi.js
+define("cordova/android/promptbasednativeapi", function(require, exports, module) {
+
+/**
+ * Implements the API of ExposedJsApi.java, but uses prompt() to communicate.
+ * This is used pre-JellyBean, where addJavascriptInterface() is disabled.
+ */
+
+module.exports = {
+    exec: function(bridgeSecret, service, action, callbackId, argsJson) {
+        return prompt(argsJson, 'gap:'+JSON.stringify([bridgeSecret, service, action, callbackId]));
+    },
+    setNativeToJsBridgeMode: function(bridgeSecret, value) {
+        prompt(value, 'gap_bridge_mode:' + bridgeSecret);
+    },
+    retrieveJsMessages: function(bridgeSecret, fromOnlineEvent) {
+        return prompt(+fromOnlineEvent, 'gap_poll:' + bridgeSecret);
+    }
+};
+
+});
+
+// file: src/common/argscheck.js
+define("cordova/argscheck", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+
+var moduleExports = module.exports;
+
+var typeMap = {
+    'A': 'Array',
+    'D': 'Date',
+    'N': 'Number',
+    'S': 'String',
+    'F': 'Function',
+    'O': 'Object'
+};
+
+function extractParamName (callee, argIndex) {
+    return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex];
+}
+
+function checkArgs (spec, functionName, args, opt_callee) {
+    if (!moduleExports.enableChecks) {
+        return;
+    }
+    var errMsg = null;
+    var typeName;
+    for (var i = 0; i < spec.length; ++i) {
+        var c = spec.charAt(i);
+        var cUpper = c.toUpperCase();
+        var arg = args[i];
+        // Asterix means allow anything.
+        if (c === '*') {
+            continue;
+        }
+        typeName = utils.typeName(arg);
+        if ((arg === null || arg === undefined) && c === cUpper) {
+            continue;
+        }
+        if (typeName !== typeMap[cUpper]) {
+            errMsg = 'Expected ' + typeMap[cUpper];
+            break;
+        }
+    }
+    if (errMsg) {
+        errMsg += ', but got ' + typeName + '.';
+        errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
+        // Don't log when running unit tests.
+        if (typeof jasmine === 'undefined') {
+            console.error(errMsg);
+        }
+        throw TypeError(errMsg);
+    }
+}
+
+function getValue (value, defaultValue) {
+    return value === undefined ? defaultValue : value;
+}
+
+moduleExports.checkArgs = checkArgs;
+moduleExports.getValue = getValue;
+moduleExports.enableChecks = true;
+
+});
+
+// file: src/common/base64.js
+define("cordova/base64", function(require, exports, module) {
+
+var base64 = exports;
+
+base64.fromArrayBuffer = function (arrayBuffer) {
+    var array = new Uint8Array(arrayBuffer);
+    return uint8ToBase64(array);
+};
+
+base64.toArrayBuffer = function (str) {
+    var decodedStr = typeof atob !== 'undefined' ? atob(str) : Buffer.from(str, 'base64').toString('binary'); // eslint-disable-line no-undef
+    var arrayBuffer = new ArrayBuffer(decodedStr.length);
+    var array = new Uint8Array(arrayBuffer);
+    for (var i = 0, len = decodedStr.length; i < len; i++) {
+        array[i] = decodedStr.charCodeAt(i);
+    }
+    return arrayBuffer;
+};
+
+// ------------------------------------------------------------------------------
+
+/* This code is based on the performance tests at http://jsperf.com/b64tests
+ * This 12-bit-at-a-time algorithm was the best performing version on all
+ * platforms tested.
+ */
+
+var b64_6bit = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+var b64_12bit;
+
+var b64_12bitTable = function () {
+    b64_12bit = [];
+    for (var i = 0; i < 64; i++) {
+        for (var j = 0; j < 64; j++) {
+            b64_12bit[i * 64 + j] = b64_6bit[i] + b64_6bit[j];
+        }
+    }
+    b64_12bitTable = function () { return b64_12bit; };
+    return b64_12bit;
+};
+
+function uint8ToBase64 (rawData) {
+    var numBytes = rawData.byteLength;
+    var output = '';
+    var segment;
+    var table = b64_12bitTable();
+    for (var i = 0; i < numBytes - 2; i += 3) {
+        segment = (rawData[i] << 16) + (rawData[i + 1] << 8) + rawData[i + 2];
+        output += table[segment >> 12];
+        output += table[segment & 0xfff];
+    }
+    if (numBytes - i === 2) {
+        segment = (rawData[i] << 16) + (rawData[i + 1] << 8);
+        output += table[segment >> 12];
+        output += b64_6bit[(segment & 0xfff) >> 6];
+        output += '=';
+    } else if (numBytes - i === 1) {
+        segment = (rawData[i] << 16);
+        output += table[segment >> 12];
+        output += '==';
+    }
+    return output;
+}
+
+});
+
+// file: src/common/builder.js
+define("cordova/builder", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+
+function each (objects, func, context) {
+    for (var prop in objects) {
+        if (objects.hasOwnProperty(prop)) {
+            func.apply(context, [objects[prop], prop]);
+        }
+    }
+}
+
+function clobber (obj, key, value) {
+    exports.replaceHookForTesting(obj, key);
+    var needsProperty = false;
+    try {
+        obj[key] = value;
+    } catch (e) {
+        needsProperty = true;
+    }
+    // Getters can only be overridden by getters.
+    if (needsProperty || obj[key] !== value) {
+        utils.defineGetter(obj, key, function () {
+            return value;
+        });
+    }
+}
+
+function assignOrWrapInDeprecateGetter (obj, key, value, message) {
+    if (message) {
+        utils.defineGetter(obj, key, function () {
+            console.log(message);
+            delete obj[key];
+            clobber(obj, key, value);
+            return value;
+        });
+    } else {
+        clobber(obj, key, value);
+    }
+}
+
+function include (parent, objects, clobber, merge) {
+    each(objects, function (obj, key) {
+        try {
+            var result = obj.path ? require(obj.path) : {};
+
+            if (clobber) {
+                // Clobber if it doesn't exist.
+                if (typeof parent[key] === 'undefined') {
+                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+                } else if (typeof obj.path !== 'undefined') {
+                    // If merging, merge properties onto parent, otherwise, clobber.
+                    if (merge) {
+                        recursiveMerge(parent[key], result);
+                    } else {
+                        assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+                    }
+                }
+                result = parent[key];
+            } else {
+                // Overwrite if not currently defined.
+                if (typeof parent[key] === 'undefined') {
+                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+                } else {
+                    // Set result to what already exists, so we can build children into it if they exist.
+                    result = parent[key];
+                }
+            }
+
+            if (obj.children) {
+                include(result, obj.children, clobber, merge);
+            }
+        } catch (e) {
+            utils.alert('Exception building Cordova JS globals: ' + e + ' for key "' + key + '"');
+        }
+    });
+}
+
+/**
+ * Merge properties from one object onto another recursively.  Properties from
+ * the src object will overwrite existing target property.
+ *
+ * @param target Object to merge properties into.
+ * @param src Object to merge properties from.
+ */
+function recursiveMerge (target, src) {
+    for (var prop in src) {
+        if (src.hasOwnProperty(prop)) {
+            if (target.prototype && target.prototype.constructor === target) {
+                // If the target object is a constructor override off prototype.
+                clobber(target.prototype, prop, src[prop]);
+            } else {
+                if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {
+                    recursiveMerge(target[prop], src[prop]);
+                } else {
+                    clobber(target, prop, src[prop]);
+                }
+            }
+        }
+    }
+}
+
+exports.buildIntoButDoNotClobber = function (objects, target) {
+    include(target, objects, false, false);
+};
+exports.buildIntoAndClobber = function (objects, target) {
+    include(target, objects, true, false);
+};
+exports.buildIntoAndMerge = function (objects, target) {
+    include(target, objects, true, true);
+};
+exports.recursiveMerge = recursiveMerge;
+exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
+exports.replaceHookForTesting = function () {};
+
+});
+
+// file: src/common/channel.js
+define("cordova/channel", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+var nextGuid = 1;
+
+/**
+ * Custom pub-sub "channel" that can have functions subscribed to it
+ * This object is used to define and control firing of events for
+ * cordova initialization, as well as for custom events thereafter.
+ *
+ * The order of events during page load and Cordova startup is as follows:
+ *
+ * onDOMContentLoaded*         Internal event that is received when the web page is loaded and parsed.
+ * onNativeReady*              Internal event that indicates the Cordova native side is ready.
+ * onCordovaReady*             Internal event fired when all Cordova JavaScript objects have been created.
+ * onDeviceReady*              User event fired to indicate that Cordova is ready
+ * onResume                    User event fired to indicate a start/resume lifecycle event
+ * onPause                     User event fired to indicate a pause lifecycle event
+ *
+ * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
+ * All listeners that subscribe after the event is fired will be executed right away.
+ *
+ * The only Cordova events that user code should register for are:
+ *      deviceready           Cordova native code is initialized and Cordova APIs can be called from JavaScript
+ *      pause                 App has moved to background
+ *      resume                App has returned to foreground
+ *
+ * Listeners can be registered as:
+ *      document.addEventListener("deviceready", myDeviceReadyListener, false);
+ *      document.addEventListener("resume", myResumeListener, false);
+ *      document.addEventListener("pause", myPauseListener, false);
+ *
+ * The DOM lifecycle events should be used for saving and restoring state
+ *      window.onload
+ *      window.onunload
+ *
+ */
+
+/**
+ * Channel
+ * @constructor
+ * @param type  String the channel name
+ */
+var Channel = function (type, sticky) {
+    this.type = type;
+    // Map of guid -> function.
+    this.handlers = {};
+    // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
+    this.state = sticky ? 1 : 0;
+    // Used in sticky mode to remember args passed to fire().
+    this.fireArgs = null;
+    // Used by onHasSubscribersChange to know if there are any listeners.
+    this.numHandlers = 0;
+    // Function that is called when the first listener is subscribed, or when
+    // the last listener is unsubscribed.
+    this.onHasSubscribersChange = null;
+};
+var channel = {
+    /**
+     * Calls the provided function only after all of the channels specified
+     * have been fired. All channels must be sticky channels.
+     */
+    join: function (h, c) {
+        var len = c.length;
+        var i = len;
+        var f = function () {
+            if (!(--i)) h();
+        };
+        for (var j = 0; j < len; j++) {
+            if (c[j].state === 0) {
+                throw Error('Can only use join with sticky channels.');
+            }
+            c[j].subscribe(f);
+        }
+        if (!len) h();
+    },
+    /* eslint-disable no-return-assign */
+    create: function (type) {
+        return channel[type] = new Channel(type, false);
+    },
+    createSticky: function (type) {
+        return channel[type] = new Channel(type, true);
+    },
+    /* eslint-enable no-return-assign */
+    /**
+     * cordova Channels that must fire before "deviceready" is fired.
+     */
+    deviceReadyChannelsArray: [],
+    deviceReadyChannelsMap: {},
+
+    /**
+     * Indicate that a feature needs to be initialized before it is ready to be used.
+     * This holds up Cordova's "deviceready" event until the feature has been initialized
+     * and Cordova.initComplete(feature) is called.
+     *
+     * @param feature {String}     The unique feature name
+     */
+    waitForInitialization: function (feature) {
+        if (feature) {
+            var c = channel[feature] || this.createSticky(feature);
+            this.deviceReadyChannelsMap[feature] = c;
+            this.deviceReadyChannelsArray.push(c);
+        }
+    },
+
+    /**
+     * Indicate that initialization code has completed and the feature is ready to be used.
+     *
+     * @param feature {String}     The unique feature name
+     */
+    initializationComplete: function (feature) {
+        var c = this.deviceReadyChannelsMap[feature];
+        if (c) {
+            c.fire();
+        }
+    }
+};
+
+function checkSubscriptionArgument (argument) {
+    if (typeof argument !== 'function' && typeof argument.handleEvent !== 'function') {
+        throw new Error(
+            'Must provide a function or an EventListener object ' +
+                'implementing the handleEvent interface.'
+        );
+    }
+}
+
+/**
+ * Subscribes the given function to the channel. Any time that
+ * Channel.fire is called so too will the function.
+ * Optionally specify an execution context for the function
+ * and a guid that can be used to stop subscribing to the channel.
+ * Returns the guid.
+ */
+Channel.prototype.subscribe = function (eventListenerOrFunction, eventListener) {
+    checkSubscriptionArgument(eventListenerOrFunction);
+    var handleEvent, guid;
+
+    if (eventListenerOrFunction && typeof eventListenerOrFunction === 'object') {
+        // Received an EventListener object implementing the handleEvent interface
+        handleEvent = eventListenerOrFunction.handleEvent;
+        eventListener = eventListenerOrFunction;
+    } else {
+        // Received a function to handle event
+        handleEvent = eventListenerOrFunction;
+    }
+
+    if (this.state === 2) {
+        handleEvent.apply(eventListener || this, this.fireArgs);
+        return;
+    }
+
+    guid = eventListenerOrFunction.observer_guid;
+    if (typeof eventListener === 'object') {
+        handleEvent = utils.close(eventListener, handleEvent);
+    }
+
+    if (!guid) {
+        // First time any channel has seen this subscriber
+        guid = '' + nextGuid++;
+    }
+    handleEvent.observer_guid = guid;
+    eventListenerOrFunction.observer_guid = guid;
+
+    // Don't add the same handler more than once.
+    if (!this.handlers[guid]) {
+        this.handlers[guid] = handleEvent;
+        this.numHandlers++;
+        if (this.numHandlers === 1) {
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+/**
+ * Unsubscribes the function with the given guid from the channel.
+ */
+Channel.prototype.unsubscribe = function (eventListenerOrFunction) {
+    checkSubscriptionArgument(eventListenerOrFunction);
+    var handleEvent, guid, handler;
+
+    if (eventListenerOrFunction && typeof eventListenerOrFunction === 'object') {
+        // Received an EventListener object implementing the handleEvent interface
+        handleEvent = eventListenerOrFunction.handleEvent;
+    } else {
+        // Received a function to handle event
+        handleEvent = eventListenerOrFunction;
+    }
+
+    guid = handleEvent.observer_guid;
+    handler = this.handlers[guid];
+    if (handler) {
+        delete this.handlers[guid];
+        this.numHandlers--;
+        if (this.numHandlers === 0) {
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+/**
+ * Calls all functions subscribed to this channel.
+ */
+Channel.prototype.fire = function (e) {
+    var fail = false; // eslint-disable-line no-unused-vars
+    var fireArgs = Array.prototype.slice.call(arguments);
+    // Apply stickiness.
+    if (this.state === 1) {
+        this.state = 2;
+        this.fireArgs = fireArgs;
+    }
+    if (this.numHandlers) {
+        // Copy the values first so that it is safe to modify it from within
+        // callbacks.
+        var toCall = [];
+        for (var item in this.handlers) {
+            toCall.push(this.handlers[item]);
+        }
+        for (var i = 0; i < toCall.length; ++i) {
+            toCall[i].apply(this, fireArgs);
+        }
+        if (this.state === 2 && this.numHandlers) {
+            this.numHandlers = 0;
+            this.handlers = {};
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+// defining them here so they are ready super fast!
+// DOM event that is received when the web page is loaded and parsed.
+channel.createSticky('onDOMContentLoaded');
+
+// Event to indicate the Cordova native side is ready.
+channel.createSticky('onNativeReady');
+
+// Event to indicate that all Cordova JavaScript objects have been created
+// and it's time to run plugin constructors.
+channel.createSticky('onCordovaReady');
+
+// Event to indicate that all automatically loaded JS plugins are loaded and ready.
+// FIXME remove this
+channel.createSticky('onPluginsReady');
+
+// Event to indicate that Cordova is ready
+channel.createSticky('onDeviceReady');
+
+// Event to indicate a resume lifecycle event
+channel.create('onResume');
+
+// Event to indicate a pause lifecycle event
+channel.create('onPause');
+
+// Channels that must fire before "deviceready" is fired.
+channel.waitForInitialization('onCordovaReady');
+channel.waitForInitialization('onDOMContentLoaded');
+
+module.exports = channel;
+
+});
+
+// file: /Users/erisu/git/apache/cordova/cordova-android/cordova-js-src/exec.js
+define("cordova/exec", function(require, exports, module) {
+
+/**
+ * Execute a cordova command.  It is up to the native side whether this action
+ * is synchronous or asynchronous.  The native side can return:
+ *      Synchronous: PluginResult object as a JSON string
+ *      Asynchronous: Empty string ""
+ * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
+ * depending upon the result of the action.
+ *
+ * @param {Function} success    The success callback
+ * @param {Function} fail       The fail callback
+ * @param {String} service      The name of the service to use
+ * @param {String} action       Action to be run in cordova
+ * @param {String[]} [args]     Zero or more arguments to pass to the method
+ */
+var cordova = require('cordova'),
+    nativeApiProvider = require('cordova/android/nativeapiprovider'),
+    utils = require('cordova/utils'),
+    base64 = require('cordova/base64'),
+    channel = require('cordova/channel'),
+    jsToNativeModes = {
+        PROMPT: 0,
+        JS_OBJECT: 1
+    },
+    nativeToJsModes = {
+        // Polls for messages using the JS->Native bridge.
+        POLLING: 0,
+        // For LOAD_URL to be viable, it would need to have a work-around for
+        // the bug where the soft-keyboard gets dismissed when a message is sent.
+        LOAD_URL: 1,
+        // For the ONLINE_EVENT to be viable, it would need to intercept all event
+        // listeners (both through addEventListener and window.ononline) as well
+        // as set the navigator property itself.
+        ONLINE_EVENT: 2,
+        EVAL_BRIDGE: 3
+    },
+    jsToNativeBridgeMode,  // Set lazily.
+    nativeToJsBridgeMode = nativeToJsModes.EVAL_BRIDGE,
+    pollEnabled = false,
+    bridgeSecret = -1;
+
+var messagesFromNative = [];
+var isProcessing = false;
+var resolvedPromise = typeof Promise == 'undefined' ? null : Promise.resolve();
+var nextTick = resolvedPromise ? function(fn) { resolvedPromise.then(fn); } : function(fn) { setTimeout(fn); };
+
+function androidExec(success, fail, service, action, args) {
+    if (bridgeSecret < 0) {
+        // If we ever catch this firing, we'll need to queue up exec()s
+        // and fire them once we get a secret. For now, I don't think
+        // it's possible for exec() to be called since plugins are parsed but
+        // not run until until after onNativeReady.
+        throw new Error('exec() called without bridgeSecret');
+    }
+    // Set default bridge modes if they have not already been set.
+    // By default, we use the failsafe, since addJavascriptInterface breaks too often
+    if (jsToNativeBridgeMode === undefined) {
+        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
+    }
+
+    // If args is not provided, default to an empty array
+    args = args || [];
+
+    // Process any ArrayBuffers in the args into a string.
+    for (var i = 0; i < args.length; i++) {
+        if (utils.typeName(args[i]) == 'ArrayBuffer') {
+            args[i] = base64.fromArrayBuffer(args[i]);
+        }
+    }
+
+    var callbackId = service + cordova.callbackId++,
+        argsJson = JSON.stringify(args);
+    if (success || fail) {
+        cordova.callbacks[callbackId] = {success:success, fail:fail};
+    }
+
+    var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);
+    // If argsJson was received by Java as null, try again with the PROMPT bridge mode.
+    // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2.  See CB-2666.
+    if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && msgs === "@Null arguments.") {
+        androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
+        androidExec(success, fail, service, action, args);
+        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
+    } else if (msgs) {
+        messagesFromNative.push(msgs);
+        // Always process async to avoid exceptions messing up stack.
+        nextTick(processMessages);
+    }
+}
+
+androidExec.init = function() {
+    bridgeSecret = +prompt('', 'gap_init:' + nativeToJsBridgeMode);
+    channel.onNativeReady.fire();
+};
+
+function pollOnceFromOnlineEvent() {
+    pollOnce(true);
+}
+
+function pollOnce(opt_fromOnlineEvent) {
+    if (bridgeSecret < 0) {
+        // This can happen when the NativeToJsMessageQueue resets the online state on page transitions.
+        // We know there's nothing to retrieve, so no need to poll.
+        return;
+    }
+    var msgs = nativeApiProvider.get().retrieveJsMessages(bridgeSecret, !!opt_fromOnlineEvent);
+    if (msgs) {
+        messagesFromNative.push(msgs);
+        // Process sync since we know we're already top-of-stack.
+        processMessages();
+    }
+}
+
+function pollingTimerFunc() {
+    if (pollEnabled) {
+        pollOnce();
+        setTimeout(pollingTimerFunc, 50);
+    }
+}
+
+function hookOnlineApis() {
+    function proxyEvent(e) {
+        cordova.fireWindowEvent(e.type);
+    }
+    // The network module takes care of firing online and offline events.
+    // It currently fires them only on document though, so we bridge them
+    // to window here (while first listening for exec()-releated online/offline
+    // events).
+    window.addEventListener('online', pollOnceFromOnlineEvent, false);
+    window.addEventListener('offline', pollOnceFromOnlineEvent, false);
+    cordova.addWindowEventHandler('online');
+    cordova.addWindowEventHandler('offline');
+    document.addEventListener('online', proxyEvent, false);
+    document.addEventListener('offline', proxyEvent, false);
+}
+
+hookOnlineApis();
+
+androidExec.jsToNativeModes = jsToNativeModes;
+androidExec.nativeToJsModes = nativeToJsModes;
+
+androidExec.setJsToNativeBridgeMode = function(mode) {
+    if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {
+        mode = jsToNativeModes.PROMPT;
+    }
+    nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);
+    jsToNativeBridgeMode = mode;
+};
+
+androidExec.setNativeToJsBridgeMode = function(mode) {
+    if (mode == nativeToJsBridgeMode) {
+        return;
+    }
+    if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {
+        pollEnabled = false;
+    }
+
+    nativeToJsBridgeMode = mode;
+    // Tell the native side to switch modes.
+    // Otherwise, it will be set by androidExec.init()
+    if (bridgeSecret >= 0) {
+        nativeApiProvider.get().setNativeToJsBridgeMode(bridgeSecret, mode);
+    }
+
+    if (mode == nativeToJsModes.POLLING) {
+        pollEnabled = true;
+        setTimeout(pollingTimerFunc, 1);
+    }
+};
+
+function buildPayload(payload, message) {
+    var payloadKind = message.charAt(0);
+    if (payloadKind == 's') {
+        payload.push(message.slice(1));
+    } else if (payloadKind == 't') {
+        payload.push(true);
+    } else if (payloadKind == 'f') {
+        payload.push(false);
+    } else if (payloadKind == 'N') {
+        payload.push(null);
+    } else if (payloadKind == 'n') {
+        payload.push(+message.slice(1));
+    } else if (payloadKind == 'A') {
+        var data = message.slice(1);
+        payload.push(base64.toArrayBuffer(data));
+    } else if (payloadKind == 'S') {
+        payload.push(window.atob(message.slice(1)));
+    } else if (payloadKind == 'M') {
+        var multipartMessages = message.slice(1);
+        while (multipartMessages !== "") {
+            var spaceIdx = multipartMessages.indexOf(' ');
+            var msgLen = +multipartMessages.slice(0, spaceIdx);
+            var multipartMessage = multipartMessages.substr(spaceIdx + 1, msgLen);
+            multipartMessages = multipartMessages.slice(spaceIdx + msgLen + 1);
+            buildPayload(payload, multipartMessage);
+        }
+    } else {
+        payload.push(JSON.parse(message));
+    }
+}
+
+// Processes a single message, as encoded by NativeToJsMessageQueue.java.
+function processMessage(message) {
+    var firstChar = message.charAt(0);
+    if (firstChar == 'J') {
+        // This is deprecated on the .java side. It doesn't work with CSP enabled.
+        eval(message.slice(1));
+    } else if (firstChar == 'S' || firstChar == 'F') {
+        var success = firstChar == 'S';
+        var keepCallback = message.charAt(1) == '1';
+        var spaceIdx = message.indexOf(' ', 2);
+        var status = +message.slice(2, spaceIdx);
+        var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);
+        var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);
+        var payloadMessage = message.slice(nextSpaceIdx + 1);
+        var payload = [];
+        buildPayload(payload, payloadMessage);
+        cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);
+    } else {
+        console.log("processMessage failed: invalid message: " + JSON.stringify(message));
+    }
+}
+
+function processMessages() {
+    // Check for the reentrant case.
+    if (isProcessing) {
+        return;
+    }
+    if (messagesFromNative.length === 0) {
+        return;
+    }
+    isProcessing = true;
+    try {
+        var msg = popMessageFromQueue();
+        // The Java side can send a * message to indicate that it
+        // still has messages waiting to be retrieved.
+        if (msg == '*' && messagesFromNative.length === 0) {
+            nextTick(pollOnce);
+            return;
+        }
+        processMessage(msg);
+    } finally {
+        isProcessing = false;
+        if (messagesFromNative.length > 0) {
+            nextTick(processMessages);
+        }
+    }
+}
+
+function popMessageFromQueue() {
+    var messageBatch = messagesFromNative.shift();
+    if (messageBatch == '*') {
+        return '*';
+    }
+
+    var spaceIdx = messageBatch.indexOf(' ');
+    var msgLen = +messageBatch.slice(0, spaceIdx);
+    var message = messageBatch.substr(spaceIdx + 1, msgLen);
+    messageBatch = messageBatch.slice(spaceIdx + msgLen + 1);
+    if (messageBatch) {
+        messagesFromNative.unshift(messageBatch);
+    }
+    return message;
+}
+
+module.exports = androidExec;
+
+});
+
+// file: src/common/exec/proxy.js
+define("cordova/exec/proxy", function(require, exports, module) {
+
+// internal map of proxy function
+var CommandProxyMap = {};
+
+module.exports = {
+
+    // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);
+    add: function (id, proxyObj) {
+        console.log('adding proxy for ' + id);
+        CommandProxyMap[id] = proxyObj;
+        return proxyObj;
+    },
+
+    // cordova.commandProxy.remove("Accelerometer");
+    remove: function (id) {
+        var proxy = CommandProxyMap[id];
+        delete CommandProxyMap[id];
+        CommandProxyMap[id] = null;
+        return proxy;
+    },
+
+    get: function (service, action) {
+        return (CommandProxyMap[service] ? CommandProxyMap[service][action] : null);
+    }
+};
+
+});
+
+// file: src/common/init.js
+define("cordova/init", function(require, exports, module) {
+
+var channel = require('cordova/channel');
+var cordova = require('cordova');
+var modulemapper = require('cordova/modulemapper');
+var platform = require('cordova/platform');
+var pluginloader = require('cordova/pluginloader');
+var utils = require('cordova/utils');
+
+var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady];
+
+function logUnfiredChannels (arr) {
+    for (var i = 0; i < arr.length; ++i) {
+        if (arr[i].state !== 2) {
+            console.log('Channel not fired: ' + arr[i].type);
+        }
+    }
+}
+
+window.setTimeout(function () {
+    if (channel.onDeviceReady.state !== 2) {
+        console.log('deviceready has not fired after 5 seconds.');
+        logUnfiredChannels(platformInitChannelsArray);
+        logUnfiredChannels(channel.deviceReadyChannelsArray);
+    }
+}, 5000);
+
+// Replace navigator before any modules are required(), to ensure it happens as soon as possible.
+// We replace it so that properties that can't be clobbered can instead be overridden.
+function replaceNavigator (origNavigator) {
+    var CordovaNavigator = function () {};
+    CordovaNavigator.prototype = origNavigator;
+    var newNavigator = new CordovaNavigator();
+    // This work-around really only applies to new APIs that are newer than Function.bind.
+    // Without it, APIs such as getGamepads() break.
+    if (CordovaNavigator.bind) {
+        for (var key in origNavigator) {
+            if (typeof origNavigator[key] === 'function') {
+                newNavigator[key] = origNavigator[key].bind(origNavigator);
+            } else {
+                (function (k) {
+                    utils.defineGetterSetter(newNavigator, key, function () {
+                        return origNavigator[k];
+                    });
+                })(key);
+            }
+        }
+    }
+    return newNavigator;
+}
+
+if (window.navigator) {
+    window.navigator = replaceNavigator(window.navigator);
+}
+
+if (!window.console) {
+    window.console = {
+        log: function () {}
+    };
+}
+if (!window.console.warn) {
+    window.console.warn = function (msg) {
+        this.log('warn: ' + msg);
+    };
+}
+
+// Register pause, resume and deviceready channels as events on document.
+channel.onPause = cordova.addDocumentEventHandler('pause');
+channel.onResume = cordova.addDocumentEventHandler('resume');
+channel.onActivated = cordova.addDocumentEventHandler('activated');
+channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
+
+// Listen for DOMContentLoaded and notify our channel subscribers.
+if (document.readyState === 'complete' || document.readyState === 'interactive') {
+    channel.onDOMContentLoaded.fire();
+} else {
+    document.addEventListener('DOMContentLoaded', function () {
+        channel.onDOMContentLoaded.fire();
+    }, false);
+}
+
+// _nativeReady is global variable that the native side can set
+// to signify that the native code is ready. It is a global since
+// it may be called before any cordova JS is ready.
+if (window._nativeReady) {
+    channel.onNativeReady.fire();
+}
+
+modulemapper.clobbers('cordova', 'cordova');
+modulemapper.clobbers('cordova/exec', 'cordova.exec');
+modulemapper.clobbers('cordova/exec', 'Cordova.exec');
+
+// Call the platform-specific initialization.
+platform.bootstrap && platform.bootstrap();
+
+// Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js.
+// The delay allows the attached modules to be defined before the plugin loader looks for them.
+setTimeout(function () {
+    pluginloader.load(function () {
+        channel.onPluginsReady.fire();
+    });
+}, 0);
+
+/**
+ * Create all cordova objects once native side is ready.
+ */
+channel.join(function () {
+    modulemapper.mapModules(window);
+
+    platform.initialize && platform.initialize();
+
+    // Fire event to notify that all objects are created
+    channel.onCordovaReady.fire();
+
+    // Fire onDeviceReady event once page has fully loaded, all
+    // constructors have run and cordova info has been received from native
+    // side.
+    channel.join(function () {
+        require('cordova').fireDocumentEvent('deviceready');
+    }, channel.deviceReadyChannelsArray);
+
+}, platformInitChannelsArray);
+
+});
+
+// file: src/common/modulemapper.js
+define("cordova/modulemapper", function(require, exports, module) {
+
+var builder = require('cordova/builder');
+var moduleMap = define.moduleMap; // eslint-disable-line no-undef
+var symbolList;
+var deprecationMap;
+
+exports.reset = function () {
+    symbolList = [];
+    deprecationMap = {};
+};
+
+function addEntry (strategy, moduleName, symbolPath, opt_deprecationMessage) {
+    if (!(moduleName in moduleMap)) {
+        throw new Error('Module ' + moduleName + ' does not exist.');
+    }
+    symbolList.push(strategy, moduleName, symbolPath);
+    if (opt_deprecationMessage) {
+        deprecationMap[symbolPath] = opt_deprecationMessage;
+    }
+}
+
+// Note: Android 2.3 does have Function.bind().
+exports.clobbers = function (moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('c', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.merges = function (moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('m', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.defaults = function (moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('d', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.runs = function (moduleName) {
+    addEntry('r', moduleName, null);
+};
+
+function prepareNamespace (symbolPath, context) {
+    if (!symbolPath) {
+        return context;
+    }
+    var parts = symbolPath.split('.');
+    var cur = context;
+    for (var i = 0, part; part = parts[i]; ++i) { // eslint-disable-line no-cond-assign
+        cur = cur[part] = cur[part] || {};
+    }
+    return cur;
+}
+
+exports.mapModules = function (context) {
+    var origSymbols = {};
+    context.CDV_origSymbols = origSymbols;
+    for (var i = 0, len = symbolList.length; i < len; i += 3) {
+        var strategy = symbolList[i];
+        var moduleName = symbolList[i + 1];
+        var module = require(moduleName);
+        // <runs/>
+        if (strategy === 'r') {
+            continue;
+        }
+        var symbolPath = symbolList[i + 2];
+        var lastDot = symbolPath.lastIndexOf('.');
+        var namespace = symbolPath.substr(0, lastDot);
+        var lastName = symbolPath.substr(lastDot + 1);
+
+        var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;
+        var parentObj = prepareNamespace(namespace, context);
+        var target = parentObj[lastName];
+
+        if (strategy === 'm' && target) {
+            builder.recursiveMerge(target, module);
+        } else if ((strategy === 'd' && !target) || (strategy !== 'd')) {
+            if (!(symbolPath in origSymbols)) {
+                origSymbols[symbolPath] = target;
+            }
+            builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
+        }
+    }
+};
+
+exports.getOriginalSymbol = function (context, symbolPath) {
+    var origSymbols = context.CDV_origSymbols;
+    if (origSymbols && (symbolPath in origSymbols)) {
+        return origSymbols[symbolPath];
+    }
+    var parts = symbolPath.split('.');
+    var obj = context;
+    for (var i = 0; i < parts.length; ++i) {
+        obj = obj && obj[parts[i]];
+    }
+    return obj;
+};
+
+exports.reset();
+
+});
+
+// file: /Users/erisu/git/apache/cordova/cordova-android/cordova-js-src/platform.js
+define("cordova/platform", function(require, exports, module) {
+
+// The last resume event that was received that had the result of a plugin call.
+var lastResumeEvent = null;
+
+module.exports = {
+    id: 'android',
+    bootstrap: function() {
+        var channel = require('cordova/channel'),
+            cordova = require('cordova'),
+            exec = require('cordova/exec'),
+            modulemapper = require('cordova/modulemapper');
+
+        // Get the shared secret needed to use the bridge.
+        exec.init();
+
+        // TODO: Extract this as a proper plugin.
+        modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');
+
+        var APP_PLUGIN_NAME = Number(cordova.platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';
+
+        // Inject a listener for the backbutton on the document.
+        var backButtonChannel = cordova.addDocumentEventHandler('backbutton');
+        backButtonChannel.onHasSubscribersChange = function() {
+            // If we just attached the first handler or detached the last handler,
+            // let native know we need to override the back button.
+            exec(null, null, APP_PLUGIN_NAME, "overrideBackbutton", [this.numHandlers == 1]);
+        };
+
+        // Add hardware MENU and SEARCH button handlers
+        cordova.addDocumentEventHandler('menubutton');
+        cordova.addDocumentEventHandler('searchbutton');
+
+        function bindButtonChannel(buttonName) {
+            // generic button bind used for volumeup/volumedown buttons
+            var volumeButtonChannel = cordova.addDocumentEventHandler(buttonName + 'button');
+            volumeButtonChannel.onHasSubscribersChange = function() {
+                exec(null, null, APP_PLUGIN_NAME, "overrideButton", [buttonName, this.numHandlers == 1]);
+            };
+        }
+        // Inject a listener for the volume buttons on the document.
+        bindButtonChannel('volumeup');
+        bindButtonChannel('volumedown');
+
+        // The resume event is not "sticky", but it is possible that the event
+        // will contain the result of a plugin call. We need to ensure that the
+        // plugin result is delivered even after the event is fired (CB-10498)
+        var cordovaAddEventListener = document.addEventListener;
+
+        document.addEventListener = function(evt, handler, capture) {
+            cordovaAddEventListener(evt, handler, capture);
+
+            if (evt === 'resume' && lastResumeEvent) {
+                handler(lastResumeEvent);
+            }
+        };
+
+        // Let native code know we are all done on the JS side.
+        // Native code will then un-hide the WebView.
+        channel.onCordovaReady.subscribe(function() {
+            exec(onMessageFromNative, null, APP_PLUGIN_NAME, 'messageChannel', []);
+            exec(null, null, APP_PLUGIN_NAME, "show", []);
+        });
+    }
+};
+
+function onMessageFromNative(msg) {
+    var cordova = require('cordova');
+    var action = msg.action;
+
+    switch (action)
+    {
+        // Button events
+        case 'backbutton':
+        case 'menubutton':
+        case 'searchbutton':
+        // App life cycle events
+        case 'pause':
+        // Volume events
+        case 'volumedownbutton':
+        case 'volumeupbutton':
+            cordova.fireDocumentEvent(action);
+            break;
+        case 'resume':
+            if(arguments.length > 1 && msg.pendingResult) {
+                if(arguments.length === 2) {
+                    msg.pendingResult.result = arguments[1];
+                } else {
+                    // The plugin returned a multipart message
+                    var res = [];
+                    for(var i = 1; i < arguments.length; i++) {
+                        res.push(arguments[i]);
+                    }
+                    msg.pendingResult.result = res;
+                }
+
+                // Save the plugin result so that it can be delivered to the js
+                // even if they miss the initial firing of the event
+                lastResumeEvent = msg;
+            }
+            cordova.fireDocumentEvent(action, msg);
+            break;
+        default:
+            throw new Error('Unknown event action ' + action);
+    }
+}
+
+});
+
+// file: /Users/erisu/git/apache/cordova/cordova-android/cordova-js-src/plugin/android/app.js
+define("cordova/plugin/android/app", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+var APP_PLUGIN_NAME = Number(require('cordova').platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';
+
+module.exports = {
+    /**
+    * Clear the resource cache.
+    */
+    clearCache:function() {
+        exec(null, null, APP_PLUGIN_NAME, "clearCache", []);
+    },
+
+    /**
+    * Load the url into the webview or into new browser instance.
+    *
+    * @param url           The URL to load
+    * @param props         Properties that can be passed in to the activity:
+    *      wait: int                           => wait msec before loading URL
+    *      loadingDialog: "Title,Message"      => display a native loading dialog
+    *      loadUrlTimeoutValue: int            => time in msec to wait before triggering a timeout error
+    *      clearHistory: boolean              => clear webview history (default=false)
+    *      openExternal: boolean              => open in a new browser (default=false)
+    *
+    * Example:
+    *      navigator.app.loadUrl("http://server/myapp/index.html", {wait:2000, loadingDialog:"Wait,Loading App", loadUrlTimeoutValue: 60000});
+    */
+    loadUrl:function(url, props) {
+        exec(null, null, APP_PLUGIN_NAME, "loadUrl", [url, props]);
+    },
+
+    /**
+    * Cancel loadUrl that is waiting to be loaded.
+    */
+    cancelLoadUrl:function() {
+        exec(null, null, APP_PLUGIN_NAME, "cancelLoadUrl", []);
+    },
+
+    /**
+    * Clear web history in this web view.
+    * Instead of BACK button loading the previous web page, it will exit the app.
+    */
+    clearHistory:function() {
+        exec(null, null, APP_PLUGIN_NAME, "clearHistory", []);
+    },
+
+    /**
+    * Go to previous page displayed.
+    * This is the same as pressing the backbutton on Android device.
+    */
+    backHistory:function() {
+        exec(null, null, APP_PLUGIN_NAME, "backHistory", []);
+    },
+
+    /**
+    * Override the default behavior of the Android back button.
+    * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
+    *
+    * Note: The user should not have to call this method.  Instead, when the user
+    *       registers for the "backbutton" event, this is automatically done.
+    *
+    * @param override        T=override, F=cancel override
+    */
+    overrideBackbutton:function(override) {
+        exec(null, null, APP_PLUGIN_NAME, "overrideBackbutton", [override]);
+    },
+
+    /**
+    * Override the default behavior of the Android volume button.
+    * If overridden, when the volume button is pressed, the "volume[up|down]button"
+    * JavaScript event will be fired.
+    *
+    * Note: The user should not have to call this method.  Instead, when the user
+    *       registers for the "volume[up|down]button" event, this is automatically done.
+    *
+    * @param button          volumeup, volumedown
+    * @param override        T=override, F=cancel override
+    */
+    overrideButton:function(button, override) {
+        exec(null, null, APP_PLUGIN_NAME, "overrideButton", [button, override]);
+    },
+
+    /**
+    * Exit and terminate the application.
+    */
+    exitApp:function() {
+        return exec(null, null, APP_PLUGIN_NAME, "exitApp", []);
+    }
+};
+
+});
+
+// file: src/common/pluginloader.js
+define("cordova/pluginloader", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+// Helper function to inject a <script> tag.
+// Exported for testing.
+exports.injectScript = function (url, onload, onerror) {
+    var script = document.createElement('script');
+    // onload fires even when script fails loads with an error.
+    script.onload = onload;
+    // onerror fires for malformed URLs.
+    script.onerror = onerror;
+    script.src = url;
+    document.head.appendChild(script);
+};
+
+function injectIfNecessary (id, url, onload, onerror) {
+    onerror = onerror || onload;
+    if (id in define.moduleMap) { // eslint-disable-line no-undef
+        onload();
+    } else {
+        exports.injectScript(url, function () {
+            if (id in define.moduleMap) { // eslint-disable-line no-undef
+                onload();
+            } else {
+                onerror();
+            }
+        }, onerror);
+    }
+}
+
+function onScriptLoadingComplete (moduleList, finishPluginLoading) {
+    // Loop through all the plugins and then through their clobbers and merges.
+    for (var i = 0, module; module = moduleList[i]; i++) { // eslint-disable-line no-cond-assign
+        if (module.clobbers && module.clobbers.length) {
+            for (var j = 0; j < module.clobbers.length; j++) {
+                modulemapper.clobbers(module.id, module.clobbers[j]);
+            }
+        }
+
+        if (module.merges && module.merges.length) {
+            for (var k = 0; k < module.merges.length; k++) {
+                modulemapper.merges(module.id, module.merges[k]);
+            }
+        }
+
+        // Finally, if runs is truthy we want to simply require() the module.
+        if (module.runs) {
+            modulemapper.runs(module.id);
+        }
+    }
+
+    finishPluginLoading();
+}
+
+// Handler for the cordova_plugins.js content.
+// See plugman's plugin_loader.js for the details of this object.
+// This function is only called if the really is a plugins array that isn't empty.
+// Otherwise the onerror response handler will just call finishPluginLoading().
+function handlePluginsObject (path, moduleList, finishPluginLoading) {
+    // Now inject the scripts.
+    var scriptCounter = moduleList.length;
+
+    if (!scriptCounter) {
+        finishPluginLoading();
+        return;
+    }
+    function scriptLoadedCallback () {
+        if (!--scriptCounter) {
+            onScriptLoadingComplete(moduleList, finishPluginLoading);
+        }
+    }
+
+    for (var i = 0; i < moduleList.length; i++) {
+        injectIfNecessary(moduleList[i].id, path + moduleList[i].file, scriptLoadedCallback);
+    }
+}
+
+function findCordovaPath () {
+    var path = null;
+    var scripts = document.getElementsByTagName('script');
+    var term = '/cordova.js';
+    for (var n = scripts.length - 1; n > -1; n--) {
+        var src = scripts[n].src.replace(/\?.*$/, ''); // Strip any query param (CB-6007).
+        if (src.indexOf(term) === (src.length - term.length)) {
+            path = src.substring(0, src.length - term.length) + '/';
+            break;
+        }
+    }
+    return path;
+}
+
+// Tries to load all plugins' js-modules.
+// This is an async process, but onDeviceReady is blocked on onPluginsReady.
+// onPluginsReady is fired when there are no plugins to load, or they are all done.
+exports.load = function (callback) {
+    var pathPrefix = findCordovaPath();
+    if (pathPrefix === null) {
+        console.log('Could not find cordova.js script tag. Plugin loading may fail.');
+        pathPrefix = '';
+    }
+    injectIfNecessary('cordova/plugin_list', pathPrefix + 'cordova_plugins.js', function () {
+        var moduleList = require('cordova/plugin_list');
+        handlePluginsObject(pathPrefix, moduleList, callback);
+    }, callback);
+};
+
+});
+
+// file: src/common/urlutil.js
+define("cordova/urlutil", function(require, exports, module) {
+
+/**
+ * For already absolute URLs, returns what is passed in.
+ * For relative URLs, converts them to absolute ones.
+ */
+exports.makeAbsolute = function makeAbsolute (url) {
+    var anchorEl = document.createElement('a');
+    anchorEl.href = url;
+    return anchorEl.href;
+};
+
+});
+
+// file: src/common/utils.js
+define("cordova/utils", function(require, exports, module) {
+
+var utils = exports;
+
+/**
+ * Defines a property getter / setter for obj[key].
+ */
+utils.defineGetterSetter = function (obj, key, getFunc, opt_setFunc) {
+    if (Object.defineProperty) {
+        var desc = {
+            get: getFunc,
+            configurable: true
+        };
+        if (opt_setFunc) {
+            desc.set = opt_setFunc;
+        }
+        Object.defineProperty(obj, key, desc);
+    } else {
+        obj.__defineGetter__(key, getFunc);
+        if (opt_setFunc) {
+            obj.__defineSetter__(key, opt_setFunc);
+        }
+    }
+};
+
+/**
+ * Defines a property getter for obj[key].
+ */
+utils.defineGetter = utils.defineGetterSetter;
+
+utils.arrayIndexOf = function (a, item) {
+    if (a.indexOf) {
+        return a.indexOf(item);
+    }
+    var len = a.length;
+    for (var i = 0; i < len; ++i) {
+        if (a[i] === item) {
+            return i;
+        }
+    }
+    return -1;
+};
+
+/**
+ * Returns whether the item was found in the array.
+ */
+utils.arrayRemove = function (a, item) {
+    var index = utils.arrayIndexOf(a, item);
+    if (index !== -1) {
+        a.splice(index, 1);
+    }
+    return index !== -1;
+};
+
+utils.typeName = function (val) {
+    return Object.prototype.toString.call(val).slice(8, -1);
+};
+
+/**
+ * Returns an indication of whether the argument is an array or not
+ */
+utils.isArray = Array.isArray ||
+                function (a) { return utils.typeName(a) === 'Array'; };
+
+/**
+ * Returns an indication of whether the argument is a Date or not
+ */
+utils.isDate = function (d) {
+    return (d instanceof Date);
+};
+
+/**
+ * Does a deep clone of the object.
+ */
+utils.clone = function (obj) {
+    if (!obj || typeof obj === 'function' || utils.isDate(obj) || typeof obj !== 'object') {
+        return obj;
+    }
+
+    var retVal, i;
+
+    if (utils.isArray(obj)) {
+        retVal = [];
+        for (i = 0; i < obj.length; ++i) {
+            retVal.push(utils.clone(obj[i]));
+        }
+        return retVal;
+    }
+
+    retVal = {};
+    for (i in obj) {
+        // https://issues.apache.org/jira/browse/CB-11522 'unknown' type may be returned in
+        // custom protocol activation case on Windows Phone 8.1 causing "No such interface supported" exception
+        // on cloning.
+        if ((!(i in retVal) || retVal[i] !== obj[i]) && typeof obj[i] !== 'undefined' && typeof obj[i] !== 'unknown') { // eslint-disable-line valid-typeof
+            retVal[i] = utils.clone(obj[i]);
+        }
+    }
+    return retVal;
+};
+
+/**
+ * Returns a wrapped version of the function
+ */
+utils.close = function (context, func, params) {
+    return function () {
+        var args = params || arguments;
+        return func.apply(context, args);
+    };
+};
+
+// ------------------------------------------------------------------------------
+function UUIDcreatePart (length) {
+    var uuidpart = '';
+    for (var i = 0; i < length; i++) {
+        var uuidchar = parseInt((Math.random() * 256), 10).toString(16);
+        if (uuidchar.length === 1) {
+            uuidchar = '0' + uuidchar;
+        }
+        uuidpart += uuidchar;
+    }
+    return uuidpart;
+}
+
+/**
+ * Create a UUID
+ */
+utils.createUUID = function () {
+    return UUIDcreatePart(4) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(6);
+};
+
+/**
+ * Extends a child object from a parent object using classical inheritance
+ * pattern.
+ */
+utils.extend = (function () {
+    // proxy used to establish prototype chain
+    var F = function () {};
+    // extend Child from Parent
+    return function (Child, Parent) {
+
+        F.prototype = Parent.prototype;
+        Child.prototype = new F();
+        Child.__super__ = Parent.prototype;
+        Child.prototype.constructor = Child;
+    };
+}());
+
+/**
+ * Alerts a message in any available way: alert or console.log.
+ */
+utils.alert = function (msg) {
+    if (window.alert) {
+        window.alert(msg);
+    } else if (console && console.log) {
+        console.log(msg);
+    }
+};
+
+});
+
+window.cordova = require('cordova');
+// file: src/scripts/bootstrap.js
+
+require('cordova/init');
+
+})();
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/cordova_plugins.js b/platforms/android/app/src/main/assets/www/cordova_plugins.js
new file mode 100644
index 0000000..049ccd6
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/cordova_plugins.js
@@ -0,0 +1,339 @@
+cordova.define('cordova/plugin_list', function(require, exports, module) {
+  module.exports = [
+    {
+      "id": "cordova-plugin-fingerprint-aio.Fingerprint",
+      "file": "plugins/cordova-plugin-fingerprint-aio/www/Fingerprint.js",
+      "pluginId": "cordova-plugin-fingerprint-aio",
+      "clobbers": [
+        "Fingerprint"
+      ]
+    },
+    {
+      "id": "cordova-plugin-touch-id.TouchID",
+      "file": "plugins/cordova-plugin-touch-id/www/TouchID.js",
+      "pluginId": "cordova-plugin-touch-id",
+      "clobbers": [
+        "window.plugins.touchid"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.DirectoryEntry",
+      "file": "plugins/cordova-plugin-file/www/DirectoryEntry.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.DirectoryEntry"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.DirectoryReader",
+      "file": "plugins/cordova-plugin-file/www/DirectoryReader.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.DirectoryReader"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.Entry",
+      "file": "plugins/cordova-plugin-file/www/Entry.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.Entry"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.File",
+      "file": "plugins/cordova-plugin-file/www/File.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.File"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileEntry",
+      "file": "plugins/cordova-plugin-file/www/FileEntry.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileEntry"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileError",
+      "file": "plugins/cordova-plugin-file/www/FileError.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileError"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileReader",
+      "file": "plugins/cordova-plugin-file/www/FileReader.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileReader"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileSystem",
+      "file": "plugins/cordova-plugin-file/www/FileSystem.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileSystem"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileUploadOptions",
+      "file": "plugins/cordova-plugin-file/www/FileUploadOptions.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileUploadOptions"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileUploadResult",
+      "file": "plugins/cordova-plugin-file/www/FileUploadResult.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileUploadResult"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileWriter",
+      "file": "plugins/cordova-plugin-file/www/FileWriter.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileWriter"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.Flags",
+      "file": "plugins/cordova-plugin-file/www/Flags.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.Flags"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.LocalFileSystem",
+      "file": "plugins/cordova-plugin-file/www/LocalFileSystem.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.LocalFileSystem"
+      ],
+      "merges": [
+        "window"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.Metadata",
+      "file": "plugins/cordova-plugin-file/www/Metadata.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.Metadata"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.ProgressEvent",
+      "file": "plugins/cordova-plugin-file/www/ProgressEvent.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.ProgressEvent"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.fileSystems",
+      "file": "plugins/cordova-plugin-file/www/fileSystems.js",
+      "pluginId": "cordova-plugin-file"
+    },
+    {
+      "id": "cordova-plugin-file.requestFileSystem",
+      "file": "plugins/cordova-plugin-file/www/requestFileSystem.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.requestFileSystem"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.resolveLocalFileSystemURI",
+      "file": "plugins/cordova-plugin-file/www/resolveLocalFileSystemURI.js",
+      "pluginId": "cordova-plugin-file",
+      "merges": [
+        "window"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.isChrome",
+      "file": "plugins/cordova-plugin-file/www/browser/isChrome.js",
+      "pluginId": "cordova-plugin-file",
+      "runs": true
+    },
+    {
+      "id": "cordova-plugin-file.androidFileSystem",
+      "file": "plugins/cordova-plugin-file/www/android/FileSystem.js",
+      "pluginId": "cordova-plugin-file",
+      "merges": [
+        "FileSystem"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.fileSystems-roots",
+      "file": "plugins/cordova-plugin-file/www/fileSystems-roots.js",
+      "pluginId": "cordova-plugin-file",
+      "runs": true
+    },
+    {
+      "id": "cordova-plugin-file.fileSystemPaths",
+      "file": "plugins/cordova-plugin-file/www/fileSystemPaths.js",
+      "pluginId": "cordova-plugin-file",
+      "merges": [
+        "cordova"
+      ],
+      "runs": true
+    },
+    {
+      "id": "cordova-plugin-advanced-http.cookie-handler",
+      "file": "plugins/cordova-plugin-advanced-http/www/cookie-handler.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.global-configs",
+      "file": "plugins/cordova-plugin-advanced-http/www/global-configs.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.helpers",
+      "file": "plugins/cordova-plugin-advanced-http/www/helpers.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.js-util",
+      "file": "plugins/cordova-plugin-advanced-http/www/js-util.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.local-storage-store",
+      "file": "plugins/cordova-plugin-advanced-http/www/local-storage-store.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.lodash",
+      "file": "plugins/cordova-plugin-advanced-http/www/lodash.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.messages",
+      "file": "plugins/cordova-plugin-advanced-http/www/messages.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.public-interface",
+      "file": "plugins/cordova-plugin-advanced-http/www/public-interface.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.tough-cookie",
+      "file": "plugins/cordova-plugin-advanced-http/www/umd-tough-cookie.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.url-util",
+      "file": "plugins/cordova-plugin-advanced-http/www/url-util.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.http",
+      "file": "plugins/cordova-plugin-advanced-http/www/advanced-http.js",
+      "pluginId": "cordova-plugin-advanced-http",
+      "clobbers": [
+        "cordova.plugin.http"
+      ]
+    },
+    {
+      "id": "cordova-plugin-statusbar.statusbar",
+      "file": "plugins/cordova-plugin-statusbar/www/statusbar.js",
+      "pluginId": "cordova-plugin-statusbar",
+      "clobbers": [
+        "window.StatusBar"
+      ]
+    },
+    {
+      "id": "cordova-plugin-qrscanner.QRScanner",
+      "file": "plugins/cordova-plugin-qrscanner/www/www.min.js",
+      "pluginId": "cordova-plugin-qrscanner",
+      "clobbers": [
+        "QRScanner"
+      ]
+    },
+    {
+      "id": "cordova-plugin-camera.Camera",
+      "file": "plugins/cordova-plugin-camera/www/CameraConstants.js",
+      "pluginId": "cordova-plugin-camera",
+      "clobbers": [
+        "Camera"
+      ]
+    },
+    {
+      "id": "cordova-plugin-camera.CameraPopoverOptions",
+      "file": "plugins/cordova-plugin-camera/www/CameraPopoverOptions.js",
+      "pluginId": "cordova-plugin-camera",
+      "clobbers": [
+        "CameraPopoverOptions"
+      ]
+    },
+    {
+      "id": "cordova-plugin-camera.camera",
+      "file": "plugins/cordova-plugin-camera/www/Camera.js",
+      "pluginId": "cordova-plugin-camera",
+      "clobbers": [
+        "navigator.camera"
+      ]
+    },
+    {
+      "id": "cordova-plugin-camera.CameraPopoverHandle",
+      "file": "plugins/cordova-plugin-camera/www/CameraPopoverHandle.js",
+      "pluginId": "cordova-plugin-camera",
+      "clobbers": [
+        "CameraPopoverHandle"
+      ]
+    },
+    {
+      "id": "cordova-plugin-inappbrowser.inappbrowser",
+      "file": "plugins/cordova-plugin-inappbrowser/www/inappbrowser.js",
+      "pluginId": "cordova-plugin-inappbrowser",
+      "clobbers": [
+        "cordova.InAppBrowser.open",
+        "window.open"
+      ]
+    },
+    {
+      "id": "cordova-plugin-device.device",
+      "file": "plugins/cordova-plugin-device/www/device.js",
+      "pluginId": "cordova-plugin-device",
+      "clobbers": [
+        "device"
+      ]
+    },
+    {
+      "id": "cordova-plugin-themeablebrowser.themeablebrowser",
+      "file": "plugins/cordova-plugin-themeablebrowser/www/themeablebrowser.js",
+      "pluginId": "cordova-plugin-themeablebrowser",
+      "clobbers": [
+        "cordova.ThemeableBrowser"
+      ]
+    }
+  ];
+  module.exports.metadata = {
+    "cordova-plugin-add-swift-support": "2.0.2",
+    "cordova-plugin-fingerprint-aio": "1.7.0",
+    "cordova-plugin-touch-id": "3.3.1",
+    "cordova-plugin-whitelist": "1.3.3",
+    "cordova-plugin-file": "6.0.1",
+    "cordova-plugin-advanced-http": "2.1.1",
+    "cordova-plugin-statusbar": "2.4.2",
+    "cordova-plugin-disable-ios11-statusbar": "1.0.0",
+    "cordova-plugin-qrscanner": "3.0.1",
+    "cordova-plugin-camera": "4.0.3",
+    "cordova-plugin-inappbrowser": "3.0.0",
+    "cordova-plugin-device": "2.0.2",
+    "cordova-plugin-themeablebrowser": "0.2.17"
+  };
+});
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/css/aui-iconfont.ttf b/platforms/android/app/src/main/assets/www/css/aui-iconfont.ttf
new file mode 100755
index 0000000..2c9d80e
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/css/aui-iconfont.ttf
Binary files differ
diff --git a/platforms/android/app/src/main/assets/www/css/aui.css b/platforms/android/app/src/main/assets/www/css/aui.css
new file mode 100644
index 0000000..c77e083
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/css/aui.css
@@ -0,0 +1,2731 @@
+/*

+ * =========================================================================

+ * APIClud - AUI UI 框架    流浪男  QQ:343757327  http://www.auicss.com

+ * Verson 2.1

+ * =========================================================================

+ */

+ /*初始化类*/

+@charset "UTF-8";

+html{

+	font-family: "Helvetica Neue", Helvetica, sans-serif;

+	font-size: 20px;

+}

+html,body {

+	-webkit-touch-callout:none;

+	-webkit-text-size-adjust:none;

+	-webkit-tap-highlight-color:rgba(0, 0, 0, 0);

+	-webkit-user-select:none;

+	width: 100%;

+}

+body {

+	line-height: 1.5;

+	font-size: 0.8rem;

+	color: #212121;

+	background-color: #f5f5f5;

+	outline: 0;

+}

+html,body,header,section,footer,div,ul,ol,li,img,a,span,em,del,legend,center,strong,var,fieldset,form,label,dl,dt,dd,cite,input,hr,time,mark,code,figcaption,figure,textarea,h1,h2,h3,h4,h5,h6,p{

+	margin:0;

+	border:0;

+	padding:0;

+	font-style:normal;

+}

+* {

+	-webkit-box-sizing: border-box;

+	      	box-sizing: border-box;

+	-webkit-user-select: none;

+	-webkit-tap-highlight-color: transparent;

+	outline: none;

+}

+@media only screen and (min-width: 400px) {

+	html {

+		font-size: 21.33333333px !important;

+	}

+}

+@media only screen and (min-width: 414px) {

+	html {

+		font-size: 21px !important;

+	}

+}

+@media only screen and (min-width: 480px) {

+	html {

+		font-size: 25.6px !important;

+	}

+}

+ul, li {

+	list-style: none;

+}

+p {

+	font-size: 0.7rem;

+	color: #757575;

+}

+a {

+	color: #0062cc;

+	text-decoration: none;

+	background-color: transparent;

+}

+textarea {

+	overflow: hidden;

+	resize: none;

+}

+button {

+	overflow: visible;

+}

+button,select {

+	text-transform: none;

+}

+button,input,select,textarea {

+	font: inherit;

+	color: inherit;

+}

+/*自动隐藏文字*/

+.aui-ellipsis-1 {

+	overflow: hidden;

+	white-space: nowrap;

+	text-overflow: ellipsis;

+}

+.aui-ellipsis {

+	display: -webkit-box;

+	overflow: hidden;

+	text-overflow: ellipsis;

+	word-wrap: break-word;

+	word-break: break-all;

+	white-space: normal !important;

+	-webkit-line-clamp: 1;

+	-webkit-box-orient: vertical;

+}

+.aui-ellipsis-2 {

+	display: -webkit-box;

+	overflow: hidden;

+	text-overflow: ellipsis;

+	word-wrap: break-word;

+	word-break: break-all;

+	white-space: normal !important;

+	-webkit-line-clamp: 2;

+	-webkit-box-orient: vertical;

+}

+/*水平线*/

+.aui-hr {

+	width: 100%;

+	position: relative;

+	border-top: 1px solid #dddddd;

+	height: 1px;

+}

+@media screen and (-webkit-min-device-pixel-ratio:1.5) {

+	.aui-hr{

+		border: none;

+        background-size: 100% 1px;

+		background-repeat: no-repeat;

+		background-position: top;

+        background-image: linear-gradient(0,#dddddd,#dddddd 50%,transparent 50%);

+        background-image: -webkit-linear-gradient(90deg,#dddddd,#dddddd 50%,transparent 50%);

+	}

+}

+/*内外边距类*/

+.aui-padded-0 {

+	padding: 0 !important;

+}

+.aui-padded-5 {

+	padding: 0.25rem !important;

+}

+.aui-padded-10 {

+	padding: 0.5rem !important;

+}

+.aui-padded-15 {

+	padding: 0.75rem !important;

+}

+.aui-padded-t-0 {

+	padding-top: 0 !important;

+}

+.aui-padded-t-5 {

+	padding-top: 0.25rem !important;

+}

+.aui-padded-t-10 {

+	padding-top: 0.5rem !important;

+}

+.aui-padded-t-15 {

+	padding-top: 0.75rem !important;

+}

+.aui-padded-b-0 {

+	padding-bottom: 0 !important;

+}

+.aui-padded-b-5 {

+	padding-bottom: 0.25rem !important;

+}

+.aui-padded-b-10 {

+	padding-bottom: 0.5rem !important;

+}

+.aui-padded-b-15 {

+	padding-bottom: 0.75rem !important;

+}

+.aui-padded-l-0 {

+	padding-left: 0 !important;

+}

+.aui-padded-l-5 {

+	padding-left: 0.25rem !important;

+}

+.aui-padded-l-10 {

+	padding-left: 0.5rem !important;

+}

+.aui-padded-l-15 {

+	padding-left: 0.75rem !important;

+}

+.aui-padded-r-0 {

+	padding-right: 0 !important;

+}

+.aui-padded-r-5 {

+	padding-right: 0.25rem !important;

+}

+.aui-padded-r-10 {

+	padding-right: 0.5rem !important;

+}

+.aui-padded-r-15 {

+	padding-right: 0.75rem !important;

+}

+.aui-margin-0 {

+	margin: 0 !important;

+}

+.aui-margin-5 {

+	margin: 0.25rem !important;

+}

+.aui-margin-10 {

+	margin: 0.5rem !important;

+}

+.aui-margin-15 {

+	margin: 0.75rem !important;

+}

+.aui-margin-t-0 {

+	margin-top: 0.25rem !important;

+}

+.aui-margin-t-5 {

+	margin-top: 0 !important;

+}

+.aui-margin-t-10 {

+	margin-top: 0.5rem !important;

+}

+.aui-margin-t-15 {

+	margin-top: 0.75rem !important;

+}

+.aui-margin-b-0 {

+	margin-bottom: 0 !important;

+}

+.aui-margin-b-5 {

+	margin-bottom: 0.25rem !important;

+}

+.aui-margin-b-10 {

+	margin-bottom: 0.5rem !important;

+}

+.aui-margin-b-15 {

+	margin-bottom: 0.75rem !important;

+}

+.aui-margin-l-0 {

+	margin-left: 0 !important;

+}

+.aui-margin-l-5 {

+	margin-left: 0.25rem !important;

+}

+.aui-margin-l-10 {

+	margin-left: 0.5rem !important;

+}

+.aui-margin-l-15 {

+	margin-left: 0.75rem !important;

+}

+.aui-margin-r-0 {

+	margin-right: 0 !important;

+}

+.aui-margin-r-5 {

+	margin-right: 0.25rem !important;

+}

+.aui-margin-r-10 {

+	margin-right: 0.5rem !important;

+}

+.aui-margin-r-15 {

+	margin-right: 0.75rem !important;

+}

+.aui-clearfix {

+	clear: both;

+}

+.aui-clearfix:before {

+	display: table;

+	content: " ";

+}

+.aui-clearfix:after {

+	clear: both;

+}

+/*文字对齐*/

+.aui-text-left {

+	text-align: left !important;

+}

+.aui-text-center {

+	text-align: center !important;

+}

+.aui-text-justify {

+	text-align: justify !important;

+}

+.aui-text-right {

+	text-align: right !important;

+}

+/*文字、背景颜色*/

+h1,h2,h3,h4,h5,h6 {

+	font-weight: 400;

+}

+h1 {

+	font-size: 1.2rem;

+}

+h2 {

+	font-size: 1rem;

+}

+h3 {

+	font-size: 0.8rem;

+}

+h4 {

+	font-size: 0.7rem;

+}

+h5 {

+	font-size: 0.7rem;

+	font-weight: normal;

+	color: #757575;

+}

+h6 {

+	font-size: 0.7rem;

+	font-weight: normal;

+	color: #757575;

+}

+h1 small,h2 small,h3 small,h4 small {

+	font-weight: normal;

+	line-height: 1;

+	color: #757575;

+}

+h5 small,h6 small {

+	font-weight: normal;

+	line-height: 1;

+	color: #757575;

+}

+h1 small,h2 small,h3 small {

+	font-size: 65%;

+}

+h4 small,h5 small,h6 small {

+	font-size: 75%;

+}

+img {

+	max-width: 100%;

+	display: block;

+}

+.aui-font-size-12 {

+	font-size: 0.6rem !important;

+}

+.aui-font-size-14 {

+	font-size: 0.7rem !important;

+}

+.aui-font-size-16 {

+	font-size: 0.8rem !important;

+}

+.aui-font-size-18 {

+	font-size: 0.9rem !important;

+}

+.aui-font-size-20 {

+	font-size: 1rem !important;

+}

+.aui-text-default {

+	color: #212121 !important;

+}

+.aui-text-white {

+	color: #ffffff !important;

+}

+.aui-text-primary {

+	color: #00bcd4 !important;

+}

+.aui-text-success {

+	color: #009688 !important;

+}

+.aui-text-info {

+	color: #03a9f4 !important;

+}

+.aui-text-warning {

+	color: #ffc107 !important;

+}

+.aui-text-danger {

+	color: #e51c23 !important;

+}

+.aui-text-pink {

+	color: #e91e63 !important;

+}

+.aui-text-purple {

+	color: #673ab7 !important;

+}

+.aui-text-indigo {

+	color: #3f51b5 !important;

+}

+.aui-text-green {

+	color: #7cba59 !important;

+}

+.aui-text-orange {

+	color: #e0620d !important;

+}

+.aui-bg-default {

+	background-color: #f5f5f5 !important;

+}

+.aui-bg-primary {

+	background-color: #00bcd4 !important;

+}

+.aui-bg-success {

+	background-color: #009688 !important;

+}

+.aui-bg-info {

+	background-color: #03a9f4 !important;

+}

+.aui-bg-warning {

+	background-color: #f1c40f !important;

+}

+.aui-bg-danger {

+	background-color: #e51c23 !important;

+}

+.aui-bg-pink {

+	background-color: #e91e63 !important;

+}

+.aui-bg-purple {

+	background-color: #673ab7 !important;

+}

+.aui-bg-indigo {

+	background-color: #3f51b5 !important;

+}

+.aui-bg-gray {

+	background-color: #8a8a8a !important;

+}

+

+/*警告、成功颜色*/

+.aui-warning,

+.aui-warning label,

+.aui-warning .aui-input,

+.aui-warning .aui-iconfont {

+	color: #e51c23 !important;

+}

+.aui-success,

+.aui-success label,

+.aui-success .aui-input,

+.aui-success .aui-iconfont {

+	color: #009688 !important;

+}

+/*对齐,显示,隐藏等*/

+.aui-pull-right {

+	float: right !important;

+}

+.aui-pull-left {

+	float: left !important;

+}

+.aui-hide {

+	display: none !important;

+}

+.aui-show {

+	display: block !important;

+}

+.aui-invisible {

+	visibility: hidden;

+}

+.aui-inline {

+	display: inline-block;

+	vertical-align: top;

+}

+.aui-mask {

+    position: fixed;

+    width: 100%;

+    height: 100%;

+    top: 0;

+    left: 0;

+    background: rgba(0, 0, 0, 0.3);

+    opacity: 0;

+    z-index: 8;

+    visibility: hidden;

+    -webkit-transition: opacity .3s,-webkit-transform .3s;

+    transition: opacity .3s,transform .3s;

+}

+.aui-mask.aui-mask-in {

+	visibility: visible;

+  	opacity: 1;

+}

+.aui-mask.aui-mask-out {

+	opacity: 0;

+}

+img.aui-img-round {

+	border-radius: 50%;

+}

+/*基本容器*/

+.aui-content {

+	-webkit-overflow-scrolling: touch;

+	overflow-x: hidden;

+	word-break: break-all;

+}

+.aui-content-padded {

+  	margin: 0.75rem;

+  	position: relative;

+  	word-break: break-all;

+  	-webkit-overflow-scrolling: touch;

+}

+/*栅格类*/

+.aui-row {

+	overflow: hidden;

+	margin: 0;

+}

+.aui-row-padded {

+	margin-left: -0.125rem;

+	margin-right: -0.125rem;

+}

+.aui-row-padded [class*=aui-col-xs-] {

+	padding: 0.125rem;

+}

+.aui-col-xs-1,.aui-col-xs-2,.aui-col-xs-3,.aui-col-xs-4,.aui-col-xs-5,.aui-col-xs-6,.aui-col-xs-7,.aui-col-xs-8,.aui-col-xs-9,.aui-col-xs-10,.aui-col-xs-11,.aui-col-5 {

+	position: relative;

+	float: left;

+}

+.aui-col-xs-12 {

+	width: 100%;

+	position: relative;

+}

+.aui-col-xs-11 {

+	width: 91.66666667%;

+}

+.aui-col-xs-10 {

+	width: 83.33333333%;

+}

+.aui-col-xs-9 {

+	width: 75%;

+}

+.aui-col-xs-8 {

+	width: 66.66666667%;

+}

+.aui-col-xs-7 {

+	width: 58.33333333%;

+}

+.aui-col-xs-6 {

+	width: 50%;

+}

+.aui-col-xs-5 {

+	width: 41.66666667%;

+}

+.aui-col-xs-4 {

+	width: 33.33333333%;

+}

+.aui-col-xs-3 {

+	width: 25%;

+}

+.aui-col-xs-2 {

+	width: 16.66666667%;

+}

+.aui-col-xs-1 {

+	width: 8.33333333%;

+}

+.aui-col-5 {

+	width: 20%;

+}

+/*标签*/

+.aui-label {

+	display: inline-block;

+	padding: 0.2em 0.25em;

+	font-size: 0.6rem;

+	line-height: 1;

+	color: #616161;

+    background-color: #dddddd;

+	text-align: center;

+	white-space: nowrap;

+	vertical-align: middle;

+	border-radius: 0.15em;

+	position: relative;

+}

+

+.aui-label-primary {

+	color: #ffffff;

+	background-color: #00bcd4;

+}

+.aui-label-success {

+	color: #ffffff;

+	background-color: #009688;

+}

+.aui-label-info {

+  color: #ffffff;

+  background-color: #03a9f4;

+}

+.aui-label-warning {

+	color: #ffffff;

+	background-color: #ffc107;

+}

+.aui-label-danger {

+	color: #ffffff;

+	background-color: #e51c23;

+}

+.aui-label-outlined {

+	background-color: transparent;

+	position: relative;

+}

+.aui-label-outlined:after {

+    -webkit-border-radius: 2px;

+    border-radius: 2px;

+    height: 200%;

+    content: '';

+    width: 200%;

+	border: 1px solid #d9d9d9;

+    position: absolute;

+    top: -1px;

+    left: -1px;

+    transform: scale(0.5);

+    -webkit-transform: scale(0.5);

+    transform-origin: 0 0;

+    -webkit-transform-origin: 0 0;

+    z-index: 1;

+}

+.aui-label-outlined.aui-label-primary,

+.aui-label-outlined.aui-label-primary:after {

+	color: #00bcd4;

+	border-color: #00bcd4;

+}

+.aui-label-outlined.aui-label-success,

+.aui-label-outlined.aui-label-success:after {

+	color: #009688;

+	border-color: #009688;

+}

+.aui-label-outlined.aui-label-info,

+.aui-label-outlined.aui-label-info:after {

+  	color: #03a9f4;

+  	border-color: #03a9f4;

+}

+.aui-label-outlined.aui-label-warning,

+.aui-label-outlined.aui-label-warning:after {

+	color: #ffc107;

+	border-color: #ffc107;

+}

+.aui-label-outlined.aui-label-danger,

+.aui-label-outlined.aui-label-danger:after {

+	color: #e51c23;

+	border-color: #e51c23;

+}

+.aui-label .aui-iconfont {

+	font-size: 0.6rem;

+}

+/*角标*/

+.aui-badge {

+	display: inline-block;

+	width: auto;

+	text-align: center;

+	min-width: 0.8rem;

+	height: 0.8rem;

+    line-height: 0.8rem;

+    padding: 0 0.2rem;

+    font-size: 0.6rem;

+    color: #ffffff;

+    background-color: #ff2600;

+    border-radius: 0.4rem;

+    position: absolute;

+    top: 0.2rem;

+    left: 60%;

+    z-index: 99;

+}

+.aui-dot {

+	display: inline-block;

+    width: 0.4rem;

+    height: 0.4rem;

+    background: #ff2600;

+    border-radius: 0.5rem;

+    position: absolute;

+    top: 0.3rem;

+    right: 20%;

+    z-index: 99;

+}

+/*按钮样式*/

+button, .aui-btn {

+	position: relative;

+	display: inline-block;

+	font-size: 0.7rem;

+	font-weight: 400;

+	font-family: inherit;

+	text-decoration: none;

+	text-align: center;

+	margin: 0;

+	background: #dddddd;

+	padding: 0 0.6rem;

+	height: 1.5rem;

+	line-height: 1.5rem;

+	border-radius: 0.2rem;

+	white-space: nowrap;

+	text-overflow: ellipsis;

+	vertical-align: middle;

+	-webkit-box-sizing: border-box;

+			box-sizing: border-box;

+	-webkit-user-select: none;

+	      	user-select: none;

+}

+.aui-btn:active {

+	color: #212121;

+	background-color: #bdbdbd;

+}

+.aui-btn-primary {

+	color: #ffffff;

+	background-color: #00bcd4;

+}

+.aui-btn-primary.aui-active, .aui-btn-primary:active {

+	color: #ffffff;

+	background-color: #00acc1;

+}

+.aui-btn-success {

+	color: #ffffff;

+	background-color: #009688;

+}

+.aui-btn-success.aui-active, .aui-btn-success:active {

+	color: #fff;

+	background-color: #00897b;

+}

+.aui-btn-info {

+	color: #ffffff !important;

+	background-color: #03a9f4 !important;

+}

+.aui-btn-info.aui-active, .aui-btn-info:active {

+	color: #fff !important;

+	background-color: #067cb1 !important;

+}

+.aui-btn-warning {

+	color: #ffffff !important;

+	background-color: #ffc107 !important;

+}

+.aui-btn-warning.aui-active, .aui-btn-warning:active {

+	color: #ffffff !important;

+	background-color: #ffb300 !important;

+}

+.aui-btn-danger {

+	color: #ffffff !important;

+	background-color: #e51c23 !important;

+}

+.aui-btn-danger.aui-active, .aui-btn-danger:active {

+	color: #ffffff !important;

+	background-color: #dd191b !important;

+}

+.aui-btn-orangle {

+	color: #ffffff !important;

+	background-color: #efb336 !important;

+}

+.aui-btn-orangle.aui-active, .aui-btn-orangle:active {

+	color: #fff !important;

+	background-color: #e98f36 !important;

+}

+.aui-btn-blue {

+	color: #ffffff !important;

+	background-color: #17abe3 !important;

+}

+.aui-btn-blue.aui-active, .aui-btn-blue:active {

+	color: #fff !important;

+	background-color: #1195db !important;

+}

+.aui-btn-green {

+	color: #ffffff !important;

+	background-color: #36ab60 !important;

+}

+.aui-btn-green.aui-active, .aui-btn-green:active {

+	color: #fff !important;

+	background-color: #36ab60 !important;

+}

+.aui-btn-block {

+	display: block;

+	width: 100%;

+	height: 2.5rem;

+	line-height: 2.55rem;

+	margin-bottom: 0;

+	font-size: 0.9rem;

+}

+.aui-btn-block.aui-btn-sm {

+	font-size: 0.7rem;

+	height: 1.8rem;

+	line-height: 1.85rem;

+}

+.aui-btn .aui-iconfont, .aui-btn-block .aui-iconfont {

+	margin-right: 0.3rem;

+}

+.aui-btn .aui-badge, .aui-btn-block .aui-badge {

+	margin-left: 0.3rem;

+}

+.aui-btn-outlined {

+	background: transparent !important;

+	border: 1px solid #bdbdbd;

+}

+.aui-btn-outlined:active {

+	background: transparent !important;

+}

+.aui-btn-default.aui-btn-outlined {

+	color: #bdc3c7 !important;

+	border: 1px solid #dcdcdc !important;

+}

+.aui-btn-primary.aui-btn-outlined {

+	color: #00bcd4 !important;

+	border: 1px solid #00bcd4 !important;

+}

+.aui-btn-success.aui-btn-outlined {

+	color: #009688 !important;

+	border: 1px solid #009688 !important;

+}

+.aui-btn-info.aui-btn-outlined {

+	color: #03a9f4 !important;

+	border: 1px solid #03a9f4 !important;

+}

+.aui-btn-warning.aui-btn-outlined {

+	color: #ffc107 !important;

+	border: 1px solid #ffc107 !important;

+}

+.aui-btn-danger.aui-btn-outlined {

+	color: #e51c23 !important;

+	border: 1px solid #e51c23 !important;

+}

+/*

+*表单类\输入框\radio\checkbox

+**/

+.aui-input,

+input[type="text"],

+input[type="password"],

+input[type="search"],

+input[type="email"],

+input[type="tel"],

+input[type="url"],

+input[type="date"],

+input[type="datetime-local"],

+input[type="time"],

+input[type="number"],

+select,

+textarea {

+    border: none;

+    background-color: transparent;

+    border-radius: 0;

+    box-shadow: none;

+    display: block;

+    padding: 0;

+    margin: 0;

+    width: 100%;

+    height: 2.2rem;

+    line-height: normal;

+    color: #424242;

+    font-size: 0.8rem;

+    font-family: inherit;

+    box-sizing: border-box;

+    -webkit-user-select: text;

+            user-select: text;

+    -webkit-appearance: none;

+            appearance: none;

+}

+input[type="search"]::-webkit-search-cancel-button {

+	display: none;

+}

+.aui-scroll-x {

+	position: relative;

+	overflow-y: auto;

+	-webkit-overflow-scrolling: touch;

+}

+.aui-scroll-y {

+	position: relative;

+	width: 100%;

+	overflow-x: auto;

+	-webkit-overflow-scrolling: touch;

+}

+::-webkit-scrollbar{

+	width:0px;

+}

+/*列表*/

+.aui-list {

+    position: relative;

+    font-size: 0.8rem;

+    background-color: #ffffff;

+    border-top: 1px solid #dddddd;

+}

+.aui-list .aui-content {

+	overflow: hidden;

+}

+.aui-list.aui-list-noborder,

+.aui-list.aui-list-noborder {

+    border-top: none;

+}

+.aui-list .aui-list-header {

+    background-color: #dddddd;

+    color: #212121;

+    position: relative;

+    font-size: 0.6rem;

+    padding: 0.4rem 0.75rem;

+    -webkit-box-sizing: border-box;

+    		box-sizing: border-box;

+    display: -webkit-box;

+    display: -webkit-flex;

+    display: flex;

+    -webkit-box-pack: justify;

+    -webkit-justify-content: space-between;

+    		justify-content: space-between;

+    -webkit-box-align: center;

+    -webkit-align-items: center;

+    		align-items: center;

+}

+.aui-list .aui-list-item {

+    list-style: none;

+    margin: 0;

+    padding: 0;

+    padding-left: 0.75rem;

+    color: #212121;

+    border-bottom: 1px solid #f2f2f2;

+    position: relative;

+    min-height: 2.2rem;

+    -webkit-box-sizing: border-box;

+    		box-sizing: border-box;

+    display: -webkit-box;

+    display: -webkit-flex;

+    display: flex;

+    -webkit-box-pack: justify;

+    -webkit-justify-content: space-between;

+    		justify-content: space-between;

+}

+.aui-list.aui-list-noborder .aui-list-item:last-child {

+    border-bottom: 0;

+}

+.aui-list .aui-list-item-inner {

+    position: relative;

+    min-height: 2.2rem;

+	padding-right: 0.75rem;

+    width: 100%;

+    -webkit-box-sizing: border-box;

+    		box-sizing: border-box;

+    display: -webkit-box;

+    display: -webkit-flex;

+    display: flex;

+    -webkit-box-flex: 1;

+    -webkit-box-pack: justify;

+    -webkit-justify-content: space-between;

+			justify-content: space-between;

+    -webkit-box-align: center;

+    -webkit-align-items: center;

+			align-items: center;

+}

+

+.aui-list .aui-list-item:active {

+    background-color: #f5f5f5;

+}

+.aui-list .aui-list-item-text {

+    font-size: 0.7rem;

+    color: #757575;

+    position: relative;

+    -webkit-box-sizing: border-box;

+    		box-sizing: border-box;

+    display: -webkit-box;

+    display: -webkit-flex;

+    display: flex;

+    -webkit-box-pack: justify;

+    -webkit-justify-content: space-between;

+            justify-content: space-between;

+    -webkit-align-items: center;

+    		align-items: center;

+}

+.aui-list .aui-list-item-title {

+    font-size: 0.8rem;

+    position: relative;

+    max-width: 100%;

+    color: #212121;

+}

+.aui-list .aui-list-item-right,

+.aui-list-item-title-row em {

+	max-width: 50%;

+	position: relative;

+    font-size: 0.6rem;

+    color: #757575;

+    margin-left: 0.25rem;

+}

+.aui-list .aui-list-item-inner p {

+    overflow: hidden;

+}

+.aui-list .aui-list-media-list {

+    -webkit-box-orient: vertical;

+    -webkit-box-direction: normal;

+    -webkit-flex-direction: column;

+            flex-direction: column;

+}

+.aui-media-list-item-inner {

+	-webkit-box-sizing: border-box;

+			box-sizing: border-box;

+    display: -webkit-box;

+    display: -webkit-flex;

+    display: flex;

+}

+.aui-media-list .aui-list-item {

+	display: block;

+}

+.aui-media-list .aui-list-item-inner {

+	display: block;

+	padding-top: 0.5rem;

+    padding-bottom: 0.5rem;

+}

+.aui-media-list-item-inner + .aui-info {

+	margin-right: 0.75rem;

+}

+.aui-list .aui-list-item-media {

+	width: 4.5rem;

+	position: relative;

+    padding: 0.5rem 0;

+    padding-right: 0.75rem;

+    display: inherit;

+    -webkit-flex-shrink: 0;

+    		flex-shrink: 0;

+    -webkit-flex-wrap: nowrap;

+    		flex-wrap: nowrap;

+    -webkit-box-align: center;

+    -webkit-align-items: flex-start;

+            align-items: flex-start;

+}

+.aui-list .aui-list-item-media img {

+	width: 100%;

+    display: block;

+}

+.aui-list .aui-list-item-media-list {

+	margin-top: 0.25rem;

+	padding-right: 0;

+	display: block;

+}

+.aui-list [class*=aui-col-xs-] img{

+    max-width: 100%;

+    width: 100%;

+    display: block;

+}

+.aui-list-item-middle .aui-list-item-inner:after {

+	display: block;

+}

+.aui-list .aui-list-item-middle > .aui-list-item-media,

+.aui-list .aui-list-item-middle > .aui-list-item-inner,

+.aui-list .aui-list-item-middle > * {

+    -webkit-box-align: center;

+    		box-align: center;

+    -webkit-align-items: center;

+    		align-items: center;

+}

+.aui-list .aui-list-item-center > .aui-list-item-media,

+.aui-list .aui-list-item-center > .aui-list-item-inner,

+.aui-list .aui-list-item-center {

+    -webkit-box-pack: center;

+    -webkit-justify-content: center;

+        	justify-content: center;

+}

+.aui-list .aui-list-item i.aui-iconfont {

+    -webkit-align-self: center;

+            align-self: center;

+    font-size: 0.8rem;

+}

+.aui-list-item-inner.aui-list-item-arrow {

+    overflow: hidden;

+    padding-right: 1.5rem;

+}

+.aui-list-item-arrow:before {

+    content: '';

+    width: 0.4rem;

+    height: 0.4rem;

+    position: absolute;

+    top: 50%;

+    right: 0.75rem;

+    margin-top: -0.2rem;

+    background: transparent;

+    border: 1px solid #dddddd;

+    border-top: none;

+    border-right: none;

+    z-index: 2;

+    -webkit-border-radius: 0;

+            border-radius: 0;

+    -webkit-transform: rotate(-135deg);

+            transform: rotate(-135deg);

+}

+.aui-list-item.aui-list-item-arrow {

+    padding-right: 0.75rem;

+}

+.aui-list label {

+    line-height: 1.3rem;

+}

+.aui-list.aui-form-list .aui-list-item:active {

+	background-color: #ffffff;

+}

+.aui-list.aui-form-list .aui-list-item-inner {

+	-webkit-box-sizing: border-box;

+    		box-sizing: border-box;

+    display: -webkit-box;

+    display: -webkit-flex;

+    display: flex;

+	padding: 0;

+}

+.aui-list .aui-list-item-label,

+.aui-list .aui-list-item-label-icon {

+	color: #212121;

+    width: 35%;

+    min-width: 1.5rem;

+    margin: 0;

+    padding: 0;

+    padding-right: 0.25rem;

+    line-height: 2.2rem;

+    position: relative;

+    overflow: hidden;

+    white-space: nowrap;

+    max-width: 100%;

+    -webkit-box-sizing: border-box;

+    		box-sizing: border-box;

+    display: -webkit-box;

+    display: -webkit-flex;

+    display: flex;

+    -webkit-align-items: center;

+            align-items: center;

+}

+.aui-list .aui-list-item-label-icon {

+    width: auto;

+    padding-right: 0.75rem;

+}

+.aui-list .aui-list-item-input {

+    width: 100%;

+    padding: 0;

+    padding-right: 0.75rem;

+    -webkit-box-flex: 1;

+            box-flex: 1;

+    -webkit-flex-shrink: 1;

+            flex-shrink: 1;

+}

+.aui-list.aui-select-list .aui-list-item:active {

+	background-color: #ffffff;

+}

+.aui-list.aui-select-list .aui-list-item-inner {

+    display: block;

+    padding-top: 0.5rem;

+    padding-bottom: 0.5rem;

+    -webkit-align-self: stretch;

+    		align-self: stretch;

+}

+.aui-list.aui-select-list .aui-list-item-label {

+	width: auto;

+	min-width: 2.2rem;

+    padding: 0.5rem 0;

+    padding-right: 0.75rem;

+}

+.aui-list.aui-form-list .aui-list-item-btn {

+	padding: 0.75rem 0.75rem 0.75rem 0;

+}

+.aui-list textarea {

+    overflow: auto;

+    margin: 0.5rem 0;

+    height: 3rem;

+    line-height: 1rem;

+    resize: none;

+}

+.aui-list .aui-list-item-right .aui-badge,

+.aui-list .aui-list-item-right .aui-dot {

+	display: inherit;

+}

+@media screen and (-webkit-min-device-pixel-ratio:1.5) {

+	.aui-list {

+		border: none;

+        background-size: 100% 1px;

+		background-repeat: no-repeat;

+		background-position: top;

+        background-image: linear-gradient(0,#dddddd,#dddddd 50%,transparent 50%);

+	}

+	.aui-list .aui-list-item {

+		border: none;

+        background-size: 100% 1px;

+		background-repeat: no-repeat;

+		background-position: bottom;

+        background-image: linear-gradient(0,#dddddd,#dddddd 50%,transparent 50%);

+        background-image: -webkit-linear-gradient(90deg,#dddddd,#dddddd 50%,transparent 50%);

+	}

+

+	.aui-list.aui-list-in .aui-list-item {

+		border: none;

+        background-size: 100% 1px;

+		background-repeat: no-repeat;

+		background-position: 0.75rem bottom;

+        background-image: linear-gradient(0,#dddddd,#dddddd 50%,transparent 50%);

+        background-image: -webkit-linear-gradient(90deg,#dddddd,#dddddd 50%,transparent 50%);

+	}

+	.aui-list.aui-list-in .aui-list-item:last-child {

+		background-position: bottom;

+	}

+	.aui-list.aui-list-noborder,

+	.aui-list.aui-list-noborder .aui-list-item:last-child {

+		border: none;

+        background-size: 100% 0;

+        background-image: none;

+	}

+}

+/*tab切换类*/

+.aui-tab {

+	position: relative;

+    background-color: #ffffff;

+    display: -webkit-box;

+    display: -webkit-flex;

+    display: flex;

+    -webkit-flex-wrap: nowrap;

+            flex-wrap: nowrap;

+    -webkit-align-self: center;

+            align-self: center;

+}

+.aui-tab-item {

+    width: 100%;

+    height: 2.2rem;

+    line-height: 2.2rem;

+    position: relative;

+    font-size: 0.7rem;

+    text-align: center;

+    color: #212121;

+    margin-left: -1px;

+    -webkit-box-flex: 1;

+            box-flex: 1;

+}

+.aui-tab-item.aui-active {

+    color: #03a9f4;

+    border-bottom: 2px solid #03a9f4;

+}

+/*卡片列表布局*/

+.aui-card-list {

+	position: relative;

+    margin-bottom: 0.35rem;

+    background: #ffffff;

+}

+.aui-card-list-header,

+.aui-card-list-footer {

+	position: relative;

+	min-height: 2.2rem;

+    padding: 0.5rem 0.75rem;

+    -webkit-box-sizing: border-box;

+    		box-sizing: border-box;

+    display: -webkit-box;

+    display: -webkit-flex;

+    display: flex;

+    -webkit-box-pack: justify;

+    -webkit-justify-content: space-between;

+    		justify-content: space-between;

+    -webkit-box-align: center;

+    -webkit-align-items: center;

+    		align-items: center;

+}

+.aui-card-list-header {

+	font-size: 0.8rem;

+	color: #212121;

+}

+.aui-card-list-header.aui-card-list-user {

+	display: block;

+}

+.aui-card-list-user-avatar {

+	width: 2rem;

+	float: left;

+	margin-right: 0.5rem;

+}

+.aui-card-list-user-avatar img {

+	width: 100%;

+	display: block;

+}

+.aui-card-list-user-name {

+	color: #212121;

+	position: relative;

+	font-size: 0.7rem;

+	-webkit-box-sizing: border-box;

+			box-sizing: border-box;

+    display: -webkit-box;

+    display: -webkit-flex;

+    display: flex;

+    -webkit-box-pack: justify;

+    -webkit-justify-content: space-between;

+    		justify-content: space-between;

+    -webkit-box-align: center;

+    -webkit-align-items: center;

+    		align-items: center;

+}

+.aui-card-list-user-name > *,

+.aui-card-list-user-name small {

+	position: relative;

+}

+.aui-card-list-user-name small {

+	color: #757575;

+}

+.aui-card-list-user-info {

+	color: #757575;

+	font-size: 0.6rem;

+}

+.aui-card-list-content {

+	position: relative;

+}

+.aui-card-list-content-padded {

+	position: relative;

+	padding: 0.5rem 0.75rem;

+}

+.aui-card-list-content,

+.aui-card-list-content-padded {

+	word-break: break-all;

+	font-size: 0.7rem;

+	color: #212121;

+}

+.aui-card-list-content img,

+.aui-card-list-content-padded img {

+	width: 100%;

+	display: block;

+}

+.aui-card-list-footer {

+	font-size: 0.7rem;

+	color: #757575;

+}

+.aui-card-list-footer > * {

+	position: relative;

+}

+.aui-card-list-footer.aui-text-center {

+	display: -webkit-box;

+    display: -webkit-flex;

+    display: flex;

+	-webkit-box-pack: center;

+    box-pack: center;

+    -webkit-justify-content: center;

+    justify-content: center;

+}

+.aui-card-list-footer .aui-iconfont {

+	font-size: 0.9rem;

+}

+/*宫格布局*/

+.aui-grid {

+	width: 100%;

+	background-color: #ffffff;

+	display: table;

+	table-layout: fixed;

+}

+.aui-grid [class*=aui-col-] {

+	display: table-cell;

+	position: relative;

+    text-align: center;

+    vertical-align: middle;

+    padding: 0.6rem 0;

+}

+.aui-grid [class*=aui-col-xs-]:active {

+	background-color: #f5f5f5;

+}

+.aui-grid [class*=top-btn]:active {

+	background-color: #048cca;

+}

+.aui-grid .aui-iconfont {

+	position: relative;

+    z-index: 20;

+    top: 0;

+    height: 1.4rem;

+    font-size: 1.4rem;

+    line-height: 1.4rem;

+}

+.aui-grid .aui-grid-label {

+	display: block;

+    font-size: 0.7rem;

+    position: relative;

+    margin-top: 0.25rem;

+}

+.aui-grid .aui-badge {

+	position: absolute;

+    top: 0.5rem;

+    left: 60%;

+    z-index: 99;

+}

+.aui-grid .aui-dot {

+	position: absolute;

+    top: 0.5rem;

+    right: 20%;

+    z-index: 99;

+}

+/*单选、多选、开关*/

+.aui-radio,

+.aui-checkbox {

+    width: 1.2rem;

+    height: 1.2rem;

+    background-color: #ffffff;

+    border: solid 1px #dddddd;

+    -webkit-border-radius: 0.6rem;

+    border-radius: 0.6rem;

+    font-size: 0.8rem;

+    margin: 0;

+    padding: 0;

+    position: relative;

+    display: inline-block;

+    vertical-align: top;

+    cursor: default;

+    -webkit-appearance: none;

+    -webkit-user-select: none;

+            user-select: none;

+    -webkit-transition: background-color ease 0.1s;

+            transition: background-color ease 0.1s;

+}

+.aui-checkbox {

+    border-radius: 0.1rem;

+}

+.aui-radio:checked,

+.aui-radio.aui-checked,

+.aui-checkbox:checked,

+.aui-checkbox.aui-checked {

+    background-color: #03a9f4;

+    border: solid 1px #03a9f4;

+    text-align: center;

+    background-clip: padding-box;

+}

+.aui-radio:checked:before,

+.aui-radio.aui-checked:before,

+.aui-checkbox:checked:before,

+.aui-checkbox.aui-checked:before,

+.aui-radio:checked:after,

+.aui-radio.aui-checked:after,

+.aui-checkbox:checked:after,

+.aui-checkbox.aui-checked:after {

+    content: '';

+    width: 0.5rem;

+    height: 0.3rem;

+    position: absolute;

+    top: 50%;

+    left: 50%;

+    margin-left: -0.25rem;

+    margin-top: -0.25rem;

+    background: transparent;

+    border: 1px solid #ffffff;

+    border-top: none;

+    border-right: none;

+    z-index: 2;

+    -webkit-border-radius: 0;

+            border-radius: 0;

+    -webkit-transform: rotate(-45deg);

+            transform: rotate(-45deg);

+}

+.aui-radio:disabled,

+.aui-radio.aui-disabled,

+.aui-checkbox:disabled,

+.aui-checkbox.aui-disabled {

+    background-color: #dddddd;

+    border: solid 1px #dddddd;

+}

+.aui-radio:disabled:before,

+.aui-radio.aui-disabled:before,

+.aui-radio:disabled:after,

+.aui-radio.aui-disabled:after,

+.aui-checkbox:disabled:before,

+.aui-checkbox.aui-disabled:before,

+.aui-checkbox:disabled:after,

+.aui-checkbox.aui-disabled:after {

+    content: '';

+    width: 0.5rem;

+    height: 0.3rem;

+    position: absolute;

+    top: 50%;

+    left: 50%;

+    margin-left: -0.25rem;

+    margin-top: -0.25rem;

+    background: transparent;

+    border: 1px solid #ffffff;

+    border-top: none;

+    border-right: none;

+    z-index: 2;

+    -webkit-border-radius: 0;

+            border-radius: 0;

+    -webkit-transform: rotate(-45deg);

+            transform: rotate(-45deg);

+}

+.aui-switch {

+    width: 2.3rem;

+    height: 1.2rem;

+    position: relative;

+    vertical-align: top;

+    border: 1px solid #dddddd;

+    background-color: #dddddd;

+    border-radius: 0.6rem;

+    background-clip: content-box;

+    display: inline-block;

+    outline: none;

+    -webkit-appearance: none;

+            appearance: none;

+    -webkit-user-select: none;

+            user-select: none;

+    -webkit-box-sizing: border-box;

+            box-sizing: border-box;

+    -webkit-background-clip: padding-box;

+            background-clip: padding-box;

+    -webkit-transition: all 0.2s linear;

+            transition: all 0.2s linear;

+}

+.aui-switch:before {

+    width: 1.1rem;

+    height: 1.1rem;

+    position: absolute;

+    top: 0;

+    left: 0;

+    border-radius: 0.6rem;

+    background-color: #fff;

+    content: '';

+    -webkit-transition: left 0.2s;

+            transition: left 0.2s;

+}

+.aui-switch:checked {

+    border-color: #03a9f4;

+    background-color: #03a9f4;

+}

+.aui-switch:checked:before {

+    left: 1.1rem;

+}

+/*导航栏*/

+.aui-bar {

+	position: relative;

+	top: 0;

+	right: 0;

+	left: 0;

+	z-index: 10;

+	width: 100%;

+	min-height: 2.25rem;

+	font-size: 0.9rem;

+	text-align: center;

+	display: table;

+}

+.aui-bar-nav {

+	top: 0;

+	line-height: 2.25rem;

+	background-color: #03a9f4;

+	color: #ffffff;

+}

+.aui-title a {

+	color: inherit;

+}

+.aui-bar-nav .aui-title {

+	min-height: 2.25rem;

+	position: absolute;

+	margin: 0;

+	text-align: center;

+	white-space: nowrap;

+	right: 2rem;

+	left: 2rem;

+	width: auto;

+	overflow: hidden;

+	/*text-overflow: ellipsis;*/

+	z-index: 2;

+}

+.aui-bar-nav a {

+	color: #ffffff;

+}

+.aui-bar-nav .aui-iconfont {

+	position: relative;

+	z-index: 20;

+	font-size: 0.9rem;

+	color: #ffffff;

+	font-weight: 400;

+	line-height: 2.25rem;

+}

+.aui-bar-nav .aui-pull-left {

+	padding: 0 0.5rem;

+	font-size: 0.8rem;

+	font-weight: 400;

+	z-index: 2;

+	-webkit-box-sizing: border-box;

+			box-sizing: border-box;

+    display: -webkit-box;

+    display: -webkit-flex;

+    display: flex;

+    -webkit-align-items: center;

+            align-items: center;

+}

+.aui-bar-nav .aui-pull-right {

+	padding: 0 0.5rem;

+	font-size: 0.8rem;

+	font-weight: 400;

+	z-index: 2;

+	-webkit-box-sizing: border-box;

+			box-sizing: border-box;

+    display: -webkit-box;

+    display: -webkit-flex;

+    display: flex;

+    -webkit-align-items: center;

+            align-items: center;

+}

+.aui-bar-nav .aui-btn {

+	position: relative;

+	z-index: 20;

+	height: 2.25rem;

+	line-height: 2.25rem;

+	padding-top: 0;

+	padding-bottom: 0;

+	margin: 0;

+	border-radius: 0.1rem;

+	border-width: 0;

+	background: transparent !important;

+}

+.aui-bar-nav .aui-btn.aui-btn-outlined {

+	position: relative;

+	padding: 0 0.15rem;

+	margin: 0.5rem;

+	height: 1.25rem;

+	line-height: 1.25rem;

+	border-width: 1px;

+	background: transparent !important;

+	border-color: #ffffff;

+}

+.aui-bar-nav .aui-btn:active {

+	background: none;

+}

+.aui-bar-nav .aui-btn .aui-iconfont {

+	font-size: 0.9rem;

+	line-height: 1.25rem;

+	padding: 0;

+	margin: 0;

+	color: #ffffff;

+}

+.aui-bar-light {

+	color: #03a9f4;

+	background-color: #ffffff;

+	border-bottom: 1px solid #dddddd;

+}

+.aui-bar-nav.aui-bar-light .aui-iconfont {

+	color: #03a9f4;

+}

+.aui-bar-nav.aui-bar-light .aui-btn-outlined {

+	border-color: #03a9f4;

+}

+@media screen and (-webkit-min-device-pixel-ratio:1.5) {

+	.aui-bar.aui-bar-light {

+		border: none;

+        background-size: 100% 1px;

+		background-repeat: no-repeat;

+		background-position: bottom;

+        background-image: linear-gradient(0,#dddddd,#dddddd 50%,transparent 50%);

+        background-image: -webkit-linear-gradient(90deg,#dddddd,#dddddd 50%,transparent 50%);

+	}

+}

+/*底部切换栏*/

+.aui-bar-tab {

+	position: fixed;

+	top: auto;

+	bottom: 0;

+	table-layout: fixed;

+	background-color: #ffffff;

+	color: #757575;

+}

+.aui-bar-tab .aui-bar-tab-item {

+	display: table-cell;

+	position: relative;

+    width: 1%;

+    height: 2.5rem;

+    text-align: center;

+    vertical-align: middle;

+}

+.aui-bar-tab .aui-active {

+	color: #03a9f4;

+}

+.aui-bar-tab .aui-bar-tab-item .aui-iconfont {

+	position: relative;

+    z-index: 20;

+    top: 0.1rem;

+    height: 1.2rem;

+    font-size: 1rem;

+    line-height: 1rem;

+}

+.aui-bar-tab .aui-bar-tab-label {

+	display: block;

+    font-size: 0.6rem;

+    position: relative;

+}

+.aui-bar-tab .aui-badge {

+    position: absolute;

+    top: 0.1rem;

+    left: 55%;

+    z-index: 99;

+}

+.aui-bar-tab .aui-dot {

+    position: absolute;

+    top: 0.1rem;

+    right: 30%;

+    z-index: 99;

+}

+/*按钮工具栏*/

+.aui-bar-btn {

+	position: relative;

+    font-size: 0.7rem;

+    display: table;

+    white-space: nowrap;

+    margin: 0 auto;

+    padding: 0;

+    border: none;

+    width: 100%;

+    min-height: 1.8rem;

+}

+.aui-bar-btn-item {

+    display: table-cell;

+    position: relative;

+    width: 1%;

+    line-height: 1.6rem;

+    text-align: center;

+    vertical-align: middle;

+    border-radius: 0;

+    position: relative;

+    border-width: 1px;

+    border-style: solid;

+    border-color: #03a9f4;

+    border-left-width: 0;

+}

+.aui-bar-btn .aui-input,

+.aui-bar-btn input,

+.aui-bar-btn select {

+	padding-left: 0.25rem;

+	padding-right: 0.25rem;

+    height: 1.8rem;

+}

+.aui-bar-btn-sm {

+    min-height: 1.3rem;

+}

+.aui-bar-btn.aui-bar-btn-sm  .aui-input,

+.aui-bar-btn.aui-bar-btn-sm  input,

+.aui-bar-btn.aui-bar-btn-sm  select {

+    height: 1.2rem;

+}

+.aui-bar-btn-sm .aui-bar-btn-item {

+    line-height: 1.3rem;

+    font-size: 0.6rem;

+}

+.aui-bar-btn-item.aui-active {

+    background-color: #03a9f4;

+    color: #ffffff;

+}

+.aui-bar-btn-item:first-child {

+    border-left-width: 1px;

+    border-top-left-radius: 0.2rem;

+    border-bottom-left-radius: 0.2rem;

+}

+.aui-bar-btn-item:last-child {

+    border-top-right-radius: 0.2rem;

+    border-bottom-right-radius: 0.2rem;

+    border-left: 0px;

+}

+.aui-bar-btn.aui-bar-btn-full .aui-bar-btn-item:first-child {

+    border-left-width: 0;

+    border-top-left-radius: 0;

+    border-bottom-left-radius: 0;

+}

+.aui-bar-btn.aui-bar-btn-full .aui-bar-btn-item:last-child {

+    border-right-width: 0;

+    border-top-right-radius: 0;

+    border-bottom-right-radius: 0;

+}

+.aui-bar-btn.aui-bar-btn-round .aui-bar-btn-item:first-child {

+    border-top-left-radius: 1.5rem;

+    border-bottom-left-radius: 1.5rem;

+}

+.aui-bar-btn.aui-bar-btn-round .aui-bar-btn-item:last-child {

+    border-top-right-radius: 1.5rem;

+    border-bottom-right-radius: 1.5rem;

+}

+.aui-bar-nav .aui-bar-btn {

+	margin-top: 0.45rem;

+	margin-bottom: 0.4rem;

+    min-height: 1.3rem;

+}

+.aui-bar-nav .aui-bar-btn-item {

+    line-height: 1.3rem;

+    border-color: #ffffff;

+}

+.aui-bar-nav .aui-bar-btn-item.aui-active {

+    background-color: #ffffff;

+    color: #03a9f4;

+}

+.aui-bar-nav.aui-bar-light .aui-bar-btn-item {

+    border-color: #03a9f4;

+}

+.aui-bar-nav.aui-bar-light .aui-bar-btn-item.aui-active {

+    background-color: #03a9f4;

+    color: #ffffff;

+}

+.aui-bar-nav > .aui-bar-btn {

+	width: 50%;

+}

+.aui-info {

+	position: relative;

+    padding: 0.5rem 0;

+    font-size: 0.7rem;

+    color: #757575;

+    background-color: transparent;

+    -webkit-box-sizing: border-box;

+    		box-sizing: border-box;

+    display: -webkit-box;

+    display: -webkit-flex;

+    display: flex;

+    -webkit-box-pack: justify;

+    -webkit-justify-content: space-between;

+    		justify-content: space-between;

+    -webkit-box-align: center;

+    -webkit-align-items: center;

+    		align-items: center;

+

+}

+.aui-info-item {

+	-webkit-box-sizing: border-box;

+			box-sizing: border-box;

+	display: -webkit-box;

+    display: -webkit-flex;

+    display: flex;

+    -webkit-box-align: center;

+    -webkit-align-items: center;

+    		align-items: center;

+}

+.aui-info-item > *,

+.aui-info > * {

+	display: inherit;

+	position: relative;

+}

+/*进度条*/

+.aui-progress {

+	width: 100%;

+	height: 1rem;

+	border-radius: 0.2rem;

+	overflow: hidden;

+	background-color: #f0f0f0;

+}

+.aui-progress-bar {

+	float: left;

+	width: 0;

+	height: 100%;

+	font-size: 0.6rem;

+	line-height: 1rem;

+	color: #ffffff;

+	text-align: center;

+	background-color: #03a9f4;

+}

+.aui-progress.sm,

+.aui-progress-sm {

+	height: 0.5rem;

+}

+.aui-progress.sm,

+.aui-progress-sm,

+.aui-progress.sm .aui-progress-bar,

+.aui-progress-sm .aui-progress-bar {

+	border-radius: 1px;

+}

+.aui-progress.xs,

+.aui-progress-xs {

+	height: 0.35rem;

+}

+.aui-progress.xs,

+.aui-progress-xs,

+.aui-progress.xs .progress-bar,

+.aui-progress-xs .progress-bar {

+	border-radius: 1px;

+}

+.aui-progress.xxs,

+.aui-progress-xxs {

+	height: 0.15rem;

+}

+.aui-progress.xxs,

+.aui-progress-xxs,

+.aui-progress.xxs .progress-bar,

+.aui-progress-xxs .progress-bar {

+	border-radius: 1px;

+}

+/*滑块*/

+.aui-range {

+    position: relative;

+    display: inline-block;

+}

+.aui-range input[type='range']{

+    height: 0.2rem;

+    border: 0;

+    border-radius: 2px;

+    background-color: #f0f0f0;

+    position: relative;

+    -webkit-appearance: none !important;

+}

+.aui-range input[type='range']::-webkit-slider-thumb {

+    width: 1.2rem;

+    height: 1.2rem;

+    border-radius: 50%;

+    border-color: #03a9f4;

+    background-color: #03a9f4;

+    -webkit-appearance: none !important;

+}

+.aui-range .aui-range-tip {

+    font-size: 1rem;

+    position: absolute;

+    z-index: 999;

+    top: -1.5rem;

+    width: 2.4rem;

+    height: 1.5rem;

+    line-height: 1.5rem;

+    text-align: center;

+    color: #666666;

+    border: 1px solid #dddddd;

+    border-radius: 0.3rem;

+    background-color: #ffffff;

+}

+.aui-input-row .aui-range input[type='range'] {

+	width: 90%;

+	margin-left: 5%;

+}

+/*搜索条*/

+.aui-searchbar {

+    display: -webkit-box;

+    -webkit-box-pack: center;

+    -webkit-box-align: center;

+    height: 2.2rem;

+    overflow: hidden;

+    width: 100%;

+    background-color: #ebeced;

+    color: #9e9e9e;

+    -webkit-backface-visibility: hidden;

+  			backface-visibility: hidden;

+}

+.aui-searchbar.focus {

+    -webkit-box-pack: start;

+}

+.aui-searchbar-input {

+    margin: 0 0.5rem;

+	background-color: #ffffff;

+    border-radius: 0.25rem;

+    height: 1.4rem;

+    line-height: 1.4rem;

+    font-size: 0.7rem;

+    position: relative;

+    padding-left: 0.5rem;

+    display: -webkit-box;

+    -webkit-box-flex: 1;

+}

+.aui-searchbar form {

+	width: 90%;

+}

+.aui-searchbar-input input {

+    color: #666666;

+    width: 80%;

+    padding: 0;

+    margin: 0;

+    height: 1.4rem;

+    line-height: normal;

+    border: 0;

+    -webkit-appearance: none;

+    font-size: 0.7rem;

+}

+.aui-searchbar input::-webkit-input-placeholder {

+	color: #ccc;

+}

+.aui-searchbar .aui-iconfont {

+    line-height: 1.4rem;

+    margin-right: 0.25rem;

+    color: #9e9e9e !important;

+}

+.aui-searchbar .aui-searchbar-btn {

+	font-size: 0.7rem;

+	color: #666666;

+	margin-right: -2.2rem;

+	width: 2.2rem;

+	height: 1.4rem;

+	padding-right: 0.5rem;

+	line-height: 1.4rem;

+	text-align: center;

+	-webkit-transition: all .3s;

+	      	transition: all .3s;

+}

+.aui-searchbar-clear-btn {

+	position: absolute;

+	right: 5px;

+	top: 3px;

+	width: 1.1rem;

+	height: 1.1rem;

+	background: #eeeeee;

+	border-radius: 50%;

+	line-height: 0.6rem;

+	text-align: center;

+	display: none;

+}

+.aui-searchbar-clear-btn .aui-iconfont {

+	font-size: 0.6rem;

+	margin: 0 auto;

+	position: relative;

+	top: -2px;

+}

+.aui-searchbar .aui-searchbar-btn .aui-iconfont {

+	color: #666666;

+}

+/*信息提示条*/

+.aui-tips {

+    padding: 0 0.75rem;

+    width: 100%;

+    z-index: 99;

+    height: 1.9rem;

+    line-height: 1.9rem;

+   	position: relative;

+    background-color: rgba(0,0,0,.6);

+    color: #ffffff;

+    display: -webkit-box;

+    display: -webkit-flex;

+    display: flex;

+    -webkit-box-pack: justify;

+    -webkit-justify-content: space-between;

+            justify-content: space-between;

+    -webkit-align-items: center;

+    		align-items: center;

+}

+.aui-tips .aui-tips-title {

+	padding: 0 0.5rem;

+	font-size: 0.7rem;

+    position: relative;

+    max-width: 100%;

+}

+/*toast*/

+.aui-toast {

+	background: rgba(0, 0, 0, 0.7);

+	text-align: center;

+	border-radius: 0.25rem;

+	color: #ffffff;

+	position: fixed;

+	z-index: 300;

+	top: 45%;

+	left: 50%;

+	width: 7.5em;

+	min-height: 6em;

+	margin-left: -3.75em;

+	margin-top: -4rem;

+	display: none;

+}

+.aui-toast .aui-iconfont {

+	margin-top: 0.2rem;

+	display: block;

+	font-size: 2.6rem;

+}

+.aui-toast-content {

+  margin: 0 0 0.75rem;

+}

+.aui-toast-loading {

+    background-color: #ffffff;

+    border-radius: 100%;

+    margin: 0.75rem 0;

+    -webkit-animation-fill-mode: both;

+        	animation-fill-mode: both;

+    border: 2px solid #ffffff;

+    border-bottom-color: transparent;

+    height: 2.25rem;

+    width: 2.25rem;

+    background: transparent !important;

+    display: inline-block;

+    -webkit-animation: rotate 1s 0s linear infinite;

+        	animation: rotate 1s 0s linear infinite;

+}

+/*dialog*/

+.aui-dialog {

+	width: 13.5rem;

+	text-align: center;

+	position: fixed;

+	z-index: 999;

+	left: 50%;

+	margin-left: -6.75rem;

+	margin-top: 0;

+	top: 45%;

+	border-radius: 0.3rem;

+	opacity: 0;

+	background-color: #ffffff;

+	-webkit-transform: translate3d(0, 0, 0) scale(1.2);

+          	transform: translate3d(0, 0, 0) scale(1.2);

+ 	-webkit-transition-property: -webkit-transform, opacity;

+          	transition-property: transform, opacity;

+    /*display: none;*/

+}

+.aui-dialog-header {

+    padding: 0.5rem 0.75rem 0 0.75rem;

+    text-align: center;

+    font-size: 1em;

+    color: #212121;

+}

+.aui-dialog-body {

+    padding: 0.75rem;

+    overflow: hidden;

+    font-size: 0.875em;

+    color: #757575;

+}

+.aui-dialog-body input {

+	border: 1px solid #dddddd;

+	height: 1.8rem;

+	line-height: 1.8rem;

+	min-height: 1.8rem;

+	padding-left: 0.25rem;

+	padding-right: 0.25rem;

+}

+.aui-dialog-footer {

+    position: relative;

+    font-size: 1em;

+    border-top: 1px solid #dddddd;

+    display: -webkit-box;

+    display: -webkit-flex;

+    display: flex;

+    -webkit-box-pack: center;

+	-webkit-justify-content: center;

+			justify-content: center;

+}

+.aui-dialog-btn {

+	position: relative;

+	display: block;

+    width: 100%;

+	padding: 0 0.25rem;

+	height: 2.2rem;

+	font-size: 0.8rem;

+	line-height: 2.2rem;

+	text-align: center;

+	color: #0894ec;

+	border-right: 1px solid #dddddd;

+	white-space: nowrap;

+	text-overflow: ellipsis;

+	overflow: hidden;

+	-webkit-box-sizing: border-box;

+			box-sizing: border-box;

+	-webkit-box-flex: 1;

+			box-flex: 1;

+}

+.aui-dialog-btn:last-child {

+	border-right: none;

+}

+.aui-dialog.aui-dialog-in {

+	opacity: 1;

+	-webkit-transition-duration: 300ms;

+	      transition-duration: 300ms;

+	-webkit-transform: translate3d(0, 0, 0) scale(1);

+	      transform: translate3d(0, 0, 0) scale(1);

+}

+.aui-dialog.aui-dialog-out {

+	opacity: 0;

+	-webkit-transition-duration: 300ms;

+	      transition-duration: 300ms;

+	-webkit-transform: translate3d(0, 0, 0) scale(0.815);

+	      transform: translate3d(0, 0, 0) scale(0.815);

+}

+@media only screen and (-webkit-min-device-pixel-ratio: 1.5) {

+    .aui-dialog-footer {

+		border: none;

+        background-size: 100% 1px;

+		background-repeat: no-repeat;

+		background-position: top;

+        background-image: linear-gradient(0,#dddddd,#dddddd 50%,transparent 50%);

+        background-image: -webkit-linear-gradient(90deg,#dddddd,#dddddd 50%,transparent 50%);

+	}

+	.aui-dialog-btn {

+		border: none;

+        background-image: -webkit-linear-gradient(0deg, #dddddd, #dddddd 50%, transparent 50%);

+        background-image: linear-gradient(270deg, #dddddd, #dddddd 50%, transparent 50%);

+        background-size: 1px 100%;

+        background-repeat: no-repeat;

+        background-position: right;

+	}

+	.aui-dialog-btn:last-child {

+		border: none;

+        background-size: 0 100%;

+	}

+	.aui-dialog-body input {

+        border: none;

+        background-image: -webkit-linear-gradient(270deg, #dddddd, #dddddd 50%, transparent 50%), -webkit-linear-gradient(180deg, #dddddd, #dddddd 50%, transparent 50%), -webkit-linear-gradient(90deg, #dddddd, #dddddd 50%, transparent 50%), -webkit-linear-gradient(0, #dddddd, #dddddd 50%, transparent 50%);

+        background-image: linear-gradient(180deg, #dddddd, #dddddd 50%, transparent 50%), linear-gradient(270deg, #dddddd, #dddddd 50%, transparent 50%), linear-gradient(0deg, #dddddd, #dddddd 50%, transparent 50%), linear-gradient(90deg, #dddddd, #dddddd 50%, transparent 50%);

+        background-size: 100% 1px, 1px 100%, 100% 1px, 1px 100%;

+        background-repeat: no-repeat;

+        background-position: top, right top, bottom, left top;

+    }

+}

+/*popup*/

+.aui-popup {

+    padding: 0;

+    margin: 0;

+    background: transparent;

+    position: fixed;

+    height: auto;

+    min-width: 7rem;

+    min-height: 4.5rem;

+    z-index: 999;

+    opacity: 0;

+ 	-webkit-transition-property: -webkit-transform, opacity;

+          	transition-property: transform, opacity;

+}

+.aui-popup.aui-popup-in {

+	opacity: 1;

+	-webkit-transition-duration: 300ms;

+	      transition-duration: 300ms;

+}

+.aui-popup.aui-popup-out {

+	opacity: 0;

+	-webkit-transition-duration: 300ms;

+	      transition-duration: 300ms;

+}

+.aui-popup-right {

+    right: 0.75rem;

+}

+.aui-popup-content {

+    background-color: #ffffff;

+    border-radius: 0.2rem;

+    overflow: hidden;

+    min-height: 4.5rem;

+    height: 100%;

+}

+.aui-popup-top,

+.aui-popup-top-left,

+.aui-popup-top-right {

+    top: 0.45rem;

+}

+.aui-popup-top {

+    left: 50%;

+    margin-left: -3.5rem;

+}

+.aui-popup-top-left {

+    left: 0.45rem;

+}

+.aui-popup-top-right {

+    right: 0.45rem;

+}

+.aui-popup-arrow {

+    position: absolute;

+    width: 10px;

+    height: 10px;

+    -webkit-transform-origin: 50% 50% 0;

+            transform-origin: 50% 50% 0;

+    background-color: transparent;

+    background-image: -webkit-linear-gradient(45deg, #ffffff, #ffffff 50%, transparent 50%);

+    background-image: linear-gradient(45deg, #ffffff, #ffffff 50%, transparent 50%);

+}

+.aui-popup-top .aui-popup-arrow,

+.aui-popup-top-left .aui-popup-arrow,

+.aui-popup-top-right .aui-popup-arrow {

+    top: 0.2rem;

+    -webkit-transform: rotate(135deg);

+            transform: rotate(135deg);

+}

+.aui-popup-top .aui-popup-arrow {

+    left: 50%;

+    margin-left: -0.25rem;

+    margin-top: -0.4rem;

+}

+.aui-popup-top-left .aui-popup-arrow {

+    left: 0.25rem;

+    margin-top: -0.4rem;

+}

+.aui-popup-top-right .aui-popup-arrow {

+    right: 0.25rem;

+    margin-top: -0.4rem;

+}

+.aui-popup-bottom,

+.aui-popup-bottom-left,

+.aui-popup-bottom-right {

+    bottom: 0.45rem;

+}

+.aui-popup-bottom {

+    left: 50%;

+    margin-left: -3.5rem;

+}

+.aui-popup-bottom-left {

+    left: 0.45rem;

+}

+.aui-popup-bottom-right {

+    right: 0.45rem;

+}

+.aui-popup-bottom .aui-popup-arrow,

+.aui-popup-bottom-left .aui-popup-arrow,

+.aui-popup-bottom-right .aui-popup-arrow {

+    -webkit-transform: rotate(-45deg);

+            transform: rotate(-45deg);

+    bottom: 0.2rem;

+}

+.aui-popup-bottom .aui-popup-arrow {

+    left: 50%;

+    margin-left: -0.25rem;

+    margin-bottom: -0.4rem;

+}

+.aui-popup-bottom-left .aui-popup-arrow {

+    left: 0.25rem;

+    margin-bottom: -0.4rem;

+}

+.aui-popup-bottom-right .aui-popup-arrow {

+    right: 0.25rem;

+    margin-bottom: -0.4rem;

+}

+.aui-popup .aui-list {

+	background: transparent;

+}

+.aui-popup-content .aui-list img {

+	display: block;

+	width: 1rem;

+}

+/*actionsheet*/

+.aui-actionsheet {

+    width: 100%;

+    position: fixed;

+    bottom: 0;

+    left: 0;

+    padding: 0 0.5rem;

+    z-index: 999;

+    opacity: 0;

+    -webkit-transition: opacity .3s,-webkit-transform .3s;

+    transition: opacity .3s,transform .3s;

+    -webkit-transform: translate3d(0,100%,0);

+    transform: translate3d(0,100%,0);

+}

+.aui-actionsheet-btn {

+    background-color: #ffffff;

+    border-radius: 6px;

+    text-align: center;

+    margin-bottom: 0.5rem;

+}

+.aui-actionsheet-title {

+    font-size: 0.6rem;

+    color: #999999;

+    line-height: 1.8rem;

+}

+.aui-actionsheet-btn-item {

+    height: 2.2rem;

+    line-height: 2.2rem;

+    color: #0075f0;

+}

+/*sharebox*/

+.aui-sharebox {

+    width: 100%;

+    position: fixed;

+    bottom: 0;

+    left: 0;

+    z-index: 999;

+    background-color: #ffffff;

+    opacity: 0;

+    -webkit-transition: opacity .3s,-webkit-transform .3s;

+    transition: opacity .3s,transform .3s;

+    -webkit-transform: translate3d(0,100%,0);

+    transform: translate3d(0,100%,0);

+}

+.aui-sharebox .aui-row {

+    padding: 0.5rem 0;

+}

+.aui-sharebox img {

+    display: block;

+    width: 50%;

+    margin: 0 auto;

+}

+.aui-sharebox.aui-grid [class*=aui-col-] {

+    padding: 0.5rem 0;

+}

+.aui-sharebox.aui-grid .aui-grid-label {

+    font-size: 0.6rem;

+    color: #757575;

+}

+.aui-sharebox-close-btn {

+    width: 100%;

+    height: 2.2rem;

+    line-height: 2.2rem;

+    color: #757575;

+    text-align: center;

+    font-size: 0.7rem;

+}

+/*折叠菜单*/

+.aui-collapse-header.aui-active {

+    background: #ececec;

+}

+.aui-collapse .aui-list-item:active{

+    background: #ececec;

+}

+.aui-collapse-content {

+    display: none;

+}

+.aui-collapse-content .aui-list-item:last-child {

+    border-bottom: 0;

+}

+@media screen and (-webkit-min-device-pixel-ratio:1.5) {

+    .aui-collapse-content .aui-list-item:last-child {

+        background-position: bottom;

+    }

+    .aui-list.aui-collapse.aui-list-noborder,

+    .aui-list.aui-collapse.aui-list-noborder .aui-collapse-content:last-child .aui-list-item:last-child {

+        border: none;

+        background-size: 100% 1px;

+        background-repeat: no-repeat;

+        background-position: 0 bottom;

+        background-image: linear-gradient(0,#dddddd,#dddddd 50%,transparent 50%);

+        background-image: -webkit-linear-gradient(90deg,#dddddd,#dddddd 50%,transparent 50%);

+    }

+    .aui-list.aui-collapse.aui-list-noborder,

+    .aui-list.aui-collapse.aui-list-noborder .aui-collapse-item:last-child .aui-list-item:last-child {

+        border: none;

+        background-size: 100% 0;

+        background-image: none;

+    }

+    .aui-list.aui-collapse.aui-list-noborder .aui-collapse-item:last-child .aui-list-item.aui-collapse-header,

+    .aui-list.aui-collapse.aui-list-noborder .aui-collapse-content .aui-list-item:last-child  {

+        border: none;

+        background-size: 100% 0;

+        background-image: none;

+    }

+}

+.aui-collapse-header.aui-active .aui-collapse-arrow {

+    display: block;

+    transform: rotate(180deg);

+    -webkit-transform: rotate(180deg);

+}

+/*聊天气泡*/

+.aui-chat {

+    width: 100%;

+    height: 100%;

+    padding: 0.5rem;

+}

+.aui-chat .aui-chat-item {

+    position: relative;

+    width: 100%;

+    margin-bottom: 0.75rem;

+    overflow: hidden;

+    display: block;

+}

+.aui-chat .aui-chat-header {

+    width: 100%;

+    text-align: center;

+    margin-bottom: 0.75rem;

+    font-size: 0.6rem;

+    color: #757575;

+}

+.aui-chat .aui-chat-left {

+    float: left;

+}

+.aui-chat .aui-chat-right {

+    float: right;

+}

+.aui-chat .aui-chat-media {

+    display: inline-block;

+    max-width: 2rem;

+}

+.aui-chat .aui-chat-media img {

+    width: 100%;

+    border-radius: 50%;

+}

+.aui-chat .aui-chat-inner {

+    position: relative;

+    overflow: hidden;

+    display: inherit;

+}

+.aui-chat .aui-chat-arrow {

+    content: '';

+    position: absolute;

+    width: 0.6rem;

+    height: 0.6rem;

+    top: 0.2rem;

+    -webkit-transform-origin: 50% 50% 0;

+            transform-origin: 50% 50% 0;

+    background-color: transparent;

+}

+.aui-chat .aui-chat-left .aui-chat-arrow {

+    background-image: -webkit-linear-gradient(45deg, #b3e5fc, #b3e5fc 50%, transparent 50%);

+    background-image: linear-gradient(45deg, #b3e5fc, #b3e5fc 50%, transparent 50%);

+    -webkit-transform: rotate(45deg);

+            transform: rotate(45deg);

+    left: -0.25rem;

+}

+.aui-chat .aui-chat-right .aui-chat-arrow {

+    background-image: -webkit-linear-gradient(45deg, #ffffff, #ffffff 50%, transparent 50%);

+    background-image: linear-gradient(45deg, #ffffff, #ffffff 50%, transparent 50%);

+    -webkit-transform: rotate(-135deg);

+            transform: rotate(-135deg);

+    right: -0.25rem;

+}

+.aui-chat .aui-chat-content {

+    color: #212121;

+    font-size: 0.7rem;

+    border-radius: 0.2rem;

+    min-height: 2rem;

+    position: relative;

+    padding: 0.5rem;

+    max-width: 80%;

+    word-break: break-all;

+    word-wrap: break-word;

+}

+.aui-chat .aui-chat-content img {

+    max-width: 100%;

+    display: block;

+}

+.aui-chat .aui-chat-status {

+    position: relative;

+    width: 2rem;

+    height: 2rem;

+    line-height: 2rem;

+    text-align: center;

+}

+.aui-chat .aui-chat-name {

+    width: 100%;

+    position: relative;

+    font-size: 0.6rem;

+    color: #757575;

+    margin-bottom: 0.25rem;

+}

+.aui-chat .aui-chat-left .aui-chat-name {

+    left: 0.5rem;

+}

+.aui-chat .aui-chat-left .aui-chat-status {

+    left: 0.5rem;

+    float: left;

+}

+.aui-chat .aui-chat-left .aui-chat-media {

+    width: 2rem;

+    float: left;

+}

+.aui-chat .aui-chat-left .aui-chat-inner {

+    max-width: 70%;

+}

+.aui-chat .aui-chat-left .aui-chat-content{

+    background-color: #b3e5fc;

+    float: left;

+    left: 0.5rem;

+}

+.aui-chat .aui-chat-right .aui-chat-media {

+    width: 2rem;

+    float: right;

+}

+.aui-chat .aui-chat-right .aui-chat-inner {

+    float: right;

+    max-width: 70%;

+}

+.aui-chat .aui-chat-right .aui-chat-name {

+    float: right;

+    right: 0.5rem;

+    text-align: right;

+}

+.aui-chat .aui-chat-right .aui-chat-content {

+    background-color: #ffffff;

+    right: 0.5rem;

+    float: right;

+}

+.aui-chat .aui-chat-right .aui-chat-status {

+    float: right;

+    right: 0.5rem;

+}

+/*边框样式*/

+.aui-border-l {

+    border-left: 1px solid #dddddd;

+}

+.aui-border-r {

+    border-right: 1px solid #dddddd;

+}

+.aui-border-t {

+    border-top: 1px solid #dddddd;

+}

+.aui-border-b {

+    border-bottom: 1px solid #dddddd;

+}

+.aui-border {

+    border: 1px solid #dddddd;

+}

+@media screen and (-webkit-min-device-pixel-ratio:1.5) {

+	.aui-border-l {

+		border: none;

+        background-image: -webkit-linear-gradient(0deg, #dddddd, #dddddd 50%, transparent 50%);

+        background-image: linear-gradient(270deg, #dddddd, #dddddd 50%, transparent 50%);

+        background-size: 1px 100%;

+        background-repeat: no-repeat;

+        background-position: left;

+	}

+	.aui-border-r {

+		border: none;

+        background-image: -webkit-linear-gradient(0deg, #dddddd, #dddddd 50%, transparent 50%);

+        background-image: linear-gradient(270deg, #dddddd, #dddddd 50%, transparent 50%);

+        background-size: 1px 100%;

+        background-repeat: no-repeat;

+        background-position: right;

+	}

+	.aui-border-t{

+		border: none;

+        background-size: 100% 1px;

+		background-repeat: no-repeat;

+		background-position: top;

+        background-image: linear-gradient(0,#dddddd,#dddddd 50%,transparent 50%);

+        background-image: -webkit-linear-gradient(90deg,#dddddd,#dddddd 50%,transparent 50%);

+	}

+	.aui-border-b {

+		border: none;

+        background-size: 100% 1px;

+		background-repeat: no-repeat;

+		background-position: bottom;

+        background-image: linear-gradient(0,#dddddd,#dddddd 50%,transparent 50%);

+        background-image: -webkit-linear-gradient(90deg,#dddddd,#dddddd 50%,transparent 50%);

+	}

+	.aui-border{

+        border: none;

+        background-image: -webkit-linear-gradient(270deg, #dddddd, #dddddd 50%, transparent 50%), -webkit-linear-gradient(180deg, #dddddd, #dddddd 50%, transparent 50%), -webkit-linear-gradient(90deg, #dddddd, #dddddd 50%, transparent 50%), -webkit-linear-gradient(0, #dddddd, #dddddd 50%, transparent 50%);

+        background-image: linear-gradient(180deg, #dddddd, #dddddd 50%, transparent 50%), linear-gradient(270deg, #dddddd, #dddddd 50%, transparent 50%), linear-gradient(0deg, #dddddd, #dddddd 50%, transparent 50%), linear-gradient(90deg, #dddddd, #dddddd 50%, transparent 50%);

+        background-size: 100% 1px, 1px 100%, 100% 1px, 1px 100%;

+        background-repeat: no-repeat;

+        background-position: top, right top, bottom, left top;

+    }

+}

+/*时间轴*/

+.aui-timeline {

+    position: relative;

+    padding: 0;

+    list-style: none;

+}

+.aui-timeline:before {

+    content: '';

+    position: absolute;

+    top: 0;

+    left: 1.85rem;

+    width: 2px;

+    height: 100%;

+    background: #ececec;

+    z-index: 0;

+}

+.aui-timeline .aui-timeline-item {

+    position: relative;

+    margin-bottom: 0.35rem;

+}

+.aui-timeline .aui-timeline-item-header {

+	background-color: #ececec;

+	padding: 0.2rem 0.5rem;

+	margin: 0.75rem;

+    text-align: center;

+    display: inline-block;

+    position: relative;

+    z-index: 1;

+    font-size: 0.7rem;

+}

+.aui-timeline .aui-timeline-item-label {

+    width: 2.5rem;

+    height: 1.5rem;

+    line-height: 1.5rem;

+    font-size: 0.7em;

+    background-color: #ececec;

+    position: absolute;

+    text-align: center;

+    left: 0.75rem;

+    top: 0;

+}

+.aui-timeline .aui-timeline-item-label-icon {

+    width: 1.5rem;

+    height: 1.5rem;

+    font-size: 0.7rem;

+    line-height: 1.5rem;

+    background-color: #ececec;

+    position: absolute;

+    border-radius: 50%;

+    text-align: center;

+    left: 1.15rem;

+    top: 0;

+}

+.aui-timeline .aui-timeline-item-inner {

+    margin-left: 3.75rem;

+    margin-right: 0.75rem;

+    padding: 0;

+    position: relative;

+}

+/*基础动画类*/

+@keyframes rotate {

+    0% {

+        -webkit-transform: rotate(0deg) scale(1);

+            	transform: rotate(0deg) scale(1);

+    }

+    50% {

+        -webkit-transform: rotate(180deg) scale(1);

+            	transform: rotate(180deg) scale(1);

+    }

+    100% {

+        -webkit-transform: rotate(360deg) scale(1);

+            	transform: rotate(360deg) scale(1);

+    }

+}

+@-webkit-keyframes rotate {

+    0% {

+        -webkit-transform: rotate(0deg) scale(1);

+            	transform: rotate(0deg) scale(1);

+    }

+    50% {

+        -webkit-transform: rotate(180deg) scale(1);

+            	transform: rotate(180deg) scale(1);

+    }

+    100% {

+        -webkit-transform: rotate(360deg) scale(1);

+            	transform: rotate(360deg) scale(1);

+    }

+}

+@keyframes bounce {

+	0%, 100% {

+	-webkit-transform: scale(0.0);

+			transform: scale(0.0);

+	}

+	50% {

+	-webkit-transform: scale(1.0);

+			transform: scale(1.0);

+	}

+}

+@-webkit-keyframes bounce {

+	0%, 100% {

+		-webkit-transform: scale(0.0);

+				transform: scale(0.0);

+	}

+	50% {

+		-webkit-transform: scale(1.0);

+				transform: scale(1.0);

+	}

+}

+@keyframes fadeIn {

+    from { opacity: 0.3; }

+    to { opacity: 1; }

+}

+@-webkit-keyframes fadeIn {

+    from { opacity: 0.3; }

+    to { opacity: 1; }

+}

+@font-face {

+	font-family: "aui_iconfont";

+	src: url('aui-iconfont.ttf') format('truetype');

+}

+.aui-iconfont {

+	position: relative;

+	font-family:"aui_iconfont" !important;

+	font-size: 0.7rem;

+	font-style:normal;

+	-webkit-font-smoothing: antialiased;

+	-moz-osx-font-smoothing: grayscale;

+}

+.aui-icon-menu:before { content: "\e6eb"; }

+.aui-icon-paper:before { content: "\e6ec"; }

+.aui-icon-info:before { content: "\e6ed"; }

+.aui-icon-question:before { content: "\e6ee"; }

+.aui-icon-left:before { content: "\e6f4"; }

+.aui-icon-right:before { content: "\e6f5"; }

+.aui-icon-top:before { content: "\e6f6"; }

+.aui-icon-down:before { content: "\e6f7"; }

+.aui-icon-share:before { content: "\e700"; }

+.aui-icon-comment:before { content: "\e701"; }

+.aui-icon-edit:before { content: "\e6d3"; }

+.aui-icon-trash:before { content: "\e6d4"; }

+.aui-icon-recovery:before { content: "\e6dc"; }

+.aui-icon-refresh:before { content: "\e6dd"; }

+.aui-icon-close:before { content: "\e6d8"; }

+.aui-icon-cart:before { content: "\e6df"; }

+.aui-icon-star:before { content: "\e6e0"; }

+.aui-icon-plus:before { content: "\e6e3"; }

+.aui-icon-minus:before { content: "\e62d"; }

+.aui-icon-correct:before { content: "\e6e5"; }

+.aui-icon-search:before { content: "\e6e6"; }

+.aui-icon-gear:before { content: "\e6e8"; }

+.aui-icon-map:before { content: "\e6d2"; }

+.aui-icon-location:before { content: "\e6d1"; }

+.aui-icon-image:before { content: "\e6ce"; }

+.aui-icon-phone:before { content: "\e6c4"; }

+.aui-icon-camera:before { content: "\e6cd"; }

+.aui-icon-video:before { content: "\e6cc"; }

+.aui-icon-qq:before { content: "\e6cb"; }

+.aui-icon-wechat:before { content: "\e6c9"; }

+.aui-icon-weibo:before { content: "\e6c8"; }

+.aui-icon-note:before { content: "\e6c6"; }

+.aui-icon-mail:before { content: "\e6c5"; }

+.aui-icon-wechat-circle:before { content: "\e6ca"; }

+.aui-icon-home:before { content: "\e706"; }

+.aui-icon-forward:before { content: "\e6d9"; }

+.aui-icon-back:before { content: "\e6da"; }

+.aui-icon-laud:before { content: "\e64b"; }

+.aui-icon-lock:before { content: "\e6ef"; }

+.aui-icon-unlock:before { content: "\e62f"; }

+.aui-icon-like:before { content: "\e62b"; }

+.aui-icon-my:before { content: "\e610"; }

+.aui-icon-more:before { content: "\e625"; }

+.aui-icon-mobile:before { content: "\e697"; }

+.aui-icon-calendar:before { content: "\e68a"; }

+.aui-icon-date:before { content: "\e68c"; }

+.aui-icon-display:before { content: "\e612"; }

+.aui-icon-hide:before { content: "\e624"; }

+.aui-icon-pencil:before { content: "\e615"; }

+.aui-icon-flag:before { content: "\e6f1"; }

+.aui-icon-cert:before { content: "\e704"; }

+

+.aui-card-list-user:after {

+	width: 100%;

+    height: 1px;

+    background-color: #f2f2f2;

+    display: block;

+    content: '';

+    position: absolute;

+    top: auto;

+    right: auto;

+    bottom: 0;

+    left: 0;

+    z-index: 2;

+    -webkit-transform-origin: 50% 100%;

+            transform-origin: 50% 100%;

+    pointer-events: none;

+}

+.aui-list [class*=top-btn]:active {

+	background-color: #048cca;

+}

diff --git a/platforms/android/app/src/main/assets/www/css/index.css b/platforms/android/app/src/main/assets/www/css/index.css
new file mode 100644
index 0000000..b23e33c
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/css/index.css
@@ -0,0 +1,149 @@
+body {
+    background: #F1F4F4;
+}
+
+.mainbg {
+    background: #03a9f4;
+}
+
+.lightbg {
+    background: #54C8FF;
+}
+
+.tab-bottom button.active::after {
+    background-color: transparent;
+}
+
+.maincolor {
+    color: #03a9f4;
+}
+
+.qrscanner {
+    width: 100%;
+    background: transparent none !important;
+    padding-top: 52px;
+}
+
+.qrscanner-area {
+    height: 100mm;
+    background: url(../img/scanner.svg) no-repeat center center;
+    background-size: contain;
+}
+
+.through-line {
+    left: 20%;
+    width: 60%;
+    height: 2px;
+    background: red;
+    position: absolute;
+    animation: myfirst 2s linear infinite alternate;
+}
+
+@keyframes myfirst {
+    0% {
+        background: #03a9f4;
+        top: 180px;
+    }
+
+    25% {
+        background: #03a9f4;
+        top: 215px;
+    }
+
+    50% {
+        background: #03a9f4;
+        top: 250px;
+    }
+
+    75% {
+        background: #03a9f4;
+        top: 285px;
+    }
+
+    100% {
+        background: #03a9f4;
+        top: 320px;
+    }
+}
+
+.button-bottom {
+    width: 128px;
+    position: absolute;
+    left: 50%;
+    bottom: 80px;
+    margin-left: -64px;
+}
+
+.icon-camera {
+    float: left;
+}
+
+.vcodedisabled {
+    color: #999 !important;
+}
+
+.login-top {
+    height: 200px;
+    background: #03a9f4;
+    color: #fff;
+    font-size: 36px;
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    align-items: center;
+}
+
+.weui-toast_content {
+    color: #fff;
+}
+
+.center-in {
+    flex-direction: row;
+    justify-content: center;
+    align-items: center;
+    display: flex;
+}
+
+.top-title {
+    color: #fff;
+    font-size: 20px !important;
+    margin-top: 5px;
+}
+
+.user-info {
+    width: 150%;
+    position: relative;
+    left: -25%;
+    padding-left: 25%;
+    border-bottom-left-radius: 50%;
+    border-bottom-right-radius: 50%;
+    padding-bottom: 1.5rem;
+}
+
+.text-white {
+    color: #ffffff !important;
+}
+
+.text-light {
+    color: #999 !important;
+}
+
+.bg-white {
+    background-color: #ffffff;
+}
+.demos-header {
+    padding: 20px 0;
+    background-color: #03a9f4;
+}
+.demos-title {
+    text-align: center;
+    font-size: 40px;
+    color: #fff;
+    font-weight: 400;
+    margin: 0 15%;
+}
+.detail-title{
+    text-align: center;
+    font-size: 16px;
+    color: #fff;
+}
diff --git a/platforms/android/app/src/main/assets/www/css/jquery-weui.min.css b/platforms/android/app/src/main/assets/www/css/jquery-weui.min.css
new file mode 100755
index 0000000..145c336
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/css/jquery-weui.min.css
@@ -0,0 +1,6 @@
+/** 
+* jQuery WeUI V1.2.1 
+* By 言川
+* http://lihongxun945.github.io/jquery-weui/
+ */
+.preloader{width:20px;height:20px;-webkit-transform-origin:50%;transform-origin:50%;-webkit-animation:preloader-spin 1s steps(12,end) infinite;animation:preloader-spin 1s steps(12,end) infinite}.preloader:after{display:block;width:100%;height:100%;content:"";background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20viewBox%3D'0%200%20120%20120'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20xmlns%3Axlink%3D'http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink'%3E%3Cdefs%3E%3Cline%20id%3D'l'%20x1%3D'60'%20x2%3D'60'%20y1%3D'7'%20y2%3D'27'%20stroke%3D'%236c6c6c'%20stroke-width%3D'11'%20stroke-linecap%3D'round'%2F%3E%3C%2Fdefs%3E%3Cg%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(30%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(60%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(90%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(120%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(150%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.37'%20transform%3D'rotate(180%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.46'%20transform%3D'rotate(210%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.56'%20transform%3D'rotate(240%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.66'%20transform%3D'rotate(270%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.75'%20transform%3D'rotate(300%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.85'%20transform%3D'rotate(330%2060%2C60)'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");background-repeat:no-repeat;background-position:50%;background-size:100%}@-webkit-keyframes preloader-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}label>*{pointer-events:none}html{font-size:20px}body{font-size:16px}@media only screen and (min-width:400px){html{font-size:21.33px!important}}@media only screen and (min-width:414px){html{font-size:22.08px!important}}@media only screen and (min-width:480px){html{font-size:25.6px!important}}.weui_navbar{z-index:10}.weui-mask,.weui-popup-container,.weui-popup-overlay{z-index:1000}.weui-row{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-lines:multiple;-moz-box-lines:multiple;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.weui-row>[class*=col-]{box-sizing:border-box}.weui-row .col-auto{width:100%}.weui-row .weui-col-100{width:100%;width:calc((100% - 15px*0)/ 1)}.weui-row.weui-no-gutter .weui-col-100{width:100%}.weui-row .weui-col-95{width:95%;width:calc((100% - 15px*.05263157894736836)/ 1.0526315789473684)}.weui-row.weui-no-gutter .weui-col-95{width:95%}.weui-row .weui-col-90{width:90%;width:calc((100% - 15px*.11111111111111116)/ 1.1111111111111112)}.weui-row.weui-no-gutter .weui-col-90{width:90%}.weui-row .weui-col-85{width:85%;width:calc((100% - 15px*.17647058823529416)/ 1.1764705882352942)}.weui-row.weui-no-gutter .weui-col-85{width:85%}.weui-row .weui-col-80{width:80%;width:calc((100% - 15px*.25)/ 1.25)}.weui-row.weui-no-gutter .weui-col-80{width:80%}.weui-row .weui-col-75{width:75%;width:calc((100% - 15px*.33333333333333326)/ 1.3333333333333333)}.weui-row.weui-no-gutter .weui-col-75{width:75%}.weui-row .weui-col-66{width:66.66666666666666%;width:calc((100% - 15px*.5000000000000002)/ 1.5000000000000002)}.weui-row.weui-no-gutter .weui-col-66{width:66.66666666666666%}.weui-row .weui-col-60{width:60%;width:calc((100% - 15px*.6666666666666667)/ 1.6666666666666667)}.weui-row.weui-no-gutter .weui-col-60{width:60%}.weui-row .weui-col-50{width:50%;width:calc((100% - 15px*1)/ 2)}.weui-row.weui-no-gutter .weui-col-50{width:50%}.weui-row .weui-col-40{width:40%;width:calc((100% - 15px*1.5)/ 2.5)}.weui-row.weui-no-gutter .weui-col-40{width:40%}.weui-row .weui-col-33{width:33.333333333333336%;width:calc((100% - 15px*2)/ 3)}.weui-row.weui-no-gutter .weui-col-33{width:33.333333333333336%}.weui-row .weui-col-25{width:25%;width:calc((100% - 15px*3)/ 4)}.weui-row.weui-no-gutter .weui-col-25{width:25%}.weui-row .weui-col-20{width:20%;width:calc((100% - 15px*4)/ 5)}.weui-row.weui-no-gutter .weui-col-20{width:20%}.weui-row .weui-col-15{width:15%;width:calc((100% - 15px*5.666666666666667)/ 6.666666666666667)}.weui-row.weui-no-gutter .weui-col-15{width:15%}.weui-row .weui-col-10{width:10%;width:calc((100% - 15px*9)/ 10)}.weui-row.weui-no-gutter .weui-col-10{width:10%}.weui-row .weui-col-5{width:5%;width:calc((100% - 15px*19)/ 20)}.weui-row.weui-no-gutter .weui-col-5{width:5%}.weui-row .weui-col-auto:nth-last-child(1),.weui-row .weui-col-auto:nth-last-child(1)~.weui-col-auto{width:100%;width:calc((100% - 15px*0)/ 1)}.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(1),.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(1)~.weui-col-auto{width:100%}.weui-row .weui-col-auto:nth-last-child(2),.weui-row .weui-col-auto:nth-last-child(2)~.weui-col-auto{width:50%;width:calc((100% - 15px*1)/ 2)}.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(2),.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(2)~.weui-col-auto{width:50%}.weui-row .weui-col-auto:nth-last-child(3),.weui-row .weui-col-auto:nth-last-child(3)~.weui-col-auto{width:33.33333333%;width:calc((100% - 15px*2)/ 3)}.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(3),.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(3)~.weui-col-auto{width:33.33333333%}.weui-row .weui-col-auto:nth-last-child(4),.weui-row .weui-col-auto:nth-last-child(4)~.weui-col-auto{width:25%;width:calc((100% - 15px*3)/ 4)}.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(4),.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(4)~.weui-col-auto{width:25%}.weui-row .weui-col-auto:nth-last-child(5),.weui-row .weui-col-auto:nth-last-child(5)~.weui-col-auto{width:20%;width:calc((100% - 15px*4)/ 5)}.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(5),.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(5)~.weui-col-auto{width:20%}.weui-row .weui-col-auto:nth-last-child(6),.weui-row .weui-col-auto:nth-last-child(6)~.weui-col-auto{width:16.66666667%;width:calc((100% - 15px*5)/ 6)}.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(6),.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(6)~.weui-col-auto{width:16.66666667%}.weui-row .weui-col-auto:nth-last-child(7),.weui-row .weui-col-auto:nth-last-child(7)~.weui-col-auto{width:14.28571429%;width:calc((100% - 15px*6)/ 7)}.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(7),.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(7)~.weui-col-auto{width:14.28571429%}.weui-row .weui-col-auto:nth-last-child(8),.weui-row .weui-col-auto:nth-last-child(8)~.weui-col-auto{width:12.5%;width:calc((100% - 15px*7)/ 8)}.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(8),.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(8)~.weui-col-auto{width:12.5%}.weui-row .weui-col-auto:nth-last-child(9),.weui-row .weui-col-auto:nth-last-child(9)~.weui-col-auto{width:11.11111111%;width:calc((100% - 15px*8)/ 9)}.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(9),.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(9)~.weui-col-auto{width:11.11111111%}.weui-row .weui-col-auto:nth-last-child(10),.weui-row .weui-col-auto:nth-last-child(10)~.weui-col-auto{width:10%;width:calc((100% - 15px*9)/ 10)}.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(10),.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(10)~.weui-col-auto{width:10%}.weui-row .weui-col-auto:nth-last-child(11),.weui-row .weui-col-auto:nth-last-child(11)~.weui-col-auto{width:9.09090909%;width:calc((100% - 15px*10)/ 11)}.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(11),.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(11)~.weui-col-auto{width:9.09090909%}.weui-row .weui-col-auto:nth-last-child(12),.weui-row .weui-col-auto:nth-last-child(12)~.weui-col-auto{width:8.33333333%;width:calc((100% - 15px*11)/ 12)}.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(12),.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(12)~.weui-col-auto{width:8.33333333%}.weui-row .weui-col-auto:nth-last-child(13),.weui-row .weui-col-auto:nth-last-child(13)~.weui-col-auto{width:7.69230769%;width:calc((100% - 15px*12)/ 13)}.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(13),.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(13)~.weui-col-auto{width:7.69230769%}.weui-row .weui-col-auto:nth-last-child(14),.weui-row .weui-col-auto:nth-last-child(14)~.weui-col-auto{width:7.14285714%;width:calc((100% - 15px*13)/ 14)}.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(14),.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(14)~.weui-col-auto{width:7.14285714%}.weui-row .weui-col-auto:nth-last-child(15),.weui-row .weui-col-auto:nth-last-child(15)~.weui-col-auto{width:6.66666667%;width:calc((100% - 15px*14)/ 15)}.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(15),.weui-row.weui-no-gutter .weui-col-auto:nth-last-child(15)~.weui-col-auto{width:6.66666667%}@media all and (min-width:768px){.row .tablet-100{width:100%;width:calc((100% - 15px*0)/ 1)}.row.no-gutter .tablet-100{width:100%}.row .tablet-95{width:95%;width:calc((100% - 15px*.05263157894736836)/ 1.0526315789473684)}.row.no-gutter .tablet-95{width:95%}.row .tablet-90{width:90%;width:calc((100% - 15px*.11111111111111116)/ 1.1111111111111112)}.row.no-gutter .tablet-90{width:90%}.row .tablet-85{width:85%;width:calc((100% - 15px*.17647058823529416)/ 1.1764705882352942)}.row.no-gutter .tablet-85{width:85%}.row .tablet-80{width:80%;width:calc((100% - 15px*.25)/ 1.25)}.row.no-gutter .tablet-80{width:80%}.row .tablet-75{width:75%;width:calc((100% - 15px*.33333333333333326)/ 1.3333333333333333)}.row.no-gutter .tablet-75{width:75%}.row .tablet-66{width:66.66666666666666%;width:calc((100% - 15px*.5000000000000002)/ 1.5000000000000002)}.row.no-gutter .tablet-66{width:66.66666666666666%}.row .tablet-60{width:60%;width:calc((100% - 15px*.6666666666666667)/ 1.6666666666666667)}.row.no-gutter .tablet-60{width:60%}.row .tablet-50{width:50%;width:calc((100% - 15px*1)/ 2)}.row.no-gutter .tablet-50{width:50%}.row .tablet-40{width:40%;width:calc((100% - 15px*1.5)/ 2.5)}.row.no-gutter .tablet-40{width:40%}.row .tablet-33{width:33.333333333333336%;width:calc((100% - 15px*2)/ 3)}.row.no-gutter .tablet-33{width:33.333333333333336%}.row .tablet-25{width:25%;width:calc((100% - 15px*3)/ 4)}.row.no-gutter .tablet-25{width:25%}.row .tablet-20{width:20%;width:calc((100% - 15px*4)/ 5)}.row.no-gutter .tablet-20{width:20%}.row .tablet-15{width:15%;width:calc((100% - 15px*5.666666666666667)/ 6.666666666666667)}.row.no-gutter .tablet-15{width:15%}.row .tablet-10{width:10%;width:calc((100% - 15px*9)/ 10)}.row.no-gutter .tablet-10{width:10%}.row .tablet-5{width:5%;width:calc((100% - 15px*19)/ 20)}.row.no-gutter .tablet-5{width:5%}.row .tablet-auto:nth-last-child(1),.row .tablet-auto:nth-last-child(1)~.col-auto{width:100%;width:calc((100% - 15px*0)/ 1)}.row.no-gutter .tablet-auto:nth-last-child(1),.row.no-gutter .tablet-auto:nth-last-child(1)~.tablet-auto{width:100%}.row .tablet-auto:nth-last-child(2),.row .tablet-auto:nth-last-child(2)~.col-auto{width:50%;width:calc((100% - 15px*1)/ 2)}.row.no-gutter .tablet-auto:nth-last-child(2),.row.no-gutter .tablet-auto:nth-last-child(2)~.tablet-auto{width:50%}.row .tablet-auto:nth-last-child(3),.row .tablet-auto:nth-last-child(3)~.col-auto{width:33.33333333%;width:calc((100% - 15px*2)/ 3)}.row.no-gutter .tablet-auto:nth-last-child(3),.row.no-gutter .tablet-auto:nth-last-child(3)~.tablet-auto{width:33.33333333%}.row .tablet-auto:nth-last-child(4),.row .tablet-auto:nth-last-child(4)~.col-auto{width:25%;width:calc((100% - 15px*3)/ 4)}.row.no-gutter .tablet-auto:nth-last-child(4),.row.no-gutter .tablet-auto:nth-last-child(4)~.tablet-auto{width:25%}.row .tablet-auto:nth-last-child(5),.row .tablet-auto:nth-last-child(5)~.col-auto{width:20%;width:calc((100% - 15px*4)/ 5)}.row.no-gutter .tablet-auto:nth-last-child(5),.row.no-gutter .tablet-auto:nth-last-child(5)~.tablet-auto{width:20%}.row .tablet-auto:nth-last-child(6),.row .tablet-auto:nth-last-child(6)~.col-auto{width:16.66666667%;width:calc((100% - 15px*5)/ 6)}.row.no-gutter .tablet-auto:nth-last-child(6),.row.no-gutter .tablet-auto:nth-last-child(6)~.tablet-auto{width:16.66666667%}.row .tablet-auto:nth-last-child(7),.row .tablet-auto:nth-last-child(7)~.col-auto{width:14.28571429%;width:calc((100% - 15px*6)/ 7)}.row.no-gutter .tablet-auto:nth-last-child(7),.row.no-gutter .tablet-auto:nth-last-child(7)~.tablet-auto{width:14.28571429%}.row .tablet-auto:nth-last-child(8),.row .tablet-auto:nth-last-child(8)~.col-auto{width:12.5%;width:calc((100% - 15px*7)/ 8)}.row.no-gutter .tablet-auto:nth-last-child(8),.row.no-gutter .tablet-auto:nth-last-child(8)~.tablet-auto{width:12.5%}.row .tablet-auto:nth-last-child(9),.row .tablet-auto:nth-last-child(9)~.col-auto{width:11.11111111%;width:calc((100% - 15px*8)/ 9)}.row.no-gutter .tablet-auto:nth-last-child(9),.row.no-gutter .tablet-auto:nth-last-child(9)~.tablet-auto{width:11.11111111%}.row .tablet-auto:nth-last-child(10),.row .tablet-auto:nth-last-child(10)~.col-auto{width:10%;width:calc((100% - 15px*9)/ 10)}.row.no-gutter .tablet-auto:nth-last-child(10),.row.no-gutter .tablet-auto:nth-last-child(10)~.tablet-auto{width:10%}.row .tablet-auto:nth-last-child(11),.row .tablet-auto:nth-last-child(11)~.col-auto{width:9.09090909%;width:calc((100% - 15px*10)/ 11)}.row.no-gutter .tablet-auto:nth-last-child(11),.row.no-gutter .tablet-auto:nth-last-child(11)~.tablet-auto{width:9.09090909%}.row .tablet-auto:nth-last-child(12),.row .tablet-auto:nth-last-child(12)~.col-auto{width:8.33333333%;width:calc((100% - 15px*11)/ 12)}.row.no-gutter .tablet-auto:nth-last-child(12),.row.no-gutter .tablet-auto:nth-last-child(12)~.tablet-auto{width:8.33333333%}.row .tablet-auto:nth-last-child(13),.row .tablet-auto:nth-last-child(13)~.col-auto{width:7.69230769%;width:calc((100% - 15px*12)/ 13)}.row.no-gutter .tablet-auto:nth-last-child(13),.row.no-gutter .tablet-auto:nth-last-child(13)~.tablet-auto{width:7.69230769%}.row .tablet-auto:nth-last-child(14),.row .tablet-auto:nth-last-child(14)~.col-auto{width:7.14285714%;width:calc((100% - 15px*13)/ 14)}.row.no-gutter .tablet-auto:nth-last-child(14),.row.no-gutter .tablet-auto:nth-last-child(14)~.tablet-auto{width:7.14285714%}.row .tablet-auto:nth-last-child(15),.row .tablet-auto:nth-last-child(15)~.col-auto{width:6.66666667%;width:calc((100% - 15px*14)/ 15)}.row.no-gutter .tablet-auto:nth-last-child(15),.row.no-gutter .tablet-auto:nth-last-child(15)~.tablet-auto{width:6.66666667%}}.weui-cell__hd img{display:block;margin-right:5px}.weui-cell_swiped .weui-cell__bd{-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s}.swipeout-touching .weui-cell__bd{-webkit-transition:none;transition:none}.weui-dialog,.weui-toast{-webkit-transition-duration:.2s;transition-duration:.2s;opacity:0;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);-webkit-transform-origin:0 0;transform-origin:0 0;visibility:hidden;margin:0;top:45%;z-index:2000}.weui-dialog .weui-dialog__btn.default,.weui-toast .weui-dialog__btn.default{color:#5f646e}.weui-dialog .weui-dialog__btn+.weui-dialog__btn,.weui-toast .weui-dialog__btn+.weui-dialog__btn{position:relative}.weui-dialog .weui-dialog__btn+.weui-dialog__btn:after,.weui-toast .weui-dialog__btn+.weui-dialog__btn:after{content:" ";position:absolute;left:0;top:0;width:1px;height:100%;border-left:1px solid #D5D5D6;color:#D5D5D6;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(.5);transform:scaleX(.5)}.weui-dialog.weui-dialog--visible,.weui-dialog.weui-toast--visible,.weui-toast.weui-dialog--visible,.weui-toast.weui-toast--visible{opacity:1;visibility:visible}.weui-toast_forbidden{color:#F76260}.weui-toast_cancel .weui-icon-toast:before{content:"\EA0D"}.weui-toast_forbidden .weui-icon-toast:before{content:"\EA0B";color:#F76260}.weui-toast_text{min-height:1em;width:auto;height:45px;border-radius:25px;margin-left:0;-webkit-transform:scale(.9) translate3d(-50%,0,0);transform:scale(.9) translate3d(-50%,0,0);-webkit-transform-origin:left;transform-origin:left}.weui-toast_text.weui-toast--visible{-webkit-transform:scale(1) translate3d(-50%,0,0);transform:scale(1) translate3d(-50%,0,0)}.weui-toast_text .weui-icon-toast{display:none}.weui-toast_text .weui-toast_content{margin:10px 15px}.weui-mask{opacity:0;-webkit-transition-duration:.3s;transition-duration:.3s;visibility:hidden}.weui-mask.weui-mask--visible{opacity:1;visibility:visible}.weui-prompt-input{padding:4px 6px;border:1px solid #ccc;box-sizing:border-box;height:2em;width:80%;margin-top:10px}.weui-pull-to-refresh{margin-top:-50px;-webkit-transition:-webkit-transform .4s;transition:-webkit-transform .4s;transition:transform .4s;transition:transform .4s,-webkit-transform .4s}.weui-pull-to-refresh.refreshing{-webkit-transform:translate3d(0,50px,0);transform:translate3d(0,50px,0)}.weui-pull-to-refresh.touching{-webkit-transition-duration:0s;transition-duration:0s}.weui-pull-to-refresh__layer{height:30px;line-height:30px;padding:10px;text-align:center}.weui-pull-to-refresh__layer .down{display:inline-block}.weui-pull-to-refresh__layer .refresh,.weui-pull-to-refresh__layer .up{display:none}.weui-pull-to-refresh__layer .weui-pull-to-refresh__arrow{display:inline-block;z-index:10;width:20px;height:20px;margin-right:4px;vertical-align:-4px;background:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2026%2040'%3E%3Cpolygon%20points%3D'9%2C22%209%2C0%2017%2C0%2017%2C22%2026%2C22%2013.5%2C40%200%2C22'%20fill%3D'%238c8c8c'%2F%3E%3C%2Fsvg%3E") center no-repeat;background-size:13px 20px;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transform:rotate(0) translate3d(0,0,0);transform:rotate(0) translate3d(0,0,0)}.weui-pull-to-refresh__layer .weui-pull-to-refresh__preloader{display:none;vertical-align:-4px;margin-right:4px;width:20px;height:20px;-webkit-transform-origin:50%;transform-origin:50%;-webkit-animation:preloader-spin 1s steps(12,end) infinite;animation:preloader-spin 1s steps(12,end) infinite}.weui-pull-to-refresh__layer .weui-pull-to-refresh__preloader:after{display:block;width:100%;height:100%;content:"";background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20viewBox%3D'0%200%20120%20120'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20xmlns%3Axlink%3D'http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink'%3E%3Cdefs%3E%3Cline%20id%3D'l'%20x1%3D'60'%20x2%3D'60'%20y1%3D'7'%20y2%3D'27'%20stroke%3D'%236c6c6c'%20stroke-width%3D'11'%20stroke-linecap%3D'round'%2F%3E%3C%2Fdefs%3E%3Cg%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(30%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(60%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(90%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(120%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(150%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.37'%20transform%3D'rotate(180%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.46'%20transform%3D'rotate(210%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.56'%20transform%3D'rotate(240%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.66'%20transform%3D'rotate(270%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.75'%20transform%3D'rotate(300%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.85'%20transform%3D'rotate(330%2060%2C60)'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");background-repeat:no-repeat;background-position:50%;background-size:100%}.pull-up .weui-pull-to-refresh__layer .down,.refreshing .weui-pull-to-refresh__layer .down{display:none}.pull-up .weui-pull-to-refresh__layer .weui-pull-to-refresh__arrow{display:inline-block;-webkit-transform:rotate(180deg) translate3d(0,0,0);transform:rotate(180deg) translate3d(0,0,0)}.pull-down .weui-pull-to-refresh__layer .down,.pull-down .weui-pull-to-refresh__layer .weui-pull-to-refresh__arrow,.pull-up .weui-pull-to-refresh__layer .up{display:inline-block}.refreshing .weui-pull-to-refresh__layer .weui-pull-to-refresh__arrow{display:none}.refreshing .weui-pull-to-refresh__layer .refresh,.refreshing .weui-pull-to-refresh__layer .weui-pull-to-refresh__preloader{display:inline-block}@keyframes preloader-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.weui-tab__bd-item.weui-pull-to-refresh{position:absolute;top:50px}.toolbar,.weui-tabbar__item{position:relative}.weui-tabbar__item.weui-bar__item--on .weui-tabbar__label{color:#04BE02}.weui-navbar__item{color:#888}.weui-navbar__item.weui-bar__item--on{color:#666;background-color:#f1f1f1}.toolbar,.toolbar .title{font-size:.85rem;color:#3d4145;width:100%}.weui-tab__bd{box-sizing:border-box;height:100%}.weui-tab__bd .weui-tab__bd-item{display:none;height:100%;overflow:auto}.weui-tab__bd .weui-tab__bd-item.weui-tab__bd-item--active{display:block}.weui-navbar+.weui-tab__bd{padding-top:50px}.toolbar{line-height:1.5;background:#f7f7f8}.toolbar:before{content:'';position:absolute;left:0;top:0;bottom:auto;right:auto;height:1px;width:100%;background-color:#d9d9d9;display:block;z-index:15;-webkit-transform-origin:50% 0;transform-origin:50% 0}@media only screen and (-webkit-min-device-pixel-ratio:2){.toolbar:before{-webkit-transform:scaleY(.5);transform:scaleY(.5)}}@media only screen and (-webkit-min-device-pixel-ratio:3){.toolbar:before{-webkit-transform:scaleY(.33);transform:scaleY(.33)}}.toolbar .toolbar-inner{height:2.2rem;display:-webkit-box;display:-ms-flexbox;display:flex;text-align:center}.toolbar .title{position:absolute;display:block;padding:0;font-weight:400;line-height:2.2rem;text-align:center;white-space:nowrap}.toolbar .picker-button{position:absolute;right:0;box-sizing:border-box;height:2.2rem;line-height:2.2rem;color:#04BE02;z-index:1;padding:0 .5rem}.weui-picker-modal{width:100%;position:absolute;bottom:0;text-align:center;border-radius:0;opacity:.6;color:#3d4145;-webkit-transition-duration:.3s;transition-duration:.3s;height:13rem;background:#EFEFF4;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);-webkit-transition-property:opacity,-webkit-transform;transition-property:opacity,-webkit-transform;transition-property:transform,opacity;transition-property:transform,opacity,-webkit-transform}.weui-picker-modal.picker-modal-inline{height:10.8rem;opacity:1;position:static;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.weui-picker-modal.picker-modal-inline .toolbar{display:none}.weui-picker-modal.picker-columns-single .picker-items-col{width:100%}.weui-picker-modal.weui-picker-modal-visible{opacity:1;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.weui-picker-modal .picker-modal-inner{position:relative;height:10.8rem}.weui-picker-modal .picker-columns{width:100%;height:13rem;z-index:11500}.popover .weui-picker-modal .picker-columns,.weui-picker-modal .picker-columns.picker-modal-inline{height:10rem}@media (orientation:landscape) and (max-height:415px){.weui-picker-modal .picker-columns:not(.picker-modal-inline){height:10rem}}.weui-picker-modal .popover.popover-picker-columns{width:14rem}.weui-picker-modal .picker-items{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:100%;padding:0;text-align:right;font-size:1rem;font-weight:400;-webkit-mask-box-image:-webkit-linear-gradient(bottom,transparent,transparent 5%,#fff 20%,#fff 80%,transparent 95%,transparent);-webkit-mask-box-image:linear-gradient(to top,transparent,transparent 5%,#fff 20%,#fff 80%,transparent 95%,transparent)}.weui-picker-modal .bar+.picker-items{height:10.8rem}.weui-picker-modal .picker-items-col{overflow:hidden;position:relative;max-height:100%}.weui-picker-modal .picker-items-col.picker-items-col-left{text-align:left}.weui-picker-modal .picker-items-col.picker-items-col-center{text-align:center}.weui-picker-modal .picker-items-col.picker-items-col-right{text-align:right}.weui-picker-modal .picker-items-col.picker-items-col-divider{color:#3d4145;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.weui-picker-modal .picker-items-col-wrapper{-webkit-transition:.3s;transition:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.weui-picker-modal .picker-item{height:32px;line-height:32px;padding:0 10px;white-space:nowrap;position:relative;overflow:hidden;text-overflow:ellipsis;color:#9b9b9b;left:0;top:0;width:100%;box-sizing:border-box;-webkit-transition:.3s;transition:.3s}.picker-items-col-absolute .weui-picker-modal .picker-item{position:absolute}.weui-picker-modal .picker-item.picker-item-far{pointer-events:none}.weui-picker-modal .picker-item.picker-selected{color:#3d4145;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);-webkit-transform:rotateX(0);transform:rotateX(0)}.weui-picker-modal .picker-center-highlight{height:32px;box-sizing:border-box;position:absolute;left:0;width:100%;top:50%;margin-top:-16px;pointer-events:none}.weui-picker-modal .picker-center-highlight:after,.weui-picker-modal .picker-center-highlight:before{content:'';position:absolute;right:auto;height:1px;background-color:#D9D9D9;display:block;z-index:15;left:0;width:100%}.weui-picker-modal .picker-center-highlight:before{top:0;bottom:auto;-webkit-transform-origin:50% 0;transform-origin:50% 0}@media only screen and (-webkit-min-device-pixel-ratio:2){.weui-picker-modal .picker-center-highlight:before{-webkit-transform:scaleY(.5);transform:scaleY(.5)}}@media only screen and (-webkit-min-device-pixel-ratio:3){.weui-picker-modal .picker-center-highlight:before{-webkit-transform:scaleY(.33);transform:scaleY(.33)}}.weui-picker-modal .picker-center-highlight:after{bottom:0;top:auto;-webkit-transform-origin:50% 100%;transform-origin:50% 100%}@media only screen and (-webkit-min-device-pixel-ratio:2){.weui-picker-modal .picker-center-highlight:after{-webkit-transform:scaleY(.5);transform:scaleY(.5)}}@media only screen and (-webkit-min-device-pixel-ratio:3){.weui-picker-modal .picker-center-highlight:after{-webkit-transform:scaleY(.33);transform:scaleY(.33)}}.weui-picker-modal .picker-3d .picker-items{overflow:hidden;-webkit-perspective:1200px;perspective:1200px}.weui-picker-modal .picker-3d .picker-item,.weui-picker-modal .picker-3d .picker-items-col,.weui-picker-modal .picker-3d .picker-items-col-wrapper{-webkit-transform-style:preserve-3d;transform-style:preserve-3d}.weui-picker-modal .picker-3d .picker-items-col{overflow:visible}.weui-picker-modal .picker-3d .picker-item{-webkit-transform-origin:center center -110px;transform-origin:center center -110px;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.weui-picker-container,.weui-picker-overlay{position:fixed;bottom:0;left:0;right:0;height:0;width:100%;z-index:1000}.picker-calendar-row:after,.picker-calendar-week-days:after{content:'';z-index:15;left:0;right:auto}.city-picker .picker-items-col{-webkit-box-flex:1;-ms-flex:1;flex:1;max-width:7rem}.weui-picker-container .weui-cells{margin:0;text-align:left}.datetime-picker .picker-item{text-overflow:initial}.weui-select-modal{height:auto}.weui-select-modal .weui-cells{margin:0;text-align:left;overflow-y:auto;overflow-x:hidden;max-height:16rem}.weui-select-modal .weui-cells:after{display:none}.weui-picker-calendar{background:#fff;height:15rem;width:100%;overflow:hidden}.weui-picker-calendar .picker-modal-inner{overflow:hidden;height:12.8rem}.picker-calendar-week-days{height:.9rem;background:#f7f7f8;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:11px;box-sizing:border-box;position:relative}.picker-calendar-week-days:after{position:absolute;bottom:0;top:auto;height:1px;width:100%;background-color:#c4c4c4;display:block;-webkit-transform-origin:50% 100%;transform-origin:50% 100%}@media only screen and (-webkit-min-device-pixel-ratio:2){.picker-calendar-week-days:after{-webkit-transform:scaleY(.5);transform:scaleY(.5)}}@media only screen and (-webkit-min-device-pixel-ratio:3){.picker-calendar-week-days:after{-webkit-transform:scaleY(.33);transform:scaleY(.33)}}.picker-calendar-week-days .picker-calendar-week-day{-webkit-flex-shrink:1;-ms-flex:0 1 auto;-ms-flex-negative:1;flex-shrink:1;width:14.28571429%;width:calc(100% / 7);line-height:17px;text-align:center}.picker-calendar-week-days+.picker-calendar-months{height:11.9rem}.picker-calendar-months{width:100%;height:100%;overflow:hidden;position:relative}.picker-calendar-months-wrapper{position:relative;width:100%;height:100%;-webkit-transition:.3s;transition:.3s}.picker-calendar-month{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-ms-flex-direction:column;flex-direction:column;width:100%;height:100%;position:absolute;left:0;top:0}.picker-calendar-row{height:16.66666667%;height:calc(100% / 6);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-flex-shrink:1;-ms-flex:0 1 auto;-ms-flex-negative:1;flex-shrink:1;width:100%;position:relative}.picker-calendar-row:after{position:absolute;bottom:0;top:auto;height:1px;width:100%;background-color:#ccc;display:block;-webkit-transform-origin:50% 100%;transform-origin:50% 100%}@media only screen and (-webkit-min-device-pixel-ratio:2){.picker-calendar-row:after{-webkit-transform:scaleY(.5);transform:scaleY(.5)}}@media only screen and (-webkit-min-device-pixel-ratio:3){.picker-calendar-row:after{-webkit-transform:scaleY(.33);transform:scaleY(.33)}}.weui-picker-modal .picker-calendar-row:last-child:after{display:none}.picker-calendar-day{-webkit-flex-shrink:1;-ms-flex:0 1 auto;-ms-flex-negative:1;flex-shrink:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;box-sizing:border-box;width:14.28571429%;width:calc(100% / 7);text-align:center;color:#3d4145;font-size:15px;cursor:pointer}.picker-calendar-day.picker-calendar-day-next,.picker-calendar-day.picker-calendar-day-prev{color:#ccc}.picker-calendar-day.picker-calendar-day-disabled{color:#d4d4d4;cursor:auto}.picker-calendar-day.picker-calendar-day-today span{background:#e3e3e3}.picker-calendar-day.picker-calendar-day-selected span{background:#04BE02;color:#fff}.picker-calendar-day span{display:inline-block;border-radius:100%;width:30px;height:30px;line-height:30px}.picker-calendar-month-picker,.picker-calendar-year-picker{-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;width:50%;max-width:200px;-webkit-flex-shrink:10;-ms-flex-negative:10;flex-shrink:10}.picker-calendar-month-picker span,.picker-calendar-year-picker span{-webkit-flex-shrink:1;-ms-flex:0 1 auto;-ms-flex-negative:1;flex-shrink:1;position:relative;overflow:hidden;text-overflow:ellipsis}.picker-calendar.picker-modal-inline .picker-calendar-week-days,.popover .picker-calendar .picker-calendar-week-days{background:0 0}.swiper-button-next,.swiper-button-prev,i.icon{background-position:center;background-repeat:no-repeat}.picker-calendar.picker-modal-inline .picker-calendar-week-days:after,.picker-calendar.picker-modal-inline .picker-calendar-week-days:before,.picker-calendar.picker-modal-inline .toolbar:after,.picker-calendar.picker-modal-inline .toolbar:before,.popover .picker-calendar .picker-calendar-week-days:after,.popover .picker-calendar .picker-calendar-week-days:before,.popover .picker-calendar .toolbar:after,.popover .picker-calendar .toolbar:before{display:none}.picker-calendar.picker-modal-inline .picker-calendar-week-days~.picker-calendar-months:before,.picker-calendar.picker-modal-inline .toolbar~.picker-modal-inner .picker-calendar-months:before,.popover .picker-calendar .picker-calendar-week-days~.picker-calendar-months:before,.popover .picker-calendar .toolbar~.picker-modal-inner .picker-calendar-months:before{content:'';position:absolute;left:0;top:0;bottom:auto;right:auto;height:1px;width:100%;background-color:#c4c4c4;display:block;z-index:15;-webkit-transform-origin:50% 0;transform-origin:50% 0}@media only screen and (-webkit-min-device-pixel-ratio:2){.picker-calendar.picker-modal-inline .picker-calendar-week-days~.picker-calendar-months:before,.picker-calendar.picker-modal-inline .toolbar~.picker-modal-inner .picker-calendar-months:before,.popover .picker-calendar .picker-calendar-week-days~.picker-calendar-months:before,.popover .picker-calendar .toolbar~.picker-modal-inner .picker-calendar-months:before{-webkit-transform:scaleY(.5);transform:scaleY(.5)}}@media only screen and (-webkit-min-device-pixel-ratio:3){.picker-calendar.picker-modal-inline .picker-calendar-week-days~.picker-calendar-months:before,.picker-calendar.picker-modal-inline .toolbar~.picker-modal-inner .picker-calendar-months:before,.popover .picker-calendar .picker-calendar-week-days~.picker-calendar-months:before,.popover .picker-calendar .toolbar~.picker-modal-inner .picker-calendar-months:before{-webkit-transform:scaleY(.33);transform:scaleY(.33)}}.picker-calendar-month-picker,.picker-calendar-year-picker{display:block;line-height:2.2rem;-webkit-box-flex:1;-ms-flex:1;flex:1}.picker-calendar-month-picker a.icon-only,.picker-calendar-year-picker a.icon-only{min-width:36px;float:left;width:25%;height:2.2rem;line-height:2rem}.picker-calendar-month-picker .current-month-value,.picker-calendar-month-picker .current-year-value,.picker-calendar-year-picker .current-month-value,.picker-calendar-year-picker .current-year-value{float:left;width:50%;height:2.2rem}i.icon{display:inline-block;vertical-align:middle;background-size:100% auto;font-style:normal;position:relative}i.icon.icon-next,i.icon.icon-prev{width:.75rem;height:.75rem}.swiper-slide,.swiper-wrapper{width:100%;height:100%;position:relative}i.icon.icon-next{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2015%2015'%3E%3Cg%3E%3Cpath%20fill%3D'%2304BE02'%20d%3D'M1%2C1.6l11.8%2C5.8L1%2C13.4V1.6%20M0%2C0v15l15-7.6L0%2C0L0%2C0z'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E")}i.icon.icon-prev{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2015%2015'%3E%3Cg%3E%3Cpath%20fill%3D'%2304BE02'%20d%3D'M14%2C1.6v11.8L2.2%2C7.6L14%2C1.6%20M15%2C0L0%2C7.6L15%2C15V0L15%2C0z'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.swiper-container{margin:0 auto;position:relative;overflow:hidden;z-index:1}.swiper-container-no-flexbox .swiper-slide{float:left}.swiper-container-vertical>.swiper-wrapper{-webkit-box-orient:vertical;-ms-flex-direction:column;flex-direction:column}.swiper-wrapper{z-index:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-transition-property:-webkit-transform;transition-property:-webkit-transform;transition-property:transform;transition-property:transform,-webkit-transform;box-sizing:content-box}.swiper-container-android .swiper-slide,.swiper-wrapper{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.swiper-container-multirow>.swiper-wrapper{-webkit-box-lines:multiple;-moz-box-lines:multiple;-ms-flex-wrap:wrap;flex-wrap:wrap}.swiper-container-free-mode>.swiper-wrapper{-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out;margin:0 auto}.swiper-slide{-webkit-flex-shrink:0;-ms-flex:0 0 auto;-ms-flex-negative:0;flex-shrink:0}.swiper-container-autoheight,.swiper-container-autoheight .swiper-slide{height:auto}.swiper-container-autoheight .swiper-wrapper{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;-webkit-transition-property:-webkit-transform,height;-webkit-transition-property:height,-webkit-transform;transition-property:height,-webkit-transform;transition-property:transform,height;transition-property:transform,height,-webkit-transform}.swiper-container .swiper-notification{position:absolute;left:0;top:0;pointer-events:none;opacity:0;z-index:-1000}.swiper-wp8-horizontal{-ms-touch-action:pan-y;touch-action:pan-y}.swiper-wp8-vertical{-ms-touch-action:pan-x;touch-action:pan-x}.swiper-button-next,.swiper-button-prev{position:absolute;top:50%;width:27px;height:44px;margin-top:-22px;z-index:10;cursor:pointer;background-size:27px 44px}.swiper-button-next.swiper-button-disabled,.swiper-button-prev.swiper-button-disabled{opacity:.35;cursor:auto;pointer-events:none}.swiper-button-prev,.swiper-container-rtl .swiper-button-next{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23007aff'%2F%3E%3C%2Fsvg%3E");left:10px;right:auto}.swiper-button-prev.swiper-button-black,.swiper-container-rtl .swiper-button-next.swiper-button-black{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23000000'%2F%3E%3C%2Fsvg%3E")}.swiper-button-prev.swiper-button-white,.swiper-container-rtl .swiper-button-next.swiper-button-white{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23ffffff'%2F%3E%3C%2Fsvg%3E")}.swiper-button-next,.swiper-container-rtl .swiper-button-prev{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23007aff'%2F%3E%3C%2Fsvg%3E");right:10px;left:auto}.swiper-button-next.swiper-button-black,.swiper-container-rtl .swiper-button-prev.swiper-button-black{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23000000'%2F%3E%3C%2Fsvg%3E")}.swiper-button-next.swiper-button-white,.swiper-container-rtl .swiper-button-prev.swiper-button-white{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23ffffff'%2F%3E%3C%2Fsvg%3E")}.swiper-pagination{position:absolute;text-align:center;-webkit-transition:.3s;transition:.3s;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);z-index:10}.swiper-pagination.swiper-pagination-hidden{opacity:0}.swiper-container-horizontal>.swiper-pagination-bullets,.swiper-pagination-custom,.swiper-pagination-fraction{bottom:10px;left:0;width:100%}.swiper-pagination-bullet{width:8px;height:8px;display:inline-block;border-radius:100%;background:#000;opacity:.2}button.swiper-pagination-bullet{border:none;margin:0;padding:0;box-shadow:none;-moz-appearance:none;-ms-appearance:none;-webkit-appearance:none;appearance:none}.swiper-pagination-clickable .swiper-pagination-bullet{cursor:pointer}.swiper-pagination-white .swiper-pagination-bullet{background:#fff}.swiper-pagination-bullet-active{opacity:1;background:#04BE02}.swiper-pagination-white .swiper-pagination-bullet-active{background:#fff}.swiper-pagination-black .swiper-pagination-bullet-active{background:#000}.swiper-container-vertical>.swiper-pagination-bullets{right:10px;top:50%;-webkit-transform:translate3d(0,-50%,0);transform:translate3d(0,-50%,0)}.swiper-container-vertical>.swiper-pagination-bullets .swiper-pagination-bullet{margin:5px 0;display:block}.swiper-container-horizontal>.swiper-pagination-bullets .swiper-pagination-bullet{margin:0 5px}.swiper-pagination-progress{background:rgba(0,0,0,.25);position:absolute}.swiper-pagination-progress .swiper-pagination-progressbar{background:#007aff;position:absolute;left:0;top:0;width:100%;height:100%;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:left top;transform-origin:left top}.swiper-container-rtl .swiper-pagination-progress .swiper-pagination-progressbar{-webkit-transform-origin:right top;transform-origin:right top}.swiper-container-horizontal>.swiper-pagination-progress{width:100%;height:4px;left:0;top:0}.swiper-container-vertical>.swiper-pagination-progress{width:4px;height:100%;left:0;top:0}.swiper-pagination-progress.swiper-pagination-white{background:rgba(255,255,255,.5)}.swiper-pagination-progress.swiper-pagination-white .swiper-pagination-progressbar{background:#fff}.swiper-pagination-progress.swiper-pagination-black .swiper-pagination-progressbar{background:#000}.swiper-container-3d{-webkit-perspective:1200px;-o-perspective:1200px;perspective:1200px}.swiper-container-3d .swiper-cube-shadow,.swiper-container-3d .swiper-slide,.swiper-container-3d .swiper-slide-shadow-bottom,.swiper-container-3d .swiper-slide-shadow-left,.swiper-container-3d .swiper-slide-shadow-right,.swiper-container-3d .swiper-slide-shadow-top,.swiper-container-3d .swiper-wrapper{-webkit-transform-style:preserve-3d;transform-style:preserve-3d}.swiper-container-3d .swiper-slide-shadow-bottom,.swiper-container-3d .swiper-slide-shadow-left,.swiper-container-3d .swiper-slide-shadow-right,.swiper-container-3d .swiper-slide-shadow-top{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none;z-index:10}.swiper-container-3d .swiper-slide-shadow-left{background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,0)));background-image:-webkit-linear-gradient(right,rgba(0,0,0,.5),rgba(0,0,0,0));background-image:linear-gradient(to left,rgba(0,0,0,.5),rgba(0,0,0,0))}.swiper-container-3d .swiper-slide-shadow-right{background-image:-webkit-gradient(linear,right top,left top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,0)));background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5),rgba(0,0,0,0));background-image:linear-gradient(to right,rgba(0,0,0,.5),rgba(0,0,0,0))}.swiper-container-3d .swiper-slide-shadow-top{background-image:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,.5)),to(rgba(0,0,0,0)));background-image:-webkit-linear-gradient(bottom,rgba(0,0,0,.5),rgba(0,0,0,0));background-image:linear-gradient(to top,rgba(0,0,0,.5),rgba(0,0,0,0))}.swiper-container-3d .swiper-slide-shadow-bottom{background-image:-webkit-gradient(linear,left bottom,left top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,0)));background-image:-webkit-linear-gradient(top,rgba(0,0,0,.5),rgba(0,0,0,0));background-image:linear-gradient(to bottom,rgba(0,0,0,.5),rgba(0,0,0,0))}.swiper-container-coverflow .swiper-wrapper,.swiper-container-flip .swiper-wrapper{-ms-perspective:1200px}.swiper-container-cube,.swiper-container-flip{overflow:visible}.swiper-container-cube .swiper-slide,.swiper-container-flip .swiper-slide{pointer-events:none;-webkit-backface-visibility:hidden;backface-visibility:hidden;z-index:1}.swiper-container-cube .swiper-slide .swiper-slide,.swiper-container-flip .swiper-slide .swiper-slide{pointer-events:none}.swiper-container-cube .swiper-slide-active,.swiper-container-cube .swiper-slide-active .swiper-slide-active,.swiper-container-flip .swiper-slide-active,.swiper-container-flip .swiper-slide-active .swiper-slide-active{pointer-events:auto}.swiper-container-cube .swiper-slide-shadow-bottom,.swiper-container-cube .swiper-slide-shadow-left,.swiper-container-cube .swiper-slide-shadow-right,.swiper-container-cube .swiper-slide-shadow-top,.swiper-container-flip .swiper-slide-shadow-bottom,.swiper-container-flip .swiper-slide-shadow-left,.swiper-container-flip .swiper-slide-shadow-right,.swiper-container-flip .swiper-slide-shadow-top{z-index:0;-webkit-backface-visibility:hidden;backface-visibility:hidden}.swiper-container-cube .swiper-slide{visibility:hidden;-webkit-transform-origin:0 0;transform-origin:0 0;width:100%;height:100%}.swiper-container-cube.swiper-container-rtl .swiper-slide{-webkit-transform-origin:100% 0;transform-origin:100% 0}.swiper-container-cube .swiper-slide-active,.swiper-container-cube .swiper-slide-next,.swiper-container-cube .swiper-slide-next+.swiper-slide,.swiper-container-cube .swiper-slide-prev{pointer-events:auto;visibility:visible}.swiper-container-cube .swiper-cube-shadow{position:absolute;left:0;bottom:0;width:100%;height:100%;background:#000;opacity:.6;-webkit-filter:blur(50px);filter:blur(50px);z-index:0}.swiper-container-fade.swiper-container-free-mode .swiper-slide{-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.swiper-container-fade .swiper-slide{pointer-events:none;-webkit-transition-property:opacity;transition-property:opacity}.swiper-container-fade .swiper-slide .swiper-slide{pointer-events:none}.swiper-container-fade .swiper-slide-active,.swiper-container-fade .swiper-slide-active .swiper-slide-active{pointer-events:auto}.swiper-scrollbar{border-radius:10px;position:relative;-ms-touch-action:none;background:rgba(0,0,0,.1)}.swiper-container-horizontal>.swiper-scrollbar{position:absolute;left:1%;bottom:3px;z-index:50;height:5px;width:98%}.swiper-container-vertical>.swiper-scrollbar{position:absolute;right:3px;top:1%;z-index:50;width:5px;height:98%}.swiper-scrollbar-drag{height:100%;width:100%;position:relative;background:rgba(0,0,0,.5);border-radius:10px;left:0;top:0}.swiper-scrollbar-cursor-drag{cursor:move}.swiper-lazy-preloader{width:42px;height:42px;position:absolute;left:50%;top:50%;margin-left:-21px;margin-top:-21px;z-index:10;-webkit-transform-origin:50%;transform-origin:50%;-webkit-animation:swiper-preloader-spin 1s steps(12,end) infinite;animation:swiper-preloader-spin 1s steps(12,end) infinite}.swiper-lazy-preloader:after{display:block;content:"";width:100%;height:100%;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20viewBox%3D'0%200%20120%20120'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20xmlns%3Axlink%3D'http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink'%3E%3Cdefs%3E%3Cline%20id%3D'l'%20x1%3D'60'%20x2%3D'60'%20y1%3D'7'%20y2%3D'27'%20stroke%3D'%236c6c6c'%20stroke-width%3D'11'%20stroke-linecap%3D'round'%2F%3E%3C%2Fdefs%3E%3Cg%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(30%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(60%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(90%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(120%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(150%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.37'%20transform%3D'rotate(180%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.46'%20transform%3D'rotate(210%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.56'%20transform%3D'rotate(240%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.66'%20transform%3D'rotate(270%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.75'%20transform%3D'rotate(300%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.85'%20transform%3D'rotate(330%2060%2C60)'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");background-position:50%;background-size:100%;background-repeat:no-repeat}.swiper-lazy-preloader-white:after{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20viewBox%3D'0%200%20120%20120'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20xmlns%3Axlink%3D'http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink'%3E%3Cdefs%3E%3Cline%20id%3D'l'%20x1%3D'60'%20x2%3D'60'%20y1%3D'7'%20y2%3D'27'%20stroke%3D'%23fff'%20stroke-width%3D'11'%20stroke-linecap%3D'round'%2F%3E%3C%2Fdefs%3E%3Cg%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(30%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(60%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(90%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(120%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(150%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.37'%20transform%3D'rotate(180%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.46'%20transform%3D'rotate(210%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.56'%20transform%3D'rotate(240%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.66'%20transform%3D'rotate(270%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.75'%20transform%3D'rotate(300%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.85'%20transform%3D'rotate(330%2060%2C60)'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E")}@-webkit-keyframes swiper-preloader-spin{100%{-webkit-transform:rotate(360deg)}}@keyframes swiper-preloader-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.weui-actionsheet{z-index:10000}.weui-popup__container,.weui-popup__overlay{position:fixed;bottom:0;left:0;right:0;width:100%;height:100%;z-index:10}.weui-popup__overlay{background-color:rgba(0,0,0,.6);opacity:0;-webkit-transition:opacity .3s;transition:opacity .3s}.weui-popup__container{display:none}.weui-popup__container.weui-popup__container--visible{display:block}.weui-popup__container .weui-cells{margin:0;text-align:left}.weui-popup__modal{width:100%;position:absolute;z-index:100;bottom:0;border-radius:0;opacity:.6;color:#3d4145;-webkit-transition-duration:.3s;transition-duration:.3s;height:100%;background:#EFEFF4;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);-webkit-transition-property:opacity,-webkit-transform;transition-property:opacity,-webkit-transform;transition-property:transform,opacity;transition-property:transform,opacity,-webkit-transform;overflow-x:hidden;overflow-y:auto}.popup-bottom .weui-popup__modal{height:auto}.weui-popup__modal .toolbar{position:absolute;left:0;top:0;right:0;z-index:1}.weui-popup__modal .modal-content{height:100%;padding-top:2.2rem;overflow:auto;box-sizing:border-box}.weui-popup__container--visible .weui-popup__overlay{opacity:1}.weui-popup__container--visible .weui-popup__modal{opacity:1;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.weui-notification{position:fixed;width:100%;min-height:3.4rem;top:-2rem;padding-top:2rem;left:0;right:0;z-index:9999;background-color:rgba(0,0,0,.85);color:#fff;font-size:.65rem;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);-webkit-transition:.4s;transition:.4s}.weui-notification.weui-notification--in{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.weui-notification.weui-notification--touching{-webkit-transition-duration:0s;transition-duration:0s}.weui-notification .weui-notification__inner{padding:.4rem .6rem 1rem;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.weui-notification .weui-notification__content{width:100%;margin:0 .4rem}.weui-notification .weui-notification__title{font-weight:700}.weui-notification .weui-notification__text{line-height:1}.weui-notification .weui-notification__media{height:1rem;width:1rem}.weui-notification .weui-notification__media img{width:100%}.weui-notification .weui-notification__handle-bar{position:absolute;bottom:.2rem;left:50%;-webkit-transform:translate3d(-50%,0,0);transform:translate3d(-50%,0,0);width:2rem;height:.3rem;border-radius:.15rem;background:#fff;opacity:.5}.weui-photo-browser-modal{position:fixed;top:0;left:0;right:0;bottom:0;background:#000;display:none;opacity:0;-webkit-transition:opacity .3s;transition:opacity .3s}.weui-photo-browser-modal.weui-photo-browser-modal-visible{opacity:1}.weui-photo-browser-modal .swiper-container{height:100%;-webkit-transform:scale(.2);transform:scale(.2);-webkit-transition:-webkit-transform .5s;transition:-webkit-transform .5s;transition:transform .5s;transition:transform .5s,-webkit-transform .5s}.weui-photo-browser-modal .swiper-container .swiper-pagination-bullet{background:#fff;visibility:hidden}.weui-photo-browser-modal .swiper-container.swiper-container-visible{-webkit-transform:scale(1);transform:scale(1)}.weui-photo-browser-modal .swiper-container.swiper-container-visible .swiper-pagination-bullet{visibility:visible;-webkit-transition-property:visibility;transition-property:visibility;-webkit-transition-delay:.5s;transition-delay:.5s}.weui-photo-browser-modal .swiper-container .swiper-pagination{bottom:10px;left:0;width:100%}.weui-photo-browser-modal .photo-container{height:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;overflow:hidden}.weui-photo-browser-modal .photo-container img{max-width:100%;margin-top:-30px}.weui-photo-browser-modal .caption{position:absolute;bottom:40px;left:0;right:0;color:#fff;text-align:center;padding:0 12px;min-height:3rem;font-size:14px;z-index:10;-webkit-transition:opacity .3s;transition:opacity .3s;-webkit-transition-delay:.5s;transition-delay:.5s;opacity:0}.weui-photo-browser-modal .caption .caption-item{display:none;opacity:0;-webkit-transition:opacity .15s;transition:opacity .15s}.weui-photo-browser-modal .caption .caption-item.active{display:block;opacity:1}.weui-photo-browser-modal .swiper-container-visible .caption{opacity:1}.color-primary{color:#04BE02}.color-danger,.color-error{color:#f6383a}.color-warning{color:#f60}.color-success{color:#4cd964}.bg-danger,.bg-error,.bg-primary,.bg-success,.bg-warning{color:#fff}.bg-primary{background-color:#04BE02}.bg-danger,.bg-error{background-color:#f6383a}.bg-warning{background-color:#f60}.bg-success{background-color:#4cd964}.weui-toptips{z-index:100;opacity:0;-webkit-transition:opacity .3s;transition:opacity .3s}.weui-toptips.weui-toptips_visible{opacity:1}.weui-icon_toast{font-size:55px;color:#fff;margin-bottom:6px}.weui-toast--forbidden .weui-icon_toast{color:#f6383a}.weui-toast--text{min-height:initial;font-size:18px;padding:8px 16px;width:auto;top:40%}.weui-toast--text .weui-icon_toast{display:none}.weui-count{display:inline-block;height:25px;line-height:25px}.weui-count .weui-count__btn{height:21px;width:21px;line-height:21px;display:inline-block;position:relative;border:1px solid #04BE02;border-radius:50%;vertical-align:-6px}.weui-count .weui-count__btn:after,.weui-count .weui-count__btn:before{content:" ";position:absolute;height:1px;width:11px;background-color:#04BE02;left:50%;top:50%;margin-left:-5.5px}.weui-count .weui-count__btn:after{height:11px;width:1px;margin-top:-5.5px;margin-left:-1px}.weui-count .weui-count__decrease:after{display:none}.weui-count .weui-count__increase{background-color:#04BE02}.weui-count .weui-count__increase:after,.weui-count .weui-count__increase:before{background-color:#fff}.weui-count .weui-count__number{background-color:transparent;font-size:.8rem;border:0;width:1.3rem;text-align:center;color:#5f646e}.weui-panel .weui-media-box__title-after{color:#9b9b9b;font-size:.65rem;float:right}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/css/weui.min.css b/platforms/android/app/src/main/assets/www/css/weui.min.css
new file mode 100755
index 0000000..1371e18
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/css/weui.min.css
@@ -0,0 +1,5 @@
+/*!
+ * WeUI v1.1.3 (https://github.com/weui/weui)
+ * Copyright 2018 Tencent, Inc.
+ * Licensed under the MIT license
+ */html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{line-height:1.6;font-family:-apple-system-font,Helvetica Neue,sans-serif}*{margin:0;padding:0}a img{border:0}a{text-decoration:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}@font-face{font-weight:400;font-style:normal;font-family:weui;src:url('data:application/octet-stream;base64,AAEAAAALAIAAAwAwR1NVQrD+s+0AAAE4AAAAQk9TLzJAKEx+AAABfAAAAFZjbWFw65cFHQAAAhwAAAJQZ2x5ZvCRR/EAAASUAAAKtGhlYWQMPROtAAAA4AAAADZoaGVhCCwD+gAAALwAAAAkaG10eEJo//8AAAHUAAAASGxvY2EYqhW4AAAEbAAAACZtYXhwASEAVQAAARgAAAAgbmFtZeNcHtgAAA9IAAAB5nBvc3T6bLhLAAARMAAAAOYAAQAAA+gAAABaA+j/////A+kAAQAAAAAAAAAAAAAAAAAAABIAAQAAAAEAACbZbxtfDzz1AAsD6AAAAADUm2dvAAAAANSbZ2///wAAA+kD6gAAAAgAAgAAAAAAAAABAAAAEgBJAAUAAAAAAAIAAAAKAAoAAAD/AAAAAAAAAAEAAAAKAB4ALAABREZMVAAIAAQAAAAAAAAAAQAAAAFsaWdhAAgAAAABAAAAAQAEAAQAAAABAAgAAQAGAAAAAQAAAAAAAQOwAZAABQAIAnoCvAAAAIwCegK8AAAB4AAxAQIAAAIABQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUGZFZABA6gHqEQPoAAAAWgPqAAAAAAABAAAAAAAAAAAAAAPoAAAD6AAAA+gAAAPoAAAD6AAAA+gAAAPoAAAD6AAAA+gAAAPoAAAD6AAAA+gAAAPoAAAD6AAAA+j//wPoAAAD6AAAAAAABQAAAAMAAAAsAAAABAAAAXQAAQAAAAAAbgADAAEAAAAsAAMACgAAAXQABABCAAAABAAEAAEAAOoR//8AAOoB//8AAAABAAQAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAAAEGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAANwAAAAAAAAAEQAA6gEAAOoBAAAAAQAA6gIAAOoCAAAAAgAA6gMAAOoDAAAAAwAA6gQAAOoEAAAABAAA6gUAAOoFAAAABQAA6gYAAOoGAAAABgAA6gcAAOoHAAAABwAA6ggAAOoIAAAACAAA6gkAAOoJAAAACQAA6goAAOoKAAAACgAA6gsAAOoLAAAACwAA6gwAAOoMAAAADAAA6g0AAOoNAAAADQAA6g4AAOoOAAAADgAA6g8AAOoPAAAADwAA6hAAAOoQAAAAEAAA6hEAAOoRAAAAEQAAAAAARgCMANIBJAF4AcQCMgJgAqgC/ANIA6YD/gROBKAE9AVaAAAAAgAAAAADrwOtABQAKQAAASIHBgcGFBcWFxYyNzY3NjQnJicmAyInJicmNDc2NzYyFxYXFhQHBgcGAfV4Z2Q7PDw7ZGfwZmQ7PDw7ZGZ4bl5bNjc3Nlte215bNjc3NlteA608O2Rn8GdjOzw8O2Nn8GdkOzz8rzc1W17bXlw1Nzc1XF7bXls1NwAAAAACAAAAAAOzA7MAFwAtAAABIgcGBwYVFBcWFxYzMjc2NzY1NCcmJyYTBwYiLwEmNjsBETQ2OwEyFhURMzIWAe52Z2Q7PT07ZGd2fGpmOz4+O2ZpIXYOKA52Dg0XXQsHJgcLXRcNA7M+O2ZqfHZnZDs9PTtkZ3Z9aWY7Pv3wmhISmhIaARcICwsI/ukaAAMAAAAAA+UD5QAXACMALAAAASIHBgcGFRQXFhcWMzI3Njc2NTQnJicmAxQrASI1AzQ7ATIHJyImNDYyFhQGAe6Ecm9BRERBb3KEiXZxQkREQnF1aQIxAwgCQgMBIxIZGSQZGQPkREJxdomEcm9BRERBb3KEinVxQkT9HQICAWICAjEZIxkZIxkAAAAAAgAAAAADsQPkABkALgAAAQYHBgc2BREUFxYXFhc2NzY3NjURJBcmJyYTAQYvASY/ATYyHwEWNjclNjIfARYB9VVVQk+v/tFHPmxebGxdbT1I/tGvT0JVo/7VBASKAwMSAQUBcQEFAgESAgUBEQQD4xMYEhk3YP6sjnVlSD8cHD9IZXWOAVRgNxkSGP62/tkDA48EBBkCAVYCAQHlAQIQBAAAAAADAAAAAAOxA+QAGwAqADMAAAEGBwYHBgcGNxEUFxYXFhc2NzY3NjURJBcmJyYHMzIWFQMUBisBIicDNDYTIiY0NjIWFAYB9UFBODssO38gRz5sXmxsXW09SP7YqFBBVW80BAYMAwImBQELBh4PFhYeFRUD5A8SDhIOEikK/q2PdWRJPh0dPklkdY8BU141GRIY/AYE/sYCAwUBOgQG/kAVHxUVHxUAAAACAAAAAAPkA+QAFwAtAAABIgcGBwYVFBcWFxYzMjc2NzY1NCcmJyYTAQYiLwEmPwE2Mh8BFjI3ATYyHwEWAe6Ecm9BQ0NCbnODiXVxQkREQnF1kf6gAQUBowMDFgEFAYUCBQEBQwIFARUEA+NEQnF1iYNzbkJDQ0FvcoSJdXFCRP6j/qUBAagEBR4CAWYBAQENAgIVBAAAAAQAAAAAA68DrQAUACkAPwBDAAABIgcGBwYUFxYXFjI3Njc2NCcmJyYDIicmJyY0NzY3NjIXFhcWFAcGBwYTBQ4BLwEmBg8BBhYfARYyNwE+ASYiFzAfAQH1eGdkOzw8O2Rn8GZkOzw8O2RmeG5eWzY3NzZbXtteWzY3NzZbXmn+9gYSBmAGDwUDBQEGfQUQBgElBQELEBUBAQOtPDtkZ/BnYzs8PDtjZ/BnZDs8/K83NVte215cNTc3NVxe215bNTcCJt0FAQVJBQIGBAcRBoAGBQEhBQ8LBAEBAAABAAAAAAO7AzoAFwAAEy4BPwE+AR8BFjY3ATYWFycWFAcBBiInPQoGBwUHGgzLDCELAh0LHwsNCgr9uQoeCgGzCyEOCw0HCZMJAQoBvgkCCg0LHQv9sQsKAAAAAAIAAAAAA+UD5gAXACwAAAEiBwYHBhUUFxYXFjMyNzY3NjU0JyYnJhMHBi8BJicmNRM0NjsBMhYVExceAQHvhHJvQUNDQm5zg4l1cUJEREJxdVcQAwT6AwIEEAMCKwIDDsUCAQPlREJxdYmDc25CQ0NBb3KEiXVxQkT9VhwEAncCAgMGAXoCAwMC/q2FAgQAAAQAAAAAA68DrQADABgALQAzAAABMB8BAyIHBgcGFBcWFxYyNzY3NjQnJicmAyInJicmNDc2NzYyFxYXFhQHBgcGAyMVMzUjAuUBAfJ4Z2Q7PDw7ZGfwZmQ7PDw7ZGZ4bl5bNjc3Nlte215bNjc3NltemyT92QKDAQEBLDw7ZGfwZ2M7PDw7Y2fwZ2Q7PPyvNzVbXtteXDU3NzVcXtteWzU3AjH9JAAAAAMAAAAAA+QD5AAXACcAMAAAASIHBgcGFRQXFhcWMzI3Njc2NTQnJicmAzMyFhUDFAYrASImNQM0NhMiJjQ2MhYUBgHuhHJvQUNDQm5zg4l1cUJEREJxdZ42BAYMAwInAwMMBh8PFhYeFhYD40RCcXWJg3NuQkNDQW9yhIl1cUJE/vYGBf7AAgMDAgFABQb+NhYfFhYfFgAABAAAAAADwAPAAAgAEgAoAD0AAAEyNjQmIgYUFhcjFTMRIxUzNSMDIgcGBwYVFBYXFjMyNzY3NjU0Jy4BAyInJicmNDc2NzYyFxYXFhQHBgcGAfQYISEwISFRjzk5yTorhG5rPT99am+DdmhlPD4+PMyFbV5bNTc3NVte2l5bNTc3NVteAqAiLyIiLyI5Hf7EHBwCsT89a26Ed8w8Pj48ZWh2g29qffyjNzVbXtpeWzU3NzVbXtpeWzU3AAADAAAAAAOoA6gACwAgADUAAAEHJwcXBxc3FzcnNwMiBwYHBhQXFhcWMjc2NzY0JyYnJgMiJyYnJjQ3Njc2MhcWFxYUBwYHBgKOmpocmpocmpocmpq2dmZiOjs7OmJm7GZiOjs7OmJmdmtdWTQ2NjRZXdZdWTQ2NjRZXQKqmpocmpocmpocmpoBGTs6YmbsZmI6Ozs6YmbsZmI6O/zCNjRZXdZdWTQ2NjRZXdZdWTQ2AAMAAAAAA+kD6gAaAC8AMAAAAQYHBiMiJyYnJjQ3Njc2MhcWFxYVFAcGBwEHATI3Njc2NCcmJyYiBwYHBhQXFhcWMwKONUBCR21dWjU3NzVaXdpdWzU2GBcrASM5/eBXS0grKysrSEuuSkkqLCwqSUpXASMrFxg2NVtd2l1aNTc3NVpdbUdCQDX+3jkBGSsrSEuuSkkqLCwqSUquS0grKwAC//8AAAPoA+gAFAAwAAABIgcGBwYQFxYXFiA3Njc2ECcmJyYTFg4BIi8BBwYuATQ/AScmPgEWHwE3Nh4BBg8BAfSIdHFDRERDcXQBEHRxQ0REQ3F0SQoBFBsKoqgKGxMKqKIKARQbCqKoChsUAQqoA+hEQ3F0/vB0cUNERENxdAEQdHFDRP1jChsTCqiiCgEUGwqiqAobFAEKqKIKARQbCqIAAAIAAAAAA+QD5AAXADQAAAEiBwYHBhUUFxYXFjMyNzY3NjU0JyYnJhMUBiMFFxYUDwEGLwEuAT8BNh8BFhQPAQUyFh0BAe6Ecm9BQ0NCbnODiXVxQkREQnF1fwQC/pGDAQEVAwTsAgEC7AQEFAIBhAFwAgMD40RCcXWJg3NuQkNDQW9yhIl1cUJE/fYCAwuVAgQCFAQE0AIFAtEEBBQCBQGVCwMDJwAAAAUAAAAAA9QD0wAjACcANwBHAEgAAAERFAYjISImNREjIiY9ATQ2MyE1NDYzITIWHQEhMhYdARQGIyERIREHIgYVERQWOwEyNjURNCYjISIGFREUFjsBMjY1ETQmKwEDeyYb/XYbJkMJDQ0JAQYZEgEvExkBBgkNDQn9CQJc0QkNDQktCQ0NCf7sCQ0NCS0JDQ0JLQMi/TQbJiYbAswMCiwJDS4SGRkSLg0JLAoM/UwCtGsNCf5NCQ0NCQGzCQ0NCf5NCQ0NCQGzCQ0AAAAAEADGAAEAAAAAAAEABAAAAAEAAAAAAAIABwAEAAEAAAAAAAMABAALAAEAAAAAAAQABAAPAAEAAAAAAAUACwATAAEAAAAAAAYABAAeAAEAAAAAAAoAKwAiAAEAAAAAAAsAEwBNAAMAAQQJAAEACABgAAMAAQQJAAIADgBoAAMAAQQJAAMACAB2AAMAAQQJAAQACAB+AAMAAQQJAAUAFgCGAAMAAQQJAAYACACcAAMAAQQJAAoAVgCkAAMAAQQJAAsAJgD6d2V1aVJlZ3VsYXJ3ZXVpd2V1aVZlcnNpb24gMS4wd2V1aUdlbmVyYXRlZCBieSBzdmcydHRmIGZyb20gRm9udGVsbG8gcHJvamVjdC5odHRwOi8vZm9udGVsbG8uY29tAHcAZQB1AGkAUgBlAGcAdQBsAGEAcgB3AGUAdQBpAHcAZQB1AGkAVgBlAHIAcwBpAG8AbgAgADEALgAwAHcAZQB1AGkARwBlAG4AZQByAGEAdABlAGQAIABiAHkAIABzAHYAZwAyAHQAdABmACAAZgByAG8AbQAgAEYAbwBuAHQAZQBsAGwAbwAgAHAAcgBvAGoAZQBjAHQALgBoAHQAdABwADoALwAvAGYAbwBuAHQAZQBsAGwAbwAuAGMAbwBtAAAAAgAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASAQIBAwEEAQUBBgEHAQgBCQEKAQsBDAENAQ4BDwEQAREBEgETAAZjaXJjbGUIZG93bmxvYWQEaW5mbwxzYWZlX3N1Y2Nlc3MJc2FmZV93YXJuB3N1Y2Nlc3MOc3VjY2Vzcy1jaXJjbGURc3VjY2Vzcy1uby1jaXJjbGUHd2FpdGluZw53YWl0aW5nLWNpcmNsZQR3YXJuC2luZm8tY2lyY2xlBmNhbmNlbAZzZWFyY2gFY2xlYXIEYmFjawZkZWxldGUAAAAA') format('truetype')}[class*=" weui-icon-"],[class^=weui-icon-]{display:inline-block;vertical-align:middle;font:normal normal normal 14px/1 weui;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased}[class*=" weui-icon-"]:before,[class^=weui-icon-]:before{display:inline-block;margin-left:.2em;margin-right:.2em}.weui-icon-circle:before{content:"\EA01"}.weui-icon-download:before{content:"\EA02"}.weui-icon-info:before{content:"\EA03"}.weui-icon-safe-success:before{content:"\EA04"}.weui-icon-safe-warn:before{content:"\EA05"}.weui-icon-success:before{content:"\EA06"}.weui-icon-success-circle:before{content:"\EA07"}.weui-icon-success-no-circle:before{content:"\EA08"}.weui-icon-waiting:before{content:"\EA09"}.weui-icon-waiting-circle:before{content:"\EA0A"}.weui-icon-warn:before{content:"\EA0B"}.weui-icon-info-circle:before{content:"\EA0C"}.weui-icon-cancel:before{content:"\EA0D"}.weui-icon-search:before{content:"\EA0E"}.weui-icon-clear:before{content:"\EA0F"}.weui-icon-back:before{content:"\EA10"}.weui-icon-delete:before{content:"\EA11"}[class*=" weui-icon_"]:before,[class^=weui-icon_]:before{margin:0}.weui-icon-success{font-size:23px;color:#09bb07}.weui-icon-waiting{font-size:23px;color:#10aeff}.weui-icon-warn{font-size:23px;color:#f43530}.weui-icon-info{font-size:23px;color:#10aeff}.weui-icon-success-circle,.weui-icon-success-no-circle{font-size:23px;color:#09bb07}.weui-icon-waiting-circle{font-size:23px;color:#10aeff}.weui-icon-circle{font-size:23px;color:#c9c9c9}.weui-icon-download,.weui-icon-info-circle{font-size:23px;color:#09bb07}.weui-icon-safe-success{color:#09bb07}.weui-icon-safe-warn{color:#ffbe00}.weui-icon-cancel{color:#f43530;font-size:22px}.weui-icon-clear,.weui-icon-search{color:#b2b2b2;font-size:14px}.weui-icon-delete.weui-icon_gallery-delete{color:#fff;font-size:22px}.weui-icon_msg{font-size:93px}.weui-icon_msg.weui-icon-warn{color:#f76260}.weui-icon_msg-primary{font-size:93px}.weui-icon_msg-primary.weui-icon-warn{color:#ffbe00}.weui-btn{position:relative;display:block;margin-left:auto;margin-right:auto;padding-left:14px;padding-right:14px;box-sizing:border-box;font-size:18px;text-align:center;text-decoration:none;color:#fff;line-height:2.55555556;border-radius:5px;-webkit-tap-highlight-color:rgba(0,0,0,0);overflow:hidden}.weui-btn:after{content:" ";width:200%;height:200%;position:absolute;top:0;left:0;border:1px solid rgba(0,0,0,.2);-webkit-transform:scale(.5);transform:scale(.5);-webkit-transform-origin:0 0;transform-origin:0 0;box-sizing:border-box;border-radius:10px}.weui-btn_inline{display:inline-block}.weui-btn_default{color:#000;background-color:#f8f8f8}.weui-btn_default:not(.weui-btn_disabled):visited{color:#000}.weui-btn_default:not(.weui-btn_disabled):active{color:rgba(0,0,0,.6);background-color:#dedede}.weui-btn_primary{background-color:#1aad19}.weui-btn_primary:not(.weui-btn_disabled):visited{color:#fff}.weui-btn_primary:not(.weui-btn_disabled):active{color:hsla(0,0%,100%,.6);background-color:#179b16}.weui-btn_warn{background-color:#e64340}.weui-btn_warn:not(.weui-btn_disabled):visited{color:#fff}.weui-btn_warn:not(.weui-btn_disabled):active{color:hsla(0,0%,100%,.6);background-color:#ce3c39}.weui-btn_disabled{color:hsla(0,0%,100%,.6)}.weui-btn_disabled.weui-btn_default{color:rgba(0,0,0,.3);background-color:#f7f7f7}.weui-btn_disabled.weui-btn_primary{background-color:#9ed99d}.weui-btn_disabled.weui-btn_warn{background-color:#ec8b89}.weui-btn_loading .weui-loading{margin:-.2em .34em 0 0}.weui-btn_loading.weui-btn_primary,.weui-btn_loading.weui-btn_warn{color:hsla(0,0%,100%,.6)}.weui-btn_loading.weui-btn_primary{background-color:#179b16}.weui-btn_loading.weui-btn_warn{background-color:#ce3c39}.weui-btn_plain-primary{color:#1aad19;border:1px solid #1aad19}.weui-btn_plain-primary:not(.weui-btn_plain-disabled):active{color:rgba(26,173,25,.6);border-color:rgba(26,173,25,.6)}.weui-btn_plain-primary:after{border-width:0}.weui-btn_plain-default{color:#353535;border:1px solid #353535}.weui-btn_plain-default:not(.weui-btn_plain-disabled):active{color:rgba(53,53,53,.6);border-color:rgba(53,53,53,.6)}.weui-btn_plain-default:after{border-width:0}.weui-btn_plain-disabled{color:rgba(0,0,0,.2);border-color:rgba(0,0,0,.2)}button.weui-btn,input.weui-btn{width:100%;border-width:0;outline:0;-webkit-appearance:none}button.weui-btn:focus,input.weui-btn:focus{outline:0}button.weui-btn_inline,button.weui-btn_mini,input.weui-btn_inline,input.weui-btn_mini{width:auto}button.weui-btn_plain-default,button.weui-btn_plain-primary,input.weui-btn_plain-default,input.weui-btn_plain-primary{border-width:1px;background-color:transparent}.weui-btn_mini{display:inline-block;padding:0 1.32em;line-height:2.3;font-size:13px}.weui-btn+.weui-btn{margin-top:15px}.weui-btn.weui-btn_inline+.weui-btn.weui-btn_inline{margin-top:auto;margin-left:15px}.weui-btn-area{margin:1.17647059em 15px .3em}.weui-btn-area_inline{display:-webkit-box;display:-webkit-flex;display:flex}.weui-btn-area_inline .weui-btn{margin-top:auto;margin-right:15px;width:100%;-webkit-box-flex:1;-webkit-flex:1;flex:1}.weui-btn-area_inline .weui-btn:last-child{margin-right:0}.weui-cells{margin-top:1.17647059em;background-color:#fff;line-height:1.47058824;font-size:17px;overflow:hidden;position:relative}.weui-cells:before{top:0;border-top:1px solid #e5e5e5;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-cells:after,.weui-cells:before{content:" ";position:absolute;left:0;right:0;height:1px;color:#e5e5e5;z-index:2}.weui-cells:after{bottom:0;border-bottom:1px solid #e5e5e5;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-cells__title{margin-top:.77em;margin-bottom:.3em;padding-left:15px;padding-right:15px;color:#999;font-size:14px}.weui-cells__title+.weui-cells{margin-top:0}.weui-cells__tips{margin-top:.3em;color:#999;padding-left:15px;padding-right:15px;font-size:14px}.weui-cell{padding:10px 15px;position:relative;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.weui-cell:before{content:" ";position:absolute;left:0;top:0;right:0;height:1px;border-top:1px solid #e5e5e5;color:#e5e5e5;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5);left:15px;z-index:2}.weui-cell:first-child:before{display:none}.weui-cell_primary{-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start}.weui-cell__bd{-webkit-box-flex:1;-webkit-flex:1;flex:1}.weui-cell__ft{text-align:right;color:#999}.weui-cell_swiped{display:block;padding:0}.weui-cell_swiped>.weui-cell__bd{position:relative;z-index:1;background-color:#fff}.weui-cell_swiped>.weui-cell__ft{position:absolute;right:0;top:0;bottom:0;display:-webkit-box;display:-webkit-flex;display:flex;color:#fff}.weui-swiped-btn{display:block;padding:10px 1em;line-height:1.47058824;color:inherit}.weui-swiped-btn_default{background-color:#c7c7cc}.weui-swiped-btn_warn{background-color:#ff3b30}.weui-cell_access{-webkit-tap-highlight-color:rgba(0,0,0,0);color:inherit}.weui-cell_access:active{background-color:#ececec}.weui-cell_access .weui-cell__ft{padding-right:13px;position:relative}.weui-cell_access .weui-cell__ft:after{content:" ";display:inline-block;height:6px;width:6px;border-width:2px 2px 0 0;border-color:#c8c8cd;border-style:solid;-webkit-transform:matrix(.71,.71,-.71,.71,0,0);transform:matrix(.71,.71,-.71,.71,0,0);position:relative;top:-2px;position:absolute;top:50%;margin-top:-4px;right:2px}.weui-cell_link{color:#586c94;font-size:14px}.weui-cell_link:first-child:before{display:block}.weui-check__label{-webkit-tap-highlight-color:rgba(0,0,0,0)}.weui-check__label:active{background-color:#ececec}.weui-check{position:absolute;left:-9999em}.weui-cells_radio .weui-cell__ft{padding-left:.35em}.weui-cells_radio .weui-check+.weui-icon-checked{min-width:16px}.weui-cells_radio .weui-check:checked+.weui-icon-checked:before{display:block;content:'\EA08';color:#09bb07;font-size:16px}.weui-cells_checkbox .weui-cell__hd{padding-right:.35em}.weui-cells_checkbox .weui-icon-checked:before{content:'\EA01';color:#c9c9c9;font-size:23px;display:block}.weui-cells_checkbox .weui-check:checked+.weui-icon-checked:before{content:'\EA06';color:#09bb07}.weui-label{display:block;width:105px;word-wrap:break-word;word-break:break-all}.weui-input{width:100%;border:0;outline:0;-webkit-appearance:none;background-color:transparent;font-size:inherit;color:inherit;height:1.47058824em;line-height:1.47058824}.weui-input::-webkit-inner-spin-button,.weui-input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.weui-textarea{display:block;border:0;resize:none;width:100%;color:inherit;font-size:1em;line-height:inherit;outline:0}.weui-textarea-counter{color:#b2b2b2;text-align:right}.weui-cell_warn .weui-textarea-counter{color:#e64340}.weui-toptips{display:none;position:fixed;-webkit-transform:translateZ(0);transform:translateZ(0);top:0;left:0;right:0;padding:5px;font-size:14px;text-align:center;color:#fff;z-index:5000;word-wrap:break-word;word-break:break-all}.weui-toptips_warn{background-color:#e64340}.weui-cells_form .weui-cell__ft{font-size:0}.weui-cells_form .weui-icon-warn{display:none}.weui-cells_form input,.weui-cells_form label[for],.weui-cells_form textarea{-webkit-tap-highlight-color:rgba(0,0,0,0)}.weui-cell_warn{color:#e64340}.weui-cell_warn .weui-icon-warn{display:inline-block}.weui-form-preview{position:relative;background-color:#fff}.weui-form-preview:before{top:0;border-top:1px solid #e5e5e5;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-form-preview:after,.weui-form-preview:before{content:" ";position:absolute;left:0;right:0;height:1px;color:#e5e5e5}.weui-form-preview:after{bottom:0;border-bottom:1px solid #e5e5e5;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-form-preview__hd{position:relative;padding:10px 15px;text-align:right;line-height:2.5em}.weui-form-preview__hd:after{content:" ";position:absolute;left:0;bottom:0;right:0;height:1px;border-bottom:1px solid #e5e5e5;color:#e5e5e5;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5);left:15px}.weui-form-preview__hd .weui-form-preview__value{font-style:normal;font-size:1.6em}.weui-form-preview__bd{padding:10px 15px;font-size:.9em;text-align:right;color:#999;line-height:2}.weui-form-preview__ft{position:relative;line-height:50px;display:-webkit-box;display:-webkit-flex;display:flex}.weui-form-preview__ft:before{content:" ";position:absolute;left:0;top:0;right:0;height:1px;border-top:1px solid #d5d5d6;color:#d5d5d6;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-form-preview__item{overflow:hidden}.weui-form-preview__label{float:left;margin-right:1em;min-width:4em;color:#999;text-align:justify;text-align-last:justify}.weui-form-preview__value{display:block;overflow:hidden;word-break:normal;word-wrap:break-word}.weui-form-preview__btn{position:relative;display:block;-webkit-box-flex:1;-webkit-flex:1;flex:1;color:#3cc51f;text-align:center;-webkit-tap-highlight-color:rgba(0,0,0,0)}button.weui-form-preview__btn{background-color:transparent;border:0;outline:0;line-height:inherit;font-size:inherit}.weui-form-preview__btn:active{background-color:#eee}.weui-form-preview__btn:after{content:" ";position:absolute;left:0;top:0;width:1px;bottom:0;border-left:1px solid #d5d5d6;color:#d5d5d6;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(.5);transform:scaleX(.5)}.weui-form-preview__btn:first-child:after{display:none}.weui-form-preview__btn_default{color:#999}.weui-form-preview__btn_primary{color:#0bb20c}.weui-cell_select{padding:0}.weui-cell_select .weui-select{padding-right:30px}.weui-cell_select .weui-cell__bd:after{content:" ";display:inline-block;height:6px;width:6px;border-width:2px 2px 0 0;border-color:#c8c8cd;border-style:solid;-webkit-transform:matrix(.71,.71,-.71,.71,0,0);transform:matrix(.71,.71,-.71,.71,0,0);position:relative;top:-2px;position:absolute;top:50%;right:15px;margin-top:-4px}.weui-select{-webkit-appearance:none;border:0;outline:0;background-color:transparent;width:100%;font-size:inherit;height:45px;line-height:45px;position:relative;z-index:1;padding-left:15px}.weui-cell_select-before{padding-right:15px}.weui-cell_select-before .weui-select{width:105px;box-sizing:border-box}.weui-cell_select-before .weui-cell__hd{position:relative}.weui-cell_select-before .weui-cell__hd:after{content:" ";position:absolute;right:0;top:0;width:1px;bottom:0;border-right:1px solid #e5e5e5;color:#e5e5e5;-webkit-transform-origin:100% 0;transform-origin:100% 0;-webkit-transform:scaleX(.5);transform:scaleX(.5)}.weui-cell_select-before .weui-cell__hd:before{content:" ";display:inline-block;height:6px;width:6px;border-width:2px 2px 0 0;border-color:#c8c8cd;border-style:solid;-webkit-transform:matrix(.71,.71,-.71,.71,0,0);transform:matrix(.71,.71,-.71,.71,0,0);position:relative;top:-2px;position:absolute;top:50%;right:15px;margin-top:-4px}.weui-cell_select-before .weui-cell__bd{padding-left:15px}.weui-cell_select-before .weui-cell__bd:after{display:none}.weui-cell_select-after{padding-left:15px}.weui-cell_select-after .weui-select{padding-left:0}.weui-cell_vcode{padding-top:0;padding-right:0;padding-bottom:0}.weui-vcode-btn,.weui-vcode-img{margin-left:5px;height:45px;vertical-align:middle}.weui-vcode-btn{display:inline-block;padding:0 .6em 0 .7em;border-left:1px solid #e5e5e5;line-height:45px;font-size:17px;color:#3cc51f}button.weui-vcode-btn{background-color:transparent;border-top:0;border-right:0;border-bottom:0;outline:0}.weui-vcode-btn:active{color:#52a341}.weui-gallery{display:none;position:fixed;top:0;right:0;bottom:0;left:0;background-color:#000;z-index:1000}.weui-gallery__img{position:absolute;top:0;right:0;bottom:60px;left:0;background:50% no-repeat;background-size:contain}.weui-gallery__opr{position:absolute;right:0;bottom:0;left:0;background-color:#0d0d0d;color:#fff;line-height:60px;text-align:center}.weui-gallery__del{display:block}.weui-cell_switch{padding-top:6.5px;padding-bottom:6.5px}.weui-switch{-webkit-appearance:none;appearance:none}.weui-switch,.weui-switch-cp__box{position:relative;width:52px;height:32px;border:1px solid #dfdfdf;outline:0;border-radius:16px;box-sizing:border-box;background-color:#dfdfdf;-webkit-transition:background-color .1s,border .1s;transition:background-color .1s,border .1s}.weui-switch-cp__box:before,.weui-switch:before{content:" ";position:absolute;top:0;left:0;width:50px;height:30px;border-radius:15px;background-color:#fdfdfd;-webkit-transition:-webkit-transform .35s cubic-bezier(.45,1,.4,1);transition:-webkit-transform .35s cubic-bezier(.45,1,.4,1);transition:transform .35s cubic-bezier(.45,1,.4,1);transition:transform .35s cubic-bezier(.45,1,.4,1),-webkit-transform .35s cubic-bezier(.45,1,.4,1)}.weui-switch-cp__box:after,.weui-switch:after{content:" ";position:absolute;top:0;left:0;width:30px;height:30px;border-radius:15px;background-color:#fff;box-shadow:0 1px 3px rgba(0,0,0,.4);-webkit-transition:-webkit-transform .35s cubic-bezier(.4,.4,.25,1.35);transition:-webkit-transform .35s cubic-bezier(.4,.4,.25,1.35);transition:transform .35s cubic-bezier(.4,.4,.25,1.35);transition:transform .35s cubic-bezier(.4,.4,.25,1.35),-webkit-transform .35s cubic-bezier(.4,.4,.25,1.35)}.weui-switch-cp__input:checked~.weui-switch-cp__box,.weui-switch:checked{border-color:#04be02;background-color:#04be02}.weui-switch-cp__input:checked~.weui-switch-cp__box:before,.weui-switch:checked:before{-webkit-transform:scale(0);transform:scale(0)}.weui-switch-cp__input:checked~.weui-switch-cp__box:after,.weui-switch:checked:after{-webkit-transform:translateX(20px);transform:translateX(20px)}.weui-switch-cp__input{position:absolute;left:-9999px}.weui-switch-cp__box{display:block}.weui-uploader__hd{display:-webkit-box;display:-webkit-flex;display:flex;padding-bottom:10px;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.weui-uploader__title{-webkit-box-flex:1;-webkit-flex:1;flex:1}.weui-uploader__info{color:#b2b2b2}.weui-uploader__bd{margin-bottom:-4px;margin-right:-9px;overflow:hidden}.weui-uploader__files{list-style:none}.weui-uploader__file{float:left;margin-right:9px;margin-bottom:9px;width:79px;height:79px;background:no-repeat 50%;background-size:cover}.weui-uploader__file_status{position:relative}.weui-uploader__file_status:before{content:" ";position:absolute;top:0;right:0;bottom:0;left:0;background-color:rgba(0,0,0,.5)}.weui-uploader__file_status .weui-uploader__file-content{display:block}.weui-uploader__file-content{display:none;position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);color:#fff}.weui-uploader__file-content .weui-icon-warn{display:inline-block}.weui-uploader__input-box{float:left;position:relative;margin-right:9px;margin-bottom:9px;width:77px;height:77px;border:1px solid #d9d9d9}.weui-uploader__input-box:after,.weui-uploader__input-box:before{content:" ";position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);background-color:#d9d9d9}.weui-uploader__input-box:before{width:2px;height:39.5px}.weui-uploader__input-box:after{width:39.5px;height:2px}.weui-uploader__input-box:active{border-color:#999}.weui-uploader__input-box:active:after,.weui-uploader__input-box:active:before{background-color:#999}.weui-uploader__input{position:absolute;z-index:1;top:0;left:0;width:100%;height:100%;opacity:0;-webkit-tap-highlight-color:rgba(0,0,0,0)}.weui-msg{padding-top:36px;text-align:center}.weui-msg__icon-area{margin-bottom:30px}.weui-msg__text-area{margin-bottom:25px;padding:0 20px}.weui-msg__text-area a{color:#586c94}.weui-msg__title{margin-bottom:5px;font-weight:400;font-size:20px}.weui-msg__desc,.weui-msg__title{word-wrap:break-word;word-break:break-all}.weui-msg__desc{font-size:14px;color:#999}.weui-msg__opr-area{margin-bottom:25px}.weui-msg__extra-area{margin-bottom:15px;font-size:14px;color:#999}.weui-msg__extra-area a{color:#586c94}@media screen and (min-height:438px){.weui-msg__extra-area{position:fixed;left:0;bottom:0;width:100%;text-align:center}}@media only screen and (device-width:375px) and (device-height:812px) and (-webkit-device-pixel-ratio:3){.weui-msg__extra-area{margin-bottom:49px}}.weui-article{padding:20px 15px;font-size:15px}.weui-article section{margin-bottom:1.5em}.weui-article h1{font-size:18px;font-weight:400;margin-bottom:.9em}.weui-article h2{font-size:16px}.weui-article h2,.weui-article h3{font-weight:400;margin-bottom:.34em}.weui-article h3{font-size:15px}.weui-article *{max-width:100%;box-sizing:border-box;word-wrap:break-word}.weui-article p{margin:0 0 .8em}.weui-tabbar{display:-webkit-box;display:-webkit-flex;display:flex;position:absolute;z-index:500;bottom:0;width:100%;background-color:#f7f7fa}.weui-tabbar:before{content:" ";position:absolute;left:0;top:0;right:0;height:1px;border-top:1px solid #c0bfc4;color:#c0bfc4;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-tabbar__item{display:block;-webkit-box-flex:1;-webkit-flex:1;flex:1;padding:5px 0 0;font-size:0;color:#999;text-align:center;-webkit-tap-highlight-color:rgba(0,0,0,0)}.weui-tabbar__item.weui-bar__item_on .weui-tabbar__icon,.weui-tabbar__item.weui-bar__item_on .weui-tabbar__icon>i,.weui-tabbar__item.weui-bar__item_on .weui-tabbar__label{color:#09bb07}.weui-tabbar__icon{display:inline-block;width:27px;height:27px}.weui-tabbar__icon>i,i.weui-tabbar__icon{font-size:24px;color:#999}.weui-tabbar__icon img{width:100%;height:100%}.weui-tabbar__label{text-align:center;color:#999;font-size:10px;line-height:1.8}.weui-navbar{display:-webkit-box;display:-webkit-flex;display:flex;position:absolute;z-index:500;top:0;width:100%;background-color:#fafafa}.weui-navbar:after{content:" ";position:absolute;left:0;bottom:0;right:0;height:1px;border-bottom:1px solid #ccc;color:#ccc;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-navbar+.weui-tab__panel{padding-top:50px;padding-bottom:0}.weui-navbar__item{position:relative;display:block;-webkit-box-flex:1;-webkit-flex:1;flex:1;padding:13px 0;text-align:center;font-size:15px;-webkit-tap-highlight-color:rgba(0,0,0,0)}.weui-navbar__item:active{background-color:#ededed}.weui-navbar__item.weui-bar__item_on{background-color:#eaeaea}.weui-navbar__item:after{content:" ";position:absolute;right:0;top:0;width:1px;bottom:0;border-right:1px solid #ccc;color:#ccc;-webkit-transform-origin:100% 0;transform-origin:100% 0;-webkit-transform:scaleX(.5);transform:scaleX(.5)}.weui-navbar__item:last-child:after{display:none}.weui-tab{position:relative;height:100%}.weui-tab__panel{box-sizing:border-box;height:100%;padding-bottom:50px;overflow:auto;-webkit-overflow-scrolling:touch}.weui-tab__content{display:none}.weui-progress{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.weui-progress__bar{background-color:#ebebeb;height:3px;-webkit-box-flex:1;-webkit-flex:1;flex:1}.weui-progress__inner-bar{width:0;height:100%;background-color:#09bb07}.weui-progress__opr{display:block;margin-left:15px;font-size:0}.weui-panel{background-color:#fff;margin-top:10px;position:relative;overflow:hidden}.weui-panel:first-child{margin-top:0}.weui-panel:before{top:0;border-top:1px solid #e5e5e5;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-panel:after,.weui-panel:before{content:" ";position:absolute;left:0;right:0;height:1px;color:#e5e5e5}.weui-panel:after{bottom:0;border-bottom:1px solid #e5e5e5;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-panel__hd{padding:14px 15px 10px;color:#999;font-size:13px;position:relative}.weui-panel__hd:after{content:" ";position:absolute;left:0;bottom:0;right:0;height:1px;border-bottom:1px solid #e5e5e5;color:#e5e5e5;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5);left:15px}.weui-media-box{padding:15px;position:relative}.weui-media-box:before{content:" ";position:absolute;left:0;top:0;right:0;height:1px;border-top:1px solid #e5e5e5;color:#e5e5e5;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5);left:15px}.weui-media-box:first-child:before{display:none}a.weui-media-box{color:#000;-webkit-tap-highlight-color:rgba(0,0,0,0)}a.weui-media-box:active{background-color:#ececec}.weui-media-box__title{font-weight:400;font-size:17px;width:auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;word-wrap:normal;word-wrap:break-word;word-break:break-all}.weui-media-box__desc{color:#999;font-size:13px;line-height:1.2;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.weui-media-box__info{margin-top:15px;padding-bottom:5px;font-size:13px;color:#cecece;line-height:1em;list-style:none;overflow:hidden}.weui-media-box__info__meta{float:left;padding-right:1em}.weui-media-box__info__meta_extra{padding-left:1em;border-left:1px solid #cecece}.weui-media-box_text .weui-media-box__title{margin-bottom:8px}.weui-media-box_appmsg{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.weui-media-box_appmsg .weui-media-box__hd{margin-right:.8em;width:60px;height:60px;line-height:60px;text-align:center}.weui-media-box_appmsg .weui-media-box__thumb{width:100%;max-height:100%;vertical-align:top}.weui-media-box_appmsg .weui-media-box__bd{-webkit-box-flex:1;-webkit-flex:1;flex:1;min-width:0}.weui-media-box_small-appmsg{padding:0}.weui-media-box_small-appmsg .weui-cells{margin-top:0}.weui-media-box_small-appmsg .weui-cells:before{display:none}.weui-grids{position:relative;overflow:hidden}.weui-grids:before{right:0;height:1px;border-top:1px solid #d9d9d9;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-grids:after,.weui-grids:before{content:" ";position:absolute;left:0;top:0;color:#d9d9d9}.weui-grids:after{width:1px;bottom:0;border-left:1px solid #d9d9d9;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(.5);transform:scaleX(.5)}.weui-grid{position:relative;float:left;padding:20px 10px;width:33.33333333%;box-sizing:border-box}.weui-grid:before{top:0;width:1px;border-right:1px solid #d9d9d9;-webkit-transform-origin:100% 0;transform-origin:100% 0;-webkit-transform:scaleX(.5);transform:scaleX(.5)}.weui-grid:after,.weui-grid:before{content:" ";position:absolute;right:0;bottom:0;color:#d9d9d9}.weui-grid:after{left:0;height:1px;border-bottom:1px solid #d9d9d9;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-grid:active{background-color:#ececec}.weui-grid__icon{width:28px;height:28px;margin:0 auto}.weui-grid__icon img{display:block;width:100%;height:100%}.weui-grid__icon+.weui-grid__label{margin-top:5px}.weui-grid__label{display:block;color:#000;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.weui-footer,.weui-grid__label{text-align:center;font-size:14px}.weui-footer{color:#999}.weui-footer a{color:#586c94}.weui-footer_fixed-bottom{position:fixed;bottom:.52em;left:0;right:0}.weui-footer__links{font-size:0}.weui-footer__link{display:inline-block;vertical-align:top;margin:0 .62em;position:relative;font-size:14px}.weui-footer__link:before{content:" ";position:absolute;left:0;top:0;width:1px;bottom:0;border-left:1px solid #c7c7c7;color:#c7c7c7;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(.5);transform:scaleX(.5);left:-.65em;top:.36em;bottom:.36em}.weui-footer__link:first-child:before{display:none}.weui-footer__text{padding:0 .34em;font-size:12px}.weui-flex{display:-webkit-box;display:-webkit-flex;display:flex}.weui-flex__item{-webkit-box-flex:1;-webkit-flex:1;flex:1}.weui-dialog{position:fixed;z-index:5000;width:80%;max-width:300px;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);background-color:#fff;text-align:center;border-radius:3px;overflow:hidden}.weui-dialog__hd{padding:1.3em 1.6em .5em}.weui-dialog__title{font-weight:400;font-size:18px}.weui-dialog__bd{padding:0 1.6em .8em;min-height:40px;font-size:15px;line-height:1.3;word-wrap:break-word;word-break:break-all;color:#999}.weui-dialog__bd:first-child{padding:2.7em 20px 1.7em;color:#353535}.weui-dialog__ft{position:relative;line-height:48px;font-size:18px;display:-webkit-box;display:-webkit-flex;display:flex}.weui-dialog__ft:after{content:" ";position:absolute;left:0;top:0;right:0;height:1px;border-top:1px solid #d5d5d6;color:#d5d5d6;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-dialog__btn{display:block;-webkit-box-flex:1;-webkit-flex:1;flex:1;color:#3cc51f;text-decoration:none;-webkit-tap-highlight-color:rgba(0,0,0,0);position:relative}.weui-dialog__btn:active{background-color:#eee}.weui-dialog__btn:after{content:" ";position:absolute;left:0;top:0;width:1px;bottom:0;border-left:1px solid #d5d5d6;color:#d5d5d6;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(.5);transform:scaleX(.5)}.weui-dialog__btn:first-child:after{display:none}.weui-dialog__btn_default{color:#353535}.weui-dialog__btn_primary{color:#0bb20c}.weui-skin_android .weui-dialog{text-align:left;box-shadow:0 6px 30px 0 rgba(0,0,0,.1)}.weui-skin_android .weui-dialog__title{font-size:21px}.weui-skin_android .weui-dialog__hd{text-align:left}.weui-skin_android .weui-dialog__bd{color:#999;padding:.25em 1.6em 2em;font-size:17px;text-align:left}.weui-skin_android .weui-dialog__bd:first-child{padding:1.6em 1.6em 2em;color:#353535}.weui-skin_android .weui-dialog__ft{display:block;text-align:right;line-height:42px;font-size:16px;padding:0 1.6em .7em}.weui-skin_android .weui-dialog__ft:after{display:none}.weui-skin_android .weui-dialog__btn{display:inline-block;vertical-align:top;padding:0 .8em}.weui-skin_android .weui-dialog__btn:after{display:none}.weui-skin_android .weui-dialog__btn:active,.weui-skin_android .weui-dialog__btn:visited{background-color:rgba(0,0,0,.06)}.weui-skin_android .weui-dialog__btn:last-child{margin-right:-.8em}.weui-skin_android .weui-dialog__btn_default{color:gray}@media screen and (min-width:1024px){.weui-dialog{width:35%}}.weui-toast{position:fixed;z-index:5000;width:7.6em;min-height:7.6em;top:180px;left:50%;margin-left:-3.8em;background:hsla(0,0%,7%,.7);text-align:center;border-radius:5px;color:#fff}.weui-icon_toast{margin:22px 0 0;display:block}.weui-icon_toast.weui-icon-success-no-circle:before{color:#fff;font-size:55px}.weui-icon_toast.weui-loading{margin:30px 0 0;width:38px;height:38px;vertical-align:baseline}.weui-toast__content{margin:0 0 15px}.weui-mask{background:rgba(0,0,0,.6)}.weui-mask,.weui-mask_transparent{position:fixed;z-index:1000;top:0;right:0;left:0;bottom:0}.weui-actionsheet{position:fixed;left:0;bottom:0;-webkit-transform:translateY(100%);transform:translateY(100%);-webkit-backface-visibility:hidden;backface-visibility:hidden;z-index:5000;width:100%;background-color:#efeff4;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s}.weui-actionsheet__title{position:relative;height:65px;padding:0 20px;line-height:1.4;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column;text-align:center;font-size:14px;color:#888;background:#fcfcfd}.weui-actionsheet__title:before{content:" ";position:absolute;left:0;bottom:0;right:0;height:1px;border-bottom:1px solid #e5e5e5;color:#e5e5e5;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-actionsheet__title .weui-actionsheet__title-text{overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.weui-actionsheet__menu{background-color:#fcfcfd}.weui-actionsheet__action{margin-top:6px;background-color:#fcfcfd}.weui-actionsheet__cell{position:relative;padding:10px 0;text-align:center;font-size:18px}.weui-actionsheet__cell:before{content:" ";position:absolute;left:0;top:0;right:0;height:1px;border-top:1px solid #e5e5e5;color:#e5e5e5;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-actionsheet__cell:active{background-color:#ececec}.weui-actionsheet__cell:first-child:before{display:none}.weui-skin_android .weui-actionsheet{position:fixed;left:50%;top:50%;bottom:auto;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);width:274px;box-sizing:border-box;-webkit-backface-visibility:hidden;backface-visibility:hidden;background:transparent;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s}.weui-skin_android .weui-actionsheet__action{display:none}.weui-skin_android .weui-actionsheet__menu{border-radius:2px;box-shadow:0 6px 30px 0 rgba(0,0,0,.1)}.weui-skin_android .weui-actionsheet__cell{padding:13px 24px;font-size:16px;line-height:1.4;text-align:left}.weui-skin_android .weui-actionsheet__cell:first-child{border-top-left-radius:2px;border-top-right-radius:2px}.weui-skin_android .weui-actionsheet__cell:last-child{border-bottom-left-radius:2px;border-bottom-right-radius:2px}.weui-actionsheet_toggle{-webkit-transform:translate(0);transform:translate(0)}.weui-loadmore{width:65%;margin:1.5em auto;line-height:1.6em;font-size:14px;text-align:center}.weui-loadmore__tips{display:inline-block;vertical-align:middle}.weui-loadmore_line{border-top:1px solid #e5e5e5;margin-top:2.4em}.weui-loadmore_line .weui-loadmore__tips{position:relative;top:-.9em;padding:0 .55em;background-color:#fff;color:#999}.weui-loadmore_dot .weui-loadmore__tips{padding:0 .16em}.weui-loadmore_dot .weui-loadmore__tips:before{content:" ";width:4px;height:4px;border-radius:50%;background-color:#e5e5e5;display:inline-block;position:relative;vertical-align:0;top:-.16em}.weui-badge{display:inline-block;padding:.15em .4em;min-width:8px;border-radius:18px;background-color:#f43530;color:#fff;line-height:1.2;text-align:center;font-size:12px;vertical-align:middle}.weui-badge_dot{padding:.4em;min-width:0}.weui-search-bar{position:relative;padding:8px 10px;display:-webkit-box;display:-webkit-flex;display:flex;box-sizing:border-box;background-color:#efeff4;-webkit-text-size-adjust:100%;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.weui-search-bar:before{top:0;border-top:1px solid #d7d6dc;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-search-bar:after,.weui-search-bar:before{content:" ";position:absolute;left:0;right:0;height:1px;color:#d7d6dc}.weui-search-bar:after{bottom:0;border-bottom:1px solid #d7d6dc;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-search-bar.weui-search-bar_focusing .weui-search-bar__cancel-btn{display:block}.weui-search-bar.weui-search-bar_focusing .weui-search-bar__label{display:none}.weui-search-bar__form{position:relative;-webkit-box-flex:1;-webkit-flex:auto;flex:auto;background-color:#efeff4}.weui-search-bar__form:after{content:'';position:absolute;left:0;top:0;width:200%;height:200%;-webkit-transform:scale(.5);transform:scale(.5);-webkit-transform-origin:0 0;transform-origin:0 0;border-radius:10px;border:1px solid #e6e6ea;box-sizing:border-box;background:#fff}.weui-search-bar__box{position:relative;padding-left:30px;padding-right:30px;height:100%;width:100%;box-sizing:border-box;z-index:1}.weui-search-bar__box .weui-search-bar__input{padding:4px 0;width:100%;height:1.42857143em;border:0;font-size:14px;line-height:1.42857143em;box-sizing:content-box;background:transparent}.weui-search-bar__box .weui-search-bar__input:focus{outline:none}.weui-search-bar__box .weui-icon-search{position:absolute;top:50%;left:10px;margin-top:-14px;line-height:28px}.weui-search-bar__box .weui-icon-clear{position:absolute;top:50%;right:0;margin-top:-14px;padding:0 10px;line-height:28px}.weui-search-bar__label{position:absolute;top:1px;right:1px;bottom:1px;left:1px;z-index:2;border-radius:3px;text-align:center;color:#9b9b9b;background:#fff}.weui-search-bar__label span{display:inline-block;font-size:14px;vertical-align:middle}.weui-search-bar__label .weui-icon-search{margin-right:5px}.weui-search-bar__cancel-btn{display:none;margin-left:10px;line-height:28px;color:#09bb07;white-space:nowrap}.weui-search-bar__input:not(:valid)~.weui-icon-clear{display:none}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration,input[type=search]::-webkit-search-results-button,input[type=search]::-webkit-search-results-decoration{display:none}.weui-picker{position:fixed;width:100%;left:0;bottom:0;z-index:5000;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translateY(100%);transform:translateY(100%);-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s}.weui-picker__hd{display:-webkit-box;display:-webkit-flex;display:flex;padding:9px 15px;background-color:#fff;position:relative;text-align:center;font-size:17px}.weui-picker__hd:after{content:" ";position:absolute;left:0;bottom:0;right:0;height:1px;border-bottom:1px solid #e5e5e5;color:#e5e5e5;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-picker__action{display:block;-webkit-box-flex:1;-webkit-flex:1;flex:1;color:#1aad19}.weui-picker__action:first-child{text-align:left;color:#888}.weui-picker__action:last-child{text-align:right}.weui-picker__bd{display:-webkit-box;display:-webkit-flex;display:flex;position:relative;background-color:#fff;height:238px;overflow:hidden}.weui-picker__group{-webkit-box-flex:1;-webkit-flex:1;flex:1;position:relative;height:100%}.weui-picker__mask{top:0;height:100%;margin:0 auto;background:-webkit-linear-gradient(top,hsla(0,0%,100%,.95),hsla(0,0%,100%,.6)),-webkit-linear-gradient(bottom,hsla(0,0%,100%,.95),hsla(0,0%,100%,.6));background:linear-gradient(180deg,hsla(0,0%,100%,.95),hsla(0,0%,100%,.6)),linear-gradient(0deg,hsla(0,0%,100%,.95),hsla(0,0%,100%,.6));background-position:top,bottom;background-size:100% 102px;background-repeat:no-repeat;-webkit-transform:translateZ(0);transform:translateZ(0)}.weui-picker__indicator,.weui-picker__mask{position:absolute;left:0;width:100%;z-index:3}.weui-picker__indicator{height:34px;top:102px}.weui-picker__indicator:before{top:0;border-top:1px solid #e5e5e5;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-picker__indicator:after,.weui-picker__indicator:before{content:" ";position:absolute;left:0;right:0;height:1px;color:#e5e5e5}.weui-picker__indicator:after{bottom:0;border-bottom:1px solid #e5e5e5;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-picker__content{position:absolute;top:0;left:0;width:100%}.weui-picker__item{padding:0;height:34px;line-height:34px;text-align:center;color:#000;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.weui-picker__item_disabled{color:#999}@-webkit-keyframes a{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes a{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.weui-animate-slide-up{-webkit-animation:a ease .3s forwards;animation:a ease .3s forwards}@-webkit-keyframes b{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes b{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.weui-animate-slide-down{-webkit-animation:b ease .3s forwards;animation:b ease .3s forwards}@-webkit-keyframes c{0%{opacity:0}to{opacity:1}}@keyframes c{0%{opacity:0}to{opacity:1}}.weui-animate-fade-in{-webkit-animation:c ease .3s forwards;animation:c ease .3s forwards}@-webkit-keyframes d{0%{opacity:1}to{opacity:0}}@keyframes d{0%{opacity:1}to{opacity:0}}.weui-animate-fade-out{-webkit-animation:d ease .3s forwards;animation:d ease .3s forwards}.weui-agree{display:block;padding:.5em 15px;font-size:13px}.weui-agree a{color:#586c94}.weui-agree__text{color:#999}.weui-agree__checkbox{-webkit-appearance:none;appearance:none;outline:0;font-size:0;border:1px solid #d1d1d1;background-color:#fff;border-radius:3px;width:13px;height:13px;position:relative;vertical-align:0;top:2px}.weui-agree__checkbox:checked:before{font-family:weui;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;text-align:center;speak:none;display:inline-block;vertical-align:middle;text-decoration:inherit;content:"\EA08";color:#09bb07;font-size:13px;position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-48%) scale(.73);transform:translate(-50%,-48%) scale(.73)}.weui-agree__checkbox:disabled{background-color:#e1e1e1}.weui-agree__checkbox:disabled:before{color:#adadad}.weui-loading{width:20px;height:20px;display:inline-block;vertical-align:middle;-webkit-animation:e 1s steps(12) infinite;animation:e 1s steps(12) infinite;background:transparent url("data:image/svg+xml;charset=utf8, %3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120' viewBox='0 0 100 100'%3E%3Cpath fill='none' d='M0 0h100v100H0z'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='%23E9E9E9' rx='5' ry='5' transform='translate(0 -30)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='%23989697' rx='5' ry='5' transform='rotate(30 105.98 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='%239B999A' rx='5' ry='5' transform='rotate(60 75.98 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='%23A3A1A2' rx='5' ry='5' transform='rotate(90 65 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='%23ABA9AA' rx='5' ry='5' transform='rotate(120 58.66 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='%23B2B2B2' rx='5' ry='5' transform='rotate(150 54.02 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='%23BAB8B9' rx='5' ry='5' transform='rotate(180 50 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='%23C2C0C1' rx='5' ry='5' transform='rotate(-150 45.98 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='%23CBCBCB' rx='5' ry='5' transform='rotate(-120 41.34 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='%23D2D2D2' rx='5' ry='5' transform='rotate(-90 35 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='%23DADADA' rx='5' ry='5' transform='rotate(-60 24.02 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='%23E2E2E2' rx='5' ry='5' transform='rotate(-30 -5.98 65)'/%3E%3C/svg%3E") no-repeat;background-size:100%}.weui-btn_loading.weui-btn_primary .weui-loading,.weui-btn_loading.weui-btn_warn .weui-loading,.weui-loading.weui-loading_transparent{background-image:url("data:image/svg+xml;charset=utf8, %3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120' viewBox='0 0 100 100'%3E%3Cpath fill='none' d='M0 0h100v100H0z'/%3E%3Crect xmlns='http://www.w3.org/2000/svg' width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.56)' rx='5' ry='5' transform='translate(0 -30)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.5)' rx='5' ry='5' transform='rotate(30 105.98 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.43)' rx='5' ry='5' transform='rotate(60 75.98 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.38)' rx='5' ry='5' transform='rotate(90 65 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.32)' rx='5' ry='5' transform='rotate(120 58.66 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.28)' rx='5' ry='5' transform='rotate(150 54.02 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.25)' rx='5' ry='5' transform='rotate(180 50 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.2)' rx='5' ry='5' transform='rotate(-150 45.98 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.17)' rx='5' ry='5' transform='rotate(-120 41.34 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.14)' rx='5' ry='5' transform='rotate(-90 35 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.1)' rx='5' ry='5' transform='rotate(-60 24.02 65)'/%3E%3Crect width='7' height='20' x='46.5' y='40' fill='rgba(255,255,255,.03)' rx='5' ry='5' transform='rotate(-30 -5.98 65)'/%3E%3C/svg%3E")}@-webkit-keyframes e{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes e{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.weui-slider{padding:15px 18px;-webkit-user-select:none;user-select:none}.weui-slider__inner{position:relative;height:2px;background-color:#e9e9e9}.weui-slider__track{height:2px;background-color:#1aad19;width:0}.weui-slider__handler{position:absolute;left:0;top:50%;width:28px;height:28px;margin-left:-14px;margin-top:-14px;border-radius:50%;background-color:#fff;box-shadow:0 0 4px rgba(0,0,0,.2)}.weui-slider-box{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.weui-slider-box .weui-slider{-webkit-box-flex:1;-webkit-flex:1;flex:1}.weui-slider-box__value{margin-left:.5em;min-width:24px;color:#888;text-align:center;font-size:14px}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/dobind.html b/platforms/android/app/src/main/assets/www/dobind.html
new file mode 100644
index 0000000..6d377b9
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/dobind.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <link rel="stylesheet" type="text/css" href="mobileui/style.css">
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="viewport-fit=cover, initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <link rel="stylesheet" type="text/css" href="css/aui.css">
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <title>绑定银行卡</title>
+</head>
+<body>
+    <header class="aui-bar aui-bar-nav" style="padding-top:25px;">
+        <a class="aui-pull-left" href="bindcard.html">
+            <span class="aui-iconfont aui-icon-left"></span>
+        </a>
+        <div class="aui-title">绑定银行卡</div>
+    </header>
+    <div>
+        <div class="weui-cells__title">验证市民卡预留的手机号</div>
+        <div class="weui-cells weui-cells_form">
+            <div class="weui-cell" style="padding:0 10px; "> 
+                <div class="weui-cell__hd"><label class="weui-label" style="width: 80px;font-size: 14px;">手机号</label></div>
+                <div class="weui-cell__bd">
+                    <input class="weui-input" type="number" id="phone" style="font-size: 14px;" placeholder="请输入市民卡预留的手机号" disabled="disabled" value="13402184553">
+                </div>
+            </div>
+            <div class="weui-cell weui-cell_vcode" style="padding:0 10px; ">
+                <div class="weui-cell__hd">
+                    <label class="weui-label" style="width: 80px;font-size: 14px;">验证码</label>
+                </div>
+                <div class="weui-cell__bd">
+                    <input class="weui-input" type="number" id="code" style="font-size: 14px;" placeholder="请输入验证码" maxlength="6">
+                </div>
+                <div class="weui-cell__ft">
+                    <button class="weui-vcode-btn" onclick="app.getCode()" id="codebtn" style="width: 100px;height: 1rem;font-size: 14px;">获取验证码</button>
+                </div>
+            </div>
+        </div>
+        
+        <section class="aui-content-padded" style="margin-top: 30px;">
+            <div class="aui-btn aui-btn-block aui-btn-info" tapmode onclick="app.doNext()">绑定</div>
+        </section>
+    </div>
+</body>
+
+</html>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/register.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/lib/jquery-weui.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/error.html b/platforms/android/app/src/main/assets/www/error.html
new file mode 100644
index 0000000..4902b3b
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/error.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <link rel="stylesheet" type="text/css" href="mobileui/style.css">
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <link rel="stylesheet" type="text/css" href="css/aui.css">
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <title>错误</title>
+</head>
+<body>
+    <header class="aui-bar aui-bar-nav" style="padding-top:25px;">
+        <a class="aui-pull-left" href="javascript:window.history.back();">
+            <span class="aui-iconfont aui-icon-left"></span>
+        </a>
+        <div class="aui-title">错误</div>
+    </header>
+    <p style="padding:10px;text-align: center;">系统错误</p>
+    <script type="text/javascript" src="cordova.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/findpwd.html b/platforms/android/app/src/main/assets/www/findpwd.html
new file mode 100644
index 0000000..a538505
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/findpwd.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <link rel="stylesheet" type="text/css" href="mobileui/style.css">
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="viewport-fit=cover, initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <link rel="stylesheet" type="text/css" href="css/aui.css">
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <title>找回登录密码</title>
+</head>
+<body>
+    <header class="aui-bar aui-bar-nav" style="padding-top:25px;">
+        <a class="aui-pull-left" href="login.html">
+            <span class="aui-iconfont aui-icon-left"></span>
+        </a>
+        <div class="aui-title">找回登录密码</div>
+    </header>
+    <div>
+        <div class="weui-cells weui-cells_form">
+            <div class="weui-cell" style="padding:0 10px; "> 
+                <div class="weui-cell__hd"><label class="weui-label" style="width: 80px;font-size: 14px;">手机号</label></div>
+                <div class="weui-cell__bd">
+                    <input class="weui-input" type="number" id="phone" style="font-size: 14px;" placeholder="请输入注册的手机号" maxlength="11">
+                </div>
+            </div>
+            <div class="weui-cell weui-cell_vcode" style="padding:0 10px; ">
+                <div class="weui-cell__hd">
+                    <label class="weui-label" style="width: 80px;font-size: 14px;">验证码</label>
+                </div>
+                <div class="weui-cell__bd">
+                    <input class="weui-input" type="number" id="code" style="font-size: 14px;" placeholder="请输入验证码" maxlength="6">
+                </div>
+                <div class="weui-cell__ft">
+                    <button class="weui-vcode-btn" onclick="app.getCode()" id="codebtn" style="width: 100px;height: 1rem;font-size: 14px;">获取验证码</button>
+                </div>
+            </div>
+        </div>
+        <section class="aui-content-padded" style="margin-top: 30px;">
+            <div class="aui-btn aui-btn-block aui-btn-info" tapmode onclick="app.doFind()">下一步</div>
+        </section>
+    </div>
+</body>
+
+</html>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/register.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/lib/jquery-weui.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/img/icon_auth.png b/platforms/android/app/src/main/assets/www/img/icon_auth.png
new file mode 100644
index 0000000..97d950d
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/img/icon_auth.png
Binary files differ
diff --git a/platforms/android/app/src/main/assets/www/img/icon_bill.png b/platforms/android/app/src/main/assets/www/img/icon_bill.png
new file mode 100644
index 0000000..37d5d65
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/img/icon_bill.png
Binary files differ
diff --git a/platforms/android/app/src/main/assets/www/img/icon_car.png b/platforms/android/app/src/main/assets/www/img/icon_car.png
new file mode 100644
index 0000000..d04eacc
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/img/icon_car.png
Binary files differ
diff --git a/platforms/android/app/src/main/assets/www/img/icon_card.png b/platforms/android/app/src/main/assets/www/img/icon_card.png
new file mode 100644
index 0000000..595945e
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/img/icon_card.png
Binary files differ
diff --git a/platforms/android/app/src/main/assets/www/img/icon_header.png b/platforms/android/app/src/main/assets/www/img/icon_header.png
new file mode 100644
index 0000000..b3a7ebe
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/img/icon_header.png
Binary files differ
diff --git a/platforms/android/app/src/main/assets/www/img/icon_meal.png b/platforms/android/app/src/main/assets/www/img/icon_meal.png
new file mode 100644
index 0000000..f503a14
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/img/icon_meal.png
Binary files differ
diff --git a/platforms/android/app/src/main/assets/www/img/icon_ok.png b/platforms/android/app/src/main/assets/www/img/icon_ok.png
new file mode 100644
index 0000000..e21b78a
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/img/icon_ok.png
Binary files differ
diff --git a/platforms/android/app/src/main/assets/www/img/icon_qrcode.png b/platforms/android/app/src/main/assets/www/img/icon_qrcode.png
new file mode 100644
index 0000000..bc1dfc7
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/img/icon_qrcode.png
Binary files differ
diff --git a/platforms/android/app/src/main/assets/www/img/icon_scan.png b/platforms/android/app/src/main/assets/www/img/icon_scan.png
new file mode 100644
index 0000000..40b59db
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/img/icon_scan.png
Binary files differ
diff --git a/platforms/android/app/src/main/assets/www/img/icon_securty.png b/platforms/android/app/src/main/assets/www/img/icon_securty.png
new file mode 100644
index 0000000..16b4ddc
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/img/icon_securty.png
Binary files differ
diff --git a/platforms/android/app/src/main/assets/www/img/icon_water.png b/platforms/android/app/src/main/assets/www/img/icon_water.png
new file mode 100644
index 0000000..a65df7e
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/img/icon_water.png
Binary files differ
diff --git a/platforms/android/app/src/main/assets/www/img/scanner.svg b/platforms/android/app/src/main/assets/www/img/scanner.svg
new file mode 100644
index 0000000..a13c92b
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/img/scanner.svg
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="210mm"
+   height="297mm"
+   viewBox="0 0 744.09448819 1052.3622047"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="aaa.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.7"
+     inkscape:cx="635.5236"
+     inkscape:cy="495.53637"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1017"
+     inkscape:window-x="-8"
+     inkscape:window-y="-8"
+     inkscape:window-maximized="1"
+     showguides="false" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Ebene 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       style="fill:#333333;fill-opacity:0.45098039;fill-rule:evenodd;stroke:#333333;stroke-width:1.06048119px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0"
+       d="m 139.32394,274.20898 c -2.43478,0 -4.74475,0.50716 -6.83985,1.41211 -1.96625,0.82082 -3.73345,2.01806 -5.21093,3.50391 -3.1756,3.1164 -5.14454,7.45787 -5.14454,12.2793 l 0,90.91406 c 0,9.5259 7.66941,17.19336 17.19532,17.19336 9.5259,0 17.19336,-7.66746 17.19336,-17.19336 l 0,-75.67774 75.13867,0 c 8.93724,0 16.13281,-7.19361 16.13281,-16.13085 0,-8.93723 -7.19557,-16.13282 -16.13281,-16.13282 l -90.04297,0 c -0.75087,-0.0994 -1.51019,-0.16797 -2.28906,-0.16797 z"
+       id="rect3338"
+       inkscape:connector-curvature="0" />
+    <path
+       inkscape:connector-curvature="0"
+       style="fill:#333333;fill-opacity:0.45098039;fill-rule:evenodd;stroke:#333333;stroke-width:1.06048119px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0"
+       d="m 631.50851,291.04712 c 0,-2.43478 -0.50716,-4.74475 -1.41211,-6.83985 -0.82082,-1.96625 -2.01806,-3.73345 -3.50391,-5.21093 -3.1164,-3.1756 -7.45787,-5.14454 -12.2793,-5.14454 l -90.91406,0 c -9.5259,0 -17.19336,7.66941 -17.19336,17.19532 0,9.5259 7.66746,17.19336 17.19336,17.19336 l 75.67774,0 0,75.13867 c 0,8.93724 7.19361,16.13281 16.13085,16.13281 8.93723,0 16.13282,-7.19557 16.13282,-16.13281 l 0,-90.04297 c 0.0994,-0.75087 0.16797,-1.51019 0.16797,-2.28906 z"
+       id="rect3338-2" />
+    <path
+       inkscape:connector-curvature="0"
+       style="fill:#333333;fill-opacity:0.45098039;fill-rule:evenodd;stroke:#333333;stroke-width:1.06048119px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0"
+       d="m 122.12824,684.96063 c 0,2.43478 0.50716,4.74475 1.41211,6.83985 0.82082,1.96626 2.01806,3.73346 3.50391,5.21094 3.1164,3.1756 7.45787,5.14454 12.2793,5.14454 l 90.91406,0 c 9.5259,0 17.19336,-7.66941 17.19336,-17.19533 0,-9.5259 -7.66746,-17.19336 -17.19336,-17.19336 l -75.67774,0 0,-75.13866 c 0,-8.93724 -7.19361,-16.13281 -16.13085,-16.13281 -8.93723,0 -16.13282,7.19557 -16.13282,16.13281 l 0,90.04296 c -0.0994,0.75087 -0.16797,1.51019 -0.16797,2.28906 z"
+       id="rect3338-6" />
+    <path
+       inkscape:connector-curvature="0"
+       style="fill:#333333;fill-opacity:0.45098039;fill-rule:evenodd;stroke:#333333;stroke-width:1.06048119px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0"
+       d="m 614.67107,702.15643 c 2.43478,0 4.74475,-0.50716 6.83985,-1.41211 1.96626,-0.82082 3.73346,-2.01806 5.21094,-3.50391 3.1756,-3.1164 5.14454,-7.45787 5.14454,-12.2793 l 0,-90.91406 c 0,-9.5259 -7.66941,-17.19336 -17.19533,-17.19336 -9.5259,0 -17.19336,7.66746 -17.19336,17.19336 l 0,75.67774 -75.13866,0 c -8.93724,0 -16.13281,7.19361 -16.13281,16.13085 0,8.93723 7.19557,16.13282 16.13281,16.13282 l 90.04296,0 c 0.75087,0.0994 1.51019,0.16797 2.28906,0.16797 z"
+       id="rect3338-6-1" />
+  </g>
+</svg>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/index.html b/platforms/android/app/src/main/assets/www/index.html
new file mode 100644
index 0000000..4afb0bf
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/index.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="viewport-fit=cover, initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <title>大理市民卡</title>
+</head>
+<body class="mainbg">
+    <div class="weui-footer weui-footer_fixed-bottom">
+        <p class="weui-footer__links">
+            <a href="#" class="weui-footer__link" style="color: white">大理市民卡</a>
+        </p>
+        <p class="weui-footer__text" style="color: white">© 2019 上海树维</p>
+    </div>
+</body>
+</html>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/index.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/lib/jquery-weui.min.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
+<script type="text/javascript">
+</script>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/bill.js b/platforms/android/app/src/main/assets/www/js/bill.js
new file mode 100644
index 0000000..4b0bca5
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/bill.js
@@ -0,0 +1,69 @@
+var curpage=1;
+var app = {
+
+    // Application Constructor
+    initialize: function() {
+        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
+    },
+    onDeviceReady: function() {
+        curpage = 1;
+        this.loadBill(curpage)
+    },
+    loadBill:function(pageno){
+        $.showLoading("加载中");
+        var param={
+            "pageno":pageno
+        }
+        V1Bills(param,function(ok,ret){
+            if(ok){
+                if(ret.code==200){
+                    if(ret.page&&ret.page.count>0){
+                        app.initBillView(ret.page)
+                    }else{
+                        $.alert("暂无数据", "提示"); 
+                    }    
+                }else{
+                    $.hideLoading();
+                    $.alert("数据加载异常,请稍后再试", "错误");
+                }
+            }else{
+                $.hideLoading();
+                $.alert("请求失败了:" + ret.status+"请稍后再试", "错误");
+            }            
+        })
+    },
+    initBillView:function(page){
+        //TODO img src
+        var data = page.data
+        var html ='';
+        for(var i=0;i<data.length;i++){
+            var bean=data[i]
+            html +='<div class="aui-card-list-header aui-card-list-user" onclick="app.toBillDetail(\''+bean.refno+'\')">';
+            html +='<div class="aui-card-list-user-avatar"><img src="img/icon_meal.png" class="aui-margin-r-10 aui-img-round" />';
+            html +='</div><div class="aui-card-list-user-name">';
+            html +='<div>'+bean.transdesc+'</div>';
+           if(bean.tradeflag=='in'){
+                html +='<div class="aui-list-item-right">+'+bean.amount+'</div>';
+            }else{
+                html +='<div class="aui-list-item-right">'+bean.amount+'</div>';
+            }
+            html +='</div><div class="aui-card-list-user-info">'+formatDateNoYear(bean.transdate,bean.transtime)+'</div></div>';
+        }
+        $("#billcontent").append(html);
+        if(page.data.length==0){
+            $("#loadNext").hide();
+        }else{
+            $("#loadNext").show();
+        }
+        $.hideLoading();
+    },
+    toBillDetail: function(refno) {
+        window.localStorage.setItem("currentrefno",refno);
+        window.location='billdetail.html';
+    },
+    loadNext:function(){
+        curpage++;
+        this.loadBill(curpage)
+    }
+};
+app.initialize();
diff --git a/platforms/android/app/src/main/assets/www/js/billdetail.js b/platforms/android/app/src/main/assets/www/js/billdetail.js
new file mode 100644
index 0000000..057b106
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/billdetail.js
@@ -0,0 +1,58 @@
+var app = {
+
+    // Application Constructor
+    initialize: function() {
+        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
+    },
+
+    onDeviceReady: function() {
+        this.loadBill()
+    },
+    loadBill: function() {
+        var refno = window.localStorage.getItem("currentrefno");
+        if (isEmpty(refno)) {
+            $.alert("加载失败了", "提示");
+            return;
+        }
+        $.showLoading("加载中");
+        var param = {
+            "billid": refno
+        }
+        V1Billdetail(param, function(ok, ret) {
+            if (ok) {
+                if (ret.code == 200) {
+                    if (ret.dtl == null) {
+                        $.hideLoading();
+                        $.alert("数据加载异常,请稍后再试", "错误");
+                    } else {
+                        app.initBillView(ret.dtl)
+                    }
+                } else {
+                    $.hideLoading();
+                    $.alert("数据加载异常,请稍后再试", "错误");
+                }
+            } else {
+                $.hideLoading();
+                $.alert("请求失败了:" + ret.status + "请稍后再试", "错误");
+            }
+        })
+    },
+    initBillView: function(data) {
+        console.log(data);
+        if (data.tradeflag == 'in') {
+            $("#amount").text('+' + data.amount)
+        } else {
+            $("#amount").text(data.amount)
+        }
+        if (data.status == 'success') {
+            $("#status").text("交易成功");
+        } else {
+            $("#status").text("交易失败");
+        }
+        $("#tranddes").text(data.transdesc);
+        $("#transtime").text(formatDate(data.transdate + '' + data.transtime, true));
+        $("#refno").text(data.refno);
+        $.hideLoading();
+    }
+};
+app.initialize();
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/bindcard.js b/platforms/android/app/src/main/assets/www/js/bindcard.js
new file mode 100644
index 0000000..53ac0cf
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/bindcard.js
@@ -0,0 +1,89 @@
+var app = {
+
+    // Application Constructor
+    initialize: function() {
+        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
+    },
+  
+    onDeviceReady: function() {
+        var uid = window.localStorage.getItem("uid");
+        var phone =  window.localStorage.getItem("phoneX");
+        if(!isEmpty(phone)){
+            $("#phone").val(phone)
+        }else{
+            phone =  window.localStorage.getItem("phone");
+            $("#phone").val(phone)
+        }
+    },
+    doNext: function() {
+        var code =  $("#code").val();
+        var cardnum =  $("#cardnum").val();
+        var name =  $("#name").val();
+        if(isEmpty(name)||isEmpty(code)||isEmpty(cardnum)){
+            return;
+        }
+        /*var agree = $("input[type=checkbox]:checked").val();
+        if(isEmpty(agree)){
+            $.alert("请同意用户协议与隐私条款", "提示");
+            return;
+        }*/
+        $.showLoading("正在处理");
+        var param={
+            "card":cardnum,
+            "code":code,
+            "name":name
+        }
+        V1Bindcard(param,function(ok,ret){
+            if(ok){
+                $.hideLoading();
+                console.log(ret)
+                if(ret.code==200){
+                     window.localStorage.setItem("paypwdtype","new"); 
+                     window.localStorage.setItem("userid",ret.userid);
+                     window.localStorage.setItem("signed",ret.signed); 
+                     window.localStorage.setItem("name",name); 
+                     window.localStorage.setItem("paypwdset",ret.paypwdset); 
+                     if(ret.paypwdset){
+                        if(!isEmpty(ret.signed)&&signed=='yes'){
+                            window.location='main.html'
+                        }else{
+                            window.location='signxy.html'
+                        }
+                     }else{
+                        window.location="paypwdset.html";
+                     }
+                }else{
+                    if(ret.code==-1){
+                        $.alert(ret.msg, "提示",function(){
+                            window.location="main.html"
+                        });
+                    }else{
+                       $.alert(ret.msg, "错误");
+                    }
+                } 
+            }else{
+                $.hideLoading();
+                $.alert("请求失败了 "+ret.status+",请稍后再试", "错误");
+            }
+        })
+    },
+    getCode :function(){
+        $.showLoading("请求中");
+        V1Code(function(ok,ret){
+            if(ok){
+                $.hideLoading();
+                if(ret.code==200){
+                    $("#codebtn").attr("disabled","disabled")
+                    $("#codebtn").addClass("vcodedisabled")
+                    btnTime('codebtn');
+                }else{
+                    $.alert(ret.msg, "错误");
+                } 
+            }else{
+                $.hideLoading();
+                $.alert("请求失败了"+ret.status+",请稍后再试", "错误");
+            }
+        })
+    }
+};
+app.initialize();
diff --git a/platforms/android/app/src/main/assets/www/js/card.js b/platforms/android/app/src/main/assets/www/js/card.js
new file mode 100644
index 0000000..9e3fe81
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/card.js
@@ -0,0 +1,56 @@
+var app = {
+
+    // Application Constructor
+    initialize: function() {
+        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
+    },
+  
+    onDeviceReady: function() {
+        var uid = window.localStorage.getItem("uid");
+        
+    },
+    doNext: function() {
+        var pwd =  $("#pwd").val();
+        if(isEmpty(pwd)){
+            return;
+        }
+        if(pwd.length!=6){
+            $.alert("支付密码为6位数字", "提示");
+            return;
+        }
+        var cum = new auiDialog({});
+        var confirm = cum.alert({
+            title: "提示",
+            msg: '确定挂失吗',
+            buttons: ['取消', '确定']
+        }, function(ret) {
+            if (ret.buttonIndex == 2) {
+                $.showLoading("正在处理");
+                var param={
+                    "pwd":pwd
+                }
+                V1CardLost(param,function(ok,ret){
+                    if(ok){
+                        $.hideLoading();
+                        if(ret.code==200){
+                             window.localStorage.removeItem("randomcode"); 
+                             var signed = window.localStorage.getItem("signed"); 
+                             window.localStorage.setItem("paypwdset",ret.paypwdset); 
+                             if(isEmpty(signed)||signed!='yes'){
+                                window.location='signxy.html'   
+                             }else{
+                                window.location='main.html'   
+                             }
+                        }else{
+                            $.alert(ret.msg, "错误");
+                        } 
+                    }else{
+                        $.hideLoading();
+                        $.alert("请求失败了"+ret.status+",请稍后再试", "错误");
+                    }
+                })
+            }
+        })
+    }
+};
+app.initialize();
diff --git a/platforms/android/app/src/main/assets/www/js/db.js b/platforms/android/app/src/main/assets/www/js/db.js
new file mode 100644
index 0000000..d9f0e9b
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/db.js
@@ -0,0 +1,8 @@
+var db = null;
+
+document.addEventListener('deviceready', function() {
+  db = window.sqlitePlugin.openDatabase({
+    name: 'my.db',
+    location: 'default',
+  });
+});
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/index.js b/platforms/android/app/src/main/assets/www/js/index.js
new file mode 100644
index 0000000..a2381c8
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/index.js
@@ -0,0 +1,66 @@
+var app = {
+    /*
+    thirdapp:
+    closeBrowser(){
+        if(history.length==1){
+            window.open('mobile/close');
+        }else{
+            history.back();
+        }
+    }
+    <a href="javascript:;" onclick="closeBrowser()">Close</a>
+
+
+    client:
+    var ref = window.open(encodeURI(url), '_blank','location=no');
+     ref.addEventListener('loadstart', function(event) {
+         if (event.url.match("mobile/close")) {
+             ref.close();
+         }
+     });
+    */
+    // Application Constructor
+    initialize: function() {
+        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
+    },
+
+    onDeviceReady: function() {
+        var uid = window.localStorage.getItem("token");
+        if (isEmpty(uid)) {
+            window.location = "login.html";
+        } else {
+            //尝试登陆
+            V1Infor(function(ok, ret) {
+                console.log(ret)
+                if (ok) {
+                    if(ret.code==200){
+                        var exp =  window.localStorage.getItem("tokenexpire");
+                        var t = parseInt(exp);
+                        //token 小于10分钟了,需要刷新
+                        console.log((ret.now-t))
+                        if(ret.now-t>1000*60*10){
+                             window.location = "login.html";
+                        }else{
+                             window.localStorage.setItem("userid",ret.userid);
+                             window.localStorage.setItem("signed",ret.signed); 
+                             window.localStorage.setItem("paypwdset",ret.paypwdset);
+                             window.localStorage.setItem("name",ret.name); 
+                             window.location = "main.html";
+                        }
+                    }
+                } else {
+                    //alert('无法请求到服务器,请检查网络并稍后再试');
+                    if (ret.status == 401) {
+                        //need login
+                        window.location = "login.html";
+                    } else {
+                        //TODO ,没有网络
+                        
+                        window.location = "main.html";
+                    }
+                }
+            })
+        }
+    }
+};
+app.initialize();
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/aui-actionsheet.js b/platforms/android/app/src/main/assets/www/js/lib/aui-actionsheet.js
new file mode 100644
index 0000000..82b97a1
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/aui-actionsheet.js
@@ -0,0 +1,118 @@
+/**
+ * aui-actionsheet.js
+ * @author 流浪男
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+(function( window, undefined ) {
+    "use strict";
+    var auiActionsheet = function() {
+    };
+    var isShow = false;
+    auiActionsheet.prototype = {
+        init: function(params,callback){
+            this.frameBounces = params.frameBounces;
+            this.title = params.title;
+            this.buttons = params.buttons;
+            this.cancelTitle = params.cancelTitle;
+            this.destructiveTitle = params.destructiveTitle;
+            this.maskDiv;
+            this.actionsheetDiv;
+            var self = this;
+            self.open(params,callback);
+        },
+        open: function(params,callback) {
+            var titleHtml='',buttonsHtml='',destructiveHtml='',cancelHtml='',btnHtml='';
+        	var self = this;
+            if(self.actionsheetDiv || (!self.title && !self.buttons && !self.cancelTitle && !self.destructiveTitle))return;
+            if(!self.maskDiv){
+                self.maskDiv = document.createElement("div");
+                self.maskDiv.className = "aui-mask";
+                document.body.appendChild(self.maskDiv);
+            }
+            self.actionsheetDiv = document.createElement("div");
+            self.actionsheetDiv.className = "aui-actionsheet";
+            document.body.appendChild(self.actionsheetDiv);
+            if(self.title){
+                titleHtml = '<div class="aui-actionsheet-title aui-border-b aui-font-size-12">'+self.title+'</div>';
+            }
+            if(self.buttons && self.buttons.length){
+                for(var i = 0; i < self.buttons.length;i++){
+                    if(i == self.buttons.length-1){
+                        buttonsHtml += '<div class="aui-actionsheet-btn-item">'+self.buttons[i]+'</div>';
+                    }else{
+                        buttonsHtml += '<div class="aui-actionsheet-btn-item aui-border-b">'+self.buttons[i]+'</div>';
+                    }
+                }
+            }
+            if(self.destructiveTitle){
+                destructiveHtml = '<div class="aui-actionsheet-btn-item aui-border-t aui-text-danger">'+self.destructiveTitle+'</div>';
+            }else{
+                var destructiveHtml = '';
+            }
+            if(self.title || (self.buttons && self.buttons.length)){
+                btnHtml = '<div class="aui-actionsheet-btn">'+titleHtml+''+buttonsHtml+''+destructiveHtml+'</div>';
+            }
+            if(self.cancelTitle){
+                cancelHtml = '<div class="aui-actionsheet-btn"><div class="aui-actionsheet-btn-item">'+self.cancelTitle+'</div></div>';
+            }
+            self.actionsheetDiv.insertAdjacentHTML('beforeend', btnHtml+cancelHtml);
+            var actionsheetHeight = document.querySelector(".aui-actionsheet").offsetHeight;
+            self.maskDiv.classList.add("aui-mask-in");
+            self.actionsheetDiv.style.webkitTransform = self.actionsheetDiv.style.transform = "translate3d(0,0,0)";
+            self.actionsheetDiv.style.opacity = 1;
+            self.actionsheetDiv.addEventListener("touchmove", function(event){
+                event.preventDefault();
+            })
+            self.maskDiv.addEventListener("touchmove", function(event){
+                event.preventDefault();
+            })
+            if(typeof(api) != 'undefined' && typeof(api) == 'object' && self.frameBounces){
+                api.setFrameAttr({
+                    bounces:false
+                });
+            }
+            var actionsheetButtons = document.querySelectorAll(".aui-actionsheet-btn-item");
+            if(actionsheetButtons && actionsheetButtons.length > 0){
+                setTimeout(function(){
+                    self.maskDiv.onclick = function(){self.close();return;};
+                    for(var ii = 0; ii < actionsheetButtons.length; ii++){
+                        (function(e){
+                            actionsheetButtons[e].onclick = function(){
+                                if(callback){
+                                    callback({
+                                        buttonIndex: e+1,
+                                        buttonTitle: this.textContent
+                                    });
+                                };
+                                self.close();
+                                return;
+                            }
+                        })(ii)
+                    }
+                }, 350)
+            }
+        },
+        close: function(){
+            var self = this;
+            if(typeof(api) != 'undefined' && typeof(api) == 'object' && self.frameBounces){
+                api.setFrameAttr({
+                    bounces:true
+                });
+            }
+            if(self.actionsheetDiv){
+                var actionsheetHeight = self.actionsheetDiv.offsetHeight;
+                self.actionsheetDiv.style.webkitTransform = self.actionsheetDiv.style.transform = "translate3d(0,"+actionsheetHeight+"px,0)";
+                self.maskDiv.style.opacity = 0;
+                setTimeout(function(){
+                    if(self.maskDiv){
+                        self.maskDiv.parentNode.removeChild(self.maskDiv);
+                    }
+                    self.actionsheetDiv.parentNode.removeChild(self.actionsheetDiv);
+                    self.actionsheetDiv = self.maskDiv = false;
+                }, 300)
+            }
+        }
+    };
+	window.auiActionsheet = auiActionsheet;
+})(window);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/aui-collapse.js b/platforms/android/app/src/main/assets/www/js/lib/aui-collapse.js
new file mode 100644
index 0000000..491100f
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/aui-collapse.js
@@ -0,0 +1,44 @@
+/**
+ * aui-collapse.js
+ * @author 流浪男
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+(function( window, undefined ) {
+    "use strict";
+    var auiCollapse = function(params) {
+        this.init(params);
+    };
+    auiCollapse.prototype = {
+        init: function(params,callback){
+            var collapseHeader = document.querySelectorAll(".aui-collapse-header");
+            if(collapseHeader.length){
+                for(var i=0;i<collapseHeader.length;i++){
+                    (function(e){
+                        collapseHeader[e].onclick = function(){
+                            if(collapseHeader[e].nextSibling.nextElementSibling.className.indexOf("aui-collapse-content") > -1){
+                                if(collapseHeader[e].nextSibling.nextElementSibling.className.indexOf("aui-show") > -1){
+                                    collapseHeader[e].nextSibling.nextElementSibling.classList.remove("aui-show");
+                                    collapseHeader[e].classList.remove("aui-active");
+                                }else{
+                                    if(params.autoHide){
+                                        if(document.querySelector(".aui-collapse-header.aui-active")){
+                                            document.querySelector(".aui-collapse-header.aui-active").classList.remove("aui-active");
+                                        }
+                                        if(document.querySelector(".aui-collapse-content.aui-show")){
+                                            document.querySelector(".aui-collapse-content.aui-show").classList.remove("aui-show");
+                                        }
+                                    }
+
+                                    collapseHeader[e].nextSibling.nextElementSibling.classList.toggle("aui-show");
+                                    collapseHeader[e].classList.toggle("aui-active");
+                                }
+                            }
+                        }
+                    })(i)
+                }
+            }
+        }
+    };
+	window.auiCollapse = auiCollapse;
+})(window);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/aui-dialog.js b/platforms/android/app/src/main/assets/www/js/lib/aui-dialog.js
new file mode 100644
index 0000000..90e85aa
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/aui-dialog.js
@@ -0,0 +1,125 @@
+/**
+ * aui-dialog.js
+ * @author 流浪男
+ * @todo more things to abstract, e.g. Loading css etc.
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+(function( window, undefined ) {
+    "use strict";
+    var auiDialog = function() {
+    };
+    var isShow = false;
+    auiDialog.prototype = {
+        params: {
+            title:'',
+            msg:'',
+            buttons: ['取消','确定'],
+            input:false
+        },
+        create: function(params,callback) {
+        	var self = this;
+            var dialogHtml = '';
+            var buttonsHtml = '';
+            var headerHtml = params.title ? '<div class="aui-dialog-header">' + params.title + '</div>' : '<div class="aui-dialog-header">' + self.params.title + '</div>';
+            if(params.input){
+                params.text = params.text ? params.text: '';
+                var msgHtml = '<div class="aui-dialog-body"><input type="text" placeholder="'+params.text+'"></div>';
+            }else{
+                var msgHtml = params.msg ? '<div class="aui-dialog-body">' + params.msg + '</div>' : '<div class="aui-dialog-body">' + self.params.msg + '</div>';
+            }
+            var buttons = params.buttons ? params.buttons : self.params.buttons;
+            if (buttons && buttons.length > 0) {
+                for (var i = 0; i < buttons.length; i++) {
+                    buttonsHtml += '<div class="aui-dialog-btn" tapmode button-index="'+i+'">'+buttons[i]+'</div>';
+                }
+            }
+            var footerHtml = '<div class="aui-dialog-footer">'+buttonsHtml+'</div>';
+            dialogHtml = '<div class="aui-dialog">'+headerHtml+msgHtml+footerHtml+'</div>';
+            document.body.insertAdjacentHTML('beforeend', dialogHtml);
+            // listen buttons click
+            var dialogButtons = document.querySelectorAll(".aui-dialog-btn");
+            if(dialogButtons && dialogButtons.length > 0){
+                for(var ii = 0; ii < dialogButtons.length; ii++){
+                    dialogButtons[ii].onclick = function(){
+                        if(callback){
+                            if(params.input){
+                                callback({
+                                    buttonIndex: parseInt(this.getAttribute("button-index"))+1,
+                                    text: document.querySelector("input").value
+                                });
+                            }else{
+                                callback({
+                                    buttonIndex: parseInt(this.getAttribute("button-index"))+1
+                                });
+                            }
+                        };
+                        self.close();
+                        return;
+                    }
+                }
+            }
+            self.open();
+        },
+        open: function(){
+            if(!document.querySelector(".aui-dialog"))return;
+            var self = this;
+            document.querySelector(".aui-dialog").style.marginTop =  "-"+Math.round(document.querySelector(".aui-dialog").offsetHeight/2)+"px";
+            if(!document.querySelector(".aui-mask")){
+                var maskHtml = '<div class="aui-mask"></div>';
+                document.body.insertAdjacentHTML('beforeend', maskHtml);
+            }
+            // document.querySelector(".aui-dialog").style.display = "block";
+            setTimeout(function(){
+                document.querySelector(".aui-dialog").classList.add("aui-dialog-in");
+                document.querySelector(".aui-mask").classList.add("aui-mask-in");
+                document.querySelector(".aui-dialog").classList.add("aui-dialog-in");
+            }, 10)
+            document.querySelector(".aui-mask").addEventListener("touchmove", function(e){
+                e.preventDefault();
+            })
+            document.querySelector(".aui-dialog").addEventListener("touchmove", function(e){
+                e.preventDefault();
+            })
+            return;
+        },
+        close: function(){
+            var self = this;
+            document.querySelector(".aui-mask").classList.remove("aui-mask-in");
+            document.querySelector(".aui-dialog").classList.remove("aui-dialog-in");
+            document.querySelector(".aui-dialog").classList.add("aui-dialog-out");
+            if (document.querySelector(".aui-dialog:not(.aui-dialog-out)")) {
+                setTimeout(function(){
+                    if(document.querySelector(".aui-dialog"))document.querySelector(".aui-dialog").parentNode.removeChild(document.querySelector(".aui-dialog"));
+                    self.open();
+                    return true;
+                },200)
+            }else{
+                document.querySelector(".aui-mask").classList.add("aui-mask-out");
+                document.querySelector(".aui-dialog").addEventListener("webkitTransitionEnd", function(){
+                    self.remove();
+                })
+                document.querySelector(".aui-dialog").addEventListener("transitionend", function(){
+                    self.remove();
+                })
+            }
+        },
+        remove: function(){
+            if(document.querySelector(".aui-dialog"))document.querySelector(".aui-dialog").parentNode.removeChild(document.querySelector(".aui-dialog"));
+            if(document.querySelector(".aui-mask")){
+                document.querySelector(".aui-mask").classList.remove("aui-mask-out");
+            }
+            return true;
+        },
+        alert: function(params,callback){
+        	var self = this;
+            return self.create(params,callback);
+        },
+        prompt:function(params,callback){
+            var self = this;
+            params.input = true;
+            return self.create(params,callback);
+        }
+    };
+	window.auiDialog = auiDialog;
+})(window);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/aui-lazyload.js b/platforms/android/app/src/main/assets/www/js/lib/aui-lazyload.js
new file mode 100644
index 0000000..17e24f0
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/aui-lazyload.js
@@ -0,0 +1,48 @@
+/**

+ * aui-lazyload.js

+ * @author 流浪男

+ * Licensed under the MIT license.

+ * http://www.opensource.org/licenses/mit-license.php

+ */

+(function( window, undefined ) {

+    "use strict";

+    var _loadImgNodes;

+    var auiLazyload = function(params) {

+        this.errorImage = params.errorImage||false;

+        this._init(params);

+    };

+    auiLazyload.prototype = {

+        _init: function(params) {

+            var self = this;

+            _loadImgNodes = document.querySelectorAll('[data-src]');

+            self._judgeImages();

+            window.addEventListener('scroll', function(){

+                _loadImgNodes = document.querySelectorAll('[data-src]');

+                self._judgeImages();

+            }, false);

+        },

+        _judgeImages:function() {

+            var self = this;

+            if(_loadImgNodes.length){

+                for(var i = 0;  i < _loadImgNodes.length; i++){

+                    if (_loadImgNodes[i].getBoundingClientRect().top < window.innerHeight) {

+                        self._loadImage(_loadImgNodes[i]);

+                    }

+                }

+            }

+        },

+        _loadImage:function(el){

+            var self = this;

+            var img = new Image();

+            img.src = el.getAttribute('data-src');

+            el.src = el.getAttribute('data-src');

+            el.removeAttribute("data-src");

+            // // 图片加载失败

+            img.onerror = function() {

+                el.src = self.errorImage || el.getAttribute('src');

+                el.removeAttribute("data-src");

+            };

+        }

+    }

+    window.auiLazyload = auiLazyload;

+})(window);

diff --git a/platforms/android/app/src/main/assets/www/js/lib/aui-list-swipe-backup.js b/platforms/android/app/src/main/assets/www/js/lib/aui-list-swipe-backup.js
new file mode 100644
index 0000000..7bffd23
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/aui-list-swipe-backup.js
@@ -0,0 +1,243 @@
+/**
+ * aui-list-swipe.js 列表页滑动菜单
+ * verson 0.0.3
+ * @author 流浪男 && Beck
+ * http://www.auicss.com
+ * @todo more things to abstract, e.g. Loading css etc.
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+ (function(window) {
+	"use strict";
+	var translateVal,
+		friction = 1,
+		firstTouchX,
+		firstTouchxy,
+		firstTouchY,
+		firstTouch,
+		firstTouchTime,
+		touchXDelta,
+		handleTranslateVal;
+	var TranslateZero = "translate3d(0,0,0)",
+		TranslateCent = "translate3d(100%,0,0)";
+	var swipeHandle = false,
+		btnWidth = false,
+		swipeBtnsRight = false;
+	var isMoved = false,isOpened=false;
+	var d = false;
+	var auiListSwipe = function (callback) {
+		this._init(callback);
+	}
+	auiListSwipe.prototype = {
+		// var self = this;
+		_init: function(callback){
+			var self = this;
+			// var d = document.querySelectorAll("selectors")
+			window.addEventListener('touchstart', function(event){
+				if(isOpened){
+					console.log(1)
+					// return;
+					isOpened = false;
+					return;
+				}
+				if(swipeHandle){
+					event.preventDefault();
+					self.setTranslate(swipeHandle,"0px");
+					swipeHandle.classList.remove("aui-swipe-opened");
+					swipeHandle = false;
+					return;
+				}
+				isMoved = false;
+				swipeHandle = false;
+				var target = event.target;
+				// 过滤点击
+				for(; target && target !== document; target = target.parentNode){
+					// console.log(target.classList)
+					if (target.classList){
+						if (target.classList.contains("aui-swipe-handle")) {
+							swipeHandle = target;
+							firstTouch = event.changedTouches[0];
+							firstTouchX = firstTouch.clientX;
+							firstTouchY = firstTouch.clientY;
+							firstTouchTime = event.timeStamp;
+							if(swipeHandle.className.indexOf("aui-swipe-opened") > -1){
+							// 	console.log(1)
+								// self.setTranslate(swipeHandle,"0px");
+								// swipeHandle.classList.remove("aui-swipe-opened");
+								event.preventDefault();
+								return;
+							}else{
+								// setTimeout(function(){
+									self.toggleEvents(swipeHandle,callback);
+								// }, 100)
+
+							}
+
+						}
+					}
+				}
+
+
+			})
+			// window.addEventListener('touchmove', function(event){
+			// 	if(swipeHandle){
+			// 		// event.preventDefault();
+			// 		// self.setTranslate(swipeHandle,"0px");
+			// 		// swipeHandle.classList.remove("aui-swipe-opened");
+			// 		// swipeHandle = false;
+			// 		// return;
+			// 	}
+			// 	if(document.querySelector(".aui-swipe-opened")){
+			// 		event.preventDefault();
+			// 		if(swipeHandle != document.querySelector(".aui-swipe-opened")){
+			// 			self.setTranslate(document.querySelector(".aui-swipe-opened"),"0px");
+			//         	document.querySelector(".aui-swipe-opened").classList.remove("aui-swipe-opened");
+			//         	isOpened = false;
+
+			//         	event.stopPropagation()
+			//         	return;
+			// 		}
+			// 	}
+			// })
+			window.addEventListener("touchmove", function(){
+
+			})
+		},
+		toggleEvents:function(element,callback){
+			if(!swipeHandle){
+				return;
+			}
+			var self = this;
+			self.setTransform(element,300);
+			element.addEventListener('touchstart', function(event){
+				// if(element.className.indexOf("aui-swipe-opened") > -1){
+				// 	self.setTranslate(element,"0px");
+				// 	element.classList.remove("aui-swipe-opened");
+				// 	return;
+				// }
+				//:active样式引起列表背景色冲突
+
+				element.parentNode.style.backgroundColor = "#ffffff";
+				if(!element.nextSibling)return;
+			},false)
+			element.addEventListener('touchmove', function(event){
+				if(document.querySelector(".aui-swipe-opened")){
+					event.preventDefault();
+					if(swipeHandle != document.querySelector(".aui-swipe-opened")){
+						self.setTranslate(document.querySelector(".aui-swipe-opened"),"0px");
+			        	document.querySelector(".aui-swipe-opened").classList.remove("aui-swipe-opened");
+			        	isOpened = false;
+			        	event.stopPropagation()
+			        	return;
+					}
+				}
+				// self.getAngle(event)
+				self.setTransform(element,0);
+				// if(element.className.indexOf("aui-swipe-opened") > -1)return;
+
+				if(element.parentNode.querySelector(".aui-swipe-btn")){
+					btnWidth = element.parentNode.querySelector(".aui-swipe-btn").offsetWidth;
+				}
+				// 列表触摸滑动时如果有已经显示的将其关闭,并退出。
+				var touchMoveObj = event.changedTouches[0],
+					touchX = touchMoveObj.clientX;
+				touchXDelta = -Math.pow(firstTouchX-touchX, 0.85);
+				handleTranslateVal = touchXDelta/friction;
+				// touchXDelta = touchX - firstTouchX;
+				// handleTranslateVal = touchXDelta/0.15;
+				// console.log(handleTranslateVal)
+		        var moveX = touchMoveObj.clientX - firstTouchX;
+		        var moveY = touchMoveObj.clientY - firstTouchY;
+		        var direction = self.getDirection(moveX,moveY);
+		        var angle = self.getAngle(Math.abs(moveX),Math.abs(moveY));
+		        // console.log(isMoved);
+
+		        // // 解决滑动屏幕返回时事件冲突,主要针对部分特殊机型
+		        // if(touchMoveObj.screenX < 0){
+		        // 	firstTouchxy = '';
+		        // }
+		        if(direction == "right"){
+		        	isMoved = false;
+		        	event.preventDefault();
+		        }
+		        if(direction == "top" || direction == "down"){
+		        	isMoved = false;
+		        	return;
+		        }
+		        if(angle <= 15 && direction === 'left'){
+		        	event.preventDefault()
+		        	isMoved = true;
+		        }
+		        // console.log(handleTranslateVal)
+		        // if(isMoved)self.setTranslate(element,""+(handleTranslateVal+10)+"px");
+		        if((event.timeStamp - firstTouchTime) >= 100 && touchXDelta < 0 && touchMoveObj.screenX > 0 && isMoved){
+		        	// event.stopPropagation();
+		        	// element.classList.add("aui-swipe-moving");
+		        	// event.preventDefault();
+		        	if(element.className.indexOf("aui-swipe-opened") <= -1){
+						if((handleTranslateVal+10) > -btnWidth){
+				        	self.setTranslate(element,""+(handleTranslateVal+10)+"px");
+				        }
+					}else{
+						return
+					}
+
+			    }
+			},false)
+			element.addEventListener('touchend', function(event){
+				self.setTransform(element,300);
+				var touchEndObj = event.changedTouches[0];
+				var touchEndxy = {
+						x: touchEndObj.clientX || 0,
+						y: touchEndObj.clientY || 0
+					};
+				var toucheEndX = touchEndObj.clientX - firstTouchX;
+		        var toucheEndY = touchEndObj.clientY - firstTouchY;
+		        var direction = self.getDirection(toucheEndX,toucheEndY);
+		        // element.classList.remove("aui-swipe-moving");
+	        	if(direction=='left' && handleTranslateVal < (-btnWidth/3) && isMoved){
+		        	self.setTranslate(element,""+-btnWidth+"px");
+		        	element.classList.add("aui-swipe-opened");
+		        	callback({
+		        		'status':true,
+		        		'dom':element
+		        	})
+		        	isOpened = true;
+				}else{
+					element.classList.remove("aui-swipe-opened");
+		        	self.setTranslate(element,"0px");
+		        	isOpened = false;
+				}
+				// isMoved = false;
+				console.log(isOpened)
+			},true)
+		},
+		setTransform : function (el,value){
+			el.style.webkitTransitionDuration = el.style.transitionDuration = value+'ms';
+		},
+		setTranslate : function (el,value){
+			if(el)el.style.webkitTransform = el.style.transform = "translate3d("+value+",0,0)";
+		},
+		getDistance : function(p1, p2, props) {
+			if (!props) { props = ['x', 'y'];}
+			var x = p2[props[0]] - p1[props[0]];
+			var y = p2[props[1]] - p1[props[1]];
+			return Math.sqrt((x * x) + (y * y));
+		},
+		getAngle:function(moveX, moveY){
+		       // var x = Math.abs(x1 - x2);
+		       // var y = Math.abs(y1 - y2);
+		       var z = Math.sqrt(moveX*moveX + moveY*moveY);
+		       return  Math.round((Math.asin(moveY / z) / Math.PI*180));
+		},
+		getDirection : function(x, y) {
+			if (x === y) { return '';}
+			if (Math.abs(x) >= Math.abs(y)) {
+	            return x > 0 ? 'right' : 'left';
+	        } else {
+	           	return y > 0 ? 'down' : 'up';
+	        }
+		}
+	}
+	window.auiListSwipe = auiListSwipe;
+})(window);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/aui-list-swipe.js b/platforms/android/app/src/main/assets/www/js/lib/aui-list-swipe.js
new file mode 100755
index 0000000..3669b70
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/aui-list-swipe.js
@@ -0,0 +1,221 @@
+/**
+ * aui-list-swipe.js 列表页滑动菜单
+ * verson 0.0.3
+ * @author 流浪男 && Beck
+ * http://www.auicss.com
+ * @todo more things to abstract, e.g. Loading css etc.
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+ (function(window) {
+	"use strict";
+	var translateVal,
+		friction = 1,
+		firstTouchX,
+		firstTouchxy,
+		firstTouchY,
+		firstTouch,
+		firstTouchTime,
+		touchXDelta,
+		handleTranslateVal;
+	var TranslateZero = "translate3d(0,0,0)",
+		TranslateCent = "translate3d(100%,0,0)";
+	var swipeHandle = false,
+		btnWidth = false,
+		swipeBtnsRight = false;
+	var isMoved = false,isOpened=false;
+	var d = false;
+	var auiListSwipe = function (callback) {
+		this._init(callback);
+	}
+	auiListSwipe.prototype = {
+		// var self = this;
+		_init: function(callback){
+			var self = this;
+			// var d = document.querySelectorAll("selectors")
+			window.addEventListener('touchstart', function(event){
+				// 如果已经打开,将已经打开的关闭
+				if(isOpened && swipeHandle){
+					// isOpened = false;
+					self.setTranslate(swipeHandle,"0px");
+					swipeHandle.classList.remove("aui-swipe-opened");
+					return;
+				}else{
+					var target = event.target;
+					// 过滤点击
+					for(; target && target !== document; target = target.parentNode){
+						// console.log(target.classList)
+						if (target.classList){
+							if (target.classList.contains("aui-swipe-handle")) {
+								swipeHandle = target;
+								firstTouch = event.changedTouches[0];
+								firstTouchX = firstTouch.clientX;
+								firstTouchY = firstTouch.clientY;
+								firstTouchTime = event.timeStamp;
+								if(swipeHandle.className.indexOf("aui-swipe-opened") > -1){
+								// 	console.log(1)
+									// self.setTranslate(swipeHandle,"0px");
+									// swipeHandle.classList.remove("aui-swipe-opened");
+									event.preventDefault();
+									return;
+								}else{
+									// setTimeout(function(){
+										self.toggleEvents(swipeHandle,callback);
+									// }, 100)
+
+								}
+
+							}
+						}
+					}
+				}
+				// if(swipeHandle){
+				// 	event.preventDefault();
+				// 	self.setTranslate(swipeHandle,"0px");
+				// 	swipeHandle.classList.remove("aui-swipe-opened");
+				// 	swipeHandle = false;
+				// 	return;
+				// }
+				// isMoved = false;
+				// swipeHandle = false;
+			})
+		},
+		toggleEvents:function(element,callback){
+			if(!swipeHandle){
+				return;
+			}
+			var self = this;
+			self.setTransform(element,300);
+			element.addEventListener('touchstart', function(event){
+				// if(element.className.indexOf("aui-swipe-opened") > -1){
+				// 	self.setTranslate(element,"0px");
+				// 	element.classList.remove("aui-swipe-opened");
+				// 	return;
+				// }
+				//:active样式引起列表背景色冲突
+
+				element.parentNode.style.backgroundColor = "#ffffff";
+				if(!element.nextSibling)return;
+			},false)
+			element.addEventListener('touchmove', function(event){
+				event.preventDefault();
+				if(document.querySelector(".aui-swipe-opened")){
+					event.preventDefault();
+					if(swipeHandle != document.querySelector(".aui-swipe-opened")){
+						self.setTranslate(document.querySelector(".aui-swipe-opened"),"0px");
+			        	document.querySelector(".aui-swipe-opened").classList.remove("aui-swipe-opened");
+			        	isOpened = false;
+			        	event.stopPropagation()
+			        	return;
+					}
+				}
+				// self.getAngle(event)
+				self.setTransform(element,0);
+				// if(element.className.indexOf("aui-swipe-opened") > -1)return;
+
+				if(element.parentNode.querySelector(".aui-swipe-btn")){
+					btnWidth = element.parentNode.querySelector(".aui-swipe-btn").offsetWidth;
+				}
+				// 列表触摸滑动时如果有已经显示的将其关闭,并退出。
+				var touchMoveObj = event.changedTouches[0],
+					touchX = touchMoveObj.clientX;
+				touchXDelta = -Math.pow(firstTouchX-touchX, 0.85);
+				handleTranslateVal = touchXDelta/friction;
+				// touchXDelta = touchX - firstTouchX;
+				// handleTranslateVal = touchXDelta/0.15;
+				// console.log(handleTranslateVal)
+		        var moveX = touchMoveObj.clientX - firstTouchX;
+		        var moveY = touchMoveObj.clientY - firstTouchY;
+		        var direction = self.getDirection(moveX,moveY);
+		        var angle = self.getAngle(Math.abs(moveX),Math.abs(moveY));
+		        // console.log(isMoved);
+
+		        // // 解决滑动屏幕返回时事件冲突,主要针对部分特殊机型
+		        // if(touchMoveObj.screenX < 0){
+		        // 	firstTouchxy = '';
+		        // }
+		        if(direction == "right"){
+		        	isMoved = false;
+		        	event.preventDefault();
+		        }
+		        if(direction == "top" || direction == "down"){
+		        	isMoved = false;
+		        	return;
+		        }
+		        if(angle <= 15 && direction === 'left'){
+		        	event.preventDefault()
+		        	isMoved = true;
+		        }
+		        // console.log(handleTranslateVal)
+		        // if(isMoved)self.setTranslate(element,""+(handleTranslateVal+10)+"px");
+		        if((event.timeStamp - firstTouchTime) >= 100 && touchXDelta < 0 && touchMoveObj.screenX > 0 && isMoved){
+		        	// event.stopPropagation();
+		        	// element.classList.add("aui-swipe-moving");
+		        	// event.preventDefault();
+		        	if(element.className.indexOf("aui-swipe-opened") <= -1){
+						if((handleTranslateVal+10) > -btnWidth){
+				        	self.setTranslate(element,""+(handleTranslateVal+10)+"px");
+				        }
+					}else{
+						return
+					}
+
+			    }
+			},false)
+			element.addEventListener('touchend', function(event){
+				self.setTransform(element,300);
+				var touchEndObj = event.changedTouches[0];
+				var touchEndxy = {
+						x: touchEndObj.clientX || 0,
+						y: touchEndObj.clientY || 0
+					};
+				var toucheEndX = touchEndObj.clientX - firstTouchX;
+		        var toucheEndY = touchEndObj.clientY - firstTouchY;
+		        var direction = self.getDirection(toucheEndX,toucheEndY);
+		        // element.classList.remove("aui-swipe-moving");
+	        	if(direction=='left' && handleTranslateVal < (-btnWidth/3) && isMoved){
+		        	self.setTranslate(element,""+-btnWidth+"px");
+		        	element.classList.add("aui-swipe-opened");
+		        	callback({
+		        		'status':true,
+		        		'dom':element
+		        	})
+		        	// isOpened = true;
+				}else{
+					element.classList.remove("aui-swipe-opened");
+		        	self.setTranslate(element,"0px");
+		        	isOpened = false;
+				}
+				// isMoved = false;
+				console.log(isOpened)
+			},true)
+		},
+		setTransform : function (el,value){
+			el.style.webkitTransitionDuration = el.style.transitionDuration = value+'ms';
+		},
+		setTranslate : function (el,value){
+			if(el)el.style.webkitTransform = el.style.transform = "translate3d("+value+",0,0)";
+		},
+		getDistance : function(p1, p2, props) {
+			if (!props) { props = ['x', 'y'];}
+			var x = p2[props[0]] - p1[props[0]];
+			var y = p2[props[1]] - p1[props[1]];
+			return Math.sqrt((x * x) + (y * y));
+		},
+		getAngle:function(moveX, moveY){
+		       // var x = Math.abs(x1 - x2);
+		       // var y = Math.abs(y1 - y2);
+		       var z = Math.sqrt(moveX*moveX + moveY*moveY);
+		       return  Math.round((Math.asin(moveY / z) / Math.PI*180));
+		},
+		getDirection : function(x, y) {
+			if (x === y) { return '';}
+			if (Math.abs(x) >= Math.abs(y)) {
+	            return x > 0 ? 'right' : 'left';
+	        } else {
+	           	return y > 0 ? 'down' : 'up';
+	        }
+		}
+	}
+	window.auiListSwipe = auiListSwipe;
+})(window);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/aui-popup-new.js b/platforms/android/app/src/main/assets/www/js/lib/aui-popup-new.js
new file mode 100644
index 0000000..3c1a128
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/aui-popup-new.js
@@ -0,0 +1,135 @@
+/**
+ * aui-popup.js
+ * @author 流浪男
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+(function( window, undefined ) {
+    "use strict";
+    var auiPopup = function() {
+    };
+    var isShow = false;
+    auiPopup.prototype = {
+        init: function(params,callback){
+            this.frameBounces = params.frameBounces;
+            this.location = params.location;
+            this.buttons = params.buttons;
+            this.maskDiv;
+            this.popupDiv;
+            var self = this;
+            self.open(params,callback);
+        },
+        open: function(params,callback) {
+            var buttonsHtml='',locationClass = 'aui-popup-top';
+        	var self = this;
+            if(self.popupDiv){
+                self.close();
+                return;
+            }
+            if(!self.maskDiv){
+                self.maskDiv = document.createElement("div");
+                self.maskDiv.className = "aui-mask";
+                document.body.appendChild(self.maskDiv);
+            }
+            switch (self.location) {
+                case "top":
+                    locationClass = 'aui-popup-top';
+                    break;
+                case "top-left":
+                    locationClass = 'aui-popup-top-left';
+                    break;
+                case "top-right":
+                    locationClass = 'aui-popup-top-right';
+                    break;
+                case "bottom":
+                    locationClass = 'aui-popup-bottom';
+                    break;
+                case "bottom-left":
+                    locationClass = 'aui-popup-bottom-left';
+                    break;
+                case "bottom-right":
+                    locationClass = 'aui-popup-bottom-right';
+                    break;
+                default:
+                    locationClass = 'aui-popup-top';
+                    break;
+            }
+            self.popupDiv = document.createElement("div");
+            self.popupDiv.className = "aui-popup "+locationClass;
+            self.popupDiv.innerHTML = '<div class="aui-popup-arrow"></div><div class="aui-popup-content"></div>';
+            document.body.appendChild(self.popupDiv);
+            if(self.buttons && self.buttons.length){
+                buttonsHtml += '<ul class="aui-list aui-list-noborder">';
+                for(var i = 0; i < self.buttons.length;i++){
+                    buttonsHtml += '<li class="aui-list-item aui-list-item-middle">';
+                    buttonsHtml += '<div class="aui-list-item-label-icon"><img src="'+self.buttons[i].image+'"></div>';
+                    buttonsHtml += '<div class="aui-list-item-inner">'+self.buttons[i].text+'</div>';
+                    buttonsHtml += '</li>';
+                }
+                buttonsHtml += '</ul>';
+            }
+            document.querySelector(".aui-popup .aui-popup-content").insertAdjacentHTML('beforeend', buttonsHtml);
+            var actionsheetHeight = document.querySelector(".aui-popup").offsetHeight;
+            self.maskDiv.classList.add("aui-mask-in");
+            self.popupDiv.classList.add("aui-popup-in");
+            self.popupDiv.addEventListener("touchmove", function(event){
+                event.preventDefault();
+            })
+            self.maskDiv.addEventListener("touchmove", function(event){
+                event.preventDefault();
+            })
+            if(typeof(api) != 'undefined' && typeof(api) == 'object' && self.frameBounces){
+                api.setFrameAttr({
+                    bounces:false
+                });
+            }
+            var popupButtons = document.querySelectorAll(".aui-popup .aui-list-item");
+            if(popupButtons && popupButtons.length > 0){
+                setTimeout(function(){
+                    self.maskDiv.onclick = function(){self.close();return;};
+                    for(var ii = 0; ii < popupButtons.length; ii++){
+                        (function(e){
+                            popupButtons[e].onclick = function(){
+                                if(self.buttons[e].value){
+                                    var _value = self.buttons[e].value;
+                                }else{
+                                    var _value = null;
+                                }
+                                if(callback){
+                                    callback({
+                                        buttonIndex: e+1,
+                                        buttonTitle: this.textContent,
+                                        buttonValue: _value
+                                    });
+                                };
+                                self.close();
+                                return;
+                            }
+                        })(ii)
+                    }
+                }, 350)
+            }
+        },
+        close: function(){
+            var self = this;
+            if(typeof(api) != 'undefined' && typeof(api) == 'object' && self.frameBounces){
+                api.setFrameAttr({
+                    bounces:true
+                });
+            }
+            if(self.popupDiv){
+                var actionsheetHeight = self.popupDiv.offsetHeight;
+                self.popupDiv.classList.add("aui-popup-out");
+                self.maskDiv.style.opacity = 0;
+                setTimeout(function(){
+                    if(self.maskDiv){
+                        self.maskDiv.parentNode.removeChild(self.maskDiv);
+                    }
+                    self.popupDiv.parentNode.removeChild(self.popupDiv);
+                    self.maskDiv = self.popupDiv = false;
+                }, 300)
+            }
+        }
+    };
+	window.auiPopup = auiPopup;
+})(window);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/aui-popup.js b/platforms/android/app/src/main/assets/www/js/lib/aui-popup.js
new file mode 100644
index 0000000..fe26259
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/aui-popup.js
@@ -0,0 +1,94 @@
+/**
+ * aui-popup.js
+ * @author 流浪男
+ * @todo more things to abstract, e.g. Loading css etc.
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+(function( window, undefined ) {
+    "use strict";
+    var auiPopup = function() {
+        this._init();
+    };
+    var	CLASS_MASK = "aui-mask",
+    	CLASS_MASK_IN = 'aui-mask-in',
+    	CLASS_MASK_OUT = 'aui-mask-out',
+        CLASS_POPUP = 'aui-popup',
+    	CLASS_POPUP_IN = 'aui-popup-in',
+    	CLASS_POPUP_OUT = 'aui-popup-out',
+    	CLASS_POPUP_FOR = 'aui-popup-for';
+    var	__MASK = '.'+CLASS_MASK,
+    	__MASK_IN = '.'+CLASS_MASK_IN,
+    	__MASK_OUT = '.'+CLASS_MASK_OUT,
+        __POPUP = '.'+CLASS_POPUP,
+    	__POPUP_IN = '.'+CLASS_POPUP_IN,
+    	__POPUP_OUT = '.'+CLASS_POPUP_OUT;
+    var popupStatus = false;
+    auiPopup.prototype = {
+        _init: function() {
+        	var self = this;
+        	var _btn = document.querySelectorAll("["+CLASS_POPUP_FOR+"]");
+        	if(_btn){
+        		for(var i=0;i<_btn.length;i++){
+        			_btn[i].setAttribute("tapmode", "");
+        			_btn[i].onclick = function(e){
+        				var popupId = this.getAttribute(CLASS_POPUP_FOR);
+        				var popupDom = document.getElementById(popupId);
+        				if(popupDom){
+							if(popupDom.className.indexOf(CLASS_POPUP_IN) > -1 || document.querySelector(__POPUP_IN)){
+					            self.hide(popupDom);
+					        }else{
+					        	self.show(popupDom);
+					        }
+        				}else{
+        					return;
+        				}
+					}
+        		}
+        	}
+        },
+        show: function(el){
+        	var self = this;
+        	if(el.className.indexOf(CLASS_POPUP_IN) > -1 || document.querySelector(__POPUP_IN)){
+	            self.hide(el);
+	            return;
+	        }
+            if(popupStatus) return;
+        	if(!document.querySelector(__MASK)){
+				var maskHtml = '<div class="aui-mask"></div>';
+				document.body.insertAdjacentHTML('beforeend', maskHtml);
+			}
+        	el.style.display = "block";
+        	setTimeout(function(){
+        		document.querySelector(__MASK).classList.add(CLASS_MASK_IN);
+	            el.classList.add(CLASS_POPUP_IN);
+                popupStatus = true;
+	        }, 10)
+	        document.querySelector(__MASK).addEventListener("touchstart", function(event){
+	        	event.preventDefault();
+	        	self.hide(el);
+	        })
+            el.addEventListener("touchmove", function(event){
+                event.preventDefault();
+            },false)
+        },
+        hide: function(el){
+            if(!popupStatus) return;
+        	document.querySelector(__MASK).classList.remove(CLASS_MASK_IN);
+        	document.querySelector(__MASK).classList.add(CLASS_MASK_OUT);
+        	if(!document.querySelector(__POPUP_IN))return;
+            document.querySelector(__POPUP_IN).classList.add(CLASS_POPUP_OUT);
+            document.querySelector(__POPUP_IN).classList.remove(CLASS_POPUP_IN);
+	        setTimeout(function(){
+                if(!document.querySelector(__POPUP_OUT))return;
+	        	document.querySelector(__POPUP_OUT).style.display = "none";
+	            document.querySelector(__POPUP_OUT).classList.remove(CLASS_POPUP_OUT);
+	            if(document.querySelector(__MASK)){
+					document.querySelector(__MASK).parentNode.removeChild(document.querySelector(__MASK));
+				}
+                popupStatus = false;
+	        }, 300)
+        }
+    };
+	window.auiPopup = auiPopup;
+})(window);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/aui-pull-refresh.js b/platforms/android/app/src/main/assets/www/js/lib/aui-pull-refresh.js
new file mode 100644
index 0000000..8f3bba3
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/aui-pull-refresh.js
@@ -0,0 +1,174 @@
+/**
+ * aui-pull-refresh.js
+ * @author 流浪男
+ * @todo more things to abstract, e.g. Loading css etc.
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+(function(window) {
+	'use strict';
+	/**
+	 * Extend obj function
+	 *
+	 * This is an object extender function. It allows us to extend an object
+	 * by passing in additional variables and overwriting the defaults.
+	 */
+	var auiPullToRefresh = function (params,callback) {
+		this.extend(this.params, params);
+		this._init(callback);
+	}
+	var touchYDelta;
+	var isLoading = false;
+	var docElem = window.document.documentElement,
+		loadWrapH,
+		win = {width: window.innerWidth, height: window.innerHeight},
+		winfactor= 0.2,
+		translateVal,
+		isMoved = false,
+		firstTouchY, initialScroll;
+	auiPullToRefresh.prototype = {
+		params: {
+            container: document.querySelector('.aui-refresh-content'),
+			friction: 2.5,
+			triggerDistance: 100,
+			callback:false
+        },
+        _init : function(callback) {
+			var self = this;
+			var loadingHtml = '<div class="aui-refresh-load"><div class="aui-refresh-pull-arrow"></div></div>';
+			self.params.container.insertAdjacentHTML('afterbegin', loadingHtml);
+			self.params.container.addEventListener('touchstart', function(ev){
+				self.touchStart(ev)
+			});
+			self.params.container.addEventListener('touchmove', function(ev){
+				self.touchMove(ev)
+			});
+			self.params.container.addEventListener('touchend', function(ev){
+				self.touchEnd(ev,callback);
+			});
+		},
+		touchStart : function(ev) {
+			// this.params.container.classList.remove("refreshing");
+			if (isLoading) {
+				return;
+			}
+			isMoved = false;
+			this.params.container.style.webkitTransitionDuration =
+		    this.params.container.style.transitionDuration = '0ms';
+			touchYDelta = '';
+			var touchobj = ev.changedTouches[0];
+			// register first touch "y"
+			firstTouchY = parseInt(touchobj.clientY);
+			initialScroll = this.scrollY();
+		},
+		touchMove : function (ev) {
+			if (isLoading) {
+				ev.preventDefault();
+				return;
+			}
+			var self = this;
+			var moving = function() {
+				var touchobj = ev.changedTouches[0], // reference first touch point for this event
+					touchY = parseInt(touchobj.clientY);
+					touchYDelta = touchY - firstTouchY;
+				if ( self.scrollY() === 0 && touchYDelta > 0  ) {
+					ev.preventDefault();
+				}
+				if ( initialScroll > 0 || self.scrollY() > 0 || self.scrollY() === 0 && touchYDelta < 0 ) {
+					firstTouchY = touchY;
+					return;
+				}
+				translateVal = Math.pow(touchYDelta, 0.85);
+				self.params.container.style.webkitTransform = self.params.container.style.transform = 'translate3d(0, ' + translateVal + 'px, 0)';
+				isMoved = true;
+				if(touchYDelta > self.params.triggerDistance){
+					self.params.container.classList.add("aui-refresh-pull-up");
+					self.params.container.classList.remove("aui-refresh-pull-down");
+				}else{
+					self.params.container.classList.add("aui-refresh-pull-down");
+					self.params.container.classList.remove("aui-refresh-pull-up");
+				}
+			};
+			this.throttle(moving(), 20);
+		},
+		touchEnd : function (ev,callback) {
+			var self =this;
+			if (isLoading|| !isMoved) {
+				isMoved = false;
+				return;
+			}
+			// 根据下拉高度判断是否加载
+			if( touchYDelta >= this.params.triggerDistance) {
+				isLoading = true; //正在加载中
+				ev.preventDefault();
+				this.params.container.style.webkitTransitionDuration =
+		    	this.params.container.style.transitionDuration = '300ms';
+				this.params.container.style.webkitTransform =
+				this.params.container.style.transform = 'translate3d(0,60px,0)';
+				document.querySelector(".aui-refresh-pull-arrow").style.webkitTransitionDuration =
+		    	document.querySelector(".aui-refresh-pull-arrow").style.transitionDuration = '0ms';
+				self.params.container.classList.add("aui-refreshing");
+				if(callback){
+					callback({
+						status:"success"
+					});
+				}
+			}else{
+				this.params.container.style.webkitTransitionDuration =
+		    	this.params.container.style.transitionDuration = '300ms';
+				this.params.container.style.webkitTransform =
+				this.params.container.style.transform = 'translate3d(0,0,0)';
+				if(callback){
+					callback({
+						status:"fail"
+					});
+				}
+			}
+			isMoved = false;
+			return;
+		},
+		cancelLoading : function () {
+			var self =this;
+			isLoading = false;
+			self.params.container.classList.remove("aui-refreshing");
+			document.querySelector(".aui-refresh-pull-arrow").style.webkitTransitionDuration =
+		    	document.querySelector(".aui-refresh-pull-arrow").style.transitionDuration = '300ms';
+			this.params.container.style.webkitTransitionDuration =
+		    	this.params.container.style.transitionDuration = '0ms';
+			self.params.container.style.webkitTransform =
+			self.params.container.style.transform = 'translate3d(0,0,0)';
+			self.params.container.classList.remove("aui-refresh-pull-up");
+			self.params.container.classList.add("aui-refresh-pull-down");
+			return;
+		},
+		scrollY : function() {
+			return window.pageYOffset || docElem.scrollTop;
+		},
+		throttle : function(fn, delay) {
+			var allowSample = true;
+			return function(e) {
+				if (allowSample) {
+					allowSample = false;
+					setTimeout(function() { allowSample = true; }, delay);
+					fn(e);
+				}
+			};
+		},
+		winresize : function () {
+			var resize = function() {
+				win = {width: window.innerWidth, height: window.innerHeight};
+			};
+			throttle(resize(), 10);
+		},
+		extend: function(a, b) {
+			for (var key in b) {
+			  	if (b.hasOwnProperty(key)) {
+			  		a[key] = b[key];
+			  	}
+		  	}
+		  	return a;
+		 }
+	}
+	window.auiPullToRefresh = auiPullToRefresh;
+
+})(window);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/aui-range.js b/platforms/android/app/src/main/assets/www/js/lib/aui-range.js
new file mode 100644
index 0000000..ed42002
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/aui-range.js
@@ -0,0 +1,53 @@
+/*

+ * AUI JAVASCRIPT PLUGIN

+ * 滑动 aui-range

+ * Copyright (c) 2015 auicss.com @流浪男  QQ:343757327  群:344869952

+ */

+ (function( window, undefined ) {

+    "use strict";

+    var auiRange = function(params,callback) {

+        this._init(params,callback);

+    };

+    var time=null;

+    var distance,offsetLeft,tooltipWidth;

+    auiRange.prototype = {

+        _init: function(params,callback) {

+            var self = this;

+            distance = Math.abs(params.element.max - params.element.min);

+            offsetLeft = params.element.offsetLeft;

+            tooltipWidth = params.element.offsetWidth - 28;

+            params.element.insertAdjacentHTML('afterend','<div class="aui-range-tip aui-hide">'+params.element.value+'</div>');

+            var scaleWidth = (tooltipWidth / distance) * Math.abs(params.element.value - params.element.min);

+            params.element.nextSibling.style.left = (offsetLeft + scaleWidth - 11)+'px';

+            params.element.addEventListener("input",function(){

+                self._showTip(params.element,callback);

+            });

+            params.element.addEventListener("touchmove",function(){

+                self._showTip(params.element,callback);

+            });

+            params.element.addEventListener("touchend",function(){

+                self._hideTip(params.element);

+            });

+        },

+        _showTip: function(el,callback){

+            el.nextSibling.classList.remove("aui-hide");

+            var scaleWidth = (tooltipWidth / distance) * Math.abs(el.value - el.min);

+            el.nextSibling.style.left = (offsetLeft + scaleWidth - 11)+'px';

+            el.nextSibling.innerText = el.value;

+            callback({

+                value:el.value

+            });

+        },

+        _hideTip : function(el){

+            if (time) {

+                clearTimeout(time);

+            }

+            time = setTimeout(function() {

+                el.nextSibling.classList.add("aui-hide");

+            }, 1500);

+        }

+    }

+    window.auiRange = auiRange;

+})(window);

+

+

diff --git a/platforms/android/app/src/main/assets/www/js/lib/aui-scroll.js b/platforms/android/app/src/main/assets/www/js/lib/aui-scroll.js
new file mode 100644
index 0000000..88cd0c6
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/aui-scroll.js
@@ -0,0 +1,66 @@
+/**
+ * aui-scroll.js
+ * @author  流浪男
+ * @todo more things to abstract, e.g. Loading css etc.
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+(function(window) {
+	'use strict';
+	var isToBottom = false,isMoved = false;
+	var auiScroll = function (params,callback) {
+		this.extend(this.params, params);
+		this._init(params,callback);
+	}
+	auiScroll.prototype = {
+		params: {
+			listren:false,
+            distance: 100
+        },
+		_init : function(params,callback) {
+			var self = this;
+			if(self.params.listen){
+				document.body.addEventListener("touchmove", function(e){
+					self.scroll(callback);
+				});
+				document.body.addEventListener("touchend", function(e){
+					self.scroll(callback);
+				});
+			}
+			window.onscroll = function(){
+				self.scroll(callback);
+			}
+		},
+		scroll : function (callback) {
+			var self = this;
+			var clientHeight = document.documentElement.scrollTop === 0 ? document.body.clientHeight : document.documentElement.clientHeight;
+			var scrollTop = document.documentElement.scrollTop === 0 ? document.body.scrollTop : document.documentElement.scrollTop;
+			var scrollHeight = document.documentElement.scrollTop === 0 ? document.body.scrollHeight : document.documentElement.scrollHeight;
+
+			if (scrollHeight-scrollTop-self.params.distance <= window.innerHeight) {
+	        	isToBottom = true;
+	        	if(isToBottom){
+	        		callback({
+	        			"scrollTop":scrollTop,
+	        			"isToBottom":true
+	        		})
+	        	}
+	        }else{
+	        	isToBottom = false;
+	        	callback({
+        			"scrollTop":scrollTop,
+        			"isToBottom":false
+        		})
+	        }
+		},
+        extend: function(a, b) {
+			for (var key in b) {
+			  	if (b.hasOwnProperty(key)) {
+			  		a[key] = b[key];
+			  	}
+		  	}
+		  	return a;
+		}
+	}
+	window.auiScroll = auiScroll;
+})(window);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/aui-sharebox.js b/platforms/android/app/src/main/assets/www/js/lib/aui-sharebox.js
new file mode 100644
index 0000000..45b1513
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/aui-sharebox.js
@@ -0,0 +1,119 @@
+/**
+ * aui-sharebox.js
+ * @author 流浪男
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+(function( window, undefined ) {
+    "use strict";
+    var auiSharebox = function() {
+    };
+    var isShow = false;
+    auiSharebox.prototype = {
+        init: function(params,callback){
+            this.frameBounces = params.frameBounces;
+            this.col = params.col;
+            this.buttons = params.buttons;
+            this.cancelTitle = params.cancelTitle;
+            this.maskDiv;
+            this.shareBoxDiv;
+            var self = this;
+            self.open(params,callback);
+        },
+        open: function(params,callback) {
+            var shareboxHtml='',buttonsHtml = '';
+        	var self = this;
+            if(self.shareBoxDiv || !self.buttons)return;
+            if(!self.maskDiv){
+                self.maskDiv = document.createElement("div");
+                self.maskDiv.className = "aui-mask";
+                document.body.appendChild(self.maskDiv);
+            }
+            if(!self.col)self.col = 5;
+            self.shareBoxDiv = document.createElement("div");
+            self.shareBoxDiv.className = "aui-sharebox aui-grid";
+            document.body.appendChild(self.shareBoxDiv);
+            if(self.buttons && self.buttons.length){
+                buttonsHtml = '<div class="aui-row aui-row-padded">';
+                for(var i = 0; i < self.buttons.length;i++){
+                    if(self.col == 5){
+                        buttonsHtml += '<div class="aui-col-5 aui-sharebox-btn">';
+                    }else{
+                        buttonsHtml += '<div class="aui-col-xs-'+(12/self.col)+' aui-sharebox-btn">';
+                    }
+                    if(self.buttons[i].image)buttonsHtml += '<img src="'+self.buttons[i].image+'">';
+                    if(self.buttons[i].text)buttonsHtml += '<div class="aui-grid-label">'+self.buttons[i].text+'</div>';
+                    buttonsHtml += '</div>';
+                }
+                buttonsHtml += '</div>';
+            }
+            if(self.cancelTitle){
+                buttonsHtml += '<div class="aui-sharebox-close-btn aui-border-t">'+this.cancelTitle+'</div>';
+            }
+            self.shareBoxDiv.innerHTML = buttonsHtml;
+            var actionsheetHeight = self.shareBoxDiv.offsetHeight;
+            self.maskDiv.classList.add("aui-mask-in");
+            self.shareBoxDiv.style.webkitTransform = self.shareBoxDiv.style.transform = "translate3d(0,0,0)";
+            self.shareBoxDiv.style.opacity = 1;
+            self.shareBoxDiv.addEventListener("touchmove", function(event){
+                event.preventDefault();
+            })
+            self.maskDiv.addEventListener("touchmove", function(event){
+                event.preventDefault();
+            })
+            if(typeof(api) != 'undefined' && typeof(api) == 'object' && self.frameBounces){
+                api.setFrameAttr({
+                    bounces:false
+                });
+            }
+            var shareboxButtons = document.querySelectorAll(".aui-sharebox-btn");
+            if(shareboxButtons && shareboxButtons.length > 0){
+                setTimeout(function(){
+                    self.maskDiv.onclick = function(){self.close();return;};
+                    for(var ii = 0; ii < shareboxButtons.length; ii++){
+                        (function(e){
+                            shareboxButtons[e].onclick = function(){
+                                if(self.buttons[e].value){
+                                    var _value = self.buttons[e].value;
+                                }else{
+                                    var _value = null;
+                                }
+                                if(callback){
+                                    callback({
+                                        buttonIndex: e+1,
+                                        buttonValue:_value
+                                    });
+                                };
+                                self.close();
+                                return;
+                            }
+                        })(ii)
+                    }
+                }, 350)
+
+            }
+            document.querySelector(".aui-sharebox-close-btn").onclick = function(){self.close();return;};
+        },
+        close: function(){
+            var self = this;
+            if(typeof(api) != 'undefined' && typeof(api) == 'object' && self.frameBounces){
+                api.setFrameAttr({
+                    bounces:true
+                });
+            }
+            if(self.shareBoxDiv){
+                var actionsheetHeight = self.shareBoxDiv.offsetHeight;
+                self.shareBoxDiv.style.webkitTransform = self.shareBoxDiv.style.transform = "translate3d(0,"+actionsheetHeight+"px,0)";
+                self.maskDiv.style.opacity = 0;
+                setTimeout(function(){
+                    if(self.maskDiv){
+                        self.maskDiv.parentNode.removeChild(self.maskDiv);
+                    }
+                    self.shareBoxDiv.parentNode.removeChild(self.shareBoxDiv);
+                    self.maskDiv = self.shareBoxDiv = false;
+                }, 300)
+            }
+        }
+    };
+	window.auiSharebox = auiSharebox;
+})(window);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/aui-skin.js b/platforms/android/app/src/main/assets/www/js/lib/aui-skin.js
new file mode 100644
index 0000000..1bf6039
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/aui-skin.js
@@ -0,0 +1,89 @@
+/**
+ * aui-skin.js
+ * @author 流浪男
+ * @todo more things to abstract, e.g. Loading css etc.
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+(function( window, undefined ) {
+    "use strict";
+    var auiSkin = function(params) {
+    	this.extend(this.params, params);
+        this._init();
+    };
+    var fileRef;
+    auiSkin.prototype = {
+        params: {
+            name: "", //主题名字
+            skinPath:  "",//主题路径
+            default:   false, //默认是否立即使用
+            beginTime: "",//开始时间
+            endTime:   ""//结束时间
+        },
+        _init: function() {
+        	var self = this;
+            if(!self.params.name)return;
+        	if(!self.params.skinPath)return;
+            fileRef = document.createElement('link');
+            fileRef.setAttribute("rel","stylesheet");
+            fileRef.setAttribute("type","text/css");
+            fileRef.setAttribute("aui-skin-name",self.params.name);
+            fileRef.setAttribute("href",self.params.skinPath);
+            if(self.params.default){
+                document.getElementsByTagName("head")[0].appendChild(fileRef);
+            }else{
+                if(!self.params.beginTime || !self.params.endTime)return;
+                if(!self.check(self.params.beginTime,self.params.endTime))return;
+                var _date = new Date();
+                if(_date.getMinutes() < 10){
+                    var nowM = "0"+_date.getMinutes();
+                }else{
+                    var nowM = _date.getMinutes();
+                }
+                var nowTime = _date.getHours()+":"+nowM;
+                var b = parseInt(self.params.beginTime.replace(":", ''));
+                var e = parseInt(self.params.endTime.replace(":", ''));
+                var n = parseInt(nowTime.replace(":", ''));
+                if(b > e){
+                    if(n >= b || n <= e)self.setSkin();
+                }else if(b < e){
+                    if(n >= b && n <= e)self.setSkin();
+                }else{
+                    self.removeSkin();
+                }
+            }
+        },
+        setSkin:function(){
+            document.getElementsByTagName("head")[0].appendChild(fileRef);
+        },
+        removeSkin:function(){
+            var self = this;
+            if(document.querySelector("link[aui-skin-name='"+self.params.name+"']"))
+            document.querySelector("link[aui-skin-name='"+self.params.name+"']").parentNode.removeChild(document.querySelector("link[aui-skin-name='"+self.params.name+"']"));
+        },
+        check:function(beginTime,endTime){
+            var strb = beginTime.split (":");
+            if (strb.length != 2)return false;
+            var stre = endTime.split (":");
+            if (stre.length != 2)return false;
+            var b = new Date ();
+            var e = new Date ();
+            b.setHours (strb[0]);
+            b.setMinutes (strb[1]);
+            e.setHours (stre[0]);
+            e.setMinutes (stre[1]);
+            if(strb[0] > 24 || strb[0] < 0 || stre[0] > 24 || stre[0] < 0)return false;
+            if(strb[1] > 59 || strb[1] < 0 || stre[1] > 59 || stre[1] < 0)return false;
+            return true;
+        },
+        extend: function(a, b) {
+			for (var key in b) {
+			  	if (b.hasOwnProperty(key)) {
+			  		a[key] = b[key];
+			  	}
+		  	}
+		  	return a;
+		}
+    };
+	window.auiSkin = auiSkin;
+})(window);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/aui-slide.js b/platforms/android/app/src/main/assets/www/js/lib/aui-slide.js
new file mode 100644
index 0000000..2f44157
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/aui-slide.js
@@ -0,0 +1,333 @@
+/**
+ * aui-slide.js 轮播组件
+ * @author 流浪男
+ * http://www.auicss.com
+ * @todo more things to abstract, e.g. Loading css etc.
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+(function(window) {
+	"use strict";
+
+	var translateVal,
+		firstTouchX,
+		firstTouchY,
+		touchXDelta,
+		handleTranslateVal;
+	var touchStartTime; //开始触摸事件
+	var offsetX,
+		offsetY,
+		isScrolling;
+	// CLASS 组装
+	var	CLASS_SLIDER_NODE = "aui-slide-node",
+		CLASS_SLIDE_PAGE_WRAP = "aui-slide-page-wrap",
+		CLASS_SLIDE_PAGE = "aui-slide-page",
+		CLASS_SLIDE_PAGE_ACTIVE = "aui-slide-page-active",
+		CLASS_SLIDE_PAGE_DOT = "aui-slide-page-dot",
+		CLASS_SLIDE_PAGE_LINE = "aui-slide-page-line";
+
+	var __SLIDER_NODE = "."+CLASS_SLIDER_NODE,
+		__SLIDE_PAGE_WRAP = "."+CLASS_SLIDE_PAGE_WRAP,
+		__SLIDE_PAGE = "."+CLASS_SLIDE_PAGE,
+		__SLIDE_PAGE_ACTIVE = "."+CLASS_SLIDE_PAGE_ACTIVE;
+
+	auiSlide.prototype.options = {
+		container:'',
+		width:'auto',
+		height:'auto',
+		speed: 300, //滑动速速
+		autoPlay: 0, //自动播放
+		pageShow: true, //是否显示分页器
+		pageStyle: 'dot',
+		dotPosition: 'center',
+		friction:1, //阻力
+		loop:true,
+		currentPage:false,
+		PageCount:false
+	};
+	auiSlide.prototype._init = function(options) {
+		extend(this.options, options);
+		if(!this.options.container){
+			return;
+		}
+		this.index = 0; //索引值
+		this.continuous = true;//用于判断长度为2时的特殊处理
+		this.container = this.options.container;
+		// console.log(this.options.loop);
+		this.loop = this.options.loop;
+		this.speed = this.options.speed;
+		this.container.style.position = "relative";
+		this.container.style.width = this.options.width+"px";
+		this.container.style.height = this.options.height+"px";
+
+		var element = this.container.children[0];
+		this.slideWrap = element;
+		this.slideNodeList = this.slideWrap.querySelectorAll(__SLIDER_NODE);
+		if(!element || !this.slideNodeList){
+			return;
+		}
+		// this.options.pageCount(this.slideNodeList.length);
+		this.slideWrapWidth = this.slideWrap.offsetWidth;
+		this.slideNodeListLength = this.slideNodeList.length;
+
+		if (this.slideNodeListLength == 2) { //当长度为2时作特殊处理
+			element.appendChild(this.slideWrap.children[0].cloneNode(true));
+			element.appendChild(this.slideWrap.children[1].cloneNode(true));
+			this.slideWrap = element;
+			this.slideNodeList = this.slideWrap.querySelectorAll(__SLIDER_NODE);
+	    	this.slideNodeListLength = this.slideNodeList.length;
+	    	this.continuous = false;
+	    }
+		for (var i = 0; i < this.slideNodeListLength; i++) {
+			this.slideNodeList[i] && (this.slideNodeList[i].style.webkitTransform = this.slideNodeList[i].style.transform = "translate3d("+(this.slideWrapWidth*i)+"px,0,0)");
+		}
+
+		if(this.slideNodeListLength > 1) {
+			if(this.options.pageShow){
+				this.createPagination(0);
+				this.setPageDotPosition();
+			}
+			if(this.options.autoPlay > 500 && this.loop){
+				this.autoPlay(0);
+			}
+			this.slideWrap.addEventListener('touchstart', this.touchStart.bind(this), false);
+			this.slideWrap.addEventListener('touchmove', this.touchMove.bind(this), false);
+			this.slideWrap.addEventListener('touchend', this.touchEnd.bind(this), false);
+		}
+	};
+	// 当分页器为圆点时位置设置
+	auiSlide.prototype.setPageDotPosition = function(){
+		var self = this;
+		var pageDotPosition = self.options.dotPosition;
+		this.container.querySelector(__SLIDE_PAGE_WRAP).style.textAlign = pageDotPosition;
+	};
+	// 自动播放
+	auiSlide.prototype.autoPlay = function (index) {
+		var self = this;
+		setInterval(function(){
+			self.slideTo(self.getCircle(self.index-1), -self.slideWrapWidth, 0);
+	        self.slideTo(self.getCircle(self.index+2), self.slideWrapWidth, 0);
+	        self.slideTo(self.index, -self.slideWrapWidth, self.options.speed);
+	        self.slideTo(self.getCircle(self.index+1), 0, self.options.speed);
+	        self.index = self.getCircle(self.index+1);
+	        self.setPaginationActive(self.index);
+		}, self.options.autoPlay)
+	};
+	// 设置当前分页
+	auiSlide.prototype.setPaginationActive = function(index){
+		var self = this;
+		if(self.options.currentPage){
+			self.options.currentPage(index);
+		}
+		if(!this.container.querySelector(__SLIDE_PAGE_WRAP)){
+			return;
+		}
+		var pageList = this.container.querySelectorAll(__SLIDE_PAGE);
+		if(this.container.querySelector(__SLIDE_PAGE+__SLIDE_PAGE_ACTIVE)){
+			this.container.querySelector(__SLIDE_PAGE+__SLIDE_PAGE_ACTIVE).classList.remove(CLASS_SLIDE_PAGE_ACTIVE);
+		}
+		if(!this.continuous){
+			if(this.index == 3){
+				pageList[1].classList.add(CLASS_SLIDE_PAGE_ACTIVE);
+			}else if(this.index==2){
+				pageList[0].classList.add(CLASS_SLIDE_PAGE_ACTIVE);
+			}else{
+				pageList[this.index].classList.add(CLASS_SLIDE_PAGE_ACTIVE);
+			}
+		}else{
+			pageList[this.index].classList.add(CLASS_SLIDE_PAGE_ACTIVE);
+		}
+
+	};
+	// 创建分页器
+	auiSlide.prototype.createPagination = function(index){
+		var self = this;
+		var pageWrap = this.container.querySelector(__SLIDE_PAGE_WRAP);
+		if(!pageWrap){
+			return;
+		}
+		pageWrap.innerHTML = '';
+		var pageShowHtml = '';
+		switch (self.options.pageStyle) {
+			case "dot":// 原点
+						if (!this.continuous) {
+							for (var i = 0; i < 2; i++) {
+								pageShowHtml += '<span class="'+CLASS_SLIDE_PAGE+' '+CLASS_SLIDE_PAGE_DOT+'"></span>';
+							}
+						}else{
+							for (var i = 0; i < this.slideNodeListLength; i++) {
+								pageShowHtml += '<span class="'+CLASS_SLIDE_PAGE+' '+CLASS_SLIDE_PAGE_DOT+'"></span>';
+							}
+						}
+						pageWrap.innerHTML = pageShowHtml;
+						self.setPaginationActive(0);
+				break;
+			case "line":// 线条
+						if (!this.continuous) {
+							for (var i = 0; i < 2; i++) {
+								pageShowHtml += '<span class="'+CLASS_SLIDE_PAGE+' '+CLASS_SLIDE_PAGE_LINE+'" style="width:50%"></span>';
+							}
+						}else{
+							for (var i = 0; i < this.slideNodeListLength; i++) {
+								pageShowHtml += '<span class="'+CLASS_SLIDE_PAGE+' '+CLASS_SLIDE_PAGE_LINE+'" style="width:'+(100/this.slideNodeListLength)+'%"></span>';
+							}
+						}
+						pageWrap.innerHTML = pageShowHtml;
+						self.setPaginationActive(0);
+				break;
+		}
+	};
+	// 总页数
+	auiSlide.prototype.pageCount = function() {
+		var self = this;
+		return self.slideNodeList.length;
+	};
+	auiSlide.prototype.touchStart = function(event) {
+		touchStartTime = new Date() * 1;
+		firstTouchX = parseInt(event.changedTouches[0].pageX);
+		firstTouchY = parseInt(event.changedTouches[0].pageY);
+		isScrolling = undefined;
+	};
+	auiSlide.prototype.touchMove = function(event) {
+		var touchMoveObj = event.changedTouches[0],
+				touchX = parseInt(touchMoveObj.pageX);
+			touchXDelta = touchX - firstTouchX;
+			handleTranslateVal = touchXDelta/this.options.friction;
+		//  滑动位移
+		offsetX = parseInt(touchMoveObj.pageX) - firstTouchX;
+        offsetY = parseInt(touchMoveObj.pageY) - firstTouchY;
+        var direction = this.getDirection(offsetX,offsetY);
+        if ( typeof isScrolling == 'undefined') {
+			isScrolling = !!( isScrolling || Math.abs(offsetX) < Math.abs(offsetY) );
+		}
+		if(!isScrolling){
+			event.preventDefault();
+			if(!this.loop){ //不循环
+				if(!this.continuous && this.index==1 && direction=='left'){
+					return;
+				}
+				if(!this.continuous && this.index==0 && direction=='right'){
+					return;
+				}
+				if(this.index == this.slideNodeList.length-1){
+					if(handleTranslateVal <= 0){
+						return;
+					}
+					this.setTranslate(this.getCircle(this.index-1), handleTranslateVal - this.slideWrapWidth, 0);
+				}else if(this.index == 0){
+					if(handleTranslateVal >= 0){
+						return;
+					}
+					this.setTranslate(this.getCircle(this.index+1), this.slideWrapWidth, 0);
+				}
+			}
+
+			this.setTranslate(this.getCircle(this.index-1), handleTranslateVal - this.slideWrapWidth, 0);
+			this.setTranslate(this.index, handleTranslateVal , 0);
+			this.setTranslate(this.getCircle(this.index+1), handleTranslateVal + this.slideWrapWidth, 0);
+
+		}
+	};
+	auiSlide.prototype.touchEnd = function(event) {
+		var touchEndObj = event.changedTouches[0];
+		var touchEndX = parseInt(touchEndObj.pageX) - firstTouchX;
+        var touchEndY = parseInt(touchEndObj.pageY) - firstTouchY;
+		var touchEndxy = {
+				x: touchEndObj.pageX || 0,
+				y: touchEndObj.pageY || 0
+			};
+		var moveDirection = this.getDirection(touchEndX,touchEndY); //滑动方向
+		var boundary = this.slideWrapWidth/4;
+		var duration = (new Date() * 1) - touchStartTime;
+		var isValid = Number(duration) < 250 && Math.abs(offsetX) > 20 || Math.abs(offsetX) > boundary;
+		if (isScrolling) {
+			return;
+		}
+        if(isValid){
+			if(offsetX < 0){
+				if(!this.loop && this.index == this.slideNodeList.length-1){
+					return;
+				}
+
+				if(!this.loop && !this.continuous && this.index==1){
+					return;
+				}
+
+	        	if(offsetX < -boundary && moveDirection == 'left'){
+	        		// left
+					this.slideTo(this.getCircle(this.index-1), -this.slideWrapWidth, 0);
+		            this.slideTo(this.getCircle(this.index+2), this.slideWrapWidth, 0);
+		            this.slideTo(this.index, -this.slideWrapWidth, this.speed);
+		            this.slideTo(this.getCircle(this.index+1), 0, this.speed);
+		            this.index = this.getCircle(this.index+1);
+				}else{
+					// this.slideTo(this.getCircle(this.index-1), -this.slideWrapWidth, this.speed);
+		            this.slideTo(this.index, 0, this.speed);
+		            this.slideTo(this.getCircle(this.index+1), this.slideWrapWidth, this.speed);
+				}
+	        }else if(offsetX > 0){
+	        	if(!this.loop && this.index == 0){
+					return;
+				}
+				if(!this.loop && !this.continuous && this.index==0){
+					return;
+				}
+	        	if(offsetX > boundary && moveDirection == 'right'){
+	        		// right
+		        	this.slideTo(this.getCircle(this.index+1), this.slideWrapWidth, 0);
+		            this.slideTo(this.getCircle(this.index-2), -this.slideWrapWidth, 0);
+		            this.slideTo(this.index, this.slideWrapWidth, this.speed);
+		            this.slideTo(this.getCircle(this.index-1), 0, this.speed);
+		            this.index = this.getCircle(this.index-1);
+	        	}else{
+	        		// this.slideTo(this.getCircle(this.index-1), -this.slideWrapWidth, this.speed);
+		            this.slideTo(this.index, 0, this.speed);
+		            this.slideTo(this.getCircle(this.index+1), this.slideWrapWidth, this.speed);
+	        	}
+	        }
+        }else{
+        	if(offsetX){
+        		this.slideTo(this.getCircle(this.index-1), -this.slideWrapWidth, this.speed);
+	            this.slideTo(this.index, 0, this.speed);
+	            this.slideTo(this.getCircle(this.index+1), this.slideWrapWidth, this.speed);
+        	}
+
+        }
+        this.setPaginationActive(this.index);
+	};
+	auiSlide.prototype.setTranslate = function (index,dist,speed){
+		if(this.slideNodeList[index]){
+			this.slideNodeList[index].style.webkitTransitionDuration =
+	    	this.slideNodeList[index].style.transitionDuration = speed + 'ms';
+	    	this.slideNodeList[index].style.webkitTransform =
+	    	this.slideNodeList[index].style.transform = "translate3d("+dist+"px,0,0)";
+		}
+	};
+	auiSlide.prototype.slideTo = function (index, dist, speed) {
+		this.setTranslate(index, dist, speed);
+		// index = dist;
+	};
+	auiSlide.prototype.getCircle = function (index) {
+	    return (this.slideNodeListLength + (index % this.slideNodeListLength)) % this.slideNodeListLength;
+	};
+	auiSlide.prototype.getDirection = function(x, y) {
+		if (x === y) { return '';}
+		if (Math.abs(x) >= Math.abs(y)) {
+            return x > 0 ? 'right' : 'left';
+        } else {
+           	return y > 0 ? 'down' : 'up';
+        }
+	}
+	function extend (a, b) {
+		for (var key in b) {
+		  	if (b.hasOwnProperty(key)) {
+		  		a[key] = b[key];
+		  	}
+	  	}
+	  	return a;
+	}
+	function auiSlide (options) {
+		this._init(options);
+	}
+	window.auiSlide = auiSlide;
+})(window);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/aui-tab.js b/platforms/android/app/src/main/assets/www/js/lib/aui-tab.js
new file mode 100644
index 0000000..cb228c4
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/aui-tab.js
@@ -0,0 +1,69 @@
+/**
+ * aui-tab.js
+ * @author 流浪男
+ * @todo more things to abstract, e.g. Loading css etc.
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+(function( window, undefined ) {
+    "use strict";
+    var auiTab = function(params,callback) {
+    	this.extend(this.params, params);
+        this._init(callback);
+    };
+    var tabItems;
+    auiTab.prototype = {
+        params: {
+            element: false,
+            index: 1, //默认选中
+            repeatClick: false //是否允许重复点击
+        },
+        _init: function(callback) {
+        	var self = this;
+        	if(!self.params.element || self.params.element.nodeType!=1){
+        		return;
+        	}
+        	tabItems = self.params.element.children;
+        	if(tabItems){
+        		self.setActive();
+        		for(var i=0; i<tabItems.length; i++){
+        			tabItems[i].setAttribute("tapmode","");
+        			tabItems[i].setAttribute("data-item-order",i);
+        			tabItems[i].onclick = function(e){
+                        if(!self.params.repeatClick){
+                            if(this.className.indexOf("aui-active") > -1)return;
+                        }
+        				if(callback){
+                            callback({
+                                index: parseInt(this.getAttribute("data-item-order"))+1,
+                                dom:this
+                            })
+                        };
+        				this.parentNode.querySelector(".aui-active").classList.remove("aui-active");
+            			this.classList.add("aui-active");
+        			}
+        		}
+        	}
+        },
+        setRepeat:function(value){
+            var self = this;
+            self.params.repeatClick = value ? value : false;
+        },
+        setActive: function(index){
+        	var self = this;
+        	index = index ? index : self.params.index;
+        	var _tab = tabItems[index-1];
+        	if(_tab.parentNode.querySelector(".aui-active"))_tab.parentNode.querySelector(".aui-active").classList.remove("aui-active");
+        	_tab.classList.add("aui-active");
+        },
+        extend: function(a, b) {
+			for (var key in b) {
+			  	if (b.hasOwnProperty(key)) {
+			  		a[key] = b[key];
+			  	}
+		  	}
+		  	return a;
+		}
+    };
+	window.auiTab = auiTab;
+})(window);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/aui-toast.js b/platforms/android/app/src/main/assets/www/js/lib/aui-toast.js
new file mode 100644
index 0000000..68d41f6
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/aui-toast.js
@@ -0,0 +1,92 @@
+/**
+ * aui-popup.js
+ * @author 流浪男
+ * @todo more things to abstract, e.g. Loading css etc.
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+(function( window, undefined ) {
+    "use strict";
+    var auiToast = function() {
+        // this.create();
+    };
+    var isShow = false;
+    auiToast.prototype = {
+        create: function(params,callback) {
+            var self = this;
+            var toastHtml = '';
+            switch (params.type) {
+                case "success":
+                    var iconHtml = '<i class="aui-iconfont aui-icon-correct"></i>';
+                    break;
+                case "fail":
+                    var iconHtml = '<i class="aui-iconfont aui-icon-close"></i>';
+                    break;
+                case "custom":
+                    var iconHtml = params.html;
+                    break;
+                case "loading":
+                    var iconHtml = '<div class="aui-toast-loading"></div>';
+                    break;
+            }
+
+            var titleHtml = params.title ? '<div class="aui-toast-content">'+params.title+'</div>' : '';
+            toastHtml = '<div class="aui-toast">'+iconHtml+titleHtml+'</div>';
+            if(document.querySelector(".aui-toast"))return;
+            document.body.insertAdjacentHTML('beforeend', toastHtml);
+            var duration = params.duration ? params.duration : "2000";
+            self.show();
+            if(params.type == 'loading'){
+                if(callback){
+                    callback({
+                        status: "success"
+                    });
+                };
+            }else{
+                setTimeout(function(){
+                    self.hide();
+                }, duration)
+            }
+        },
+        show: function(){
+            var self = this;
+            document.querySelector(".aui-toast").style.display = "block";
+            document.querySelector(".aui-toast").style.marginTop =  "-"+Math.round(document.querySelector(".aui-toast").offsetHeight/2)+"px";
+            if(document.querySelector(".aui-toast"))return;
+        },
+        hide: function(){
+            var self = this;
+            if(document.querySelector(".aui-toast")){
+                document.querySelector(".aui-toast").parentNode.removeChild(document.querySelector(".aui-toast"));
+            }
+        },
+        remove: function(){
+            if(document.querySelector(".aui-dialog"))document.querySelector(".aui-dialog").parentNode.removeChild(document.querySelector(".aui-dialog"));
+            if(document.querySelector(".aui-mask")){
+                document.querySelector(".aui-mask").classList.remove("aui-mask-out");
+            }
+            return true;
+        },
+        success: function(params,callback){
+            var self = this;
+            params.type = "success";
+            return self.create(params,callback);
+        },
+        fail: function(params,callback){
+            var self = this;
+            params.type = "fail";
+            return self.create(params,callback);
+        },
+        custom:function(params,callback){
+            var self = this;
+            params.type = "custom";
+            return self.create(params,callback);
+        },
+        loading:function(params,callback){
+            var self = this;
+            params.type = "loading";
+            return self.create(params,callback);
+        }
+    };
+    window.auiToast = auiToast;
+})(window);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/city-picker.js b/platforms/android/app/src/main/assets/www/js/lib/city-picker.js
new file mode 100755
index 0000000..129755d
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/city-picker.js
@@ -0,0 +1,16713 @@
+// jshint ignore: start
++function($){
+
+$.rawCitiesData = [
+  {
+    "name":"北京",
+    "code":"110000",
+    "sub": [
+      {
+        "name": "北京市",
+        "code": "110000",
+        "sub":[
+            {
+              "name":"东城区",
+              "code":"110101"
+            },
+            {
+              "name":"西城区",
+              "code":"110102"
+            },
+            {
+              "name":"朝阳区",
+              "code":"110105"
+            },
+            {
+              "name":"丰台区",
+              "code":"110106"
+            },
+            {
+              "name":"石景山区",
+              "code":"110107"
+            },
+            {
+              "name":"海淀区",
+              "code":"110108"
+            },
+            {
+              "name":"门头沟区",
+              "code":"110109"
+            },
+            {
+              "name":"房山区",
+              "code":"110111"
+            },
+            {
+              "name":"通州区",
+              "code":"110112"
+            },
+            {
+              "name":"顺义区",
+              "code":"110113"
+            },
+            {
+              "name":"昌平区",
+              "code":"110114"
+            },
+            {
+              "name":"大兴区",
+              "code":"110115"
+            },
+            {
+              "name":"怀柔区",
+              "code":"110116"
+            },
+            {
+              "name":"平谷区",
+              "code":"110117"
+            },
+            {
+              "name":"密云县",
+              "code":"110228"
+            },
+            {
+              "name":"延庆县",
+              "code":"110229"
+            }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"天津",
+    "code":"120000",
+    "sub": [
+      {
+        "name": "天津市",
+        "code": "120000",
+        "sub":[
+            {
+              "name":"和平区",
+              "code":"120101"
+            },
+            {
+              "name":"河东区",
+              "code":"120102"
+            },
+            {
+              "name":"河西区",
+              "code":"120103"
+            },
+            {
+              "name":"南开区",
+              "code":"120104"
+            },
+            {
+              "name":"河北区",
+              "code":"120105"
+            },
+            {
+              "name":"红桥区",
+              "code":"120106"
+            },
+            {
+              "name":"东丽区",
+              "code":"120110"
+            },
+            {
+              "name":"西青区",
+              "code":"120111"
+            },
+            {
+              "name":"津南区",
+              "code":"120112"
+            },
+            {
+              "name":"北辰区",
+              "code":"120113"
+            },
+            {
+              "name":"武清区",
+              "code":"120114"
+            },
+            {
+              "name":"宝坻区",
+              "code":"120115"
+            },
+            {
+              "name":"滨海新区",
+              "code":"120116"
+            },
+            {
+              "name":"宁河县",
+              "code":"120221"
+            },
+            {
+              "name":"静海县",
+              "code":"120223"
+            },
+            {
+              "name":"蓟县",
+              "code":"120225"
+            }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"河北省",
+    "code":"130000",
+    "sub":[
+      {
+        "name":"石家庄市",
+        "code":"130100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"130101"
+          },
+          {
+            "name":"长安区",
+            "code":"130102"
+          },
+          {
+            "name":"桥西区",
+            "code":"130104"
+          },
+          {
+            "name":"新华区",
+            "code":"130105"
+          },
+          {
+            "name":"井陉矿区",
+            "code":"130107"
+          },
+          {
+            "name":"裕华区",
+            "code":"130108"
+          },
+          {
+            "name":"藁城区",
+            "code":"130109"
+          },
+          {
+            "name":"鹿泉区",
+            "code":"130110"
+          },
+          {
+            "name":"栾城区",
+            "code":"130111"
+          },
+          {
+            "name":"井陉县",
+            "code":"130121"
+          },
+          {
+            "name":"正定县",
+            "code":"130123"
+          },
+          {
+            "name":"行唐县",
+            "code":"130125"
+          },
+          {
+            "name":"灵寿县",
+            "code":"130126"
+          },
+          {
+            "name":"高邑县",
+            "code":"130127"
+          },
+          {
+            "name":"深泽县",
+            "code":"130128"
+          },
+          {
+            "name":"赞皇县",
+            "code":"130129"
+          },
+          {
+            "name":"无极县",
+            "code":"130130"
+          },
+          {
+            "name":"平山县",
+            "code":"130131"
+          },
+          {
+            "name":"元氏县",
+            "code":"130132"
+          },
+          {
+            "name":"赵县",
+            "code":"130133"
+          },
+          {
+            "name":"辛集市",
+            "code":"130181"
+          },
+          {
+            "name":"晋州市",
+            "code":"130183"
+          },
+          {
+            "name":"新乐市",
+            "code":"130184"
+          }
+        ]
+      },
+      {
+        "name":"唐山市",
+        "code":"130200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"130201"
+          },
+          {
+            "name":"路南区",
+            "code":"130202"
+          },
+          {
+            "name":"路北区",
+            "code":"130203"
+          },
+          {
+            "name":"古冶区",
+            "code":"130204"
+          },
+          {
+            "name":"开平区",
+            "code":"130205"
+          },
+          {
+            "name":"丰南区",
+            "code":"130207"
+          },
+          {
+            "name":"丰润区",
+            "code":"130208"
+          },
+          {
+            "name":"曹妃甸区",
+            "code":"130209"
+          },
+          {
+            "name":"滦县",
+            "code":"130223"
+          },
+          {
+            "name":"滦南县",
+            "code":"130224"
+          },
+          {
+            "name":"乐亭县",
+            "code":"130225"
+          },
+          {
+            "name":"迁西县",
+            "code":"130227"
+          },
+          {
+            "name":"玉田县",
+            "code":"130229"
+          },
+          {
+            "name":"遵化市",
+            "code":"130281"
+          },
+          {
+            "name":"迁安市",
+            "code":"130283"
+          }
+        ]
+      },
+      {
+        "name":"秦皇岛市",
+        "code":"130300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"130301"
+          },
+          {
+            "name":"海港区",
+            "code":"130302"
+          },
+          {
+            "name":"山海关区",
+            "code":"130303"
+          },
+          {
+            "name":"北戴河区",
+            "code":"130304"
+          },
+          {
+            "name":"青龙满族自治县",
+            "code":"130321"
+          },
+          {
+            "name":"昌黎县",
+            "code":"130322"
+          },
+          {
+            "name":"抚宁县",
+            "code":"130323"
+          },
+          {
+            "name":"卢龙县",
+            "code":"130324"
+          }
+        ]
+      },
+      {
+        "name":"邯郸市",
+        "code":"130400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"130401"
+          },
+          {
+            "name":"邯山区",
+            "code":"130402"
+          },
+          {
+            "name":"丛台区",
+            "code":"130403"
+          },
+          {
+            "name":"复兴区",
+            "code":"130404"
+          },
+          {
+            "name":"峰峰矿区",
+            "code":"130406"
+          },
+          {
+            "name":"邯郸县",
+            "code":"130421"
+          },
+          {
+            "name":"临漳县",
+            "code":"130423"
+          },
+          {
+            "name":"成安县",
+            "code":"130424"
+          },
+          {
+            "name":"大名县",
+            "code":"130425"
+          },
+          {
+            "name":"涉县",
+            "code":"130426"
+          },
+          {
+            "name":"磁县",
+            "code":"130427"
+          },
+          {
+            "name":"肥乡县",
+            "code":"130428"
+          },
+          {
+            "name":"永年县",
+            "code":"130429"
+          },
+          {
+            "name":"邱县",
+            "code":"130430"
+          },
+          {
+            "name":"鸡泽县",
+            "code":"130431"
+          },
+          {
+            "name":"广平县",
+            "code":"130432"
+          },
+          {
+            "name":"馆陶县",
+            "code":"130433"
+          },
+          {
+            "name":"魏县",
+            "code":"130434"
+          },
+          {
+            "name":"曲周县",
+            "code":"130435"
+          },
+          {
+            "name":"武安市",
+            "code":"130481"
+          }
+        ]
+      },
+      {
+        "name":"邢台市",
+        "code":"130500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"130501"
+          },
+          {
+            "name":"桥东区",
+            "code":"130502"
+          },
+          {
+            "name":"桥西区",
+            "code":"130503"
+          },
+          {
+            "name":"邢台县",
+            "code":"130521"
+          },
+          {
+            "name":"临城县",
+            "code":"130522"
+          },
+          {
+            "name":"内丘县",
+            "code":"130523"
+          },
+          {
+            "name":"柏乡县",
+            "code":"130524"
+          },
+          {
+            "name":"隆尧县",
+            "code":"130525"
+          },
+          {
+            "name":"任县",
+            "code":"130526"
+          },
+          {
+            "name":"南和县",
+            "code":"130527"
+          },
+          {
+            "name":"宁晋县",
+            "code":"130528"
+          },
+          {
+            "name":"巨鹿县",
+            "code":"130529"
+          },
+          {
+            "name":"新河县",
+            "code":"130530"
+          },
+          {
+            "name":"广宗县",
+            "code":"130531"
+          },
+          {
+            "name":"平乡县",
+            "code":"130532"
+          },
+          {
+            "name":"威县",
+            "code":"130533"
+          },
+          {
+            "name":"清河县",
+            "code":"130534"
+          },
+          {
+            "name":"临西县",
+            "code":"130535"
+          },
+          {
+            "name":"南宫市",
+            "code":"130581"
+          },
+          {
+            "name":"沙河市",
+            "code":"130582"
+          }
+        ]
+      },
+      {
+        "name":"保定市",
+        "code":"130600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"130601"
+          },
+          {
+            "name":"新市区",
+            "code":"130602"
+          },
+          {
+            "name":"北市区",
+            "code":"130603"
+          },
+          {
+            "name":"南市区",
+            "code":"130604"
+          },
+          {
+            "name":"满城县",
+            "code":"130621"
+          },
+          {
+            "name":"清苑县",
+            "code":"130622"
+          },
+          {
+            "name":"涞水县",
+            "code":"130623"
+          },
+          {
+            "name":"阜平县",
+            "code":"130624"
+          },
+          {
+            "name":"徐水县",
+            "code":"130625"
+          },
+          {
+            "name":"定兴县",
+            "code":"130626"
+          },
+          {
+            "name":"唐县",
+            "code":"130627"
+          },
+          {
+            "name":"高阳县",
+            "code":"130628"
+          },
+          {
+            "name":"容城县",
+            "code":"130629"
+          },
+          {
+            "name":"涞源县",
+            "code":"130630"
+          },
+          {
+            "name":"望都县",
+            "code":"130631"
+          },
+          {
+            "name":"安新县",
+            "code":"130632"
+          },
+          {
+            "name":"易县",
+            "code":"130633"
+          },
+          {
+            "name":"曲阳县",
+            "code":"130634"
+          },
+          {
+            "name":"蠡县",
+            "code":"130635"
+          },
+          {
+            "name":"顺平县",
+            "code":"130636"
+          },
+          {
+            "name":"博野县",
+            "code":"130637"
+          },
+          {
+            "name":"雄县",
+            "code":"130638"
+          },
+          {
+            "name":"涿州市",
+            "code":"130681"
+          },
+          {
+            "name":"定州市",
+            "code":"130682"
+          },
+          {
+            "name":"安国市",
+            "code":"130683"
+          },
+          {
+            "name":"高碑店市",
+            "code":"130684"
+          }
+        ]
+      },
+      {
+        "name":"张家口市",
+        "code":"130700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"130701"
+          },
+          {
+            "name":"桥东区",
+            "code":"130702"
+          },
+          {
+            "name":"桥西区",
+            "code":"130703"
+          },
+          {
+            "name":"宣化区",
+            "code":"130705"
+          },
+          {
+            "name":"下花园区",
+            "code":"130706"
+          },
+          {
+            "name":"宣化县",
+            "code":"130721"
+          },
+          {
+            "name":"张北县",
+            "code":"130722"
+          },
+          {
+            "name":"康保县",
+            "code":"130723"
+          },
+          {
+            "name":"沽源县",
+            "code":"130724"
+          },
+          {
+            "name":"尚义县",
+            "code":"130725"
+          },
+          {
+            "name":"蔚县",
+            "code":"130726"
+          },
+          {
+            "name":"阳原县",
+            "code":"130727"
+          },
+          {
+            "name":"怀安县",
+            "code":"130728"
+          },
+          {
+            "name":"万全县",
+            "code":"130729"
+          },
+          {
+            "name":"怀来县",
+            "code":"130730"
+          },
+          {
+            "name":"涿鹿县",
+            "code":"130731"
+          },
+          {
+            "name":"赤城县",
+            "code":"130732"
+          },
+          {
+            "name":"崇礼县",
+            "code":"130733"
+          }
+        ]
+      },
+      {
+        "name":"承德市",
+        "code":"130800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"130801"
+          },
+          {
+            "name":"双桥区",
+            "code":"130802"
+          },
+          {
+            "name":"双滦区",
+            "code":"130803"
+          },
+          {
+            "name":"鹰手营子矿区",
+            "code":"130804"
+          },
+          {
+            "name":"承德县",
+            "code":"130821"
+          },
+          {
+            "name":"兴隆县",
+            "code":"130822"
+          },
+          {
+            "name":"平泉县",
+            "code":"130823"
+          },
+          {
+            "name":"滦平县",
+            "code":"130824"
+          },
+          {
+            "name":"隆化县",
+            "code":"130825"
+          },
+          {
+            "name":"丰宁满族自治县",
+            "code":"130826"
+          },
+          {
+            "name":"宽城满族自治县",
+            "code":"130827"
+          },
+          {
+            "name":"围场满族蒙古族自治县",
+            "code":"130828"
+          }
+        ]
+      },
+      {
+        "name":"沧州市",
+        "code":"130900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"130901"
+          },
+          {
+            "name":"新华区",
+            "code":"130902"
+          },
+          {
+            "name":"运河区",
+            "code":"130903"
+          },
+          {
+            "name":"沧县",
+            "code":"130921"
+          },
+          {
+            "name":"青县",
+            "code":"130922"
+          },
+          {
+            "name":"东光县",
+            "code":"130923"
+          },
+          {
+            "name":"海兴县",
+            "code":"130924"
+          },
+          {
+            "name":"盐山县",
+            "code":"130925"
+          },
+          {
+            "name":"肃宁县",
+            "code":"130926"
+          },
+          {
+            "name":"南皮县",
+            "code":"130927"
+          },
+          {
+            "name":"吴桥县",
+            "code":"130928"
+          },
+          {
+            "name":"献县",
+            "code":"130929"
+          },
+          {
+            "name":"孟村回族自治县",
+            "code":"130930"
+          },
+          {
+            "name":"泊头市",
+            "code":"130981"
+          },
+          {
+            "name":"任丘市",
+            "code":"130982"
+          },
+          {
+            "name":"黄骅市",
+            "code":"130983"
+          },
+          {
+            "name":"河间市",
+            "code":"130984"
+          }
+        ]
+      },
+      {
+        "name":"廊坊市",
+        "code":"131000",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"131001"
+          },
+          {
+            "name":"安次区",
+            "code":"131002"
+          },
+          {
+            "name":"广阳区",
+            "code":"131003"
+          },
+          {
+            "name":"固安县",
+            "code":"131022"
+          },
+          {
+            "name":"永清县",
+            "code":"131023"
+          },
+          {
+            "name":"香河县",
+            "code":"131024"
+          },
+          {
+            "name":"大城县",
+            "code":"131025"
+          },
+          {
+            "name":"文安县",
+            "code":"131026"
+          },
+          {
+            "name":"大厂回族自治县",
+            "code":"131028"
+          },
+          {
+            "name":"霸州市",
+            "code":"131081"
+          },
+          {
+            "name":"三河市",
+            "code":"131082"
+          }
+        ]
+      },
+      {
+        "name":"衡水市",
+        "code":"131100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"131101"
+          },
+          {
+            "name":"桃城区",
+            "code":"131102"
+          },
+          {
+            "name":"枣强县",
+            "code":"131121"
+          },
+          {
+            "name":"武邑县",
+            "code":"131122"
+          },
+          {
+            "name":"武强县",
+            "code":"131123"
+          },
+          {
+            "name":"饶阳县",
+            "code":"131124"
+          },
+          {
+            "name":"安平县",
+            "code":"131125"
+          },
+          {
+            "name":"故城县",
+            "code":"131126"
+          },
+          {
+            "name":"景县",
+            "code":"131127"
+          },
+          {
+            "name":"阜城县",
+            "code":"131128"
+          },
+          {
+            "name":"冀州市",
+            "code":"131181"
+          },
+          {
+            "name":"深州市",
+            "code":"131182"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"山西省",
+    "code":"140000",
+    "sub":[
+      {
+        "name":"太原市",
+        "code":"140100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"140101"
+          },
+          {
+            "name":"小店区",
+            "code":"140105"
+          },
+          {
+            "name":"迎泽区",
+            "code":"140106"
+          },
+          {
+            "name":"杏花岭区",
+            "code":"140107"
+          },
+          {
+            "name":"尖草坪区",
+            "code":"140108"
+          },
+          {
+            "name":"万柏林区",
+            "code":"140109"
+          },
+          {
+            "name":"晋源区",
+            "code":"140110"
+          },
+          {
+            "name":"清徐县",
+            "code":"140121"
+          },
+          {
+            "name":"阳曲县",
+            "code":"140122"
+          },
+          {
+            "name":"娄烦县",
+            "code":"140123"
+          },
+          {
+            "name":"古交市",
+            "code":"140181"
+          }
+        ]
+      },
+      {
+        "name":"大同市",
+        "code":"140200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"140201"
+          },
+          {
+            "name":"城区",
+            "code":"140202"
+          },
+          {
+            "name":"矿区",
+            "code":"140203"
+          },
+          {
+            "name":"南郊区",
+            "code":"140211"
+          },
+          {
+            "name":"新荣区",
+            "code":"140212"
+          },
+          {
+            "name":"阳高县",
+            "code":"140221"
+          },
+          {
+            "name":"天镇县",
+            "code":"140222"
+          },
+          {
+            "name":"广灵县",
+            "code":"140223"
+          },
+          {
+            "name":"灵丘县",
+            "code":"140224"
+          },
+          {
+            "name":"浑源县",
+            "code":"140225"
+          },
+          {
+            "name":"左云县",
+            "code":"140226"
+          },
+          {
+            "name":"大同县",
+            "code":"140227"
+          }
+        ]
+      },
+      {
+        "name":"阳泉市",
+        "code":"140300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"140301"
+          },
+          {
+            "name":"城区",
+            "code":"140302"
+          },
+          {
+            "name":"矿区",
+            "code":"140303"
+          },
+          {
+            "name":"郊区",
+            "code":"140311"
+          },
+          {
+            "name":"平定县",
+            "code":"140321"
+          },
+          {
+            "name":"盂县",
+            "code":"140322"
+          }
+        ]
+      },
+      {
+        "name":"长治市",
+        "code":"140400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"140401"
+          },
+          {
+            "name":"城区",
+            "code":"140402"
+          },
+          {
+            "name":"郊区",
+            "code":"140411"
+          },
+          {
+            "name":"长治县",
+            "code":"140421"
+          },
+          {
+            "name":"襄垣县",
+            "code":"140423"
+          },
+          {
+            "name":"屯留县",
+            "code":"140424"
+          },
+          {
+            "name":"平顺县",
+            "code":"140425"
+          },
+          {
+            "name":"黎城县",
+            "code":"140426"
+          },
+          {
+            "name":"壶关县",
+            "code":"140427"
+          },
+          {
+            "name":"长子县",
+            "code":"140428"
+          },
+          {
+            "name":"武乡县",
+            "code":"140429"
+          },
+          {
+            "name":"沁县",
+            "code":"140430"
+          },
+          {
+            "name":"沁源县",
+            "code":"140431"
+          },
+          {
+            "name":"潞城市",
+            "code":"140481"
+          }
+        ]
+      },
+      {
+        "name":"晋城市",
+        "code":"140500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"140501"
+          },
+          {
+            "name":"城区",
+            "code":"140502"
+          },
+          {
+            "name":"沁水县",
+            "code":"140521"
+          },
+          {
+            "name":"阳城县",
+            "code":"140522"
+          },
+          {
+            "name":"陵川县",
+            "code":"140524"
+          },
+          {
+            "name":"泽州县",
+            "code":"140525"
+          },
+          {
+            "name":"高平市",
+            "code":"140581"
+          }
+        ]
+      },
+      {
+        "name":"朔州市",
+        "code":"140600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"140601"
+          },
+          {
+            "name":"朔城区",
+            "code":"140602"
+          },
+          {
+            "name":"平鲁区",
+            "code":"140603"
+          },
+          {
+            "name":"山阴县",
+            "code":"140621"
+          },
+          {
+            "name":"应县",
+            "code":"140622"
+          },
+          {
+            "name":"右玉县",
+            "code":"140623"
+          },
+          {
+            "name":"怀仁县",
+            "code":"140624"
+          }
+        ]
+      },
+      {
+        "name":"晋中市",
+        "code":"140700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"140701"
+          },
+          {
+            "name":"榆次区",
+            "code":"140702"
+          },
+          {
+            "name":"榆社县",
+            "code":"140721"
+          },
+          {
+            "name":"左权县",
+            "code":"140722"
+          },
+          {
+            "name":"和顺县",
+            "code":"140723"
+          },
+          {
+            "name":"昔阳县",
+            "code":"140724"
+          },
+          {
+            "name":"寿阳县",
+            "code":"140725"
+          },
+          {
+            "name":"太谷县",
+            "code":"140726"
+          },
+          {
+            "name":"祁县",
+            "code":"140727"
+          },
+          {
+            "name":"平遥县",
+            "code":"140728"
+          },
+          {
+            "name":"灵石县",
+            "code":"140729"
+          },
+          {
+            "name":"介休市",
+            "code":"140781"
+          }
+        ]
+      },
+      {
+        "name":"运城市",
+        "code":"140800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"140801"
+          },
+          {
+            "name":"盐湖区",
+            "code":"140802"
+          },
+          {
+            "name":"临猗县",
+            "code":"140821"
+          },
+          {
+            "name":"万荣县",
+            "code":"140822"
+          },
+          {
+            "name":"闻喜县",
+            "code":"140823"
+          },
+          {
+            "name":"稷山县",
+            "code":"140824"
+          },
+          {
+            "name":"新绛县",
+            "code":"140825"
+          },
+          {
+            "name":"绛县",
+            "code":"140826"
+          },
+          {
+            "name":"垣曲县",
+            "code":"140827"
+          },
+          {
+            "name":"夏县",
+            "code":"140828"
+          },
+          {
+            "name":"平陆县",
+            "code":"140829"
+          },
+          {
+            "name":"芮城县",
+            "code":"140830"
+          },
+          {
+            "name":"永济市",
+            "code":"140881"
+          },
+          {
+            "name":"河津市",
+            "code":"140882"
+          }
+        ]
+      },
+      {
+        "name":"忻州市",
+        "code":"140900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"140901"
+          },
+          {
+            "name":"忻府区",
+            "code":"140902"
+          },
+          {
+            "name":"定襄县",
+            "code":"140921"
+          },
+          {
+            "name":"五台县",
+            "code":"140922"
+          },
+          {
+            "name":"代县",
+            "code":"140923"
+          },
+          {
+            "name":"繁峙县",
+            "code":"140924"
+          },
+          {
+            "name":"宁武县",
+            "code":"140925"
+          },
+          {
+            "name":"静乐县",
+            "code":"140926"
+          },
+          {
+            "name":"神池县",
+            "code":"140927"
+          },
+          {
+            "name":"五寨县",
+            "code":"140928"
+          },
+          {
+            "name":"岢岚县",
+            "code":"140929"
+          },
+          {
+            "name":"河曲县",
+            "code":"140930"
+          },
+          {
+            "name":"保德县",
+            "code":"140931"
+          },
+          {
+            "name":"偏关县",
+            "code":"140932"
+          },
+          {
+            "name":"原平市",
+            "code":"140981"
+          }
+        ]
+      },
+      {
+        "name":"临汾市",
+        "code":"141000",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"141001"
+          },
+          {
+            "name":"尧都区",
+            "code":"141002"
+          },
+          {
+            "name":"曲沃县",
+            "code":"141021"
+          },
+          {
+            "name":"翼城县",
+            "code":"141022"
+          },
+          {
+            "name":"襄汾县",
+            "code":"141023"
+          },
+          {
+            "name":"洪洞县",
+            "code":"141024"
+          },
+          {
+            "name":"古县",
+            "code":"141025"
+          },
+          {
+            "name":"安泽县",
+            "code":"141026"
+          },
+          {
+            "name":"浮山县",
+            "code":"141027"
+          },
+          {
+            "name":"吉县",
+            "code":"141028"
+          },
+          {
+            "name":"乡宁县",
+            "code":"141029"
+          },
+          {
+            "name":"大宁县",
+            "code":"141030"
+          },
+          {
+            "name":"隰县",
+            "code":"141031"
+          },
+          {
+            "name":"永和县",
+            "code":"141032"
+          },
+          {
+            "name":"蒲县",
+            "code":"141033"
+          },
+          {
+            "name":"汾西县",
+            "code":"141034"
+          },
+          {
+            "name":"侯马市",
+            "code":"141081"
+          },
+          {
+            "name":"霍州市",
+            "code":"141082"
+          }
+        ]
+      },
+      {
+        "name":"吕梁市",
+        "code":"141100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"141101"
+          },
+          {
+            "name":"离石区",
+            "code":"141102"
+          },
+          {
+            "name":"文水县",
+            "code":"141121"
+          },
+          {
+            "name":"交城县",
+            "code":"141122"
+          },
+          {
+            "name":"兴县",
+            "code":"141123"
+          },
+          {
+            "name":"临县",
+            "code":"141124"
+          },
+          {
+            "name":"柳林县",
+            "code":"141125"
+          },
+          {
+            "name":"石楼县",
+            "code":"141126"
+          },
+          {
+            "name":"岚县",
+            "code":"141127"
+          },
+          {
+            "name":"方山县",
+            "code":"141128"
+          },
+          {
+            "name":"中阳县",
+            "code":"141129"
+          },
+          {
+            "name":"交口县",
+            "code":"141130"
+          },
+          {
+            "name":"孝义市",
+            "code":"141181"
+          },
+          {
+            "name":"汾阳市",
+            "code":"141182"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"内蒙古自治区",
+    "code":"150000",
+    "sub":[
+      {
+        "name":"呼和浩特市",
+        "code":"150100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"150101"
+          },
+          {
+            "name":"新城区",
+            "code":"150102"
+          },
+          {
+            "name":"回民区",
+            "code":"150103"
+          },
+          {
+            "name":"玉泉区",
+            "code":"150104"
+          },
+          {
+            "name":"赛罕区",
+            "code":"150105"
+          },
+          {
+            "name":"土默特左旗",
+            "code":"150121"
+          },
+          {
+            "name":"托克托县",
+            "code":"150122"
+          },
+          {
+            "name":"和林格尔县",
+            "code":"150123"
+          },
+          {
+            "name":"清水河县",
+            "code":"150124"
+          },
+          {
+            "name":"武川县",
+            "code":"150125"
+          }
+        ]
+      },
+      {
+        "name":"包头市",
+        "code":"150200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"150201"
+          },
+          {
+            "name":"东河区",
+            "code":"150202"
+          },
+          {
+            "name":"昆都仑区",
+            "code":"150203"
+          },
+          {
+            "name":"青山区",
+            "code":"150204"
+          },
+          {
+            "name":"石拐区",
+            "code":"150205"
+          },
+          {
+            "name":"白云鄂博矿区",
+            "code":"150206"
+          },
+          {
+            "name":"九原区",
+            "code":"150207"
+          },
+          {
+            "name":"土默特右旗",
+            "code":"150221"
+          },
+          {
+            "name":"固阳县",
+            "code":"150222"
+          },
+          {
+            "name":"达尔罕茂明安联合旗",
+            "code":"150223"
+          }
+        ]
+      },
+      {
+        "name":"乌海市",
+        "code":"150300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"150301"
+          },
+          {
+            "name":"海勃湾区",
+            "code":"150302"
+          },
+          {
+            "name":"海南区",
+            "code":"150303"
+          },
+          {
+            "name":"乌达区",
+            "code":"150304"
+          }
+        ]
+      },
+      {
+        "name":"赤峰市",
+        "code":"150400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"150401"
+          },
+          {
+            "name":"红山区",
+            "code":"150402"
+          },
+          {
+            "name":"元宝山区",
+            "code":"150403"
+          },
+          {
+            "name":"松山区",
+            "code":"150404"
+          },
+          {
+            "name":"阿鲁科尔沁旗",
+            "code":"150421"
+          },
+          {
+            "name":"巴林左旗",
+            "code":"150422"
+          },
+          {
+            "name":"巴林右旗",
+            "code":"150423"
+          },
+          {
+            "name":"林西县",
+            "code":"150424"
+          },
+          {
+            "name":"克什克腾旗",
+            "code":"150425"
+          },
+          {
+            "name":"翁牛特旗",
+            "code":"150426"
+          },
+          {
+            "name":"喀喇沁旗",
+            "code":"150428"
+          },
+          {
+            "name":"宁城县",
+            "code":"150429"
+          },
+          {
+            "name":"敖汉旗",
+            "code":"150430"
+          }
+        ]
+      },
+      {
+        "name":"通辽市",
+        "code":"150500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"150501"
+          },
+          {
+            "name":"科尔沁区",
+            "code":"150502"
+          },
+          {
+            "name":"科尔沁左翼中旗",
+            "code":"150521"
+          },
+          {
+            "name":"科尔沁左翼后旗",
+            "code":"150522"
+          },
+          {
+            "name":"开鲁县",
+            "code":"150523"
+          },
+          {
+            "name":"库伦旗",
+            "code":"150524"
+          },
+          {
+            "name":"奈曼旗",
+            "code":"150525"
+          },
+          {
+            "name":"扎鲁特旗",
+            "code":"150526"
+          },
+          {
+            "name":"霍林郭勒市",
+            "code":"150581"
+          }
+        ]
+      },
+      {
+        "name":"鄂尔多斯市",
+        "code":"150600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"150601"
+          },
+          {
+            "name":"东胜区",
+            "code":"150602"
+          },
+          {
+            "name":"达拉特旗",
+            "code":"150621"
+          },
+          {
+            "name":"准格尔旗",
+            "code":"150622"
+          },
+          {
+            "name":"鄂托克前旗",
+            "code":"150623"
+          },
+          {
+            "name":"鄂托克旗",
+            "code":"150624"
+          },
+          {
+            "name":"杭锦旗",
+            "code":"150625"
+          },
+          {
+            "name":"乌审旗",
+            "code":"150626"
+          },
+          {
+            "name":"伊金霍洛旗",
+            "code":"150627"
+          }
+        ]
+      },
+      {
+        "name":"呼伦贝尔市",
+        "code":"150700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"150701"
+          },
+          {
+            "name":"海拉尔区",
+            "code":"150702"
+          },
+          {
+            "name":"扎赉诺尔区",
+            "code":"150703"
+          },
+          {
+            "name":"阿荣旗",
+            "code":"150721"
+          },
+          {
+            "name":"莫力达瓦达斡尔族自治旗",
+            "code":"150722"
+          },
+          {
+            "name":"鄂伦春自治旗",
+            "code":"150723"
+          },
+          {
+            "name":"鄂温克族自治旗",
+            "code":"150724"
+          },
+          {
+            "name":"陈巴尔虎旗",
+            "code":"150725"
+          },
+          {
+            "name":"新巴尔虎左旗",
+            "code":"150726"
+          },
+          {
+            "name":"新巴尔虎右旗",
+            "code":"150727"
+          },
+          {
+            "name":"满洲里市",
+            "code":"150781"
+          },
+          {
+            "name":"牙克石市",
+            "code":"150782"
+          },
+          {
+            "name":"扎兰屯市",
+            "code":"150783"
+          },
+          {
+            "name":"额尔古纳市",
+            "code":"150784"
+          },
+          {
+            "name":"根河市",
+            "code":"150785"
+          }
+        ]
+      },
+      {
+        "name":"巴彦淖尔市",
+        "code":"150800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"150801"
+          },
+          {
+            "name":"临河区",
+            "code":"150802"
+          },
+          {
+            "name":"五原县",
+            "code":"150821"
+          },
+          {
+            "name":"磴口县",
+            "code":"150822"
+          },
+          {
+            "name":"乌拉特前旗",
+            "code":"150823"
+          },
+          {
+            "name":"乌拉特中旗",
+            "code":"150824"
+          },
+          {
+            "name":"乌拉特后旗",
+            "code":"150825"
+          },
+          {
+            "name":"杭锦后旗",
+            "code":"150826"
+          }
+        ]
+      },
+      {
+        "name":"乌兰察布市",
+        "code":"150900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"150901"
+          },
+          {
+            "name":"集宁区",
+            "code":"150902"
+          },
+          {
+            "name":"卓资县",
+            "code":"150921"
+          },
+          {
+            "name":"化德县",
+            "code":"150922"
+          },
+          {
+            "name":"商都县",
+            "code":"150923"
+          },
+          {
+            "name":"兴和县",
+            "code":"150924"
+          },
+          {
+            "name":"凉城县",
+            "code":"150925"
+          },
+          {
+            "name":"察哈尔右翼前旗",
+            "code":"150926"
+          },
+          {
+            "name":"察哈尔右翼中旗",
+            "code":"150927"
+          },
+          {
+            "name":"察哈尔右翼后旗",
+            "code":"150928"
+          },
+          {
+            "name":"四子王旗",
+            "code":"150929"
+          },
+          {
+            "name":"丰镇市",
+            "code":"150981"
+          }
+        ]
+      },
+      {
+        "name":"兴安盟",
+        "code":"152200",
+        "sub":[
+          {
+            "name":"乌兰浩特市",
+            "code":"152201"
+          },
+          {
+            "name":"阿尔山市",
+            "code":"152202"
+          },
+          {
+            "name":"科尔沁右翼前旗",
+            "code":"152221"
+          },
+          {
+            "name":"科尔沁右翼中旗",
+            "code":"152222"
+          },
+          {
+            "name":"扎赉特旗",
+            "code":"152223"
+          },
+          {
+            "name":"突泉县",
+            "code":"152224"
+          }
+        ]
+      },
+      {
+        "name":"锡林郭勒盟",
+        "code":"152500",
+        "sub":[
+          {
+            "name":"二连浩特市",
+            "code":"152501"
+          },
+          {
+            "name":"锡林浩特市",
+            "code":"152502"
+          },
+          {
+            "name":"阿巴嘎旗",
+            "code":"152522"
+          },
+          {
+            "name":"苏尼特左旗",
+            "code":"152523"
+          },
+          {
+            "name":"苏尼特右旗",
+            "code":"152524"
+          },
+          {
+            "name":"东乌珠穆沁旗",
+            "code":"152525"
+          },
+          {
+            "name":"西乌珠穆沁旗",
+            "code":"152526"
+          },
+          {
+            "name":"太仆寺旗",
+            "code":"152527"
+          },
+          {
+            "name":"镶黄旗",
+            "code":"152528"
+          },
+          {
+            "name":"正镶白旗",
+            "code":"152529"
+          },
+          {
+            "name":"正蓝旗",
+            "code":"152530"
+          },
+          {
+            "name":"多伦县",
+            "code":"152531"
+          }
+        ]
+      },
+      {
+        "name":"阿拉善盟",
+        "code":"152900",
+        "sub":[
+          {
+            "name":"阿拉善左旗",
+            "code":"152921"
+          },
+          {
+            "name":"阿拉善右旗",
+            "code":"152922"
+          },
+          {
+            "name":"额济纳旗",
+            "code":"152923"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"辽宁省",
+    "code":"210000",
+    "sub":[
+      {
+        "name":"沈阳市",
+        "code":"210100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"210101"
+          },
+          {
+            "name":"和平区",
+            "code":"210102"
+          },
+          {
+            "name":"沈河区",
+            "code":"210103"
+          },
+          {
+            "name":"大东区",
+            "code":"210104"
+          },
+          {
+            "name":"皇姑区",
+            "code":"210105"
+          },
+          {
+            "name":"铁西区",
+            "code":"210106"
+          },
+          {
+            "name":"苏家屯区",
+            "code":"210111"
+          },
+          {
+            "name":"浑南区",
+            "code":"210112"
+          },
+          {
+            "name":"沈北新区",
+            "code":"210113"
+          },
+          {
+            "name":"于洪区",
+            "code":"210114"
+          },
+          {
+            "name":"辽中县",
+            "code":"210122"
+          },
+          {
+            "name":"康平县",
+            "code":"210123"
+          },
+          {
+            "name":"法库县",
+            "code":"210124"
+          },
+          {
+            "name":"新民市",
+            "code":"210181"
+          }
+        ]
+      },
+      {
+        "name":"大连市",
+        "code":"210200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"210201"
+          },
+          {
+            "name":"中山区",
+            "code":"210202"
+          },
+          {
+            "name":"西岗区",
+            "code":"210203"
+          },
+          {
+            "name":"沙河口区",
+            "code":"210204"
+          },
+          {
+            "name":"甘井子区",
+            "code":"210211"
+          },
+          {
+            "name":"旅顺口区",
+            "code":"210212"
+          },
+          {
+            "name":"金州区",
+            "code":"210213"
+          },
+          {
+            "name":"长海县",
+            "code":"210224"
+          },
+          {
+            "name":"瓦房店市",
+            "code":"210281"
+          },
+          {
+            "name":"普兰店市",
+            "code":"210282"
+          },
+          {
+            "name":"庄河市",
+            "code":"210283"
+          }
+        ]
+      },
+      {
+        "name":"鞍山市",
+        "code":"210300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"210301"
+          },
+          {
+            "name":"铁东区",
+            "code":"210302"
+          },
+          {
+            "name":"铁西区",
+            "code":"210303"
+          },
+          {
+            "name":"立山区",
+            "code":"210304"
+          },
+          {
+            "name":"千山区",
+            "code":"210311"
+          },
+          {
+            "name":"台安县",
+            "code":"210321"
+          },
+          {
+            "name":"岫岩满族自治县",
+            "code":"210323"
+          },
+          {
+            "name":"海城市",
+            "code":"210381"
+          }
+        ]
+      },
+      {
+        "name":"抚顺市",
+        "code":"210400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"210401"
+          },
+          {
+            "name":"新抚区",
+            "code":"210402"
+          },
+          {
+            "name":"东洲区",
+            "code":"210403"
+          },
+          {
+            "name":"望花区",
+            "code":"210404"
+          },
+          {
+            "name":"顺城区",
+            "code":"210411"
+          },
+          {
+            "name":"抚顺县",
+            "code":"210421"
+          },
+          {
+            "name":"新宾满族自治县",
+            "code":"210422"
+          },
+          {
+            "name":"清原满族自治县",
+            "code":"210423"
+          }
+        ]
+      },
+      {
+        "name":"本溪市",
+        "code":"210500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"210501"
+          },
+          {
+            "name":"平山区",
+            "code":"210502"
+          },
+          {
+            "name":"溪湖区",
+            "code":"210503"
+          },
+          {
+            "name":"明山区",
+            "code":"210504"
+          },
+          {
+            "name":"南芬区",
+            "code":"210505"
+          },
+          {
+            "name":"本溪满族自治县",
+            "code":"210521"
+          },
+          {
+            "name":"桓仁满族自治县",
+            "code":"210522"
+          }
+        ]
+      },
+      {
+        "name":"丹东市",
+        "code":"210600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"210601"
+          },
+          {
+            "name":"元宝区",
+            "code":"210602"
+          },
+          {
+            "name":"振兴区",
+            "code":"210603"
+          },
+          {
+            "name":"振安区",
+            "code":"210604"
+          },
+          {
+            "name":"宽甸满族自治县",
+            "code":"210624"
+          },
+          {
+            "name":"东港市",
+            "code":"210681"
+          },
+          {
+            "name":"凤城市",
+            "code":"210682"
+          }
+        ]
+      },
+      {
+        "name":"锦州市",
+        "code":"210700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"210701"
+          },
+          {
+            "name":"古塔区",
+            "code":"210702"
+          },
+          {
+            "name":"凌河区",
+            "code":"210703"
+          },
+          {
+            "name":"太和区",
+            "code":"210711"
+          },
+          {
+            "name":"黑山县",
+            "code":"210726"
+          },
+          {
+            "name":"义县",
+            "code":"210727"
+          },
+          {
+            "name":"凌海市",
+            "code":"210781"
+          },
+          {
+            "name":"北镇市",
+            "code":"210782"
+          }
+        ]
+      },
+      {
+        "name":"营口市",
+        "code":"210800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"210801"
+          },
+          {
+            "name":"站前区",
+            "code":"210802"
+          },
+          {
+            "name":"西市区",
+            "code":"210803"
+          },
+          {
+            "name":"鲅鱼圈区",
+            "code":"210804"
+          },
+          {
+            "name":"老边区",
+            "code":"210811"
+          },
+          {
+            "name":"盖州市",
+            "code":"210881"
+          },
+          {
+            "name":"大石桥市",
+            "code":"210882"
+          }
+        ]
+      },
+      {
+        "name":"阜新市",
+        "code":"210900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"210901"
+          },
+          {
+            "name":"海州区",
+            "code":"210902"
+          },
+          {
+            "name":"新邱区",
+            "code":"210903"
+          },
+          {
+            "name":"太平区",
+            "code":"210904"
+          },
+          {
+            "name":"清河门区",
+            "code":"210905"
+          },
+          {
+            "name":"细河区",
+            "code":"210911"
+          },
+          {
+            "name":"阜新蒙古族自治县",
+            "code":"210921"
+          },
+          {
+            "name":"彰武县",
+            "code":"210922"
+          }
+        ]
+      },
+      {
+        "name":"辽阳市",
+        "code":"211000",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"211001"
+          },
+          {
+            "name":"白塔区",
+            "code":"211002"
+          },
+          {
+            "name":"文圣区",
+            "code":"211003"
+          },
+          {
+            "name":"宏伟区",
+            "code":"211004"
+          },
+          {
+            "name":"弓长岭区",
+            "code":"211005"
+          },
+          {
+            "name":"太子河区",
+            "code":"211011"
+          },
+          {
+            "name":"辽阳县",
+            "code":"211021"
+          },
+          {
+            "name":"灯塔市",
+            "code":"211081"
+          }
+        ]
+      },
+      {
+        "name":"盘锦市",
+        "code":"211100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"211101"
+          },
+          {
+            "name":"双台子区",
+            "code":"211102"
+          },
+          {
+            "name":"兴隆台区",
+            "code":"211103"
+          },
+          {
+            "name":"大洼县",
+            "code":"211121"
+          },
+          {
+            "name":"盘山县",
+            "code":"211122"
+          }
+        ]
+      },
+      {
+        "name":"铁岭市",
+        "code":"211200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"211201"
+          },
+          {
+            "name":"银州区",
+            "code":"211202"
+          },
+          {
+            "name":"清河区",
+            "code":"211204"
+          },
+          {
+            "name":"铁岭县",
+            "code":"211221"
+          },
+          {
+            "name":"西丰县",
+            "code":"211223"
+          },
+          {
+            "name":"昌图县",
+            "code":"211224"
+          },
+          {
+            "name":"调兵山市",
+            "code":"211281"
+          },
+          {
+            "name":"开原市",
+            "code":"211282"
+          }
+        ]
+      },
+      {
+        "name":"朝阳市",
+        "code":"211300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"211301"
+          },
+          {
+            "name":"双塔区",
+            "code":"211302"
+          },
+          {
+            "name":"龙城区",
+            "code":"211303"
+          },
+          {
+            "name":"朝阳县",
+            "code":"211321"
+          },
+          {
+            "name":"建平县",
+            "code":"211322"
+          },
+          {
+            "name":"喀喇沁左翼蒙古族自治县",
+            "code":"211324"
+          },
+          {
+            "name":"北票市",
+            "code":"211381"
+          },
+          {
+            "name":"凌源市",
+            "code":"211382"
+          }
+        ]
+      },
+      {
+        "name":"葫芦岛市",
+        "code":"211400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"211401"
+          },
+          {
+            "name":"连山区",
+            "code":"211402"
+          },
+          {
+            "name":"龙港区",
+            "code":"211403"
+          },
+          {
+            "name":"南票区",
+            "code":"211404"
+          },
+          {
+            "name":"绥中县",
+            "code":"211421"
+          },
+          {
+            "name":"建昌县",
+            "code":"211422"
+          },
+          {
+            "name":"兴城市",
+            "code":"211481"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"吉林省",
+    "code":"220000",
+    "sub":[
+      {
+        "name":"长春市",
+        "code":"220100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"220101"
+          },
+          {
+            "name":"南关区",
+            "code":"220102"
+          },
+          {
+            "name":"宽城区",
+            "code":"220103"
+          },
+          {
+            "name":"朝阳区",
+            "code":"220104"
+          },
+          {
+            "name":"二道区",
+            "code":"220105"
+          },
+          {
+            "name":"绿园区",
+            "code":"220106"
+          },
+          {
+            "name":"双阳区",
+            "code":"220112"
+          },
+          {
+            "name":"九台区",
+            "code":"220113"
+          },
+          {
+            "name":"农安县",
+            "code":"220122"
+          },
+          {
+            "name":"榆树市",
+            "code":"220182"
+          },
+          {
+            "name":"德惠市",
+            "code":"220183"
+          }
+        ]
+      },
+      {
+        "name":"吉林市",
+        "code":"220200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"220201"
+          },
+          {
+            "name":"昌邑区",
+            "code":"220202"
+          },
+          {
+            "name":"龙潭区",
+            "code":"220203"
+          },
+          {
+            "name":"船营区",
+            "code":"220204"
+          },
+          {
+            "name":"丰满区",
+            "code":"220211"
+          },
+          {
+            "name":"永吉县",
+            "code":"220221"
+          },
+          {
+            "name":"蛟河市",
+            "code":"220281"
+          },
+          {
+            "name":"桦甸市",
+            "code":"220282"
+          },
+          {
+            "name":"舒兰市",
+            "code":"220283"
+          },
+          {
+            "name":"磐石市",
+            "code":"220284"
+          }
+        ]
+      },
+      {
+        "name":"四平市",
+        "code":"220300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"220301"
+          },
+          {
+            "name":"铁西区",
+            "code":"220302"
+          },
+          {
+            "name":"铁东区",
+            "code":"220303"
+          },
+          {
+            "name":"梨树县",
+            "code":"220322"
+          },
+          {
+            "name":"伊通满族自治县",
+            "code":"220323"
+          },
+          {
+            "name":"公主岭市",
+            "code":"220381"
+          },
+          {
+            "name":"双辽市",
+            "code":"220382"
+          }
+        ]
+      },
+      {
+        "name":"辽源市",
+        "code":"220400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"220401"
+          },
+          {
+            "name":"龙山区",
+            "code":"220402"
+          },
+          {
+            "name":"西安区",
+            "code":"220403"
+          },
+          {
+            "name":"东丰县",
+            "code":"220421"
+          },
+          {
+            "name":"东辽县",
+            "code":"220422"
+          }
+        ]
+      },
+      {
+        "name":"通化市",
+        "code":"220500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"220501"
+          },
+          {
+            "name":"东昌区",
+            "code":"220502"
+          },
+          {
+            "name":"二道江区",
+            "code":"220503"
+          },
+          {
+            "name":"通化县",
+            "code":"220521"
+          },
+          {
+            "name":"辉南县",
+            "code":"220523"
+          },
+          {
+            "name":"柳河县",
+            "code":"220524"
+          },
+          {
+            "name":"梅河口市",
+            "code":"220581"
+          },
+          {
+            "name":"集安市",
+            "code":"220582"
+          }
+        ]
+      },
+      {
+        "name":"白山市",
+        "code":"220600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"220601"
+          },
+          {
+            "name":"浑江区",
+            "code":"220602"
+          },
+          {
+            "name":"江源区",
+            "code":"220605"
+          },
+          {
+            "name":"抚松县",
+            "code":"220621"
+          },
+          {
+            "name":"靖宇县",
+            "code":"220622"
+          },
+          {
+            "name":"长白朝鲜族自治县",
+            "code":"220623"
+          },
+          {
+            "name":"临江市",
+            "code":"220681"
+          }
+        ]
+      },
+      {
+        "name":"松原市",
+        "code":"220700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"220701"
+          },
+          {
+            "name":"宁江区",
+            "code":"220702"
+          },
+          {
+            "name":"前郭尔罗斯蒙古族自治县",
+            "code":"220721"
+          },
+          {
+            "name":"长岭县",
+            "code":"220722"
+          },
+          {
+            "name":"乾安县",
+            "code":"220723"
+          },
+          {
+            "name":"扶余市",
+            "code":"220781"
+          }
+        ]
+      },
+      {
+        "name":"白城市",
+        "code":"220800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"220801"
+          },
+          {
+            "name":"洮北区",
+            "code":"220802"
+          },
+          {
+            "name":"镇赉县",
+            "code":"220821"
+          },
+          {
+            "name":"通榆县",
+            "code":"220822"
+          },
+          {
+            "name":"洮南市",
+            "code":"220881"
+          },
+          {
+            "name":"大安市",
+            "code":"220882"
+          }
+        ]
+      },
+      {
+        "name":"延边朝鲜族自治州",
+        "code":"222400",
+        "sub":[
+          {
+            "name":"延吉市",
+            "code":"222401"
+          },
+          {
+            "name":"图们市",
+            "code":"222402"
+          },
+          {
+            "name":"敦化市",
+            "code":"222403"
+          },
+          {
+            "name":"珲春市",
+            "code":"222404"
+          },
+          {
+            "name":"龙井市",
+            "code":"222405"
+          },
+          {
+            "name":"和龙市",
+            "code":"222406"
+          },
+          {
+            "name":"汪清县",
+            "code":"222424"
+          },
+          {
+            "name":"安图县",
+            "code":"222426"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"黑龙江省",
+    "code":"230000",
+    "sub":[
+      {
+        "name":"哈尔滨市",
+        "code":"230100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"230101"
+          },
+          {
+            "name":"道里区",
+            "code":"230102"
+          },
+          {
+            "name":"南岗区",
+            "code":"230103"
+          },
+          {
+            "name":"道外区",
+            "code":"230104"
+          },
+          {
+            "name":"平房区",
+            "code":"230108"
+          },
+          {
+            "name":"松北区",
+            "code":"230109"
+          },
+          {
+            "name":"香坊区",
+            "code":"230110"
+          },
+          {
+            "name":"呼兰区",
+            "code":"230111"
+          },
+          {
+            "name":"阿城区",
+            "code":"230112"
+          },
+          {
+            "name":"双城区",
+            "code":"230113"
+          },
+          {
+            "name":"依兰县",
+            "code":"230123"
+          },
+          {
+            "name":"方正县",
+            "code":"230124"
+          },
+          {
+            "name":"宾县",
+            "code":"230125"
+          },
+          {
+            "name":"巴彦县",
+            "code":"230126"
+          },
+          {
+            "name":"木兰县",
+            "code":"230127"
+          },
+          {
+            "name":"通河县",
+            "code":"230128"
+          },
+          {
+            "name":"延寿县",
+            "code":"230129"
+          },
+          {
+            "name":"尚志市",
+            "code":"230183"
+          },
+          {
+            "name":"五常市",
+            "code":"230184"
+          }
+        ]
+      },
+      {
+        "name":"齐齐哈尔市",
+        "code":"230200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"230201"
+          },
+          {
+            "name":"龙沙区",
+            "code":"230202"
+          },
+          {
+            "name":"建华区",
+            "code":"230203"
+          },
+          {
+            "name":"铁锋区",
+            "code":"230204"
+          },
+          {
+            "name":"昂昂溪区",
+            "code":"230205"
+          },
+          {
+            "name":"富拉尔基区",
+            "code":"230206"
+          },
+          {
+            "name":"碾子山区",
+            "code":"230207"
+          },
+          {
+            "name":"梅里斯达斡尔族区",
+            "code":"230208"
+          },
+          {
+            "name":"龙江县",
+            "code":"230221"
+          },
+          {
+            "name":"依安县",
+            "code":"230223"
+          },
+          {
+            "name":"泰来县",
+            "code":"230224"
+          },
+          {
+            "name":"甘南县",
+            "code":"230225"
+          },
+          {
+            "name":"富裕县",
+            "code":"230227"
+          },
+          {
+            "name":"克山县",
+            "code":"230229"
+          },
+          {
+            "name":"克东县",
+            "code":"230230"
+          },
+          {
+            "name":"拜泉县",
+            "code":"230231"
+          },
+          {
+            "name":"讷河市",
+            "code":"230281"
+          }
+        ]
+      },
+      {
+        "name":"鸡西市",
+        "code":"230300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"230301"
+          },
+          {
+            "name":"鸡冠区",
+            "code":"230302"
+          },
+          {
+            "name":"恒山区",
+            "code":"230303"
+          },
+          {
+            "name":"滴道区",
+            "code":"230304"
+          },
+          {
+            "name":"梨树区",
+            "code":"230305"
+          },
+          {
+            "name":"城子河区",
+            "code":"230306"
+          },
+          {
+            "name":"麻山区",
+            "code":"230307"
+          },
+          {
+            "name":"鸡东县",
+            "code":"230321"
+          },
+          {
+            "name":"虎林市",
+            "code":"230381"
+          },
+          {
+            "name":"密山市",
+            "code":"230382"
+          }
+        ]
+      },
+      {
+        "name":"鹤岗市",
+        "code":"230400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"230401"
+          },
+          {
+            "name":"向阳区",
+            "code":"230402"
+          },
+          {
+            "name":"工农区",
+            "code":"230403"
+          },
+          {
+            "name":"南山区",
+            "code":"230404"
+          },
+          {
+            "name":"兴安区",
+            "code":"230405"
+          },
+          {
+            "name":"东山区",
+            "code":"230406"
+          },
+          {
+            "name":"兴山区",
+            "code":"230407"
+          },
+          {
+            "name":"萝北县",
+            "code":"230421"
+          },
+          {
+            "name":"绥滨县",
+            "code":"230422"
+          }
+        ]
+      },
+      {
+        "name":"双鸭山市",
+        "code":"230500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"230501"
+          },
+          {
+            "name":"尖山区",
+            "code":"230502"
+          },
+          {
+            "name":"岭东区",
+            "code":"230503"
+          },
+          {
+            "name":"四方台区",
+            "code":"230505"
+          },
+          {
+            "name":"宝山区",
+            "code":"230506"
+          },
+          {
+            "name":"集贤县",
+            "code":"230521"
+          },
+          {
+            "name":"友谊县",
+            "code":"230522"
+          },
+          {
+            "name":"宝清县",
+            "code":"230523"
+          },
+          {
+            "name":"饶河县",
+            "code":"230524"
+          }
+        ]
+      },
+      {
+        "name":"大庆市",
+        "code":"230600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"230601"
+          },
+          {
+            "name":"萨尔图区",
+            "code":"230602"
+          },
+          {
+            "name":"龙凤区",
+            "code":"230603"
+          },
+          {
+            "name":"让胡路区",
+            "code":"230604"
+          },
+          {
+            "name":"红岗区",
+            "code":"230605"
+          },
+          {
+            "name":"大同区",
+            "code":"230606"
+          },
+          {
+            "name":"肇州县",
+            "code":"230621"
+          },
+          {
+            "name":"肇源县",
+            "code":"230622"
+          },
+          {
+            "name":"林甸县",
+            "code":"230623"
+          },
+          {
+            "name":"杜尔伯特蒙古族自治县",
+            "code":"230624"
+          }
+        ]
+      },
+      {
+        "name":"伊春市",
+        "code":"230700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"230701"
+          },
+          {
+            "name":"伊春区",
+            "code":"230702"
+          },
+          {
+            "name":"南岔区",
+            "code":"230703"
+          },
+          {
+            "name":"友好区",
+            "code":"230704"
+          },
+          {
+            "name":"西林区",
+            "code":"230705"
+          },
+          {
+            "name":"翠峦区",
+            "code":"230706"
+          },
+          {
+            "name":"新青区",
+            "code":"230707"
+          },
+          {
+            "name":"美溪区",
+            "code":"230708"
+          },
+          {
+            "name":"金山屯区",
+            "code":"230709"
+          },
+          {
+            "name":"五营区",
+            "code":"230710"
+          },
+          {
+            "name":"乌马河区",
+            "code":"230711"
+          },
+          {
+            "name":"汤旺河区",
+            "code":"230712"
+          },
+          {
+            "name":"带岭区",
+            "code":"230713"
+          },
+          {
+            "name":"乌伊岭区",
+            "code":"230714"
+          },
+          {
+            "name":"红星区",
+            "code":"230715"
+          },
+          {
+            "name":"上甘岭区",
+            "code":"230716"
+          },
+          {
+            "name":"嘉荫县",
+            "code":"230722"
+          },
+          {
+            "name":"铁力市",
+            "code":"230781"
+          }
+        ]
+      },
+      {
+        "name":"佳木斯市",
+        "code":"230800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"230801"
+          },
+          {
+            "name":"向阳区",
+            "code":"230803"
+          },
+          {
+            "name":"前进区",
+            "code":"230804"
+          },
+          {
+            "name":"东风区",
+            "code":"230805"
+          },
+          {
+            "name":"郊区",
+            "code":"230811"
+          },
+          {
+            "name":"桦南县",
+            "code":"230822"
+          },
+          {
+            "name":"桦川县",
+            "code":"230826"
+          },
+          {
+            "name":"汤原县",
+            "code":"230828"
+          },
+          {
+            "name":"抚远县",
+            "code":"230833"
+          },
+          {
+            "name":"同江市",
+            "code":"230881"
+          },
+          {
+            "name":"富锦市",
+            "code":"230882"
+          }
+        ]
+      },
+      {
+        "name":"七台河市",
+        "code":"230900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"230901"
+          },
+          {
+            "name":"新兴区",
+            "code":"230902"
+          },
+          {
+            "name":"桃山区",
+            "code":"230903"
+          },
+          {
+            "name":"茄子河区",
+            "code":"230904"
+          },
+          {
+            "name":"勃利县",
+            "code":"230921"
+          }
+        ]
+      },
+      {
+        "name":"牡丹江市",
+        "code":"231000",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"231001"
+          },
+          {
+            "name":"东安区",
+            "code":"231002"
+          },
+          {
+            "name":"阳明区",
+            "code":"231003"
+          },
+          {
+            "name":"爱民区",
+            "code":"231004"
+          },
+          {
+            "name":"西安区",
+            "code":"231005"
+          },
+          {
+            "name":"东宁县",
+            "code":"231024"
+          },
+          {
+            "name":"林口县",
+            "code":"231025"
+          },
+          {
+            "name":"绥芬河市",
+            "code":"231081"
+          },
+          {
+            "name":"海林市",
+            "code":"231083"
+          },
+          {
+            "name":"宁安市",
+            "code":"231084"
+          },
+          {
+            "name":"穆棱市",
+            "code":"231085"
+          }
+        ]
+      },
+      {
+        "name":"黑河市",
+        "code":"231100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"231101"
+          },
+          {
+            "name":"爱辉区",
+            "code":"231102"
+          },
+          {
+            "name":"嫩江县",
+            "code":"231121"
+          },
+          {
+            "name":"逊克县",
+            "code":"231123"
+          },
+          {
+            "name":"孙吴县",
+            "code":"231124"
+          },
+          {
+            "name":"北安市",
+            "code":"231181"
+          },
+          {
+            "name":"五大连池市",
+            "code":"231182"
+          }
+        ]
+      },
+      {
+        "name":"绥化市",
+        "code":"231200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"231201"
+          },
+          {
+            "name":"北林区",
+            "code":"231202"
+          },
+          {
+            "name":"望奎县",
+            "code":"231221"
+          },
+          {
+            "name":"兰西县",
+            "code":"231222"
+          },
+          {
+            "name":"青冈县",
+            "code":"231223"
+          },
+          {
+            "name":"庆安县",
+            "code":"231224"
+          },
+          {
+            "name":"明水县",
+            "code":"231225"
+          },
+          {
+            "name":"绥棱县",
+            "code":"231226"
+          },
+          {
+            "name":"安达市",
+            "code":"231281"
+          },
+          {
+            "name":"肇东市",
+            "code":"231282"
+          },
+          {
+            "name":"海伦市",
+            "code":"231283"
+          }
+        ]
+      },
+      {
+        "name":"大兴安岭地区",
+        "code":"232700",
+        "sub":[
+          {
+            "name":"呼玛县",
+            "code":"232721"
+          },
+          {
+            "name":"塔河县",
+            "code":"232722"
+          },
+          {
+            "name":"漠河县",
+            "code":"232723"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"上海",
+    "code":"310000",
+    "sub": [
+      {
+        "name":"上海市",
+        "code": "310000",
+        "sub":[
+            {
+              "name":"黄浦区",
+              "code":"310101"
+            },
+            {
+              "name":"徐汇区",
+              "code":"310104"
+            },
+            {
+              "name":"长宁区",
+              "code":"310105"
+            },
+            {
+              "name":"静安区",
+              "code":"310106"
+            },
+            {
+              "name":"普陀区",
+              "code":"310107"
+            },
+            {
+              "name":"闸北区",
+              "code":"310108"
+            },
+            {
+              "name":"虹口区",
+              "code":"310109"
+            },
+            {
+              "name":"杨浦区",
+              "code":"310110"
+            },
+            {
+              "name":"闵行区",
+              "code":"310112"
+            },
+            {
+              "name":"宝山区",
+              "code":"310113"
+            },
+            {
+              "name":"嘉定区",
+              "code":"310114"
+            },
+            {
+              "name":"浦东新区",
+              "code":"310115"
+            },
+            {
+              "name":"金山区",
+              "code":"310116"
+            },
+            {
+              "name":"松江区",
+              "code":"310117"
+            },
+            {
+              "name":"青浦区",
+              "code":"310118"
+            },
+            {
+              "name":"奉贤区",
+              "code":"310120"
+            },
+            {
+              "name":"崇明县",
+              "code":"310230"
+            }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"江苏省",
+    "code":"320000",
+    "sub":[
+      {
+        "name":"南京市",
+        "code":"320100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"320101"
+          },
+          {
+            "name":"玄武区",
+            "code":"320102"
+          },
+          {
+            "name":"秦淮区",
+            "code":"320104"
+          },
+          {
+            "name":"建邺区",
+            "code":"320105"
+          },
+          {
+            "name":"鼓楼区",
+            "code":"320106"
+          },
+          {
+            "name":"浦口区",
+            "code":"320111"
+          },
+          {
+            "name":"栖霞区",
+            "code":"320113"
+          },
+          {
+            "name":"雨花台区",
+            "code":"320114"
+          },
+          {
+            "name":"江宁区",
+            "code":"320115"
+          },
+          {
+            "name":"六合区",
+            "code":"320116"
+          },
+          {
+            "name":"溧水区",
+            "code":"320117"
+          },
+          {
+            "name":"高淳区",
+            "code":"320118"
+          }
+        ]
+      },
+      {
+        "name":"无锡市",
+        "code":"320200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"320201"
+          },
+          {
+            "name":"崇安区",
+            "code":"320202"
+          },
+          {
+            "name":"南长区",
+            "code":"320203"
+          },
+          {
+            "name":"北塘区",
+            "code":"320204"
+          },
+          {
+            "name":"锡山区",
+            "code":"320205"
+          },
+          {
+            "name":"惠山区",
+            "code":"320206"
+          },
+          {
+            "name":"滨湖区",
+            "code":"320211"
+          },
+          {
+            "name":"江阴市",
+            "code":"320281"
+          },
+          {
+            "name":"宜兴市",
+            "code":"320282"
+          }
+        ]
+      },
+      {
+        "name":"徐州市",
+        "code":"320300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"320301"
+          },
+          {
+            "name":"鼓楼区",
+            "code":"320302"
+          },
+          {
+            "name":"云龙区",
+            "code":"320303"
+          },
+          {
+            "name":"贾汪区",
+            "code":"320305"
+          },
+          {
+            "name":"泉山区",
+            "code":"320311"
+          },
+          {
+            "name":"铜山区",
+            "code":"320312"
+          },
+          {
+            "name":"丰县",
+            "code":"320321"
+          },
+          {
+            "name":"沛县",
+            "code":"320322"
+          },
+          {
+            "name":"睢宁县",
+            "code":"320324"
+          },
+          {
+            "name":"新沂市",
+            "code":"320381"
+          },
+          {
+            "name":"邳州市",
+            "code":"320382"
+          }
+        ]
+      },
+      {
+        "name":"常州市",
+        "code":"320400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"320401"
+          },
+          {
+            "name":"天宁区",
+            "code":"320402"
+          },
+          {
+            "name":"钟楼区",
+            "code":"320404"
+          },
+          {
+            "name":"戚墅堰区",
+            "code":"320405"
+          },
+          {
+            "name":"新北区",
+            "code":"320411"
+          },
+          {
+            "name":"武进区",
+            "code":"320412"
+          },
+          {
+            "name":"溧阳市",
+            "code":"320481"
+          },
+          {
+            "name":"金坛市",
+            "code":"320482"
+          }
+        ]
+      },
+      {
+        "name":"苏州市",
+        "code":"320500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"320501"
+          },
+          {
+            "name":"虎丘区",
+            "code":"320505"
+          },
+          {
+            "name":"吴中区",
+            "code":"320506"
+          },
+          {
+            "name":"相城区",
+            "code":"320507"
+          },
+          {
+            "name":"姑苏区",
+            "code":"320508"
+          },
+          {
+            "name":"吴江区",
+            "code":"320509"
+          },
+          {
+            "name":"常熟市",
+            "code":"320581"
+          },
+          {
+            "name":"张家港市",
+            "code":"320582"
+          },
+          {
+            "name":"昆山市",
+            "code":"320583"
+          },
+          {
+            "name":"太仓市",
+            "code":"320585"
+          }
+        ]
+      },
+      {
+        "name":"南通市",
+        "code":"320600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"320601"
+          },
+          {
+            "name":"崇川区",
+            "code":"320602"
+          },
+          {
+            "name":"港闸区",
+            "code":"320611"
+          },
+          {
+            "name":"通州区",
+            "code":"320612"
+          },
+          {
+            "name":"海安县",
+            "code":"320621"
+          },
+          {
+            "name":"如东县",
+            "code":"320623"
+          },
+          {
+            "name":"启东市",
+            "code":"320681"
+          },
+          {
+            "name":"如皋市",
+            "code":"320682"
+          },
+          {
+            "name":"海门市",
+            "code":"320684"
+          }
+        ]
+      },
+      {
+        "name":"连云港市",
+        "code":"320700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"320701"
+          },
+          {
+            "name":"连云区",
+            "code":"320703"
+          },
+          {
+            "name":"海州区",
+            "code":"320706"
+          },
+          {
+            "name":"赣榆区",
+            "code":"320707"
+          },
+          {
+            "name":"东海县",
+            "code":"320722"
+          },
+          {
+            "name":"灌云县",
+            "code":"320723"
+          },
+          {
+            "name":"灌南县",
+            "code":"320724"
+          }
+        ]
+      },
+      {
+        "name":"淮安市",
+        "code":"320800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"320801"
+          },
+          {
+            "name":"清河区",
+            "code":"320802"
+          },
+          {
+            "name":"淮安区",
+            "code":"320803"
+          },
+          {
+            "name":"淮阴区",
+            "code":"320804"
+          },
+          {
+            "name":"清浦区",
+            "code":"320811"
+          },
+          {
+            "name":"涟水县",
+            "code":"320826"
+          },
+          {
+            "name":"洪泽县",
+            "code":"320829"
+          },
+          {
+            "name":"盱眙县",
+            "code":"320830"
+          },
+          {
+            "name":"金湖县",
+            "code":"320831"
+          }
+        ]
+      },
+      {
+        "name":"盐城市",
+        "code":"320900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"320901"
+          },
+          {
+            "name":"亭湖区",
+            "code":"320902"
+          },
+          {
+            "name":"盐都区",
+            "code":"320903"
+          },
+          {
+            "name":"响水县",
+            "code":"320921"
+          },
+          {
+            "name":"滨海县",
+            "code":"320922"
+          },
+          {
+            "name":"阜宁县",
+            "code":"320923"
+          },
+          {
+            "name":"射阳县",
+            "code":"320924"
+          },
+          {
+            "name":"建湖县",
+            "code":"320925"
+          },
+          {
+            "name":"东台市",
+            "code":"320981"
+          },
+          {
+            "name":"大丰市",
+            "code":"320982"
+          }
+        ]
+      },
+      {
+        "name":"扬州市",
+        "code":"321000",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"321001"
+          },
+          {
+            "name":"广陵区",
+            "code":"321002"
+          },
+          {
+            "name":"邗江区",
+            "code":"321003"
+          },
+          {
+            "name":"江都区",
+            "code":"321012"
+          },
+          {
+            "name":"宝应县",
+            "code":"321023"
+          },
+          {
+            "name":"仪征市",
+            "code":"321081"
+          },
+          {
+            "name":"高邮市",
+            "code":"321084"
+          }
+        ]
+      },
+      {
+        "name":"镇江市",
+        "code":"321100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"321101"
+          },
+          {
+            "name":"京口区",
+            "code":"321102"
+          },
+          {
+            "name":"润州区",
+            "code":"321111"
+          },
+          {
+            "name":"丹徒区",
+            "code":"321112"
+          },
+          {
+            "name":"丹阳市",
+            "code":"321181"
+          },
+          {
+            "name":"扬中市",
+            "code":"321182"
+          },
+          {
+            "name":"句容市",
+            "code":"321183"
+          }
+        ]
+      },
+      {
+        "name":"泰州市",
+        "code":"321200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"321201"
+          },
+          {
+            "name":"海陵区",
+            "code":"321202"
+          },
+          {
+            "name":"高港区",
+            "code":"321203"
+          },
+          {
+            "name":"姜堰区",
+            "code":"321204"
+          },
+          {
+            "name":"兴化市",
+            "code":"321281"
+          },
+          {
+            "name":"靖江市",
+            "code":"321282"
+          },
+          {
+            "name":"泰兴市",
+            "code":"321283"
+          }
+        ]
+      },
+      {
+        "name":"宿迁市",
+        "code":"321300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"321301"
+          },
+          {
+            "name":"宿城区",
+            "code":"321302"
+          },
+          {
+            "name":"宿豫区",
+            "code":"321311"
+          },
+          {
+            "name":"沭阳县",
+            "code":"321322"
+          },
+          {
+            "name":"泗阳县",
+            "code":"321323"
+          },
+          {
+            "name":"泗洪县",
+            "code":"321324"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"浙江省",
+    "code":"330000",
+    "sub":[
+      {
+        "name":"杭州市",
+        "code":"330100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"330101"
+          },
+          {
+            "name":"上城区",
+            "code":"330102"
+          },
+          {
+            "name":"下城区",
+            "code":"330103"
+          },
+          {
+            "name":"江干区",
+            "code":"330104"
+          },
+          {
+            "name":"拱墅区",
+            "code":"330105"
+          },
+          {
+            "name":"西湖区",
+            "code":"330106"
+          },
+          {
+            "name":"滨江区",
+            "code":"330108"
+          },
+          {
+            "name":"萧山区",
+            "code":"330109"
+          },
+          {
+            "name":"余杭区",
+            "code":"330110"
+          },
+          {
+            "name":"富阳区",
+            "code":"330111"
+          },
+          {
+            "name":"桐庐县",
+            "code":"330122"
+          },
+          {
+            "name":"淳安县",
+            "code":"330127"
+          },
+          {
+            "name":"建德市",
+            "code":"330182"
+          },
+          {
+            "name":"临安市",
+            "code":"330185"
+          }
+        ]
+      },
+      {
+        "name":"宁波市",
+        "code":"330200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"330201"
+          },
+          {
+            "name":"海曙区",
+            "code":"330203"
+          },
+          {
+            "name":"江东区",
+            "code":"330204"
+          },
+          {
+            "name":"江北区",
+            "code":"330205"
+          },
+          {
+            "name":"北仑区",
+            "code":"330206"
+          },
+          {
+            "name":"镇海区",
+            "code":"330211"
+          },
+          {
+            "name":"鄞州区",
+            "code":"330212"
+          },
+          {
+            "name":"象山县",
+            "code":"330225"
+          },
+          {
+            "name":"宁海县",
+            "code":"330226"
+          },
+          {
+            "name":"余姚市",
+            "code":"330281"
+          },
+          {
+            "name":"慈溪市",
+            "code":"330282"
+          },
+          {
+            "name":"奉化市",
+            "code":"330283"
+          }
+        ]
+      },
+      {
+        "name":"温州市",
+        "code":"330300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"330301"
+          },
+          {
+            "name":"鹿城区",
+            "code":"330302"
+          },
+          {
+            "name":"龙湾区",
+            "code":"330303"
+          },
+          {
+            "name":"瓯海区",
+            "code":"330304"
+          },
+          {
+            "name":"洞头县",
+            "code":"330322"
+          },
+          {
+            "name":"永嘉县",
+            "code":"330324"
+          },
+          {
+            "name":"平阳县",
+            "code":"330326"
+          },
+          {
+            "name":"苍南县",
+            "code":"330327"
+          },
+          {
+            "name":"文成县",
+            "code":"330328"
+          },
+          {
+            "name":"泰顺县",
+            "code":"330329"
+          },
+          {
+            "name":"瑞安市",
+            "code":"330381"
+          },
+          {
+            "name":"乐清市",
+            "code":"330382"
+          }
+        ]
+      },
+      {
+        "name":"嘉兴市",
+        "code":"330400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"330401"
+          },
+          {
+            "name":"南湖区",
+            "code":"330402"
+          },
+          {
+            "name":"秀洲区",
+            "code":"330411"
+          },
+          {
+            "name":"嘉善县",
+            "code":"330421"
+          },
+          {
+            "name":"海盐县",
+            "code":"330424"
+          },
+          {
+            "name":"海宁市",
+            "code":"330481"
+          },
+          {
+            "name":"平湖市",
+            "code":"330482"
+          },
+          {
+            "name":"桐乡市",
+            "code":"330483"
+          }
+        ]
+      },
+      {
+        "name":"湖州市",
+        "code":"330500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"330501"
+          },
+          {
+            "name":"吴兴区",
+            "code":"330502"
+          },
+          {
+            "name":"南浔区",
+            "code":"330503"
+          },
+          {
+            "name":"德清县",
+            "code":"330521"
+          },
+          {
+            "name":"长兴县",
+            "code":"330522"
+          },
+          {
+            "name":"安吉县",
+            "code":"330523"
+          }
+        ]
+      },
+      {
+        "name":"绍兴市",
+        "code":"330600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"330601"
+          },
+          {
+            "name":"越城区",
+            "code":"330602"
+          },
+          {
+            "name":"柯桥区",
+            "code":"330603"
+          },
+          {
+            "name":"上虞区",
+            "code":"330604"
+          },
+          {
+            "name":"新昌县",
+            "code":"330624"
+          },
+          {
+            "name":"诸暨市",
+            "code":"330681"
+          },
+          {
+            "name":"嵊州市",
+            "code":"330683"
+          }
+        ]
+      },
+      {
+        "name":"金华市",
+        "code":"330700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"330701"
+          },
+          {
+            "name":"婺城区",
+            "code":"330702"
+          },
+          {
+            "name":"金东区",
+            "code":"330703"
+          },
+          {
+            "name":"武义县",
+            "code":"330723"
+          },
+          {
+            "name":"浦江县",
+            "code":"330726"
+          },
+          {
+            "name":"磐安县",
+            "code":"330727"
+          },
+          {
+            "name":"兰溪市",
+            "code":"330781"
+          },
+          {
+            "name":"义乌市",
+            "code":"330782"
+          },
+          {
+            "name":"东阳市",
+            "code":"330783"
+          },
+          {
+            "name":"永康市",
+            "code":"330784"
+          }
+        ]
+      },
+      {
+        "name":"衢州市",
+        "code":"330800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"330801"
+          },
+          {
+            "name":"柯城区",
+            "code":"330802"
+          },
+          {
+            "name":"衢江区",
+            "code":"330803"
+          },
+          {
+            "name":"常山县",
+            "code":"330822"
+          },
+          {
+            "name":"开化县",
+            "code":"330824"
+          },
+          {
+            "name":"龙游县",
+            "code":"330825"
+          },
+          {
+            "name":"江山市",
+            "code":"330881"
+          }
+        ]
+      },
+      {
+        "name":"舟山市",
+        "code":"330900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"330901"
+          },
+          {
+            "name":"定海区",
+            "code":"330902"
+          },
+          {
+            "name":"普陀区",
+            "code":"330903"
+          },
+          {
+            "name":"岱山县",
+            "code":"330921"
+          },
+          {
+            "name":"嵊泗县",
+            "code":"330922"
+          }
+        ]
+      },
+      {
+        "name":"台州市",
+        "code":"331000",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"331001"
+          },
+          {
+            "name":"椒江区",
+            "code":"331002"
+          },
+          {
+            "name":"黄岩区",
+            "code":"331003"
+          },
+          {
+            "name":"路桥区",
+            "code":"331004"
+          },
+          {
+            "name":"玉环县",
+            "code":"331021"
+          },
+          {
+            "name":"三门县",
+            "code":"331022"
+          },
+          {
+            "name":"天台县",
+            "code":"331023"
+          },
+          {
+            "name":"仙居县",
+            "code":"331024"
+          },
+          {
+            "name":"温岭市",
+            "code":"331081"
+          },
+          {
+            "name":"临海市",
+            "code":"331082"
+          }
+        ]
+      },
+      {
+        "name":"丽水市",
+        "code":"331100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"331101"
+          },
+          {
+            "name":"莲都区",
+            "code":"331102"
+          },
+          {
+            "name":"青田县",
+            "code":"331121"
+          },
+          {
+            "name":"缙云县",
+            "code":"331122"
+          },
+          {
+            "name":"遂昌县",
+            "code":"331123"
+          },
+          {
+            "name":"松阳县",
+            "code":"331124"
+          },
+          {
+            "name":"云和县",
+            "code":"331125"
+          },
+          {
+            "name":"庆元县",
+            "code":"331126"
+          },
+          {
+            "name":"景宁畲族自治县",
+            "code":"331127"
+          },
+          {
+            "name":"龙泉市",
+            "code":"331181"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"安徽省",
+    "code":"340000",
+    "sub":[
+      {
+        "name":"合肥市",
+        "code":"340100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"340101"
+          },
+          {
+            "name":"瑶海区",
+            "code":"340102"
+          },
+          {
+            "name":"庐阳区",
+            "code":"340103"
+          },
+          {
+            "name":"蜀山区",
+            "code":"340104"
+          },
+          {
+            "name":"包河区",
+            "code":"340111"
+          },
+          {
+            "name":"长丰县",
+            "code":"340121"
+          },
+          {
+            "name":"肥东县",
+            "code":"340122"
+          },
+          {
+            "name":"肥西县",
+            "code":"340123"
+          },
+          {
+            "name":"庐江县",
+            "code":"340124"
+          },
+          {
+            "name":"巢湖市",
+            "code":"340181"
+          }
+        ]
+      },
+      {
+        "name":"芜湖市",
+        "code":"340200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"340201"
+          },
+          {
+            "name":"镜湖区",
+            "code":"340202"
+          },
+          {
+            "name":"弋江区",
+            "code":"340203"
+          },
+          {
+            "name":"鸠江区",
+            "code":"340207"
+          },
+          {
+            "name":"三山区",
+            "code":"340208"
+          },
+          {
+            "name":"芜湖县",
+            "code":"340221"
+          },
+          {
+            "name":"繁昌县",
+            "code":"340222"
+          },
+          {
+            "name":"南陵县",
+            "code":"340223"
+          },
+          {
+            "name":"无为县",
+            "code":"340225"
+          }
+        ]
+      },
+      {
+        "name":"蚌埠市",
+        "code":"340300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"340301"
+          },
+          {
+            "name":"龙子湖区",
+            "code":"340302"
+          },
+          {
+            "name":"蚌山区",
+            "code":"340303"
+          },
+          {
+            "name":"禹会区",
+            "code":"340304"
+          },
+          {
+            "name":"淮上区",
+            "code":"340311"
+          },
+          {
+            "name":"怀远县",
+            "code":"340321"
+          },
+          {
+            "name":"五河县",
+            "code":"340322"
+          },
+          {
+            "name":"固镇县",
+            "code":"340323"
+          }
+        ]
+      },
+      {
+        "name":"淮南市",
+        "code":"340400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"340401"
+          },
+          {
+            "name":"大通区",
+            "code":"340402"
+          },
+          {
+            "name":"田家庵区",
+            "code":"340403"
+          },
+          {
+            "name":"谢家集区",
+            "code":"340404"
+          },
+          {
+            "name":"八公山区",
+            "code":"340405"
+          },
+          {
+            "name":"潘集区",
+            "code":"340406"
+          },
+          {
+            "name":"凤台县",
+            "code":"340421"
+          }
+        ]
+      },
+      {
+        "name":"马鞍山市",
+        "code":"340500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"340501"
+          },
+          {
+            "name":"花山区",
+            "code":"340503"
+          },
+          {
+            "name":"雨山区",
+            "code":"340504"
+          },
+          {
+            "name":"博望区",
+            "code":"340506"
+          },
+          {
+            "name":"当涂县",
+            "code":"340521"
+          },
+          {
+            "name":"含山县",
+            "code":"340522"
+          },
+          {
+            "name":"和县",
+            "code":"340523"
+          }
+        ]
+      },
+      {
+        "name":"淮北市",
+        "code":"340600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"340601"
+          },
+          {
+            "name":"杜集区",
+            "code":"340602"
+          },
+          {
+            "name":"相山区",
+            "code":"340603"
+          },
+          {
+            "name":"烈山区",
+            "code":"340604"
+          },
+          {
+            "name":"濉溪县",
+            "code":"340621"
+          }
+        ]
+      },
+      {
+        "name":"铜陵市",
+        "code":"340700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"340701"
+          },
+          {
+            "name":"铜官山区",
+            "code":"340702"
+          },
+          {
+            "name":"狮子山区",
+            "code":"340703"
+          },
+          {
+            "name":"郊区",
+            "code":"340711"
+          },
+          {
+            "name":"铜陵县",
+            "code":"340721"
+          }
+        ]
+      },
+      {
+        "name":"安庆市",
+        "code":"340800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"340801"
+          },
+          {
+            "name":"迎江区",
+            "code":"340802"
+          },
+          {
+            "name":"大观区",
+            "code":"340803"
+          },
+          {
+            "name":"宜秀区",
+            "code":"340811"
+          },
+          {
+            "name":"怀宁县",
+            "code":"340822"
+          },
+          {
+            "name":"枞阳县",
+            "code":"340823"
+          },
+          {
+            "name":"潜山县",
+            "code":"340824"
+          },
+          {
+            "name":"太湖县",
+            "code":"340825"
+          },
+          {
+            "name":"宿松县",
+            "code":"340826"
+          },
+          {
+            "name":"望江县",
+            "code":"340827"
+          },
+          {
+            "name":"岳西县",
+            "code":"340828"
+          },
+          {
+            "name":"桐城市",
+            "code":"340881"
+          }
+        ]
+      },
+      {
+        "name":"黄山市",
+        "code":"341000",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"341001"
+          },
+          {
+            "name":"屯溪区",
+            "code":"341002"
+          },
+          {
+            "name":"黄山区",
+            "code":"341003"
+          },
+          {
+            "name":"徽州区",
+            "code":"341004"
+          },
+          {
+            "name":"歙县",
+            "code":"341021"
+          },
+          {
+            "name":"休宁县",
+            "code":"341022"
+          },
+          {
+            "name":"黟县",
+            "code":"341023"
+          },
+          {
+            "name":"祁门县",
+            "code":"341024"
+          }
+        ]
+      },
+      {
+        "name":"滁州市",
+        "code":"341100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"341101"
+          },
+          {
+            "name":"琅琊区",
+            "code":"341102"
+          },
+          {
+            "name":"南谯区",
+            "code":"341103"
+          },
+          {
+            "name":"来安县",
+            "code":"341122"
+          },
+          {
+            "name":"全椒县",
+            "code":"341124"
+          },
+          {
+            "name":"定远县",
+            "code":"341125"
+          },
+          {
+            "name":"凤阳县",
+            "code":"341126"
+          },
+          {
+            "name":"天长市",
+            "code":"341181"
+          },
+          {
+            "name":"明光市",
+            "code":"341182"
+          }
+        ]
+      },
+      {
+        "name":"阜阳市",
+        "code":"341200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"341201"
+          },
+          {
+            "name":"颍州区",
+            "code":"341202"
+          },
+          {
+            "name":"颍东区",
+            "code":"341203"
+          },
+          {
+            "name":"颍泉区",
+            "code":"341204"
+          },
+          {
+            "name":"临泉县",
+            "code":"341221"
+          },
+          {
+            "name":"太和县",
+            "code":"341222"
+          },
+          {
+            "name":"阜南县",
+            "code":"341225"
+          },
+          {
+            "name":"颍上县",
+            "code":"341226"
+          },
+          {
+            "name":"界首市",
+            "code":"341282"
+          }
+        ]
+      },
+      {
+        "name":"宿州市",
+        "code":"341300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"341301"
+          },
+          {
+            "name":"埇桥区",
+            "code":"341302"
+          },
+          {
+            "name":"砀山县",
+            "code":"341321"
+          },
+          {
+            "name":"萧县",
+            "code":"341322"
+          },
+          {
+            "name":"灵璧县",
+            "code":"341323"
+          },
+          {
+            "name":"泗县",
+            "code":"341324"
+          }
+        ]
+      },
+      {
+        "name":"六安市",
+        "code":"341500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"341501"
+          },
+          {
+            "name":"金安区",
+            "code":"341502"
+          },
+          {
+            "name":"裕安区",
+            "code":"341503"
+          },
+          {
+            "name":"寿县",
+            "code":"341521"
+          },
+          {
+            "name":"霍邱县",
+            "code":"341522"
+          },
+          {
+            "name":"舒城县",
+            "code":"341523"
+          },
+          {
+            "name":"金寨县",
+            "code":"341524"
+          },
+          {
+            "name":"霍山县",
+            "code":"341525"
+          }
+        ]
+      },
+      {
+        "name":"亳州市",
+        "code":"341600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"341601"
+          },
+          {
+            "name":"谯城区",
+            "code":"341602"
+          },
+          {
+            "name":"涡阳县",
+            "code":"341621"
+          },
+          {
+            "name":"蒙城县",
+            "code":"341622"
+          },
+          {
+            "name":"利辛县",
+            "code":"341623"
+          }
+        ]
+      },
+      {
+        "name":"池州市",
+        "code":"341700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"341701"
+          },
+          {
+            "name":"贵池区",
+            "code":"341702"
+          },
+          {
+            "name":"东至县",
+            "code":"341721"
+          },
+          {
+            "name":"石台县",
+            "code":"341722"
+          },
+          {
+            "name":"青阳县",
+            "code":"341723"
+          }
+        ]
+      },
+      {
+        "name":"宣城市",
+        "code":"341800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"341801"
+          },
+          {
+            "name":"宣州区",
+            "code":"341802"
+          },
+          {
+            "name":"郎溪县",
+            "code":"341821"
+          },
+          {
+            "name":"广德县",
+            "code":"341822"
+          },
+          {
+            "name":"泾县",
+            "code":"341823"
+          },
+          {
+            "name":"绩溪县",
+            "code":"341824"
+          },
+          {
+            "name":"旌德县",
+            "code":"341825"
+          },
+          {
+            "name":"宁国市",
+            "code":"341881"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"福建省",
+    "code":"350000",
+    "sub":[
+      {
+        "name":"福州市",
+        "code":"350100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"350101"
+          },
+          {
+            "name":"鼓楼区",
+            "code":"350102"
+          },
+          {
+            "name":"台江区",
+            "code":"350103"
+          },
+          {
+            "name":"仓山区",
+            "code":"350104"
+          },
+          {
+            "name":"马尾区",
+            "code":"350105"
+          },
+          {
+            "name":"晋安区",
+            "code":"350111"
+          },
+          {
+            "name":"闽侯县",
+            "code":"350121"
+          },
+          {
+            "name":"连江县",
+            "code":"350122"
+          },
+          {
+            "name":"罗源县",
+            "code":"350123"
+          },
+          {
+            "name":"闽清县",
+            "code":"350124"
+          },
+          {
+            "name":"永泰县",
+            "code":"350125"
+          },
+          {
+            "name":"平潭县",
+            "code":"350128"
+          },
+          {
+            "name":"福清市",
+            "code":"350181"
+          },
+          {
+            "name":"长乐市",
+            "code":"350182"
+          }
+        ]
+      },
+      {
+        "name":"厦门市",
+        "code":"350200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"350201"
+          },
+          {
+            "name":"思明区",
+            "code":"350203"
+          },
+          {
+            "name":"海沧区",
+            "code":"350205"
+          },
+          {
+            "name":"湖里区",
+            "code":"350206"
+          },
+          {
+            "name":"集美区",
+            "code":"350211"
+          },
+          {
+            "name":"同安区",
+            "code":"350212"
+          },
+          {
+            "name":"翔安区",
+            "code":"350213"
+          }
+        ]
+      },
+      {
+        "name":"莆田市",
+        "code":"350300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"350301"
+          },
+          {
+            "name":"城厢区",
+            "code":"350302"
+          },
+          {
+            "name":"涵江区",
+            "code":"350303"
+          },
+          {
+            "name":"荔城区",
+            "code":"350304"
+          },
+          {
+            "name":"秀屿区",
+            "code":"350305"
+          },
+          {
+            "name":"仙游县",
+            "code":"350322"
+          }
+        ]
+      },
+      {
+        "name":"三明市",
+        "code":"350400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"350401"
+          },
+          {
+            "name":"梅列区",
+            "code":"350402"
+          },
+          {
+            "name":"三元区",
+            "code":"350403"
+          },
+          {
+            "name":"明溪县",
+            "code":"350421"
+          },
+          {
+            "name":"清流县",
+            "code":"350423"
+          },
+          {
+            "name":"宁化县",
+            "code":"350424"
+          },
+          {
+            "name":"大田县",
+            "code":"350425"
+          },
+          {
+            "name":"尤溪县",
+            "code":"350426"
+          },
+          {
+            "name":"沙县",
+            "code":"350427"
+          },
+          {
+            "name":"将乐县",
+            "code":"350428"
+          },
+          {
+            "name":"泰宁县",
+            "code":"350429"
+          },
+          {
+            "name":"建宁县",
+            "code":"350430"
+          },
+          {
+            "name":"永安市",
+            "code":"350481"
+          }
+        ]
+      },
+      {
+        "name":"泉州市",
+        "code":"350500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"350501"
+          },
+          {
+            "name":"鲤城区",
+            "code":"350502"
+          },
+          {
+            "name":"丰泽区",
+            "code":"350503"
+          },
+          {
+            "name":"洛江区",
+            "code":"350504"
+          },
+          {
+            "name":"泉港区",
+            "code":"350505"
+          },
+          {
+            "name":"惠安县",
+            "code":"350521"
+          },
+          {
+            "name":"安溪县",
+            "code":"350524"
+          },
+          {
+            "name":"永春县",
+            "code":"350525"
+          },
+          {
+            "name":"德化县",
+            "code":"350526"
+          },
+          {
+            "name":"金门县",
+            "code":"350527"
+          },
+          {
+            "name":"石狮市",
+            "code":"350581"
+          },
+          {
+            "name":"晋江市",
+            "code":"350582"
+          },
+          {
+            "name":"南安市",
+            "code":"350583"
+          }
+        ]
+      },
+      {
+        "name":"漳州市",
+        "code":"350600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"350601"
+          },
+          {
+            "name":"芗城区",
+            "code":"350602"
+          },
+          {
+            "name":"龙文区",
+            "code":"350603"
+          },
+          {
+            "name":"云霄县",
+            "code":"350622"
+          },
+          {
+            "name":"漳浦县",
+            "code":"350623"
+          },
+          {
+            "name":"诏安县",
+            "code":"350624"
+          },
+          {
+            "name":"长泰县",
+            "code":"350625"
+          },
+          {
+            "name":"东山县",
+            "code":"350626"
+          },
+          {
+            "name":"南靖县",
+            "code":"350627"
+          },
+          {
+            "name":"平和县",
+            "code":"350628"
+          },
+          {
+            "name":"华安县",
+            "code":"350629"
+          },
+          {
+            "name":"龙海市",
+            "code":"350681"
+          }
+        ]
+      },
+      {
+        "name":"南平市",
+        "code":"350700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"350701"
+          },
+          {
+            "name":"延平区",
+            "code":"350702"
+          },
+          {
+            "name":"建阳区",
+            "code":"350703"
+          },
+          {
+            "name":"顺昌县",
+            "code":"350721"
+          },
+          {
+            "name":"浦城县",
+            "code":"350722"
+          },
+          {
+            "name":"光泽县",
+            "code":"350723"
+          },
+          {
+            "name":"松溪县",
+            "code":"350724"
+          },
+          {
+            "name":"政和县",
+            "code":"350725"
+          },
+          {
+            "name":"邵武市",
+            "code":"350781"
+          },
+          {
+            "name":"武夷山市",
+            "code":"350782"
+          },
+          {
+            "name":"建瓯市",
+            "code":"350783"
+          }
+        ]
+      },
+      {
+        "name":"龙岩市",
+        "code":"350800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"350801"
+          },
+          {
+            "name":"新罗区",
+            "code":"350802"
+          },
+          {
+            "name":"永定区",
+            "code":"350803"
+          },
+          {
+            "name":"长汀县",
+            "code":"350821"
+          },
+          {
+            "name":"上杭县",
+            "code":"350823"
+          },
+          {
+            "name":"武平县",
+            "code":"350824"
+          },
+          {
+            "name":"连城县",
+            "code":"350825"
+          },
+          {
+            "name":"漳平市",
+            "code":"350881"
+          }
+        ]
+      },
+      {
+        "name":"宁德市",
+        "code":"350900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"350901"
+          },
+          {
+            "name":"蕉城区",
+            "code":"350902"
+          },
+          {
+            "name":"霞浦县",
+            "code":"350921"
+          },
+          {
+            "name":"古田县",
+            "code":"350922"
+          },
+          {
+            "name":"屏南县",
+            "code":"350923"
+          },
+          {
+            "name":"寿宁县",
+            "code":"350924"
+          },
+          {
+            "name":"周宁县",
+            "code":"350925"
+          },
+          {
+            "name":"柘荣县",
+            "code":"350926"
+          },
+          {
+            "name":"福安市",
+            "code":"350981"
+          },
+          {
+            "name":"福鼎市",
+            "code":"350982"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"江西省",
+    "code":"360000",
+    "sub":[
+      {
+        "name":"南昌市",
+        "code":"360100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"360101"
+          },
+          {
+            "name":"东湖区",
+            "code":"360102"
+          },
+          {
+            "name":"西湖区",
+            "code":"360103"
+          },
+          {
+            "name":"青云谱区",
+            "code":"360104"
+          },
+          {
+            "name":"湾里区",
+            "code":"360105"
+          },
+          {
+            "name":"青山湖区",
+            "code":"360111"
+          },
+          {
+            "name":"南昌县",
+            "code":"360121"
+          },
+          {
+            "name":"新建县",
+            "code":"360122"
+          },
+          {
+            "name":"安义县",
+            "code":"360123"
+          },
+          {
+            "name":"进贤县",
+            "code":"360124"
+          }
+        ]
+      },
+      {
+        "name":"景德镇市",
+        "code":"360200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"360201"
+          },
+          {
+            "name":"昌江区",
+            "code":"360202"
+          },
+          {
+            "name":"珠山区",
+            "code":"360203"
+          },
+          {
+            "name":"浮梁县",
+            "code":"360222"
+          },
+          {
+            "name":"乐平市",
+            "code":"360281"
+          }
+        ]
+      },
+      {
+        "name":"萍乡市",
+        "code":"360300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"360301"
+          },
+          {
+            "name":"安源区",
+            "code":"360302"
+          },
+          {
+            "name":"湘东区",
+            "code":"360313"
+          },
+          {
+            "name":"莲花县",
+            "code":"360321"
+          },
+          {
+            "name":"上栗县",
+            "code":"360322"
+          },
+          {
+            "name":"芦溪县",
+            "code":"360323"
+          }
+        ]
+      },
+      {
+        "name":"九江市",
+        "code":"360400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"360401"
+          },
+          {
+            "name":"庐山区",
+            "code":"360402"
+          },
+          {
+            "name":"浔阳区",
+            "code":"360403"
+          },
+          {
+            "name":"九江县",
+            "code":"360421"
+          },
+          {
+            "name":"武宁县",
+            "code":"360423"
+          },
+          {
+            "name":"修水县",
+            "code":"360424"
+          },
+          {
+            "name":"永修县",
+            "code":"360425"
+          },
+          {
+            "name":"德安县",
+            "code":"360426"
+          },
+          {
+            "name":"星子县",
+            "code":"360427"
+          },
+          {
+            "name":"都昌县",
+            "code":"360428"
+          },
+          {
+            "name":"湖口县",
+            "code":"360429"
+          },
+          {
+            "name":"彭泽县",
+            "code":"360430"
+          },
+          {
+            "name":"瑞昌市",
+            "code":"360481"
+          },
+          {
+            "name":"共青城市",
+            "code":"360482"
+          }
+        ]
+      },
+      {
+        "name":"新余市",
+        "code":"360500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"360501"
+          },
+          {
+            "name":"渝水区",
+            "code":"360502"
+          },
+          {
+            "name":"分宜县",
+            "code":"360521"
+          }
+        ]
+      },
+      {
+        "name":"鹰潭市",
+        "code":"360600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"360601"
+          },
+          {
+            "name":"月湖区",
+            "code":"360602"
+          },
+          {
+            "name":"余江县",
+            "code":"360622"
+          },
+          {
+            "name":"贵溪市",
+            "code":"360681"
+          }
+        ]
+      },
+      {
+        "name":"赣州市",
+        "code":"360700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"360701"
+          },
+          {
+            "name":"章贡区",
+            "code":"360702"
+          },
+          {
+            "name":"南康区",
+            "code":"360703"
+          },
+          {
+            "name":"赣县",
+            "code":"360721"
+          },
+          {
+            "name":"信丰县",
+            "code":"360722"
+          },
+          {
+            "name":"大余县",
+            "code":"360723"
+          },
+          {
+            "name":"上犹县",
+            "code":"360724"
+          },
+          {
+            "name":"崇义县",
+            "code":"360725"
+          },
+          {
+            "name":"安远县",
+            "code":"360726"
+          },
+          {
+            "name":"龙南县",
+            "code":"360727"
+          },
+          {
+            "name":"定南县",
+            "code":"360728"
+          },
+          {
+            "name":"全南县",
+            "code":"360729"
+          },
+          {
+            "name":"宁都县",
+            "code":"360730"
+          },
+          {
+            "name":"于都县",
+            "code":"360731"
+          },
+          {
+            "name":"兴国县",
+            "code":"360732"
+          },
+          {
+            "name":"会昌县",
+            "code":"360733"
+          },
+          {
+            "name":"寻乌县",
+            "code":"360734"
+          },
+          {
+            "name":"石城县",
+            "code":"360735"
+          },
+          {
+            "name":"瑞金市",
+            "code":"360781"
+          }
+        ]
+      },
+      {
+        "name":"吉安市",
+        "code":"360800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"360801"
+          },
+          {
+            "name":"吉州区",
+            "code":"360802"
+          },
+          {
+            "name":"青原区",
+            "code":"360803"
+          },
+          {
+            "name":"吉安县",
+            "code":"360821"
+          },
+          {
+            "name":"吉水县",
+            "code":"360822"
+          },
+          {
+            "name":"峡江县",
+            "code":"360823"
+          },
+          {
+            "name":"新干县",
+            "code":"360824"
+          },
+          {
+            "name":"永丰县",
+            "code":"360825"
+          },
+          {
+            "name":"泰和县",
+            "code":"360826"
+          },
+          {
+            "name":"遂川县",
+            "code":"360827"
+          },
+          {
+            "name":"万安县",
+            "code":"360828"
+          },
+          {
+            "name":"安福县",
+            "code":"360829"
+          },
+          {
+            "name":"永新县",
+            "code":"360830"
+          },
+          {
+            "name":"井冈山市",
+            "code":"360881"
+          }
+        ]
+      },
+      {
+        "name":"宜春市",
+        "code":"360900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"360901"
+          },
+          {
+            "name":"袁州区",
+            "code":"360902"
+          },
+          {
+            "name":"奉新县",
+            "code":"360921"
+          },
+          {
+            "name":"万载县",
+            "code":"360922"
+          },
+          {
+            "name":"上高县",
+            "code":"360923"
+          },
+          {
+            "name":"宜丰县",
+            "code":"360924"
+          },
+          {
+            "name":"靖安县",
+            "code":"360925"
+          },
+          {
+            "name":"铜鼓县",
+            "code":"360926"
+          },
+          {
+            "name":"丰城市",
+            "code":"360981"
+          },
+          {
+            "name":"樟树市",
+            "code":"360982"
+          },
+          {
+            "name":"高安市",
+            "code":"360983"
+          }
+        ]
+      },
+      {
+        "name":"抚州市",
+        "code":"361000",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"361001"
+          },
+          {
+            "name":"临川区",
+            "code":"361002"
+          },
+          {
+            "name":"南城县",
+            "code":"361021"
+          },
+          {
+            "name":"黎川县",
+            "code":"361022"
+          },
+          {
+            "name":"南丰县",
+            "code":"361023"
+          },
+          {
+            "name":"崇仁县",
+            "code":"361024"
+          },
+          {
+            "name":"乐安县",
+            "code":"361025"
+          },
+          {
+            "name":"宜黄县",
+            "code":"361026"
+          },
+          {
+            "name":"金溪县",
+            "code":"361027"
+          },
+          {
+            "name":"资溪县",
+            "code":"361028"
+          },
+          {
+            "name":"东乡县",
+            "code":"361029"
+          },
+          {
+            "name":"广昌县",
+            "code":"361030"
+          }
+        ]
+      },
+      {
+        "name":"上饶市",
+        "code":"361100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"361101"
+          },
+          {
+            "name":"信州区",
+            "code":"361102"
+          },
+          {
+            "name":"上饶县",
+            "code":"361121"
+          },
+          {
+            "name":"广丰县",
+            "code":"361122"
+          },
+          {
+            "name":"玉山县",
+            "code":"361123"
+          },
+          {
+            "name":"铅山县",
+            "code":"361124"
+          },
+          {
+            "name":"横峰县",
+            "code":"361125"
+          },
+          {
+            "name":"弋阳县",
+            "code":"361126"
+          },
+          {
+            "name":"余干县",
+            "code":"361127"
+          },
+          {
+            "name":"鄱阳县",
+            "code":"361128"
+          },
+          {
+            "name":"万年县",
+            "code":"361129"
+          },
+          {
+            "name":"婺源县",
+            "code":"361130"
+          },
+          {
+            "name":"德兴市",
+            "code":"361181"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"山东省",
+    "code":"370000",
+    "sub":[
+      {
+        "name":"济南市",
+        "code":"370100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"370101"
+          },
+          {
+            "name":"历下区",
+            "code":"370102"
+          },
+          {
+            "name":"市中区",
+            "code":"370103"
+          },
+          {
+            "name":"槐荫区",
+            "code":"370104"
+          },
+          {
+            "name":"天桥区",
+            "code":"370105"
+          },
+          {
+            "name":"历城区",
+            "code":"370112"
+          },
+          {
+            "name":"长清区",
+            "code":"370113"
+          },
+          {
+            "name":"平阴县",
+            "code":"370124"
+          },
+          {
+            "name":"济阳县",
+            "code":"370125"
+          },
+          {
+            "name":"商河县",
+            "code":"370126"
+          },
+          {
+            "name":"章丘市",
+            "code":"370181"
+          }
+        ]
+      },
+      {
+        "name":"青岛市",
+        "code":"370200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"370201"
+          },
+          {
+            "name":"市南区",
+            "code":"370202"
+          },
+          {
+            "name":"市北区",
+            "code":"370203"
+          },
+          {
+            "name":"黄岛区",
+            "code":"370211"
+          },
+          {
+            "name":"崂山区",
+            "code":"370212"
+          },
+          {
+            "name":"李沧区",
+            "code":"370213"
+          },
+          {
+            "name":"城阳区",
+            "code":"370214"
+          },
+          {
+            "name":"胶州市",
+            "code":"370281"
+          },
+          {
+            "name":"即墨市",
+            "code":"370282"
+          },
+          {
+            "name":"平度市",
+            "code":"370283"
+          },
+          {
+            "name":"莱西市",
+            "code":"370285"
+          }
+        ]
+      },
+      {
+        "name":"淄博市",
+        "code":"370300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"370301"
+          },
+          {
+            "name":"淄川区",
+            "code":"370302"
+          },
+          {
+            "name":"张店区",
+            "code":"370303"
+          },
+          {
+            "name":"博山区",
+            "code":"370304"
+          },
+          {
+            "name":"临淄区",
+            "code":"370305"
+          },
+          {
+            "name":"周村区",
+            "code":"370306"
+          },
+          {
+            "name":"桓台县",
+            "code":"370321"
+          },
+          {
+            "name":"高青县",
+            "code":"370322"
+          },
+          {
+            "name":"沂源县",
+            "code":"370323"
+          }
+        ]
+      },
+      {
+        "name":"枣庄市",
+        "code":"370400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"370401"
+          },
+          {
+            "name":"市中区",
+            "code":"370402"
+          },
+          {
+            "name":"薛城区",
+            "code":"370403"
+          },
+          {
+            "name":"峄城区",
+            "code":"370404"
+          },
+          {
+            "name":"台儿庄区",
+            "code":"370405"
+          },
+          {
+            "name":"山亭区",
+            "code":"370406"
+          },
+          {
+            "name":"滕州市",
+            "code":"370481"
+          }
+        ]
+      },
+      {
+        "name":"东营市",
+        "code":"370500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"370501"
+          },
+          {
+            "name":"东营区",
+            "code":"370502"
+          },
+          {
+            "name":"河口区",
+            "code":"370503"
+          },
+          {
+            "name":"垦利县",
+            "code":"370521"
+          },
+          {
+            "name":"利津县",
+            "code":"370522"
+          },
+          {
+            "name":"广饶县",
+            "code":"370523"
+          }
+        ]
+      },
+      {
+        "name":"烟台市",
+        "code":"370600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"370601"
+          },
+          {
+            "name":"芝罘区",
+            "code":"370602"
+          },
+          {
+            "name":"福山区",
+            "code":"370611"
+          },
+          {
+            "name":"牟平区",
+            "code":"370612"
+          },
+          {
+            "name":"莱山区",
+            "code":"370613"
+          },
+          {
+            "name":"长岛县",
+            "code":"370634"
+          },
+          {
+            "name":"龙口市",
+            "code":"370681"
+          },
+          {
+            "name":"莱阳市",
+            "code":"370682"
+          },
+          {
+            "name":"莱州市",
+            "code":"370683"
+          },
+          {
+            "name":"蓬莱市",
+            "code":"370684"
+          },
+          {
+            "name":"招远市",
+            "code":"370685"
+          },
+          {
+            "name":"栖霞市",
+            "code":"370686"
+          },
+          {
+            "name":"海阳市",
+            "code":"370687"
+          }
+        ]
+      },
+      {
+        "name":"潍坊市",
+        "code":"370700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"370701"
+          },
+          {
+            "name":"潍城区",
+            "code":"370702"
+          },
+          {
+            "name":"寒亭区",
+            "code":"370703"
+          },
+          {
+            "name":"坊子区",
+            "code":"370704"
+          },
+          {
+            "name":"奎文区",
+            "code":"370705"
+          },
+          {
+            "name":"临朐县",
+            "code":"370724"
+          },
+          {
+            "name":"昌乐县",
+            "code":"370725"
+          },
+          {
+            "name":"青州市",
+            "code":"370781"
+          },
+          {
+            "name":"诸城市",
+            "code":"370782"
+          },
+          {
+            "name":"寿光市",
+            "code":"370783"
+          },
+          {
+            "name":"安丘市",
+            "code":"370784"
+          },
+          {
+            "name":"高密市",
+            "code":"370785"
+          },
+          {
+            "name":"昌邑市",
+            "code":"370786"
+          }
+        ]
+      },
+      {
+        "name":"济宁市",
+        "code":"370800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"370801"
+          },
+          {
+            "name":"任城区",
+            "code":"370811"
+          },
+          {
+            "name":"兖州区",
+            "code":"370812"
+          },
+          {
+            "name":"微山县",
+            "code":"370826"
+          },
+          {
+            "name":"鱼台县",
+            "code":"370827"
+          },
+          {
+            "name":"金乡县",
+            "code":"370828"
+          },
+          {
+            "name":"嘉祥县",
+            "code":"370829"
+          },
+          {
+            "name":"汶上县",
+            "code":"370830"
+          },
+          {
+            "name":"泗水县",
+            "code":"370831"
+          },
+          {
+            "name":"梁山县",
+            "code":"370832"
+          },
+          {
+            "name":"曲阜市",
+            "code":"370881"
+          },
+          {
+            "name":"邹城市",
+            "code":"370883"
+          }
+        ]
+      },
+      {
+        "name":"泰安市",
+        "code":"370900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"370901"
+          },
+          {
+            "name":"泰山区",
+            "code":"370902"
+          },
+          {
+            "name":"岱岳区",
+            "code":"370911"
+          },
+          {
+            "name":"宁阳县",
+            "code":"370921"
+          },
+          {
+            "name":"东平县",
+            "code":"370923"
+          },
+          {
+            "name":"新泰市",
+            "code":"370982"
+          },
+          {
+            "name":"肥城市",
+            "code":"370983"
+          }
+        ]
+      },
+      {
+        "name":"威海市",
+        "code":"371000",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"371001"
+          },
+          {
+            "name":"环翠区",
+            "code":"371002"
+          },
+          {
+            "name":"文登市",
+            "code":"371081"
+          },
+          {
+            "name":"荣成市",
+            "code":"371082"
+          },
+          {
+            "name":"乳山市",
+            "code":"371083"
+          }
+        ]
+      },
+      {
+        "name":"日照市",
+        "code":"371100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"371101"
+          },
+          {
+            "name":"东港区",
+            "code":"371102"
+          },
+          {
+            "name":"岚山区",
+            "code":"371103"
+          },
+          {
+            "name":"五莲县",
+            "code":"371121"
+          },
+          {
+            "name":"莒县",
+            "code":"371122"
+          }
+        ]
+      },
+      {
+        "name":"莱芜市",
+        "code":"371200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"371201"
+          },
+          {
+            "name":"莱城区",
+            "code":"371202"
+          },
+          {
+            "name":"钢城区",
+            "code":"371203"
+          }
+        ]
+      },
+      {
+        "name":"临沂市",
+        "code":"371300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"371301"
+          },
+          {
+            "name":"兰山区",
+            "code":"371302"
+          },
+          {
+            "name":"罗庄区",
+            "code":"371311"
+          },
+          {
+            "name":"河东区",
+            "code":"371312"
+          },
+          {
+            "name":"沂南县",
+            "code":"371321"
+          },
+          {
+            "name":"郯城县",
+            "code":"371322"
+          },
+          {
+            "name":"沂水县",
+            "code":"371323"
+          },
+          {
+            "name":"兰陵县",
+            "code":"371324"
+          },
+          {
+            "name":"费县",
+            "code":"371325"
+          },
+          {
+            "name":"平邑县",
+            "code":"371326"
+          },
+          {
+            "name":"莒南县",
+            "code":"371327"
+          },
+          {
+            "name":"蒙阴县",
+            "code":"371328"
+          },
+          {
+            "name":"临沭县",
+            "code":"371329"
+          }
+        ]
+      },
+      {
+        "name":"德州市",
+        "code":"371400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"371401"
+          },
+          {
+            "name":"德城区",
+            "code":"371402"
+          },
+          {
+            "name":"陵城区",
+            "code":"371403"
+          },
+          {
+            "name":"宁津县",
+            "code":"371422"
+          },
+          {
+            "name":"庆云县",
+            "code":"371423"
+          },
+          {
+            "name":"临邑县",
+            "code":"371424"
+          },
+          {
+            "name":"齐河县",
+            "code":"371425"
+          },
+          {
+            "name":"平原县",
+            "code":"371426"
+          },
+          {
+            "name":"夏津县",
+            "code":"371427"
+          },
+          {
+            "name":"武城县",
+            "code":"371428"
+          },
+          {
+            "name":"乐陵市",
+            "code":"371481"
+          },
+          {
+            "name":"禹城市",
+            "code":"371482"
+          }
+        ]
+      },
+      {
+        "name":"聊城市",
+        "code":"371500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"371501"
+          },
+          {
+            "name":"东昌府区",
+            "code":"371502"
+          },
+          {
+            "name":"阳谷县",
+            "code":"371521"
+          },
+          {
+            "name":"莘县",
+            "code":"371522"
+          },
+          {
+            "name":"茌平县",
+            "code":"371523"
+          },
+          {
+            "name":"东阿县",
+            "code":"371524"
+          },
+          {
+            "name":"冠县",
+            "code":"371525"
+          },
+          {
+            "name":"高唐县",
+            "code":"371526"
+          },
+          {
+            "name":"临清市",
+            "code":"371581"
+          }
+        ]
+      },
+      {
+        "name":"滨州市",
+        "code":"371600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"371601"
+          },
+          {
+            "name":"滨城区",
+            "code":"371602"
+          },
+          {
+            "name":"沾化区",
+            "code":"371603"
+          },
+          {
+            "name":"惠民县",
+            "code":"371621"
+          },
+          {
+            "name":"阳信县",
+            "code":"371622"
+          },
+          {
+            "name":"无棣县",
+            "code":"371623"
+          },
+          {
+            "name":"博兴县",
+            "code":"371625"
+          },
+          {
+            "name":"邹平县",
+            "code":"371626"
+          }
+        ]
+      },
+      {
+        "name":"菏泽市",
+        "code":"371700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"371701"
+          },
+          {
+            "name":"牡丹区",
+            "code":"371702"
+          },
+          {
+            "name":"曹县",
+            "code":"371721"
+          },
+          {
+            "name":"单县",
+            "code":"371722"
+          },
+          {
+            "name":"成武县",
+            "code":"371723"
+          },
+          {
+            "name":"巨野县",
+            "code":"371724"
+          },
+          {
+            "name":"郓城县",
+            "code":"371725"
+          },
+          {
+            "name":"鄄城县",
+            "code":"371726"
+          },
+          {
+            "name":"定陶县",
+            "code":"371727"
+          },
+          {
+            "name":"东明县",
+            "code":"371728"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"河南省",
+    "code":"410000",
+    "sub":[
+      {
+        "name":"郑州市",
+        "code":"410100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"410101"
+          },
+          {
+            "name":"中原区",
+            "code":"410102"
+          },
+          {
+            "name":"二七区",
+            "code":"410103"
+          },
+          {
+            "name":"管城回族区",
+            "code":"410104"
+          },
+          {
+            "name":"金水区",
+            "code":"410105"
+          },
+          {
+            "name":"上街区",
+            "code":"410106"
+          },
+          {
+            "name":"惠济区",
+            "code":"410108"
+          },
+          {
+            "name":"中牟县",
+            "code":"410122"
+          },
+          {
+            "name":"巩义市",
+            "code":"410181"
+          },
+          {
+            "name":"荥阳市",
+            "code":"410182"
+          },
+          {
+            "name":"新密市",
+            "code":"410183"
+          },
+          {
+            "name":"新郑市",
+            "code":"410184"
+          },
+          {
+            "name":"登封市",
+            "code":"410185"
+          }
+        ]
+      },
+      {
+        "name":"开封市",
+        "code":"410200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"410201"
+          },
+          {
+            "name":"龙亭区",
+            "code":"410202"
+          },
+          {
+            "name":"顺河回族区",
+            "code":"410203"
+          },
+          {
+            "name":"鼓楼区",
+            "code":"410204"
+          },
+          {
+            "name":"禹王台区",
+            "code":"410205"
+          },
+          {
+            "name":"祥符区",
+            "code":"410212"
+          },
+          {
+            "name":"杞县",
+            "code":"410221"
+          },
+          {
+            "name":"通许县",
+            "code":"410222"
+          },
+          {
+            "name":"尉氏县",
+            "code":"410223"
+          },
+          {
+            "name":"兰考县",
+            "code":"410225"
+          }
+        ]
+      },
+      {
+        "name":"洛阳市",
+        "code":"410300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"410301"
+          },
+          {
+            "name":"老城区",
+            "code":"410302"
+          },
+          {
+            "name":"西工区",
+            "code":"410303"
+          },
+          {
+            "name":"瀍河回族区",
+            "code":"410304"
+          },
+          {
+            "name":"涧西区",
+            "code":"410305"
+          },
+          {
+            "name":"吉利区",
+            "code":"410306"
+          },
+          {
+            "name":"洛龙区",
+            "code":"410311"
+          },
+          {
+            "name":"孟津县",
+            "code":"410322"
+          },
+          {
+            "name":"新安县",
+            "code":"410323"
+          },
+          {
+            "name":"栾川县",
+            "code":"410324"
+          },
+          {
+            "name":"嵩县",
+            "code":"410325"
+          },
+          {
+            "name":"汝阳县",
+            "code":"410326"
+          },
+          {
+            "name":"宜阳县",
+            "code":"410327"
+          },
+          {
+            "name":"洛宁县",
+            "code":"410328"
+          },
+          {
+            "name":"伊川县",
+            "code":"410329"
+          },
+          {
+            "name":"偃师市",
+            "code":"410381"
+          }
+        ]
+      },
+      {
+        "name":"平顶山市",
+        "code":"410400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"410401"
+          },
+          {
+            "name":"新华区",
+            "code":"410402"
+          },
+          {
+            "name":"卫东区",
+            "code":"410403"
+          },
+          {
+            "name":"石龙区",
+            "code":"410404"
+          },
+          {
+            "name":"湛河区",
+            "code":"410411"
+          },
+          {
+            "name":"宝丰县",
+            "code":"410421"
+          },
+          {
+            "name":"叶县",
+            "code":"410422"
+          },
+          {
+            "name":"鲁山县",
+            "code":"410423"
+          },
+          {
+            "name":"郏县",
+            "code":"410425"
+          },
+          {
+            "name":"舞钢市",
+            "code":"410481"
+          },
+          {
+            "name":"汝州市",
+            "code":"410482"
+          }
+        ]
+      },
+      {
+        "name":"安阳市",
+        "code":"410500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"410501"
+          },
+          {
+            "name":"文峰区",
+            "code":"410502"
+          },
+          {
+            "name":"北关区",
+            "code":"410503"
+          },
+          {
+            "name":"殷都区",
+            "code":"410505"
+          },
+          {
+            "name":"龙安区",
+            "code":"410506"
+          },
+          {
+            "name":"安阳县",
+            "code":"410522"
+          },
+          {
+            "name":"汤阴县",
+            "code":"410523"
+          },
+          {
+            "name":"滑县",
+            "code":"410526"
+          },
+          {
+            "name":"内黄县",
+            "code":"410527"
+          },
+          {
+            "name":"林州市",
+            "code":"410581"
+          }
+        ]
+      },
+      {
+        "name":"鹤壁市",
+        "code":"410600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"410601"
+          },
+          {
+            "name":"鹤山区",
+            "code":"410602"
+          },
+          {
+            "name":"山城区",
+            "code":"410603"
+          },
+          {
+            "name":"淇滨区",
+            "code":"410611"
+          },
+          {
+            "name":"浚县",
+            "code":"410621"
+          },
+          {
+            "name":"淇县",
+            "code":"410622"
+          }
+        ]
+      },
+      {
+        "name":"新乡市",
+        "code":"410700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"410701"
+          },
+          {
+            "name":"红旗区",
+            "code":"410702"
+          },
+          {
+            "name":"卫滨区",
+            "code":"410703"
+          },
+          {
+            "name":"凤泉区",
+            "code":"410704"
+          },
+          {
+            "name":"牧野区",
+            "code":"410711"
+          },
+          {
+            "name":"新乡县",
+            "code":"410721"
+          },
+          {
+            "name":"获嘉县",
+            "code":"410724"
+          },
+          {
+            "name":"原阳县",
+            "code":"410725"
+          },
+          {
+            "name":"延津县",
+            "code":"410726"
+          },
+          {
+            "name":"封丘县",
+            "code":"410727"
+          },
+          {
+            "name":"长垣县",
+            "code":"410728"
+          },
+          {
+            "name":"卫辉市",
+            "code":"410781"
+          },
+          {
+            "name":"辉县市",
+            "code":"410782"
+          }
+        ]
+      },
+      {
+        "name":"焦作市",
+        "code":"410800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"410801"
+          },
+          {
+            "name":"解放区",
+            "code":"410802"
+          },
+          {
+            "name":"中站区",
+            "code":"410803"
+          },
+          {
+            "name":"马村区",
+            "code":"410804"
+          },
+          {
+            "name":"山阳区",
+            "code":"410811"
+          },
+          {
+            "name":"修武县",
+            "code":"410821"
+          },
+          {
+            "name":"博爱县",
+            "code":"410822"
+          },
+          {
+            "name":"武陟县",
+            "code":"410823"
+          },
+          {
+            "name":"温县",
+            "code":"410825"
+          },
+          {
+            "name":"沁阳市",
+            "code":"410882"
+          },
+          {
+            "name":"孟州市",
+            "code":"410883"
+          }
+        ]
+      },
+      {
+        "name":"濮阳市",
+        "code":"410900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"410901"
+          },
+          {
+            "name":"华龙区",
+            "code":"410902"
+          },
+          {
+            "name":"清丰县",
+            "code":"410922"
+          },
+          {
+            "name":"南乐县",
+            "code":"410923"
+          },
+          {
+            "name":"范县",
+            "code":"410926"
+          },
+          {
+            "name":"台前县",
+            "code":"410927"
+          },
+          {
+            "name":"濮阳县",
+            "code":"410928"
+          }
+        ]
+      },
+      {
+        "name":"许昌市",
+        "code":"411000",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"411001"
+          },
+          {
+            "name":"魏都区",
+            "code":"411002"
+          },
+          {
+            "name":"许昌县",
+            "code":"411023"
+          },
+          {
+            "name":"鄢陵县",
+            "code":"411024"
+          },
+          {
+            "name":"襄城县",
+            "code":"411025"
+          },
+          {
+            "name":"禹州市",
+            "code":"411081"
+          },
+          {
+            "name":"长葛市",
+            "code":"411082"
+          }
+        ]
+      },
+      {
+        "name":"漯河市",
+        "code":"411100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"411101"
+          },
+          {
+            "name":"源汇区",
+            "code":"411102"
+          },
+          {
+            "name":"郾城区",
+            "code":"411103"
+          },
+          {
+            "name":"召陵区",
+            "code":"411104"
+          },
+          {
+            "name":"舞阳县",
+            "code":"411121"
+          },
+          {
+            "name":"临颍县",
+            "code":"411122"
+          }
+        ]
+      },
+      {
+        "name":"三门峡市",
+        "code":"411200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"411201"
+          },
+          {
+            "name":"湖滨区",
+            "code":"411202"
+          },
+          {
+            "name":"渑池县",
+            "code":"411221"
+          },
+          {
+            "name":"陕县",
+            "code":"411222"
+          },
+          {
+            "name":"卢氏县",
+            "code":"411224"
+          },
+          {
+            "name":"义马市",
+            "code":"411281"
+          },
+          {
+            "name":"灵宝市",
+            "code":"411282"
+          }
+        ]
+      },
+      {
+        "name":"南阳市",
+        "code":"411300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"411301"
+          },
+          {
+            "name":"宛城区",
+            "code":"411302"
+          },
+          {
+            "name":"卧龙区",
+            "code":"411303"
+          },
+          {
+            "name":"南召县",
+            "code":"411321"
+          },
+          {
+            "name":"方城县",
+            "code":"411322"
+          },
+          {
+            "name":"西峡县",
+            "code":"411323"
+          },
+          {
+            "name":"镇平县",
+            "code":"411324"
+          },
+          {
+            "name":"内乡县",
+            "code":"411325"
+          },
+          {
+            "name":"淅川县",
+            "code":"411326"
+          },
+          {
+            "name":"社旗县",
+            "code":"411327"
+          },
+          {
+            "name":"唐河县",
+            "code":"411328"
+          },
+          {
+            "name":"新野县",
+            "code":"411329"
+          },
+          {
+            "name":"桐柏县",
+            "code":"411330"
+          },
+          {
+            "name":"邓州市",
+            "code":"411381"
+          }
+        ]
+      },
+      {
+        "name":"商丘市",
+        "code":"411400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"411401"
+          },
+          {
+            "name":"梁园区",
+            "code":"411402"
+          },
+          {
+            "name":"睢阳区",
+            "code":"411403"
+          },
+          {
+            "name":"民权县",
+            "code":"411421"
+          },
+          {
+            "name":"睢县",
+            "code":"411422"
+          },
+          {
+            "name":"宁陵县",
+            "code":"411423"
+          },
+          {
+            "name":"柘城县",
+            "code":"411424"
+          },
+          {
+            "name":"虞城县",
+            "code":"411425"
+          },
+          {
+            "name":"夏邑县",
+            "code":"411426"
+          },
+          {
+            "name":"永城市",
+            "code":"411481"
+          }
+        ]
+      },
+      {
+        "name":"信阳市",
+        "code":"411500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"411501"
+          },
+          {
+            "name":"浉河区",
+            "code":"411502"
+          },
+          {
+            "name":"平桥区",
+            "code":"411503"
+          },
+          {
+            "name":"罗山县",
+            "code":"411521"
+          },
+          {
+            "name":"光山县",
+            "code":"411522"
+          },
+          {
+            "name":"新县",
+            "code":"411523"
+          },
+          {
+            "name":"商城县",
+            "code":"411524"
+          },
+          {
+            "name":"固始县",
+            "code":"411525"
+          },
+          {
+            "name":"潢川县",
+            "code":"411526"
+          },
+          {
+            "name":"淮滨县",
+            "code":"411527"
+          },
+          {
+            "name":"息县",
+            "code":"411528"
+          }
+        ]
+      },
+      {
+        "name":"周口市",
+        "code":"411600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"411601"
+          },
+          {
+            "name":"川汇区",
+            "code":"411602"
+          },
+          {
+            "name":"扶沟县",
+            "code":"411621"
+          },
+          {
+            "name":"西华县",
+            "code":"411622"
+          },
+          {
+            "name":"商水县",
+            "code":"411623"
+          },
+          {
+            "name":"沈丘县",
+            "code":"411624"
+          },
+          {
+            "name":"郸城县",
+            "code":"411625"
+          },
+          {
+            "name":"淮阳县",
+            "code":"411626"
+          },
+          {
+            "name":"太康县",
+            "code":"411627"
+          },
+          {
+            "name":"鹿邑县",
+            "code":"411628"
+          },
+          {
+            "name":"项城市",
+            "code":"411681"
+          }
+        ]
+      },
+      {
+        "name":"驻马店市",
+        "code":"411700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"411701"
+          },
+          {
+            "name":"驿城区",
+            "code":"411702"
+          },
+          {
+            "name":"西平县",
+            "code":"411721"
+          },
+          {
+            "name":"上蔡县",
+            "code":"411722"
+          },
+          {
+            "name":"平舆县",
+            "code":"411723"
+          },
+          {
+            "name":"正阳县",
+            "code":"411724"
+          },
+          {
+            "name":"确山县",
+            "code":"411725"
+          },
+          {
+            "name":"泌阳县",
+            "code":"411726"
+          },
+          {
+            "name":"汝南县",
+            "code":"411727"
+          },
+          {
+            "name":"遂平县",
+            "code":"411728"
+          },
+          {
+            "name":"新蔡县",
+            "code":"411729"
+          }
+        ]
+      },
+      {
+        "name":"济源市",
+        "code":"419001"
+      }
+    ]
+  },
+  {
+    "name":"湖北省",
+    "code":"420000",
+    "sub":[
+      {
+        "name":"武汉市",
+        "code":"420100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"420101"
+          },
+          {
+            "name":"江岸区",
+            "code":"420102"
+          },
+          {
+            "name":"江汉区",
+            "code":"420103"
+          },
+          {
+            "name":"硚口区",
+            "code":"420104"
+          },
+          {
+            "name":"汉阳区",
+            "code":"420105"
+          },
+          {
+            "name":"武昌区",
+            "code":"420106"
+          },
+          {
+            "name":"青山区",
+            "code":"420107"
+          },
+          {
+            "name":"洪山区",
+            "code":"420111"
+          },
+          {
+            "name":"东西湖区",
+            "code":"420112"
+          },
+          {
+            "name":"汉南区",
+            "code":"420113"
+          },
+          {
+            "name":"蔡甸区",
+            "code":"420114"
+          },
+          {
+            "name":"江夏区",
+            "code":"420115"
+          },
+          {
+            "name":"黄陂区",
+            "code":"420116"
+          },
+          {
+            "name":"新洲区",
+            "code":"420117"
+          }
+        ]
+      },
+      {
+        "name":"黄石市",
+        "code":"420200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"420201"
+          },
+          {
+            "name":"黄石港区",
+            "code":"420202"
+          },
+          {
+            "name":"西塞山区",
+            "code":"420203"
+          },
+          {
+            "name":"下陆区",
+            "code":"420204"
+          },
+          {
+            "name":"铁山区",
+            "code":"420205"
+          },
+          {
+            "name":"阳新县",
+            "code":"420222"
+          },
+          {
+            "name":"大冶市",
+            "code":"420281"
+          }
+        ]
+      },
+      {
+        "name":"十堰市",
+        "code":"420300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"420301"
+          },
+          {
+            "name":"茅箭区",
+            "code":"420302"
+          },
+          {
+            "name":"张湾区",
+            "code":"420303"
+          },
+          {
+            "name":"郧阳区",
+            "code":"420304"
+          },
+          {
+            "name":"郧西县",
+            "code":"420322"
+          },
+          {
+            "name":"竹山县",
+            "code":"420323"
+          },
+          {
+            "name":"竹溪县",
+            "code":"420324"
+          },
+          {
+            "name":"房县",
+            "code":"420325"
+          },
+          {
+            "name":"丹江口市",
+            "code":"420381"
+          }
+        ]
+      },
+      {
+        "name":"宜昌市",
+        "code":"420500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"420501"
+          },
+          {
+            "name":"西陵区",
+            "code":"420502"
+          },
+          {
+            "name":"伍家岗区",
+            "code":"420503"
+          },
+          {
+            "name":"点军区",
+            "code":"420504"
+          },
+          {
+            "name":"猇亭区",
+            "code":"420505"
+          },
+          {
+            "name":"夷陵区",
+            "code":"420506"
+          },
+          {
+            "name":"远安县",
+            "code":"420525"
+          },
+          {
+            "name":"兴山县",
+            "code":"420526"
+          },
+          {
+            "name":"秭归县",
+            "code":"420527"
+          },
+          {
+            "name":"长阳土家族自治县",
+            "code":"420528"
+          },
+          {
+            "name":"五峰土家族自治县",
+            "code":"420529"
+          },
+          {
+            "name":"宜都市",
+            "code":"420581"
+          },
+          {
+            "name":"当阳市",
+            "code":"420582"
+          },
+          {
+            "name":"枝江市",
+            "code":"420583"
+          }
+        ]
+      },
+      {
+        "name":"襄阳市",
+        "code":"420600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"420601"
+          },
+          {
+            "name":"襄城区",
+            "code":"420602"
+          },
+          {
+            "name":"樊城区",
+            "code":"420606"
+          },
+          {
+            "name":"襄州区",
+            "code":"420607"
+          },
+          {
+            "name":"南漳县",
+            "code":"420624"
+          },
+          {
+            "name":"谷城县",
+            "code":"420625"
+          },
+          {
+            "name":"保康县",
+            "code":"420626"
+          },
+          {
+            "name":"老河口市",
+            "code":"420682"
+          },
+          {
+            "name":"枣阳市",
+            "code":"420683"
+          },
+          {
+            "name":"宜城市",
+            "code":"420684"
+          }
+        ]
+      },
+      {
+        "name":"鄂州市",
+        "code":"420700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"420701"
+          },
+          {
+            "name":"梁子湖区",
+            "code":"420702"
+          },
+          {
+            "name":"华容区",
+            "code":"420703"
+          },
+          {
+            "name":"鄂城区",
+            "code":"420704"
+          }
+        ]
+      },
+      {
+        "name":"荆门市",
+        "code":"420800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"420801"
+          },
+          {
+            "name":"东宝区",
+            "code":"420802"
+          },
+          {
+            "name":"掇刀区",
+            "code":"420804"
+          },
+          {
+            "name":"京山县",
+            "code":"420821"
+          },
+          {
+            "name":"沙洋县",
+            "code":"420822"
+          },
+          {
+            "name":"钟祥市",
+            "code":"420881"
+          }
+        ]
+      },
+      {
+        "name":"孝感市",
+        "code":"420900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"420901"
+          },
+          {
+            "name":"孝南区",
+            "code":"420902"
+          },
+          {
+            "name":"孝昌县",
+            "code":"420921"
+          },
+          {
+            "name":"大悟县",
+            "code":"420922"
+          },
+          {
+            "name":"云梦县",
+            "code":"420923"
+          },
+          {
+            "name":"应城市",
+            "code":"420981"
+          },
+          {
+            "name":"安陆市",
+            "code":"420982"
+          },
+          {
+            "name":"汉川市",
+            "code":"420984"
+          }
+        ]
+      },
+      {
+        "name":"荆州市",
+        "code":"421000",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"421001"
+          },
+          {
+            "name":"沙市区",
+            "code":"421002"
+          },
+          {
+            "name":"荆州区",
+            "code":"421003"
+          },
+          {
+            "name":"公安县",
+            "code":"421022"
+          },
+          {
+            "name":"监利县",
+            "code":"421023"
+          },
+          {
+            "name":"江陵县",
+            "code":"421024"
+          },
+          {
+            "name":"石首市",
+            "code":"421081"
+          },
+          {
+            "name":"洪湖市",
+            "code":"421083"
+          },
+          {
+            "name":"松滋市",
+            "code":"421087"
+          }
+        ]
+      },
+      {
+        "name":"黄冈市",
+        "code":"421100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"421101"
+          },
+          {
+            "name":"黄州区",
+            "code":"421102"
+          },
+          {
+            "name":"团风县",
+            "code":"421121"
+          },
+          {
+            "name":"红安县",
+            "code":"421122"
+          },
+          {
+            "name":"罗田县",
+            "code":"421123"
+          },
+          {
+            "name":"英山县",
+            "code":"421124"
+          },
+          {
+            "name":"浠水县",
+            "code":"421125"
+          },
+          {
+            "name":"蕲春县",
+            "code":"421126"
+          },
+          {
+            "name":"黄梅县",
+            "code":"421127"
+          },
+          {
+            "name":"麻城市",
+            "code":"421181"
+          },
+          {
+            "name":"武穴市",
+            "code":"421182"
+          }
+        ]
+      },
+      {
+        "name":"咸宁市",
+        "code":"421200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"421201"
+          },
+          {
+            "name":"咸安区",
+            "code":"421202"
+          },
+          {
+            "name":"嘉鱼县",
+            "code":"421221"
+          },
+          {
+            "name":"通城县",
+            "code":"421222"
+          },
+          {
+            "name":"崇阳县",
+            "code":"421223"
+          },
+          {
+            "name":"通山县",
+            "code":"421224"
+          },
+          {
+            "name":"赤壁市",
+            "code":"421281"
+          }
+        ]
+      },
+      {
+        "name":"随州市",
+        "code":"421300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"421301"
+          },
+          {
+            "name":"曾都区",
+            "code":"421303"
+          },
+          {
+            "name":"随县",
+            "code":"421321"
+          },
+          {
+            "name":"广水市",
+            "code":"421381"
+          }
+        ]
+      },
+      {
+        "name":"恩施土家族苗族自治州",
+        "code":"422800",
+        "sub":[
+          {
+            "name":"恩施市",
+            "code":"422801"
+          },
+          {
+            "name":"利川市",
+            "code":"422802"
+          },
+          {
+            "name":"建始县",
+            "code":"422822"
+          },
+          {
+            "name":"巴东县",
+            "code":"422823"
+          },
+          {
+            "name":"宣恩县",
+            "code":"422825"
+          },
+          {
+            "name":"咸丰县",
+            "code":"422826"
+          },
+          {
+            "name":"来凤县",
+            "code":"422827"
+          },
+          {
+            "name":"鹤峰县",
+            "code":"422828"
+          }
+        ]
+      },
+      {
+        "name":"仙桃市",
+        "code":"429004"
+      },
+      {
+        "name":"潜江市",
+        "code":"429005"
+      },
+      {
+        "name":"天门市",
+        "code":"429006"
+      },
+      {
+        "name":"神农架林区",
+        "code":"429021"
+      }
+    ]
+  },
+  {
+    "name":"湖南省",
+    "code":"430000",
+    "sub":[
+      {
+        "name":"长沙市",
+        "code":"430100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"430101"
+          },
+          {
+            "name":"芙蓉区",
+            "code":"430102"
+          },
+          {
+            "name":"天心区",
+            "code":"430103"
+          },
+          {
+            "name":"岳麓区",
+            "code":"430104"
+          },
+          {
+            "name":"开福区",
+            "code":"430105"
+          },
+          {
+            "name":"雨花区",
+            "code":"430111"
+          },
+          {
+            "name":"望城区",
+            "code":"430112"
+          },
+          {
+            "name":"长沙县",
+            "code":"430121"
+          },
+          {
+            "name":"宁乡县",
+            "code":"430124"
+          },
+          {
+            "name":"浏阳市",
+            "code":"430181"
+          }
+        ]
+      },
+      {
+        "name":"株洲市",
+        "code":"430200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"430201"
+          },
+          {
+            "name":"荷塘区",
+            "code":"430202"
+          },
+          {
+            "name":"芦淞区",
+            "code":"430203"
+          },
+          {
+            "name":"石峰区",
+            "code":"430204"
+          },
+          {
+            "name":"天元区",
+            "code":"430211"
+          },
+          {
+            "name":"株洲县",
+            "code":"430221"
+          },
+          {
+            "name":"攸县",
+            "code":"430223"
+          },
+          {
+            "name":"茶陵县",
+            "code":"430224"
+          },
+          {
+            "name":"炎陵县",
+            "code":"430225"
+          },
+          {
+            "name":"醴陵市",
+            "code":"430281"
+          }
+        ]
+      },
+      {
+        "name":"湘潭市",
+        "code":"430300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"430301"
+          },
+          {
+            "name":"雨湖区",
+            "code":"430302"
+          },
+          {
+            "name":"岳塘区",
+            "code":"430304"
+          },
+          {
+            "name":"湘潭县",
+            "code":"430321"
+          },
+          {
+            "name":"湘乡市",
+            "code":"430381"
+          },
+          {
+            "name":"韶山市",
+            "code":"430382"
+          }
+        ]
+      },
+      {
+        "name":"衡阳市",
+        "code":"430400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"430401"
+          },
+          {
+            "name":"珠晖区",
+            "code":"430405"
+          },
+          {
+            "name":"雁峰区",
+            "code":"430406"
+          },
+          {
+            "name":"石鼓区",
+            "code":"430407"
+          },
+          {
+            "name":"蒸湘区",
+            "code":"430408"
+          },
+          {
+            "name":"南岳区",
+            "code":"430412"
+          },
+          {
+            "name":"衡阳县",
+            "code":"430421"
+          },
+          {
+            "name":"衡南县",
+            "code":"430422"
+          },
+          {
+            "name":"衡山县",
+            "code":"430423"
+          },
+          {
+            "name":"衡东县",
+            "code":"430424"
+          },
+          {
+            "name":"祁东县",
+            "code":"430426"
+          },
+          {
+            "name":"耒阳市",
+            "code":"430481"
+          },
+          {
+            "name":"常宁市",
+            "code":"430482"
+          }
+        ]
+      },
+      {
+        "name":"邵阳市",
+        "code":"430500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"430501"
+          },
+          {
+            "name":"双清区",
+            "code":"430502"
+          },
+          {
+            "name":"大祥区",
+            "code":"430503"
+          },
+          {
+            "name":"北塔区",
+            "code":"430511"
+          },
+          {
+            "name":"邵东县",
+            "code":"430521"
+          },
+          {
+            "name":"新邵县",
+            "code":"430522"
+          },
+          {
+            "name":"邵阳县",
+            "code":"430523"
+          },
+          {
+            "name":"隆回县",
+            "code":"430524"
+          },
+          {
+            "name":"洞口县",
+            "code":"430525"
+          },
+          {
+            "name":"绥宁县",
+            "code":"430527"
+          },
+          {
+            "name":"新宁县",
+            "code":"430528"
+          },
+          {
+            "name":"城步苗族自治县",
+            "code":"430529"
+          },
+          {
+            "name":"武冈市",
+            "code":"430581"
+          }
+        ]
+      },
+      {
+        "name":"岳阳市",
+        "code":"430600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"430601"
+          },
+          {
+            "name":"岳阳楼区",
+            "code":"430602"
+          },
+          {
+            "name":"云溪区",
+            "code":"430603"
+          },
+          {
+            "name":"君山区",
+            "code":"430611"
+          },
+          {
+            "name":"岳阳县",
+            "code":"430621"
+          },
+          {
+            "name":"华容县",
+            "code":"430623"
+          },
+          {
+            "name":"湘阴县",
+            "code":"430624"
+          },
+          {
+            "name":"平江县",
+            "code":"430626"
+          },
+          {
+            "name":"汨罗市",
+            "code":"430681"
+          },
+          {
+            "name":"临湘市",
+            "code":"430682"
+          }
+        ]
+      },
+      {
+        "name":"常德市",
+        "code":"430700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"430701"
+          },
+          {
+            "name":"武陵区",
+            "code":"430702"
+          },
+          {
+            "name":"鼎城区",
+            "code":"430703"
+          },
+          {
+            "name":"安乡县",
+            "code":"430721"
+          },
+          {
+            "name":"汉寿县",
+            "code":"430722"
+          },
+          {
+            "name":"澧县",
+            "code":"430723"
+          },
+          {
+            "name":"临澧县",
+            "code":"430724"
+          },
+          {
+            "name":"桃源县",
+            "code":"430725"
+          },
+          {
+            "name":"石门县",
+            "code":"430726"
+          },
+          {
+            "name":"津市市",
+            "code":"430781"
+          }
+        ]
+      },
+      {
+        "name":"张家界市",
+        "code":"430800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"430801"
+          },
+          {
+            "name":"永定区",
+            "code":"430802"
+          },
+          {
+            "name":"武陵源区",
+            "code":"430811"
+          },
+          {
+            "name":"慈利县",
+            "code":"430821"
+          },
+          {
+            "name":"桑植县",
+            "code":"430822"
+          }
+        ]
+      },
+      {
+        "name":"益阳市",
+        "code":"430900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"430901"
+          },
+          {
+            "name":"资阳区",
+            "code":"430902"
+          },
+          {
+            "name":"赫山区",
+            "code":"430903"
+          },
+          {
+            "name":"南县",
+            "code":"430921"
+          },
+          {
+            "name":"桃江县",
+            "code":"430922"
+          },
+          {
+            "name":"安化县",
+            "code":"430923"
+          },
+          {
+            "name":"沅江市",
+            "code":"430981"
+          }
+        ]
+      },
+      {
+        "name":"郴州市",
+        "code":"431000",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"431001"
+          },
+          {
+            "name":"北湖区",
+            "code":"431002"
+          },
+          {
+            "name":"苏仙区",
+            "code":"431003"
+          },
+          {
+            "name":"桂阳县",
+            "code":"431021"
+          },
+          {
+            "name":"宜章县",
+            "code":"431022"
+          },
+          {
+            "name":"永兴县",
+            "code":"431023"
+          },
+          {
+            "name":"嘉禾县",
+            "code":"431024"
+          },
+          {
+            "name":"临武县",
+            "code":"431025"
+          },
+          {
+            "name":"汝城县",
+            "code":"431026"
+          },
+          {
+            "name":"桂东县",
+            "code":"431027"
+          },
+          {
+            "name":"安仁县",
+            "code":"431028"
+          },
+          {
+            "name":"资兴市",
+            "code":"431081"
+          }
+        ]
+      },
+      {
+        "name":"永州市",
+        "code":"431100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"431101"
+          },
+          {
+            "name":"零陵区",
+            "code":"431102"
+          },
+          {
+            "name":"冷水滩区",
+            "code":"431103"
+          },
+          {
+            "name":"祁阳县",
+            "code":"431121"
+          },
+          {
+            "name":"东安县",
+            "code":"431122"
+          },
+          {
+            "name":"双牌县",
+            "code":"431123"
+          },
+          {
+            "name":"道县",
+            "code":"431124"
+          },
+          {
+            "name":"江永县",
+            "code":"431125"
+          },
+          {
+            "name":"宁远县",
+            "code":"431126"
+          },
+          {
+            "name":"蓝山县",
+            "code":"431127"
+          },
+          {
+            "name":"新田县",
+            "code":"431128"
+          },
+          {
+            "name":"江华瑶族自治县",
+            "code":"431129"
+          }
+        ]
+      },
+      {
+        "name":"怀化市",
+        "code":"431200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"431201"
+          },
+          {
+            "name":"鹤城区",
+            "code":"431202"
+          },
+          {
+            "name":"中方县",
+            "code":"431221"
+          },
+          {
+            "name":"沅陵县",
+            "code":"431222"
+          },
+          {
+            "name":"辰溪县",
+            "code":"431223"
+          },
+          {
+            "name":"溆浦县",
+            "code":"431224"
+          },
+          {
+            "name":"会同县",
+            "code":"431225"
+          },
+          {
+            "name":"麻阳苗族自治县",
+            "code":"431226"
+          },
+          {
+            "name":"新晃侗族自治县",
+            "code":"431227"
+          },
+          {
+            "name":"芷江侗族自治县",
+            "code":"431228"
+          },
+          {
+            "name":"靖州苗族侗族自治县",
+            "code":"431229"
+          },
+          {
+            "name":"通道侗族自治县",
+            "code":"431230"
+          },
+          {
+            "name":"洪江市",
+            "code":"431281"
+          }
+        ]
+      },
+      {
+        "name":"娄底市",
+        "code":"431300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"431301"
+          },
+          {
+            "name":"娄星区",
+            "code":"431302"
+          },
+          {
+            "name":"双峰县",
+            "code":"431321"
+          },
+          {
+            "name":"新化县",
+            "code":"431322"
+          },
+          {
+            "name":"冷水江市",
+            "code":"431381"
+          },
+          {
+            "name":"涟源市",
+            "code":"431382"
+          }
+        ]
+      },
+      {
+        "name":"湘西土家族苗族自治州",
+        "code":"433100",
+        "sub":[
+          {
+            "name":"吉首市",
+            "code":"433101"
+          },
+          {
+            "name":"泸溪县",
+            "code":"433122"
+          },
+          {
+            "name":"凤凰县",
+            "code":"433123"
+          },
+          {
+            "name":"花垣县",
+            "code":"433124"
+          },
+          {
+            "name":"保靖县",
+            "code":"433125"
+          },
+          {
+            "name":"古丈县",
+            "code":"433126"
+          },
+          {
+            "name":"永顺县",
+            "code":"433127"
+          },
+          {
+            "name":"龙山县",
+            "code":"433130"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"广东省",
+    "code":"440000",
+    "sub":[
+      {
+        "name":"广州市",
+        "code":"440100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"440101"
+          },
+          {
+            "name":"荔湾区",
+            "code":"440103"
+          },
+          {
+            "name":"越秀区",
+            "code":"440104"
+          },
+          {
+            "name":"海珠区",
+            "code":"440105"
+          },
+          {
+            "name":"天河区",
+            "code":"440106"
+          },
+          {
+            "name":"白云区",
+            "code":"440111"
+          },
+          {
+            "name":"黄埔区",
+            "code":"440112"
+          },
+          {
+            "name":"番禺区",
+            "code":"440113"
+          },
+          {
+            "name":"花都区",
+            "code":"440114"
+          },
+          {
+            "name":"南沙区",
+            "code":"440115"
+          },
+          {
+            "name":"从化区",
+            "code":"440117"
+          },
+          {
+            "name":"增城区",
+            "code":"440118"
+          }
+        ]
+      },
+      {
+        "name":"韶关市",
+        "code":"440200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"440201"
+          },
+          {
+            "name":"武江区",
+            "code":"440203"
+          },
+          {
+            "name":"浈江区",
+            "code":"440204"
+          },
+          {
+            "name":"曲江区",
+            "code":"440205"
+          },
+          {
+            "name":"始兴县",
+            "code":"440222"
+          },
+          {
+            "name":"仁化县",
+            "code":"440224"
+          },
+          {
+            "name":"翁源县",
+            "code":"440229"
+          },
+          {
+            "name":"乳源瑶族自治县",
+            "code":"440232"
+          },
+          {
+            "name":"新丰县",
+            "code":"440233"
+          },
+          {
+            "name":"乐昌市",
+            "code":"440281"
+          },
+          {
+            "name":"南雄市",
+            "code":"440282"
+          }
+        ]
+      },
+      {
+        "name":"深圳市",
+        "code":"440300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"440301"
+          },
+          {
+            "name":"罗湖区",
+            "code":"440303"
+          },
+          {
+            "name":"福田区",
+            "code":"440304"
+          },
+          {
+            "name":"南山区",
+            "code":"440305"
+          },
+          {
+            "name":"宝安区",
+            "code":"440306"
+          },
+          {
+            "name":"龙岗区",
+            "code":"440307"
+          },
+          {
+            "name":"盐田区",
+            "code":"440308"
+          }
+        ]
+      },
+      {
+        "name":"珠海市",
+        "code":"440400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"440401"
+          },
+          {
+            "name":"香洲区",
+            "code":"440402"
+          },
+          {
+            "name":"斗门区",
+            "code":"440403"
+          },
+          {
+            "name":"金湾区",
+            "code":"440404"
+          }
+        ]
+      },
+      {
+        "name":"汕头市",
+        "code":"440500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"440501"
+          },
+          {
+            "name":"龙湖区",
+            "code":"440507"
+          },
+          {
+            "name":"金平区",
+            "code":"440511"
+          },
+          {
+            "name":"濠江区",
+            "code":"440512"
+          },
+          {
+            "name":"潮阳区",
+            "code":"440513"
+          },
+          {
+            "name":"潮南区",
+            "code":"440514"
+          },
+          {
+            "name":"澄海区",
+            "code":"440515"
+          },
+          {
+            "name":"南澳县",
+            "code":"440523"
+          }
+        ]
+      },
+      {
+        "name":"佛山市",
+        "code":"440600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"440601"
+          },
+          {
+            "name":"禅城区",
+            "code":"440604"
+          },
+          {
+            "name":"南海区",
+            "code":"440605"
+          },
+          {
+            "name":"顺德区",
+            "code":"440606"
+          },
+          {
+            "name":"三水区",
+            "code":"440607"
+          },
+          {
+            "name":"高明区",
+            "code":"440608"
+          }
+        ]
+      },
+      {
+        "name":"江门市",
+        "code":"440700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"440701"
+          },
+          {
+            "name":"蓬江区",
+            "code":"440703"
+          },
+          {
+            "name":"江海区",
+            "code":"440704"
+          },
+          {
+            "name":"新会区",
+            "code":"440705"
+          },
+          {
+            "name":"台山市",
+            "code":"440781"
+          },
+          {
+            "name":"开平市",
+            "code":"440783"
+          },
+          {
+            "name":"鹤山市",
+            "code":"440784"
+          },
+          {
+            "name":"恩平市",
+            "code":"440785"
+          }
+        ]
+      },
+      {
+        "name":"湛江市",
+        "code":"440800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"440801"
+          },
+          {
+            "name":"赤坎区",
+            "code":"440802"
+          },
+          {
+            "name":"霞山区",
+            "code":"440803"
+          },
+          {
+            "name":"坡头区",
+            "code":"440804"
+          },
+          {
+            "name":"麻章区",
+            "code":"440811"
+          },
+          {
+            "name":"遂溪县",
+            "code":"440823"
+          },
+          {
+            "name":"徐闻县",
+            "code":"440825"
+          },
+          {
+            "name":"廉江市",
+            "code":"440881"
+          },
+          {
+            "name":"雷州市",
+            "code":"440882"
+          },
+          {
+            "name":"吴川市",
+            "code":"440883"
+          }
+        ]
+      },
+      {
+        "name":"茂名市",
+        "code":"440900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"440901"
+          },
+          {
+            "name":"茂南区",
+            "code":"440902"
+          },
+          {
+            "name":"电白区",
+            "code":"440904"
+          },
+          {
+            "name":"高州市",
+            "code":"440981"
+          },
+          {
+            "name":"化州市",
+            "code":"440982"
+          },
+          {
+            "name":"信宜市",
+            "code":"440983"
+          }
+        ]
+      },
+      {
+        "name":"肇庆市",
+        "code":"441200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"441201"
+          },
+          {
+            "name":"端州区",
+            "code":"441202"
+          },
+          {
+            "name":"鼎湖区",
+            "code":"441203"
+          },
+          {
+            "name":"广宁县",
+            "code":"441223"
+          },
+          {
+            "name":"怀集县",
+            "code":"441224"
+          },
+          {
+            "name":"封开县",
+            "code":"441225"
+          },
+          {
+            "name":"德庆县",
+            "code":"441226"
+          },
+          {
+            "name":"高要市",
+            "code":"441283"
+          },
+          {
+            "name":"四会市",
+            "code":"441284"
+          }
+        ]
+      },
+      {
+        "name":"惠州市",
+        "code":"441300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"441301"
+          },
+          {
+            "name":"惠城区",
+            "code":"441302"
+          },
+          {
+            "name":"惠阳区",
+            "code":"441303"
+          },
+          {
+            "name":"博罗县",
+            "code":"441322"
+          },
+          {
+            "name":"惠东县",
+            "code":"441323"
+          },
+          {
+            "name":"龙门县",
+            "code":"441324"
+          }
+        ]
+      },
+      {
+        "name":"梅州市",
+        "code":"441400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"441401"
+          },
+          {
+            "name":"梅江区",
+            "code":"441402"
+          },
+          {
+            "name":"梅县区",
+            "code":"441403"
+          },
+          {
+            "name":"大埔县",
+            "code":"441422"
+          },
+          {
+            "name":"丰顺县",
+            "code":"441423"
+          },
+          {
+            "name":"五华县",
+            "code":"441424"
+          },
+          {
+            "name":"平远县",
+            "code":"441426"
+          },
+          {
+            "name":"蕉岭县",
+            "code":"441427"
+          },
+          {
+            "name":"兴宁市",
+            "code":"441481"
+          }
+        ]
+      },
+      {
+        "name":"汕尾市",
+        "code":"441500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"441501"
+          },
+          {
+            "name":"城区",
+            "code":"441502"
+          },
+          {
+            "name":"海丰县",
+            "code":"441521"
+          },
+          {
+            "name":"陆河县",
+            "code":"441523"
+          },
+          {
+            "name":"陆丰市",
+            "code":"441581"
+          }
+        ]
+      },
+      {
+        "name":"河源市",
+        "code":"441600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"441601"
+          },
+          {
+            "name":"源城区",
+            "code":"441602"
+          },
+          {
+            "name":"紫金县",
+            "code":"441621"
+          },
+          {
+            "name":"龙川县",
+            "code":"441622"
+          },
+          {
+            "name":"连平县",
+            "code":"441623"
+          },
+          {
+            "name":"和平县",
+            "code":"441624"
+          },
+          {
+            "name":"东源县",
+            "code":"441625"
+          }
+        ]
+      },
+      {
+        "name":"阳江市",
+        "code":"441700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"441701"
+          },
+          {
+            "name":"江城区",
+            "code":"441702"
+          },
+          {
+            "name":"阳东区",
+            "code":"441704"
+          },
+          {
+            "name":"阳西县",
+            "code":"441721"
+          },
+          {
+            "name":"阳春市",
+            "code":"441781"
+          }
+        ]
+      },
+      {
+        "name":"清远市",
+        "code":"441800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"441801"
+          },
+          {
+            "name":"清城区",
+            "code":"441802"
+          },
+          {
+            "name":"清新区",
+            "code":"441803"
+          },
+          {
+            "name":"佛冈县",
+            "code":"441821"
+          },
+          {
+            "name":"阳山县",
+            "code":"441823"
+          },
+          {
+            "name":"连山壮族瑶族自治县",
+            "code":"441825"
+          },
+          {
+            "name":"连南瑶族自治县",
+            "code":"441826"
+          },
+          {
+            "name":"英德市",
+            "code":"441881"
+          },
+          {
+            "name":"连州市",
+            "code":"441882"
+          }
+        ]
+      },
+      {
+        "name":"东莞市",
+        "code":"441900",
+        "sub":[
+
+        ]
+      },
+      {
+        "name":"中山市",
+        "code":"442000",
+        "sub":[
+
+        ]
+      },
+      {
+        "name":"潮州市",
+        "code":"445100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"445101"
+          },
+          {
+            "name":"湘桥区",
+            "code":"445102"
+          },
+          {
+            "name":"潮安区",
+            "code":"445103"
+          },
+          {
+            "name":"饶平县",
+            "code":"445122"
+          }
+        ]
+      },
+      {
+        "name":"揭阳市",
+        "code":"445200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"445201"
+          },
+          {
+            "name":"榕城区",
+            "code":"445202"
+          },
+          {
+            "name":"揭东区",
+            "code":"445203"
+          },
+          {
+            "name":"揭西县",
+            "code":"445222"
+          },
+          {
+            "name":"惠来县",
+            "code":"445224"
+          },
+          {
+            "name":"普宁市",
+            "code":"445281"
+          }
+        ]
+      },
+      {
+        "name":"云浮市",
+        "code":"445300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"445301"
+          },
+          {
+            "name":"云城区",
+            "code":"445302"
+          },
+          {
+            "name":"云安区",
+            "code":"445303"
+          },
+          {
+            "name":"新兴县",
+            "code":"445321"
+          },
+          {
+            "name":"郁南县",
+            "code":"445322"
+          },
+          {
+            "name":"罗定市",
+            "code":"445381"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"广西壮族自治区",
+    "code":"450000",
+    "sub":[
+      {
+        "name":"南宁市",
+        "code":"450100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"450101"
+          },
+          {
+            "name":"兴宁区",
+            "code":"450102"
+          },
+          {
+            "name":"青秀区",
+            "code":"450103"
+          },
+          {
+            "name":"江南区",
+            "code":"450105"
+          },
+          {
+            "name":"西乡塘区",
+            "code":"450107"
+          },
+          {
+            "name":"良庆区",
+            "code":"450108"
+          },
+          {
+            "name":"邕宁区",
+            "code":"450109"
+          },
+          {
+            "name":"武鸣县",
+            "code":"450122"
+          },
+          {
+            "name":"隆安县",
+            "code":"450123"
+          },
+          {
+            "name":"马山县",
+            "code":"450124"
+          },
+          {
+            "name":"上林县",
+            "code":"450125"
+          },
+          {
+            "name":"宾阳县",
+            "code":"450126"
+          },
+          {
+            "name":"横县",
+            "code":"450127"
+          }
+        ]
+      },
+      {
+        "name":"柳州市",
+        "code":"450200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"450201"
+          },
+          {
+            "name":"城中区",
+            "code":"450202"
+          },
+          {
+            "name":"鱼峰区",
+            "code":"450203"
+          },
+          {
+            "name":"柳南区",
+            "code":"450204"
+          },
+          {
+            "name":"柳北区",
+            "code":"450205"
+          },
+          {
+            "name":"柳江县",
+            "code":"450221"
+          },
+          {
+            "name":"柳城县",
+            "code":"450222"
+          },
+          {
+            "name":"鹿寨县",
+            "code":"450223"
+          },
+          {
+            "name":"融安县",
+            "code":"450224"
+          },
+          {
+            "name":"融水苗族自治县",
+            "code":"450225"
+          },
+          {
+            "name":"三江侗族自治县",
+            "code":"450226"
+          }
+        ]
+      },
+      {
+        "name":"桂林市",
+        "code":"450300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"450301"
+          },
+          {
+            "name":"秀峰区",
+            "code":"450302"
+          },
+          {
+            "name":"叠彩区",
+            "code":"450303"
+          },
+          {
+            "name":"象山区",
+            "code":"450304"
+          },
+          {
+            "name":"七星区",
+            "code":"450305"
+          },
+          {
+            "name":"雁山区",
+            "code":"450311"
+          },
+          {
+            "name":"临桂区",
+            "code":"450312"
+          },
+          {
+            "name":"阳朔县",
+            "code":"450321"
+          },
+          {
+            "name":"灵川县",
+            "code":"450323"
+          },
+          {
+            "name":"全州县",
+            "code":"450324"
+          },
+          {
+            "name":"兴安县",
+            "code":"450325"
+          },
+          {
+            "name":"永福县",
+            "code":"450326"
+          },
+          {
+            "name":"灌阳县",
+            "code":"450327"
+          },
+          {
+            "name":"龙胜各族自治县",
+            "code":"450328"
+          },
+          {
+            "name":"资源县",
+            "code":"450329"
+          },
+          {
+            "name":"平乐县",
+            "code":"450330"
+          },
+          {
+            "name":"荔浦县",
+            "code":"450331"
+          },
+          {
+            "name":"恭城瑶族自治县",
+            "code":"450332"
+          }
+        ]
+      },
+      {
+        "name":"梧州市",
+        "code":"450400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"450401"
+          },
+          {
+            "name":"万秀区",
+            "code":"450403"
+          },
+          {
+            "name":"长洲区",
+            "code":"450405"
+          },
+          {
+            "name":"龙圩区",
+            "code":"450406"
+          },
+          {
+            "name":"苍梧县",
+            "code":"450421"
+          },
+          {
+            "name":"藤县",
+            "code":"450422"
+          },
+          {
+            "name":"蒙山县",
+            "code":"450423"
+          },
+          {
+            "name":"岑溪市",
+            "code":"450481"
+          }
+        ]
+      },
+      {
+        "name":"北海市",
+        "code":"450500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"450501"
+          },
+          {
+            "name":"海城区",
+            "code":"450502"
+          },
+          {
+            "name":"银海区",
+            "code":"450503"
+          },
+          {
+            "name":"铁山港区",
+            "code":"450512"
+          },
+          {
+            "name":"合浦县",
+            "code":"450521"
+          }
+        ]
+      },
+      {
+        "name":"防城港市",
+        "code":"450600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"450601"
+          },
+          {
+            "name":"港口区",
+            "code":"450602"
+          },
+          {
+            "name":"防城区",
+            "code":"450603"
+          },
+          {
+            "name":"上思县",
+            "code":"450621"
+          },
+          {
+            "name":"东兴市",
+            "code":"450681"
+          }
+        ]
+      },
+      {
+        "name":"钦州市",
+        "code":"450700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"450701"
+          },
+          {
+            "name":"钦南区",
+            "code":"450702"
+          },
+          {
+            "name":"钦北区",
+            "code":"450703"
+          },
+          {
+            "name":"灵山县",
+            "code":"450721"
+          },
+          {
+            "name":"浦北县",
+            "code":"450722"
+          }
+        ]
+      },
+      {
+        "name":"贵港市",
+        "code":"450800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"450801"
+          },
+          {
+            "name":"港北区",
+            "code":"450802"
+          },
+          {
+            "name":"港南区",
+            "code":"450803"
+          },
+          {
+            "name":"覃塘区",
+            "code":"450804"
+          },
+          {
+            "name":"平南县",
+            "code":"450821"
+          },
+          {
+            "name":"桂平市",
+            "code":"450881"
+          }
+        ]
+      },
+      {
+        "name":"玉林市",
+        "code":"450900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"450901"
+          },
+          {
+            "name":"玉州区",
+            "code":"450902"
+          },
+          {
+            "name":"福绵区",
+            "code":"450903"
+          },
+          {
+            "name":"容县",
+            "code":"450921"
+          },
+          {
+            "name":"陆川县",
+            "code":"450922"
+          },
+          {
+            "name":"博白县",
+            "code":"450923"
+          },
+          {
+            "name":"兴业县",
+            "code":"450924"
+          },
+          {
+            "name":"北流市",
+            "code":"450981"
+          }
+        ]
+      },
+      {
+        "name":"百色市",
+        "code":"451000",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"451001"
+          },
+          {
+            "name":"右江区",
+            "code":"451002"
+          },
+          {
+            "name":"田阳县",
+            "code":"451021"
+          },
+          {
+            "name":"田东县",
+            "code":"451022"
+          },
+          {
+            "name":"平果县",
+            "code":"451023"
+          },
+          {
+            "name":"德保县",
+            "code":"451024"
+          },
+          {
+            "name":"靖西县",
+            "code":"451025"
+          },
+          {
+            "name":"那坡县",
+            "code":"451026"
+          },
+          {
+            "name":"凌云县",
+            "code":"451027"
+          },
+          {
+            "name":"乐业县",
+            "code":"451028"
+          },
+          {
+            "name":"田林县",
+            "code":"451029"
+          },
+          {
+            "name":"西林县",
+            "code":"451030"
+          },
+          {
+            "name":"隆林各族自治县",
+            "code":"451031"
+          }
+        ]
+      },
+      {
+        "name":"贺州市",
+        "code":"451100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"451101"
+          },
+          {
+            "name":"八步区",
+            "code":"451102"
+          },
+          {
+            "name":"平桂管理区",
+            "code":"451119"
+          },
+          {
+            "name":"昭平县",
+            "code":"451121"
+          },
+          {
+            "name":"钟山县",
+            "code":"451122"
+          },
+          {
+            "name":"富川瑶族自治县",
+            "code":"451123"
+          }
+        ]
+      },
+      {
+        "name":"河池市",
+        "code":"451200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"451201"
+          },
+          {
+            "name":"金城江区",
+            "code":"451202"
+          },
+          {
+            "name":"南丹县",
+            "code":"451221"
+          },
+          {
+            "name":"天峨县",
+            "code":"451222"
+          },
+          {
+            "name":"凤山县",
+            "code":"451223"
+          },
+          {
+            "name":"东兰县",
+            "code":"451224"
+          },
+          {
+            "name":"罗城仫佬族自治县",
+            "code":"451225"
+          },
+          {
+            "name":"环江毛南族自治县",
+            "code":"451226"
+          },
+          {
+            "name":"巴马瑶族自治县",
+            "code":"451227"
+          },
+          {
+            "name":"都安瑶族自治县",
+            "code":"451228"
+          },
+          {
+            "name":"大化瑶族自治县",
+            "code":"451229"
+          },
+          {
+            "name":"宜州市",
+            "code":"451281"
+          }
+        ]
+      },
+      {
+        "name":"来宾市",
+        "code":"451300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"451301"
+          },
+          {
+            "name":"兴宾区",
+            "code":"451302"
+          },
+          {
+            "name":"忻城县",
+            "code":"451321"
+          },
+          {
+            "name":"象州县",
+            "code":"451322"
+          },
+          {
+            "name":"武宣县",
+            "code":"451323"
+          },
+          {
+            "name":"金秀瑶族自治县",
+            "code":"451324"
+          },
+          {
+            "name":"合山市",
+            "code":"451381"
+          }
+        ]
+      },
+      {
+        "name":"崇左市",
+        "code":"451400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"451401"
+          },
+          {
+            "name":"江州区",
+            "code":"451402"
+          },
+          {
+            "name":"扶绥县",
+            "code":"451421"
+          },
+          {
+            "name":"宁明县",
+            "code":"451422"
+          },
+          {
+            "name":"龙州县",
+            "code":"451423"
+          },
+          {
+            "name":"大新县",
+            "code":"451424"
+          },
+          {
+            "name":"天等县",
+            "code":"451425"
+          },
+          {
+            "name":"凭祥市",
+            "code":"451481"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"海南省",
+    "code":"460000",
+    "sub":[
+      {
+        "name":"海口市",
+        "code":"460100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"460101"
+          },
+          {
+            "name":"秀英区",
+            "code":"460105"
+          },
+          {
+            "name":"龙华区",
+            "code":"460106"
+          },
+          {
+            "name":"琼山区",
+            "code":"460107"
+          },
+          {
+            "name":"美兰区",
+            "code":"460108"
+          }
+        ]
+      },
+      {
+        "name":"三亚市",
+        "code":"460200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"460201"
+          },
+          {
+            "name":"海棠区",
+            "code":"460202"
+          },
+          {
+            "name":"吉阳区",
+            "code":"460203"
+          },
+          {
+            "name":"天涯区",
+            "code":"460204"
+          },
+          {
+            "name":"崖州区",
+            "code":"460205"
+          }
+        ]
+      },
+      {
+        "name":"三沙市",
+        "code":"460300",
+        "sub":[
+          {
+            "name":"西沙群岛",
+            "code":"460321"
+          },
+          {
+            "name":"南沙群岛",
+            "code":"460322"
+          },
+          {
+            "name":"中沙群岛的岛礁及其海域",
+            "code":"460323"
+          }
+        ]
+      },
+      {
+        "name":"五指山市",
+        "code":"469001"
+      },
+      {
+        "name":"琼海市",
+        "code":"469002"
+      },
+      {
+        "name":"儋州市",
+        "code":"469003"
+      },
+      {
+        "name":"文昌市",
+        "code":"469005"
+      },
+      {
+        "name":"万宁市",
+        "code":"469006"
+      },
+      {
+        "name":"东方市",
+        "code":"469007"
+      },
+      {
+        "name":"定安县",
+        "code":"469021"
+      },
+      {
+        "name":"屯昌县",
+        "code":"469022"
+      },
+      {
+        "name":"澄迈县",
+        "code":"469023"
+      },
+      {
+        "name":"临高县",
+        "code":"469024"
+      },
+      {
+        "name":"白沙黎族自治县",
+        "code":"469025"
+      },
+      {
+        "name":"昌江黎族自治县",
+        "code":"469026"
+      },
+      {
+        "name":"乐东黎族自治县",
+        "code":"469027"
+      },
+      {
+        "name":"陵水黎族自治县",
+        "code":"469028"
+      },
+      {
+        "name":"保亭黎族苗族自治县",
+        "code":"469029"
+      },
+      {
+        "name":"琼中黎族苗族自治县",
+        "code":"469030"
+      }
+    ]
+  },
+  {
+    "name":"重庆",
+    "code":"500000",
+    "sub": [
+      {
+        "name": "重庆市",
+        "code": "500000",
+        "sub":[
+            {
+              "name":"万州区",
+              "code":"500101"
+            },
+            {
+              "name":"涪陵区",
+              "code":"500102"
+            },
+            {
+              "name":"渝中区",
+              "code":"500103"
+            },
+            {
+              "name":"大渡口区",
+              "code":"500104"
+            },
+            {
+              "name":"江北区",
+              "code":"500105"
+            },
+            {
+              "name":"沙坪坝区",
+              "code":"500106"
+            },
+            {
+              "name":"九龙坡区",
+              "code":"500107"
+            },
+            {
+              "name":"南岸区",
+              "code":"500108"
+            },
+            {
+              "name":"北碚区",
+              "code":"500109"
+            },
+            {
+              "name":"綦江区",
+              "code":"500110"
+            },
+            {
+              "name":"大足区",
+              "code":"500111"
+            },
+            {
+              "name":"渝北区",
+              "code":"500112"
+            },
+            {
+              "name":"巴南区",
+              "code":"500113"
+            },
+            {
+              "name":"黔江区",
+              "code":"500114"
+            },
+            {
+              "name":"长寿区",
+              "code":"500115"
+            },
+            {
+              "name":"江津区",
+              "code":"500116"
+            },
+            {
+              "name":"合川区",
+              "code":"500117"
+            },
+            {
+              "name":"永川区",
+              "code":"500118"
+            },
+            {
+              "name":"南川区",
+              "code":"500119"
+            },
+            {
+              "name":"璧山区",
+              "code":"500120"
+            },
+            {
+              "name":"铜梁区",
+              "code":"500151"
+            },
+            {
+              "name":"潼南县",
+              "code":"500223"
+            },
+            {
+              "name":"荣昌县",
+              "code":"500226"
+            },
+            {
+              "name":"梁平县",
+              "code":"500228"
+            },
+            {
+              "name":"城口县",
+              "code":"500229"
+            },
+            {
+              "name":"丰都县",
+              "code":"500230"
+            },
+            {
+              "name":"垫江县",
+              "code":"500231"
+            },
+            {
+              "name":"武隆县",
+              "code":"500232"
+            },
+            {
+              "name":"忠县",
+              "code":"500233"
+            },
+            {
+              "name":"开县",
+              "code":"500234"
+            },
+            {
+              "name":"云阳县",
+              "code":"500235"
+            },
+            {
+              "name":"奉节县",
+              "code":"500236"
+            },
+            {
+              "name":"巫山县",
+              "code":"500237"
+            },
+            {
+              "name":"巫溪县",
+              "code":"500238"
+            },
+            {
+              "name":"石柱土家族自治县",
+              "code":"500240"
+            },
+            {
+              "name":"秀山土家族苗族自治县",
+              "code":"500241"
+            },
+            {
+              "name":"酉阳土家族苗族自治县",
+              "code":"500242"
+            },
+            {
+              "name":"彭水苗族土家族自治县",
+              "code":"500243"
+            }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"四川省",
+    "code":"510000",
+    "sub":[
+      {
+        "name":"成都市",
+        "code":"510100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"510101"
+          },
+          {
+            "name":"锦江区",
+            "code":"510104"
+          },
+          {
+            "name":"青羊区",
+            "code":"510105"
+          },
+          {
+            "name":"金牛区",
+            "code":"510106"
+          },
+          {
+            "name":"武侯区",
+            "code":"510107"
+          },
+          {
+            "name":"成华区",
+            "code":"510108"
+          },
+          {
+            "name":"龙泉驿区",
+            "code":"510112"
+          },
+          {
+            "name":"青白江区",
+            "code":"510113"
+          },
+          {
+            "name":"新都区",
+            "code":"510114"
+          },
+          {
+            "name":"温江区",
+            "code":"510115"
+          },
+          {
+            "name":"金堂县",
+            "code":"510121"
+          },
+          {
+            "name":"双流县",
+            "code":"510122"
+          },
+          {
+            "name":"郫县",
+            "code":"510124"
+          },
+          {
+            "name":"大邑县",
+            "code":"510129"
+          },
+          {
+            "name":"蒲江县",
+            "code":"510131"
+          },
+          {
+            "name":"新津县",
+            "code":"510132"
+          },
+          {
+            "name":"都江堰市",
+            "code":"510181"
+          },
+          {
+            "name":"彭州市",
+            "code":"510182"
+          },
+          {
+            "name":"邛崃市",
+            "code":"510183"
+          },
+          {
+            "name":"崇州市",
+            "code":"510184"
+          }
+        ]
+      },
+      {
+        "name":"自贡市",
+        "code":"510300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"510301"
+          },
+          {
+            "name":"自流井区",
+            "code":"510302"
+          },
+          {
+            "name":"贡井区",
+            "code":"510303"
+          },
+          {
+            "name":"大安区",
+            "code":"510304"
+          },
+          {
+            "name":"沿滩区",
+            "code":"510311"
+          },
+          {
+            "name":"荣县",
+            "code":"510321"
+          },
+          {
+            "name":"富顺县",
+            "code":"510322"
+          }
+        ]
+      },
+      {
+        "name":"攀枝花市",
+        "code":"510400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"510401"
+          },
+          {
+            "name":"东区",
+            "code":"510402"
+          },
+          {
+            "name":"西区",
+            "code":"510403"
+          },
+          {
+            "name":"仁和区",
+            "code":"510411"
+          },
+          {
+            "name":"米易县",
+            "code":"510421"
+          },
+          {
+            "name":"盐边县",
+            "code":"510422"
+          }
+        ]
+      },
+      {
+        "name":"泸州市",
+        "code":"510500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"510501"
+          },
+          {
+            "name":"江阳区",
+            "code":"510502"
+          },
+          {
+            "name":"纳溪区",
+            "code":"510503"
+          },
+          {
+            "name":"龙马潭区",
+            "code":"510504"
+          },
+          {
+            "name":"泸县",
+            "code":"510521"
+          },
+          {
+            "name":"合江县",
+            "code":"510522"
+          },
+          {
+            "name":"叙永县",
+            "code":"510524"
+          },
+          {
+            "name":"古蔺县",
+            "code":"510525"
+          }
+        ]
+      },
+      {
+        "name":"德阳市",
+        "code":"510600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"510601"
+          },
+          {
+            "name":"旌阳区",
+            "code":"510603"
+          },
+          {
+            "name":"中江县",
+            "code":"510623"
+          },
+          {
+            "name":"罗江县",
+            "code":"510626"
+          },
+          {
+            "name":"广汉市",
+            "code":"510681"
+          },
+          {
+            "name":"什邡市",
+            "code":"510682"
+          },
+          {
+            "name":"绵竹市",
+            "code":"510683"
+          }
+        ]
+      },
+      {
+        "name":"绵阳市",
+        "code":"510700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"510701"
+          },
+          {
+            "name":"涪城区",
+            "code":"510703"
+          },
+          {
+            "name":"游仙区",
+            "code":"510704"
+          },
+          {
+            "name":"三台县",
+            "code":"510722"
+          },
+          {
+            "name":"盐亭县",
+            "code":"510723"
+          },
+          {
+            "name":"安县",
+            "code":"510724"
+          },
+          {
+            "name":"梓潼县",
+            "code":"510725"
+          },
+          {
+            "name":"北川羌族自治县",
+            "code":"510726"
+          },
+          {
+            "name":"平武县",
+            "code":"510727"
+          },
+          {
+            "name":"江油市",
+            "code":"510781"
+          }
+        ]
+      },
+      {
+        "name":"广元市",
+        "code":"510800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"510801"
+          },
+          {
+            "name":"利州区",
+            "code":"510802"
+          },
+          {
+            "name":"昭化区",
+            "code":"510811"
+          },
+          {
+            "name":"朝天区",
+            "code":"510812"
+          },
+          {
+            "name":"旺苍县",
+            "code":"510821"
+          },
+          {
+            "name":"青川县",
+            "code":"510822"
+          },
+          {
+            "name":"剑阁县",
+            "code":"510823"
+          },
+          {
+            "name":"苍溪县",
+            "code":"510824"
+          }
+        ]
+      },
+      {
+        "name":"遂宁市",
+        "code":"510900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"510901"
+          },
+          {
+            "name":"船山区",
+            "code":"510903"
+          },
+          {
+            "name":"安居区",
+            "code":"510904"
+          },
+          {
+            "name":"蓬溪县",
+            "code":"510921"
+          },
+          {
+            "name":"射洪县",
+            "code":"510922"
+          },
+          {
+            "name":"大英县",
+            "code":"510923"
+          }
+        ]
+      },
+      {
+        "name":"内江市",
+        "code":"511000",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"511001"
+          },
+          {
+            "name":"市中区",
+            "code":"511002"
+          },
+          {
+            "name":"东兴区",
+            "code":"511011"
+          },
+          {
+            "name":"威远县",
+            "code":"511024"
+          },
+          {
+            "name":"资中县",
+            "code":"511025"
+          },
+          {
+            "name":"隆昌县",
+            "code":"511028"
+          }
+        ]
+      },
+      {
+        "name":"乐山市",
+        "code":"511100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"511101"
+          },
+          {
+            "name":"市中区",
+            "code":"511102"
+          },
+          {
+            "name":"沙湾区",
+            "code":"511111"
+          },
+          {
+            "name":"五通桥区",
+            "code":"511112"
+          },
+          {
+            "name":"金口河区",
+            "code":"511113"
+          },
+          {
+            "name":"犍为县",
+            "code":"511123"
+          },
+          {
+            "name":"井研县",
+            "code":"511124"
+          },
+          {
+            "name":"夹江县",
+            "code":"511126"
+          },
+          {
+            "name":"沐川县",
+            "code":"511129"
+          },
+          {
+            "name":"峨边彝族自治县",
+            "code":"511132"
+          },
+          {
+            "name":"马边彝族自治县",
+            "code":"511133"
+          },
+          {
+            "name":"峨眉山市",
+            "code":"511181"
+          }
+        ]
+      },
+      {
+        "name":"南充市",
+        "code":"511300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"511301"
+          },
+          {
+            "name":"顺庆区",
+            "code":"511302"
+          },
+          {
+            "name":"高坪区",
+            "code":"511303"
+          },
+          {
+            "name":"嘉陵区",
+            "code":"511304"
+          },
+          {
+            "name":"南部县",
+            "code":"511321"
+          },
+          {
+            "name":"营山县",
+            "code":"511322"
+          },
+          {
+            "name":"蓬安县",
+            "code":"511323"
+          },
+          {
+            "name":"仪陇县",
+            "code":"511324"
+          },
+          {
+            "name":"西充县",
+            "code":"511325"
+          },
+          {
+            "name":"阆中市",
+            "code":"511381"
+          }
+        ]
+      },
+      {
+        "name":"眉山市",
+        "code":"511400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"511401"
+          },
+          {
+            "name":"东坡区",
+            "code":"511402"
+          },
+          {
+            "name":"彭山区",
+            "code":"511403"
+          },
+          {
+            "name":"仁寿县",
+            "code":"511421"
+          },
+          {
+            "name":"洪雅县",
+            "code":"511423"
+          },
+          {
+            "name":"丹棱县",
+            "code":"511424"
+          },
+          {
+            "name":"青神县",
+            "code":"511425"
+          }
+        ]
+      },
+      {
+        "name":"宜宾市",
+        "code":"511500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"511501"
+          },
+          {
+            "name":"翠屏区",
+            "code":"511502"
+          },
+          {
+            "name":"南溪区",
+            "code":"511503"
+          },
+          {
+            "name":"宜宾县",
+            "code":"511521"
+          },
+          {
+            "name":"江安县",
+            "code":"511523"
+          },
+          {
+            "name":"长宁县",
+            "code":"511524"
+          },
+          {
+            "name":"高县",
+            "code":"511525"
+          },
+          {
+            "name":"珙县",
+            "code":"511526"
+          },
+          {
+            "name":"筠连县",
+            "code":"511527"
+          },
+          {
+            "name":"兴文县",
+            "code":"511528"
+          },
+          {
+            "name":"屏山县",
+            "code":"511529"
+          }
+        ]
+      },
+      {
+        "name":"广安市",
+        "code":"511600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"511601"
+          },
+          {
+            "name":"广安区",
+            "code":"511602"
+          },
+          {
+            "name":"前锋区",
+            "code":"511603"
+          },
+          {
+            "name":"岳池县",
+            "code":"511621"
+          },
+          {
+            "name":"武胜县",
+            "code":"511622"
+          },
+          {
+            "name":"邻水县",
+            "code":"511623"
+          },
+          {
+            "name":"华蓥市",
+            "code":"511681"
+          }
+        ]
+      },
+      {
+        "name":"达州市",
+        "code":"511700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"511701"
+          },
+          {
+            "name":"通川区",
+            "code":"511702"
+          },
+          {
+            "name":"达川区",
+            "code":"511703"
+          },
+          {
+            "name":"宣汉县",
+            "code":"511722"
+          },
+          {
+            "name":"开江县",
+            "code":"511723"
+          },
+          {
+            "name":"大竹县",
+            "code":"511724"
+          },
+          {
+            "name":"渠县",
+            "code":"511725"
+          },
+          {
+            "name":"万源市",
+            "code":"511781"
+          }
+        ]
+      },
+      {
+        "name":"雅安市",
+        "code":"511800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"511801"
+          },
+          {
+            "name":"雨城区",
+            "code":"511802"
+          },
+          {
+            "name":"名山区",
+            "code":"511803"
+          },
+          {
+            "name":"荥经县",
+            "code":"511822"
+          },
+          {
+            "name":"汉源县",
+            "code":"511823"
+          },
+          {
+            "name":"石棉县",
+            "code":"511824"
+          },
+          {
+            "name":"天全县",
+            "code":"511825"
+          },
+          {
+            "name":"芦山县",
+            "code":"511826"
+          },
+          {
+            "name":"宝兴县",
+            "code":"511827"
+          }
+        ]
+      },
+      {
+        "name":"巴中市",
+        "code":"511900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"511901"
+          },
+          {
+            "name":"巴州区",
+            "code":"511902"
+          },
+          {
+            "name":"恩阳区",
+            "code":"511903"
+          },
+          {
+            "name":"通江县",
+            "code":"511921"
+          },
+          {
+            "name":"南江县",
+            "code":"511922"
+          },
+          {
+            "name":"平昌县",
+            "code":"511923"
+          }
+        ]
+      },
+      {
+        "name":"资阳市",
+        "code":"512000",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"512001"
+          },
+          {
+            "name":"雁江区",
+            "code":"512002"
+          },
+          {
+            "name":"安岳县",
+            "code":"512021"
+          },
+          {
+            "name":"乐至县",
+            "code":"512022"
+          },
+          {
+            "name":"简阳市",
+            "code":"512081"
+          }
+        ]
+      },
+      {
+        "name":"阿坝藏族羌族自治州",
+        "code":"513200",
+        "sub":[
+          {
+            "name":"汶川县",
+            "code":"513221"
+          },
+          {
+            "name":"理县",
+            "code":"513222"
+          },
+          {
+            "name":"茂县",
+            "code":"513223"
+          },
+          {
+            "name":"松潘县",
+            "code":"513224"
+          },
+          {
+            "name":"九寨沟县",
+            "code":"513225"
+          },
+          {
+            "name":"金川县",
+            "code":"513226"
+          },
+          {
+            "name":"小金县",
+            "code":"513227"
+          },
+          {
+            "name":"黑水县",
+            "code":"513228"
+          },
+          {
+            "name":"马尔康县",
+            "code":"513229"
+          },
+          {
+            "name":"壤塘县",
+            "code":"513230"
+          },
+          {
+            "name":"阿坝县",
+            "code":"513231"
+          },
+          {
+            "name":"若尔盖县",
+            "code":"513232"
+          },
+          {
+            "name":"红原县",
+            "code":"513233"
+          }
+        ]
+      },
+      {
+        "name":"甘孜藏族自治州",
+        "code":"513300",
+        "sub":[
+          {
+            "name":"康定县",
+            "code":"513321"
+          },
+          {
+            "name":"泸定县",
+            "code":"513322"
+          },
+          {
+            "name":"丹巴县",
+            "code":"513323"
+          },
+          {
+            "name":"九龙县",
+            "code":"513324"
+          },
+          {
+            "name":"雅江县",
+            "code":"513325"
+          },
+          {
+            "name":"道孚县",
+            "code":"513326"
+          },
+          {
+            "name":"炉霍县",
+            "code":"513327"
+          },
+          {
+            "name":"甘孜县",
+            "code":"513328"
+          },
+          {
+            "name":"新龙县",
+            "code":"513329"
+          },
+          {
+            "name":"德格县",
+            "code":"513330"
+          },
+          {
+            "name":"白玉县",
+            "code":"513331"
+          },
+          {
+            "name":"石渠县",
+            "code":"513332"
+          },
+          {
+            "name":"色达县",
+            "code":"513333"
+          },
+          {
+            "name":"理塘县",
+            "code":"513334"
+          },
+          {
+            "name":"巴塘县",
+            "code":"513335"
+          },
+          {
+            "name":"乡城县",
+            "code":"513336"
+          },
+          {
+            "name":"稻城县",
+            "code":"513337"
+          },
+          {
+            "name":"得荣县",
+            "code":"513338"
+          }
+        ]
+      },
+      {
+        "name":"凉山彝族自治州",
+        "code":"513400",
+        "sub":[
+          {
+            "name":"西昌市",
+            "code":"513401"
+          },
+          {
+            "name":"木里藏族自治县",
+            "code":"513422"
+          },
+          {
+            "name":"盐源县",
+            "code":"513423"
+          },
+          {
+            "name":"德昌县",
+            "code":"513424"
+          },
+          {
+            "name":"会理县",
+            "code":"513425"
+          },
+          {
+            "name":"会东县",
+            "code":"513426"
+          },
+          {
+            "name":"宁南县",
+            "code":"513427"
+          },
+          {
+            "name":"普格县",
+            "code":"513428"
+          },
+          {
+            "name":"布拖县",
+            "code":"513429"
+          },
+          {
+            "name":"金阳县",
+            "code":"513430"
+          },
+          {
+            "name":"昭觉县",
+            "code":"513431"
+          },
+          {
+            "name":"喜德县",
+            "code":"513432"
+          },
+          {
+            "name":"冕宁县",
+            "code":"513433"
+          },
+          {
+            "name":"越西县",
+            "code":"513434"
+          },
+          {
+            "name":"甘洛县",
+            "code":"513435"
+          },
+          {
+            "name":"美姑县",
+            "code":"513436"
+          },
+          {
+            "name":"雷波县",
+            "code":"513437"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"贵州省",
+    "code":"520000",
+    "sub":[
+      {
+        "name":"贵阳市",
+        "code":"520100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"520101"
+          },
+          {
+            "name":"南明区",
+            "code":"520102"
+          },
+          {
+            "name":"云岩区",
+            "code":"520103"
+          },
+          {
+            "name":"花溪区",
+            "code":"520111"
+          },
+          {
+            "name":"乌当区",
+            "code":"520112"
+          },
+          {
+            "name":"白云区",
+            "code":"520113"
+          },
+          {
+            "name":"观山湖区",
+            "code":"520115"
+          },
+          {
+            "name":"开阳县",
+            "code":"520121"
+          },
+          {
+            "name":"息烽县",
+            "code":"520122"
+          },
+          {
+            "name":"修文县",
+            "code":"520123"
+          },
+          {
+            "name":"清镇市",
+            "code":"520181"
+          }
+        ]
+      },
+      {
+        "name":"六盘水市",
+        "code":"520200",
+        "sub":[
+          {
+            "name":"钟山区",
+            "code":"520201"
+          },
+          {
+            "name":"六枝特区",
+            "code":"520203"
+          },
+          {
+            "name":"水城县",
+            "code":"520221"
+          },
+          {
+            "name":"盘县",
+            "code":"520222"
+          }
+        ]
+      },
+      {
+        "name":"遵义市",
+        "code":"520300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"520301"
+          },
+          {
+            "name":"红花岗区",
+            "code":"520302"
+          },
+          {
+            "name":"汇川区",
+            "code":"520303"
+          },
+          {
+            "name":"遵义县",
+            "code":"520321"
+          },
+          {
+            "name":"桐梓县",
+            "code":"520322"
+          },
+          {
+            "name":"绥阳县",
+            "code":"520323"
+          },
+          {
+            "name":"正安县",
+            "code":"520324"
+          },
+          {
+            "name":"道真仡佬族苗族自治县",
+            "code":"520325"
+          },
+          {
+            "name":"务川仡佬族苗族自治县",
+            "code":"520326"
+          },
+          {
+            "name":"凤冈县",
+            "code":"520327"
+          },
+          {
+            "name":"湄潭县",
+            "code":"520328"
+          },
+          {
+            "name":"余庆县",
+            "code":"520329"
+          },
+          {
+            "name":"习水县",
+            "code":"520330"
+          },
+          {
+            "name":"赤水市",
+            "code":"520381"
+          },
+          {
+            "name":"仁怀市",
+            "code":"520382"
+          }
+        ]
+      },
+      {
+        "name":"安顺市",
+        "code":"520400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"520401"
+          },
+          {
+            "name":"西秀区",
+            "code":"520402"
+          },
+          {
+            "name":"平坝区",
+            "code":"520403"
+          },
+          {
+            "name":"普定县",
+            "code":"520422"
+          },
+          {
+            "name":"镇宁布依族苗族自治县",
+            "code":"520423"
+          },
+          {
+            "name":"关岭布依族苗族自治县",
+            "code":"520424"
+          },
+          {
+            "name":"紫云苗族布依族自治县",
+            "code":"520425"
+          }
+        ]
+      },
+      {
+        "name":"毕节市",
+        "code":"520500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"520501"
+          },
+          {
+            "name":"七星关区",
+            "code":"520502"
+          },
+          {
+            "name":"大方县",
+            "code":"520521"
+          },
+          {
+            "name":"黔西县",
+            "code":"520522"
+          },
+          {
+            "name":"金沙县",
+            "code":"520523"
+          },
+          {
+            "name":"织金县",
+            "code":"520524"
+          },
+          {
+            "name":"纳雍县",
+            "code":"520525"
+          },
+          {
+            "name":"威宁彝族回族苗族自治县",
+            "code":"520526"
+          },
+          {
+            "name":"赫章县",
+            "code":"520527"
+          }
+        ]
+      },
+      {
+        "name":"铜仁市",
+        "code":"520600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"520601"
+          },
+          {
+            "name":"碧江区",
+            "code":"520602"
+          },
+          {
+            "name":"万山区",
+            "code":"520603"
+          },
+          {
+            "name":"江口县",
+            "code":"520621"
+          },
+          {
+            "name":"玉屏侗族自治县",
+            "code":"520622"
+          },
+          {
+            "name":"石阡县",
+            "code":"520623"
+          },
+          {
+            "name":"思南县",
+            "code":"520624"
+          },
+          {
+            "name":"印江土家族苗族自治县",
+            "code":"520625"
+          },
+          {
+            "name":"德江县",
+            "code":"520626"
+          },
+          {
+            "name":"沿河土家族自治县",
+            "code":"520627"
+          },
+          {
+            "name":"松桃苗族自治县",
+            "code":"520628"
+          }
+        ]
+      },
+      {
+        "name":"黔西南布依族苗族自治州",
+        "code":"522300",
+        "sub":[
+          {
+            "name":"兴义市",
+            "code":"522301"
+          },
+          {
+            "name":"兴仁县",
+            "code":"522322"
+          },
+          {
+            "name":"普安县",
+            "code":"522323"
+          },
+          {
+            "name":"晴隆县",
+            "code":"522324"
+          },
+          {
+            "name":"贞丰县",
+            "code":"522325"
+          },
+          {
+            "name":"望谟县",
+            "code":"522326"
+          },
+          {
+            "name":"册亨县",
+            "code":"522327"
+          },
+          {
+            "name":"安龙县",
+            "code":"522328"
+          }
+        ]
+      },
+      {
+        "name":"黔东南苗族侗族自治州",
+        "code":"522600",
+        "sub":[
+          {
+            "name":"凯里市",
+            "code":"522601"
+          },
+          {
+            "name":"黄平县",
+            "code":"522622"
+          },
+          {
+            "name":"施秉县",
+            "code":"522623"
+          },
+          {
+            "name":"三穗县",
+            "code":"522624"
+          },
+          {
+            "name":"镇远县",
+            "code":"522625"
+          },
+          {
+            "name":"岑巩县",
+            "code":"522626"
+          },
+          {
+            "name":"天柱县",
+            "code":"522627"
+          },
+          {
+            "name":"锦屏县",
+            "code":"522628"
+          },
+          {
+            "name":"剑河县",
+            "code":"522629"
+          },
+          {
+            "name":"台江县",
+            "code":"522630"
+          },
+          {
+            "name":"黎平县",
+            "code":"522631"
+          },
+          {
+            "name":"榕江县",
+            "code":"522632"
+          },
+          {
+            "name":"从江县",
+            "code":"522633"
+          },
+          {
+            "name":"雷山县",
+            "code":"522634"
+          },
+          {
+            "name":"麻江县",
+            "code":"522635"
+          },
+          {
+            "name":"丹寨县",
+            "code":"522636"
+          }
+        ]
+      },
+      {
+        "name":"黔南布依族苗族自治州",
+        "code":"522700",
+        "sub":[
+          {
+            "name":"都匀市",
+            "code":"522701"
+          },
+          {
+            "name":"福泉市",
+            "code":"522702"
+          },
+          {
+            "name":"荔波县",
+            "code":"522722"
+          },
+          {
+            "name":"贵定县",
+            "code":"522723"
+          },
+          {
+            "name":"瓮安县",
+            "code":"522725"
+          },
+          {
+            "name":"独山县",
+            "code":"522726"
+          },
+          {
+            "name":"平塘县",
+            "code":"522727"
+          },
+          {
+            "name":"罗甸县",
+            "code":"522728"
+          },
+          {
+            "name":"长顺县",
+            "code":"522729"
+          },
+          {
+            "name":"龙里县",
+            "code":"522730"
+          },
+          {
+            "name":"惠水县",
+            "code":"522731"
+          },
+          {
+            "name":"三都水族自治县",
+            "code":"522732"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"云南省",
+    "code":"530000",
+    "sub":[
+      {
+        "name":"昆明市",
+        "code":"530100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"530101"
+          },
+          {
+            "name":"五华区",
+            "code":"530102"
+          },
+          {
+            "name":"盘龙区",
+            "code":"530103"
+          },
+          {
+            "name":"官渡区",
+            "code":"530111"
+          },
+          {
+            "name":"西山区",
+            "code":"530112"
+          },
+          {
+            "name":"东川区",
+            "code":"530113"
+          },
+          {
+            "name":"呈贡区",
+            "code":"530114"
+          },
+          {
+            "name":"晋宁县",
+            "code":"530122"
+          },
+          {
+            "name":"富民县",
+            "code":"530124"
+          },
+          {
+            "name":"宜良县",
+            "code":"530125"
+          },
+          {
+            "name":"石林彝族自治县",
+            "code":"530126"
+          },
+          {
+            "name":"嵩明县",
+            "code":"530127"
+          },
+          {
+            "name":"禄劝彝族苗族自治县",
+            "code":"530128"
+          },
+          {
+            "name":"寻甸回族彝族自治县",
+            "code":"530129"
+          },
+          {
+            "name":"安宁市",
+            "code":"530181"
+          }
+        ]
+      },
+      {
+        "name":"曲靖市",
+        "code":"530300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"530301"
+          },
+          {
+            "name":"麒麟区",
+            "code":"530302"
+          },
+          {
+            "name":"马龙县",
+            "code":"530321"
+          },
+          {
+            "name":"陆良县",
+            "code":"530322"
+          },
+          {
+            "name":"师宗县",
+            "code":"530323"
+          },
+          {
+            "name":"罗平县",
+            "code":"530324"
+          },
+          {
+            "name":"富源县",
+            "code":"530325"
+          },
+          {
+            "name":"会泽县",
+            "code":"530326"
+          },
+          {
+            "name":"沾益县",
+            "code":"530328"
+          },
+          {
+            "name":"宣威市",
+            "code":"530381"
+          }
+        ]
+      },
+      {
+        "name":"玉溪市",
+        "code":"530400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"530401"
+          },
+          {
+            "name":"红塔区",
+            "code":"530402"
+          },
+          {
+            "name":"江川县",
+            "code":"530421"
+          },
+          {
+            "name":"澄江县",
+            "code":"530422"
+          },
+          {
+            "name":"通海县",
+            "code":"530423"
+          },
+          {
+            "name":"华宁县",
+            "code":"530424"
+          },
+          {
+            "name":"易门县",
+            "code":"530425"
+          },
+          {
+            "name":"峨山彝族自治县",
+            "code":"530426"
+          },
+          {
+            "name":"新平彝族傣族自治县",
+            "code":"530427"
+          },
+          {
+            "name":"元江哈尼族彝族傣族自治县",
+            "code":"530428"
+          }
+        ]
+      },
+      {
+        "name":"保山市",
+        "code":"530500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"530501"
+          },
+          {
+            "name":"隆阳区",
+            "code":"530502"
+          },
+          {
+            "name":"施甸县",
+            "code":"530521"
+          },
+          {
+            "name":"腾冲县",
+            "code":"530522"
+          },
+          {
+            "name":"龙陵县",
+            "code":"530523"
+          },
+          {
+            "name":"昌宁县",
+            "code":"530524"
+          }
+        ]
+      },
+      {
+        "name":"昭通市",
+        "code":"530600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"530601"
+          },
+          {
+            "name":"昭阳区",
+            "code":"530602"
+          },
+          {
+            "name":"鲁甸县",
+            "code":"530621"
+          },
+          {
+            "name":"巧家县",
+            "code":"530622"
+          },
+          {
+            "name":"盐津县",
+            "code":"530623"
+          },
+          {
+            "name":"大关县",
+            "code":"530624"
+          },
+          {
+            "name":"永善县",
+            "code":"530625"
+          },
+          {
+            "name":"绥江县",
+            "code":"530626"
+          },
+          {
+            "name":"镇雄县",
+            "code":"530627"
+          },
+          {
+            "name":"彝良县",
+            "code":"530628"
+          },
+          {
+            "name":"威信县",
+            "code":"530629"
+          },
+          {
+            "name":"水富县",
+            "code":"530630"
+          }
+        ]
+      },
+      {
+        "name":"丽江市",
+        "code":"530700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"530701"
+          },
+          {
+            "name":"古城区",
+            "code":"530702"
+          },
+          {
+            "name":"玉龙纳西族自治县",
+            "code":"530721"
+          },
+          {
+            "name":"永胜县",
+            "code":"530722"
+          },
+          {
+            "name":"华坪县",
+            "code":"530723"
+          },
+          {
+            "name":"宁蒗彝族自治县",
+            "code":"530724"
+          }
+        ]
+      },
+      {
+        "name":"普洱市",
+        "code":"530800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"530801"
+          },
+          {
+            "name":"思茅区",
+            "code":"530802"
+          },
+          {
+            "name":"宁洱哈尼族彝族自治县",
+            "code":"530821"
+          },
+          {
+            "name":"墨江哈尼族自治县",
+            "code":"530822"
+          },
+          {
+            "name":"景东彝族自治县",
+            "code":"530823"
+          },
+          {
+            "name":"景谷傣族彝族自治县",
+            "code":"530824"
+          },
+          {
+            "name":"镇沅彝族哈尼族拉祜族自治县",
+            "code":"530825"
+          },
+          {
+            "name":"江城哈尼族彝族自治县",
+            "code":"530826"
+          },
+          {
+            "name":"孟连傣族拉祜族佤族自治县",
+            "code":"530827"
+          },
+          {
+            "name":"澜沧拉祜族自治县",
+            "code":"530828"
+          },
+          {
+            "name":"西盟佤族自治县",
+            "code":"530829"
+          }
+        ]
+      },
+      {
+        "name":"临沧市",
+        "code":"530900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"530901"
+          },
+          {
+            "name":"临翔区",
+            "code":"530902"
+          },
+          {
+            "name":"凤庆县",
+            "code":"530921"
+          },
+          {
+            "name":"云县",
+            "code":"530922"
+          },
+          {
+            "name":"永德县",
+            "code":"530923"
+          },
+          {
+            "name":"镇康县",
+            "code":"530924"
+          },
+          {
+            "name":"双江拉祜族佤族布朗族傣族自治县",
+            "code":"530925"
+          },
+          {
+            "name":"耿马傣族佤族自治县",
+            "code":"530926"
+          },
+          {
+            "name":"沧源佤族自治县",
+            "code":"530927"
+          }
+        ]
+      },
+      {
+        "name":"楚雄彝族自治州",
+        "code":"532300",
+        "sub":[
+          {
+            "name":"楚雄市",
+            "code":"532301"
+          },
+          {
+            "name":"双柏县",
+            "code":"532322"
+          },
+          {
+            "name":"牟定县",
+            "code":"532323"
+          },
+          {
+            "name":"南华县",
+            "code":"532324"
+          },
+          {
+            "name":"姚安县",
+            "code":"532325"
+          },
+          {
+            "name":"大姚县",
+            "code":"532326"
+          },
+          {
+            "name":"永仁县",
+            "code":"532327"
+          },
+          {
+            "name":"元谋县",
+            "code":"532328"
+          },
+          {
+            "name":"武定县",
+            "code":"532329"
+          },
+          {
+            "name":"禄丰县",
+            "code":"532331"
+          }
+        ]
+      },
+      {
+        "name":"红河哈尼族彝族自治州",
+        "code":"532500",
+        "sub":[
+          {
+            "name":"个旧市",
+            "code":"532501"
+          },
+          {
+            "name":"开远市",
+            "code":"532502"
+          },
+          {
+            "name":"蒙自市",
+            "code":"532503"
+          },
+          {
+            "name":"弥勒市",
+            "code":"532504"
+          },
+          {
+            "name":"屏边苗族自治县",
+            "code":"532523"
+          },
+          {
+            "name":"建水县",
+            "code":"532524"
+          },
+          {
+            "name":"石屏县",
+            "code":"532525"
+          },
+          {
+            "name":"泸西县",
+            "code":"532527"
+          },
+          {
+            "name":"元阳县",
+            "code":"532528"
+          },
+          {
+            "name":"红河县",
+            "code":"532529"
+          },
+          {
+            "name":"金平苗族瑶族傣族自治县",
+            "code":"532530"
+          },
+          {
+            "name":"绿春县",
+            "code":"532531"
+          },
+          {
+            "name":"河口瑶族自治县",
+            "code":"532532"
+          }
+        ]
+      },
+      {
+        "name":"文山壮族苗族自治州",
+        "code":"532600",
+        "sub":[
+          {
+            "name":"文山市",
+            "code":"532601"
+          },
+          {
+            "name":"砚山县",
+            "code":"532622"
+          },
+          {
+            "name":"西畴县",
+            "code":"532623"
+          },
+          {
+            "name":"麻栗坡县",
+            "code":"532624"
+          },
+          {
+            "name":"马关县",
+            "code":"532625"
+          },
+          {
+            "name":"丘北县",
+            "code":"532626"
+          },
+          {
+            "name":"广南县",
+            "code":"532627"
+          },
+          {
+            "name":"富宁县",
+            "code":"532628"
+          }
+        ]
+      },
+      {
+        "name":"西双版纳傣族自治州",
+        "code":"532800",
+        "sub":[
+          {
+            "name":"景洪市",
+            "code":"532801"
+          },
+          {
+            "name":"勐海县",
+            "code":"532822"
+          },
+          {
+            "name":"勐腊县",
+            "code":"532823"
+          }
+        ]
+      },
+      {
+        "name":"大理白族自治州",
+        "code":"532900",
+        "sub":[
+          {
+            "name":"大理市",
+            "code":"532901"
+          },
+          {
+            "name":"漾濞彝族自治县",
+            "code":"532922"
+          },
+          {
+            "name":"祥云县",
+            "code":"532923"
+          },
+          {
+            "name":"宾川县",
+            "code":"532924"
+          },
+          {
+            "name":"弥渡县",
+            "code":"532925"
+          },
+          {
+            "name":"南涧彝族自治县",
+            "code":"532926"
+          },
+          {
+            "name":"巍山彝族回族自治县",
+            "code":"532927"
+          },
+          {
+            "name":"永平县",
+            "code":"532928"
+          },
+          {
+            "name":"云龙县",
+            "code":"532929"
+          },
+          {
+            "name":"洱源县",
+            "code":"532930"
+          },
+          {
+            "name":"剑川县",
+            "code":"532931"
+          },
+          {
+            "name":"鹤庆县",
+            "code":"532932"
+          }
+        ]
+      },
+      {
+        "name":"德宏傣族景颇族自治州",
+        "code":"533100",
+        "sub":[
+          {
+            "name":"瑞丽市",
+            "code":"533102"
+          },
+          {
+            "name":"芒市",
+            "code":"533103"
+          },
+          {
+            "name":"梁河县",
+            "code":"533122"
+          },
+          {
+            "name":"盈江县",
+            "code":"533123"
+          },
+          {
+            "name":"陇川县",
+            "code":"533124"
+          }
+        ]
+      },
+      {
+        "name":"怒江傈僳族自治州",
+        "code":"533300",
+        "sub":[
+          {
+            "name":"泸水县",
+            "code":"533321"
+          },
+          {
+            "name":"福贡县",
+            "code":"533323"
+          },
+          {
+            "name":"贡山独龙族怒族自治县",
+            "code":"533324"
+          },
+          {
+            "name":"兰坪白族普米族自治县",
+            "code":"533325"
+          }
+        ]
+      },
+      {
+        "name":"迪庆藏族自治州",
+        "code":"533400",
+        "sub":[
+          {
+            "name":"香格里拉市",
+            "code":"533401"
+          },
+          {
+            "name":"德钦县",
+            "code":"533422"
+          },
+          {
+            "name":"维西傈僳族自治县",
+            "code":"533423"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"西藏自治区",
+    "code":"540000",
+    "sub":[
+      {
+        "name":"拉萨市",
+        "code":"540100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"540101"
+          },
+          {
+            "name":"城关区",
+            "code":"540102"
+          },
+          {
+            "name":"林周县",
+            "code":"540121"
+          },
+          {
+            "name":"当雄县",
+            "code":"540122"
+          },
+          {
+            "name":"尼木县",
+            "code":"540123"
+          },
+          {
+            "name":"曲水县",
+            "code":"540124"
+          },
+          {
+            "name":"堆龙德庆县",
+            "code":"540125"
+          },
+          {
+            "name":"达孜县",
+            "code":"540126"
+          },
+          {
+            "name":"墨竹工卡县",
+            "code":"540127"
+          }
+        ]
+      },
+      {
+        "name":"日喀则市",
+        "code":"540200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"540201"
+          },
+          {
+            "name":"桑珠孜区",
+            "code":"540202"
+          },
+          {
+            "name":"南木林县",
+            "code":"540221"
+          },
+          {
+            "name":"江孜县",
+            "code":"540222"
+          },
+          {
+            "name":"定日县",
+            "code":"540223"
+          },
+          {
+            "name":"萨迦县",
+            "code":"540224"
+          },
+          {
+            "name":"拉孜县",
+            "code":"540225"
+          },
+          {
+            "name":"昂仁县",
+            "code":"540226"
+          },
+          {
+            "name":"谢通门县",
+            "code":"540227"
+          },
+          {
+            "name":"白朗县",
+            "code":"540228"
+          },
+          {
+            "name":"仁布县",
+            "code":"540229"
+          },
+          {
+            "name":"康马县",
+            "code":"540230"
+          },
+          {
+            "name":"定结县",
+            "code":"540231"
+          },
+          {
+            "name":"仲巴县",
+            "code":"540232"
+          },
+          {
+            "name":"亚东县",
+            "code":"540233"
+          },
+          {
+            "name":"吉隆县",
+            "code":"540234"
+          },
+          {
+            "name":"聂拉木县",
+            "code":"540235"
+          },
+          {
+            "name":"萨嘎县",
+            "code":"540236"
+          },
+          {
+            "name":"岗巴县",
+            "code":"540237"
+          }
+        ]
+      },
+      {
+        "name":"昌都市",
+        "code":"540300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"540301"
+          },
+          {
+            "name":"卡若区",
+            "code":"540302"
+          },
+          {
+            "name":"江达县",
+            "code":"540321"
+          },
+          {
+            "name":"贡觉县",
+            "code":"540322"
+          },
+          {
+            "name":"类乌齐县",
+            "code":"540323"
+          },
+          {
+            "name":"丁青县",
+            "code":"540324"
+          },
+          {
+            "name":"察雅县",
+            "code":"540325"
+          },
+          {
+            "name":"八宿县",
+            "code":"540326"
+          },
+          {
+            "name":"左贡县",
+            "code":"540327"
+          },
+          {
+            "name":"芒康县",
+            "code":"540328"
+          },
+          {
+            "name":"洛隆县",
+            "code":"540329"
+          },
+          {
+            "name":"边坝县",
+            "code":"540330"
+          }
+        ]
+      },
+      {
+        "name":"山南地区",
+        "code":"542200",
+        "sub":[
+          {
+            "name":"乃东县",
+            "code":"542221"
+          },
+          {
+            "name":"扎囊县",
+            "code":"542222"
+          },
+          {
+            "name":"贡嘎县",
+            "code":"542223"
+          },
+          {
+            "name":"桑日县",
+            "code":"542224"
+          },
+          {
+            "name":"琼结县",
+            "code":"542225"
+          },
+          {
+            "name":"曲松县",
+            "code":"542226"
+          },
+          {
+            "name":"措美县",
+            "code":"542227"
+          },
+          {
+            "name":"洛扎县",
+            "code":"542228"
+          },
+          {
+            "name":"加查县",
+            "code":"542229"
+          },
+          {
+            "name":"隆子县",
+            "code":"542231"
+          },
+          {
+            "name":"错那县",
+            "code":"542232"
+          },
+          {
+            "name":"浪卡子县",
+            "code":"542233"
+          }
+        ]
+      },
+      {
+        "name":"那曲地区",
+        "code":"542400",
+        "sub":[
+          {
+            "name":"那曲县",
+            "code":"542421"
+          },
+          {
+            "name":"嘉黎县",
+            "code":"542422"
+          },
+          {
+            "name":"比如县",
+            "code":"542423"
+          },
+          {
+            "name":"聂荣县",
+            "code":"542424"
+          },
+          {
+            "name":"安多县",
+            "code":"542425"
+          },
+          {
+            "name":"申扎县",
+            "code":"542426"
+          },
+          {
+            "name":"索县",
+            "code":"542427"
+          },
+          {
+            "name":"班戈县",
+            "code":"542428"
+          },
+          {
+            "name":"巴青县",
+            "code":"542429"
+          },
+          {
+            "name":"尼玛县",
+            "code":"542430"
+          },
+          {
+            "name":"双湖县",
+            "code":"542431"
+          }
+        ]
+      },
+      {
+        "name":"阿里地区",
+        "code":"542500",
+        "sub":[
+          {
+            "name":"普兰县",
+            "code":"542521"
+          },
+          {
+            "name":"札达县",
+            "code":"542522"
+          },
+          {
+            "name":"噶尔县",
+            "code":"542523"
+          },
+          {
+            "name":"日土县",
+            "code":"542524"
+          },
+          {
+            "name":"革吉县",
+            "code":"542525"
+          },
+          {
+            "name":"改则县",
+            "code":"542526"
+          },
+          {
+            "name":"措勤县",
+            "code":"542527"
+          }
+        ]
+      },
+      {
+        "name":"林芝地区",
+        "code":"542600",
+        "sub":[
+          {
+            "name":"林芝县",
+            "code":"542621"
+          },
+          {
+            "name":"工布江达县",
+            "code":"542622"
+          },
+          {
+            "name":"米林县",
+            "code":"542623"
+          },
+          {
+            "name":"墨脱县",
+            "code":"542624"
+          },
+          {
+            "name":"波密县",
+            "code":"542625"
+          },
+          {
+            "name":"察隅县",
+            "code":"542626"
+          },
+          {
+            "name":"朗县",
+            "code":"542627"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"陕西省",
+    "code":"610000",
+    "sub":[
+      {
+        "name":"西安市",
+        "code":"610100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"610101"
+          },
+          {
+            "name":"新城区",
+            "code":"610102"
+          },
+          {
+            "name":"碑林区",
+            "code":"610103"
+          },
+          {
+            "name":"莲湖区",
+            "code":"610104"
+          },
+          {
+            "name":"灞桥区",
+            "code":"610111"
+          },
+          {
+            "name":"未央区",
+            "code":"610112"
+          },
+          {
+            "name":"雁塔区",
+            "code":"610113"
+          },
+          {
+            "name":"阎良区",
+            "code":"610114"
+          },
+          {
+            "name":"临潼区",
+            "code":"610115"
+          },
+          {
+            "name":"长安区",
+            "code":"610116"
+          },
+          {
+            "name":"高陵区",
+            "code":"610117"
+          },
+          {
+            "name":"蓝田县",
+            "code":"610122"
+          },
+          {
+            "name":"周至县",
+            "code":"610124"
+          },
+          {
+            "name":"户县",
+            "code":"610125"
+          }
+        ]
+      },
+      {
+        "name":"铜川市",
+        "code":"610200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"610201"
+          },
+          {
+            "name":"王益区",
+            "code":"610202"
+          },
+          {
+            "name":"印台区",
+            "code":"610203"
+          },
+          {
+            "name":"耀州区",
+            "code":"610204"
+          },
+          {
+            "name":"宜君县",
+            "code":"610222"
+          }
+        ]
+      },
+      {
+        "name":"宝鸡市",
+        "code":"610300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"610301"
+          },
+          {
+            "name":"渭滨区",
+            "code":"610302"
+          },
+          {
+            "name":"金台区",
+            "code":"610303"
+          },
+          {
+            "name":"陈仓区",
+            "code":"610304"
+          },
+          {
+            "name":"凤翔县",
+            "code":"610322"
+          },
+          {
+            "name":"岐山县",
+            "code":"610323"
+          },
+          {
+            "name":"扶风县",
+            "code":"610324"
+          },
+          {
+            "name":"眉县",
+            "code":"610326"
+          },
+          {
+            "name":"陇县",
+            "code":"610327"
+          },
+          {
+            "name":"千阳县",
+            "code":"610328"
+          },
+          {
+            "name":"麟游县",
+            "code":"610329"
+          },
+          {
+            "name":"凤县",
+            "code":"610330"
+          },
+          {
+            "name":"太白县",
+            "code":"610331"
+          }
+        ]
+      },
+      {
+        "name":"咸阳市",
+        "code":"610400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"610401"
+          },
+          {
+            "name":"秦都区",
+            "code":"610402"
+          },
+          {
+            "name":"杨陵区",
+            "code":"610403"
+          },
+          {
+            "name":"渭城区",
+            "code":"610404"
+          },
+          {
+            "name":"三原县",
+            "code":"610422"
+          },
+          {
+            "name":"泾阳县",
+            "code":"610423"
+          },
+          {
+            "name":"乾县",
+            "code":"610424"
+          },
+          {
+            "name":"礼泉县",
+            "code":"610425"
+          },
+          {
+            "name":"永寿县",
+            "code":"610426"
+          },
+          {
+            "name":"彬县",
+            "code":"610427"
+          },
+          {
+            "name":"长武县",
+            "code":"610428"
+          },
+          {
+            "name":"旬邑县",
+            "code":"610429"
+          },
+          {
+            "name":"淳化县",
+            "code":"610430"
+          },
+          {
+            "name":"武功县",
+            "code":"610431"
+          },
+          {
+            "name":"兴平市",
+            "code":"610481"
+          }
+        ]
+      },
+      {
+        "name":"渭南市",
+        "code":"610500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"610501"
+          },
+          {
+            "name":"临渭区",
+            "code":"610502"
+          },
+          {
+            "name":"华县",
+            "code":"610521"
+          },
+          {
+            "name":"潼关县",
+            "code":"610522"
+          },
+          {
+            "name":"大荔县",
+            "code":"610523"
+          },
+          {
+            "name":"合阳县",
+            "code":"610524"
+          },
+          {
+            "name":"澄城县",
+            "code":"610525"
+          },
+          {
+            "name":"蒲城县",
+            "code":"610526"
+          },
+          {
+            "name":"白水县",
+            "code":"610527"
+          },
+          {
+            "name":"富平县",
+            "code":"610528"
+          },
+          {
+            "name":"韩城市",
+            "code":"610581"
+          },
+          {
+            "name":"华阴市",
+            "code":"610582"
+          }
+        ]
+      },
+      {
+        "name":"延安市",
+        "code":"610600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"610601"
+          },
+          {
+            "name":"宝塔区",
+            "code":"610602"
+          },
+          {
+            "name":"延长县",
+            "code":"610621"
+          },
+          {
+            "name":"延川县",
+            "code":"610622"
+          },
+          {
+            "name":"子长县",
+            "code":"610623"
+          },
+          {
+            "name":"安塞县",
+            "code":"610624"
+          },
+          {
+            "name":"志丹县",
+            "code":"610625"
+          },
+          {
+            "name":"吴起县",
+            "code":"610626"
+          },
+          {
+            "name":"甘泉县",
+            "code":"610627"
+          },
+          {
+            "name":"富县",
+            "code":"610628"
+          },
+          {
+            "name":"洛川县",
+            "code":"610629"
+          },
+          {
+            "name":"宜川县",
+            "code":"610630"
+          },
+          {
+            "name":"黄龙县",
+            "code":"610631"
+          },
+          {
+            "name":"黄陵县",
+            "code":"610632"
+          }
+        ]
+      },
+      {
+        "name":"汉中市",
+        "code":"610700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"610701"
+          },
+          {
+            "name":"汉台区",
+            "code":"610702"
+          },
+          {
+            "name":"南郑县",
+            "code":"610721"
+          },
+          {
+            "name":"城固县",
+            "code":"610722"
+          },
+          {
+            "name":"洋县",
+            "code":"610723"
+          },
+          {
+            "name":"西乡县",
+            "code":"610724"
+          },
+          {
+            "name":"勉县",
+            "code":"610725"
+          },
+          {
+            "name":"宁强县",
+            "code":"610726"
+          },
+          {
+            "name":"略阳县",
+            "code":"610727"
+          },
+          {
+            "name":"镇巴县",
+            "code":"610728"
+          },
+          {
+            "name":"留坝县",
+            "code":"610729"
+          },
+          {
+            "name":"佛坪县",
+            "code":"610730"
+          }
+        ]
+      },
+      {
+        "name":"榆林市",
+        "code":"610800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"610801"
+          },
+          {
+            "name":"榆阳区",
+            "code":"610802"
+          },
+          {
+            "name":"神木县",
+            "code":"610821"
+          },
+          {
+            "name":"府谷县",
+            "code":"610822"
+          },
+          {
+            "name":"横山县",
+            "code":"610823"
+          },
+          {
+            "name":"靖边县",
+            "code":"610824"
+          },
+          {
+            "name":"定边县",
+            "code":"610825"
+          },
+          {
+            "name":"绥德县",
+            "code":"610826"
+          },
+          {
+            "name":"米脂县",
+            "code":"610827"
+          },
+          {
+            "name":"佳县",
+            "code":"610828"
+          },
+          {
+            "name":"吴堡县",
+            "code":"610829"
+          },
+          {
+            "name":"清涧县",
+            "code":"610830"
+          },
+          {
+            "name":"子洲县",
+            "code":"610831"
+          }
+        ]
+      },
+      {
+        "name":"安康市",
+        "code":"610900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"610901"
+          },
+          {
+            "name":"汉阴县",
+            "code":"610921"
+          },
+          {
+            "name":"石泉县",
+            "code":"610922"
+          },
+          {
+            "name":"宁陕县",
+            "code":"610923"
+          },
+          {
+            "name":"紫阳县",
+            "code":"610924"
+          },
+          {
+            "name":"岚皋县",
+            "code":"610925"
+          },
+          {
+            "name":"平利县",
+            "code":"610926"
+          },
+          {
+            "name":"镇坪县",
+            "code":"610927"
+          },
+          {
+            "name":"旬阳县",
+            "code":"610928"
+          },
+          {
+            "name":"白河县",
+            "code":"610929"
+          }
+        ]
+      },
+      {
+        "name":"商洛市",
+        "code":"611000",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"611001"
+          },
+          {
+            "name":"商州区",
+            "code":"611002"
+          },
+          {
+            "name":"洛南县",
+            "code":"611021"
+          },
+          {
+            "name":"丹凤县",
+            "code":"611022"
+          },
+          {
+            "name":"商南县",
+            "code":"611023"
+          },
+          {
+            "name":"山阳县",
+            "code":"611024"
+          },
+          {
+            "name":"镇安县",
+            "code":"611025"
+          },
+          {
+            "name":"柞水县",
+            "code":"611026"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"甘肃省",
+    "code":"620000",
+    "sub":[
+      {
+        "name":"兰州市",
+        "code":"620100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"620101"
+          },
+          {
+            "name":"城关区",
+            "code":"620102"
+          },
+          {
+            "name":"七里河区",
+            "code":"620103"
+          },
+          {
+            "name":"西固区",
+            "code":"620104"
+          },
+          {
+            "name":"安宁区",
+            "code":"620105"
+          },
+          {
+            "name":"红古区",
+            "code":"620111"
+          },
+          {
+            "name":"永登县",
+            "code":"620121"
+          },
+          {
+            "name":"皋兰县",
+            "code":"620122"
+          },
+          {
+            "name":"榆中县",
+            "code":"620123"
+          }
+        ]
+      },
+      {
+        "name":"嘉峪关市",
+        "code":"620200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"620201"
+          }
+        ]
+      },
+      {
+        "name":"金昌市",
+        "code":"620300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"620301"
+          },
+          {
+            "name":"金川区",
+            "code":"620302"
+          },
+          {
+            "name":"永昌县",
+            "code":"620321"
+          }
+        ]
+      },
+      {
+        "name":"白银市",
+        "code":"620400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"620401"
+          },
+          {
+            "name":"白银区",
+            "code":"620402"
+          },
+          {
+            "name":"平川区",
+            "code":"620403"
+          },
+          {
+            "name":"靖远县",
+            "code":"620421"
+          },
+          {
+            "name":"会宁县",
+            "code":"620422"
+          },
+          {
+            "name":"景泰县",
+            "code":"620423"
+          }
+        ]
+      },
+      {
+        "name":"天水市",
+        "code":"620500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"620501"
+          },
+          {
+            "name":"秦州区",
+            "code":"620502"
+          },
+          {
+            "name":"麦积区",
+            "code":"620503"
+          },
+          {
+            "name":"清水县",
+            "code":"620521"
+          },
+          {
+            "name":"秦安县",
+            "code":"620522"
+          },
+          {
+            "name":"甘谷县",
+            "code":"620523"
+          },
+          {
+            "name":"武山县",
+            "code":"620524"
+          },
+          {
+            "name":"张家川回族自治县",
+            "code":"620525"
+          }
+        ]
+      },
+      {
+        "name":"武威市",
+        "code":"620600",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"620601"
+          },
+          {
+            "name":"凉州区",
+            "code":"620602"
+          },
+          {
+            "name":"民勤县",
+            "code":"620621"
+          },
+          {
+            "name":"古浪县",
+            "code":"620622"
+          },
+          {
+            "name":"天祝藏族自治县",
+            "code":"620623"
+          }
+        ]
+      },
+      {
+        "name":"张掖市",
+        "code":"620700",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"620701"
+          },
+          {
+            "name":"甘州区",
+            "code":"620702"
+          },
+          {
+            "name":"肃南裕固族自治县",
+            "code":"620721"
+          },
+          {
+            "name":"民乐县",
+            "code":"620722"
+          },
+          {
+            "name":"临泽县",
+            "code":"620723"
+          },
+          {
+            "name":"高台县",
+            "code":"620724"
+          },
+          {
+            "name":"山丹县",
+            "code":"620725"
+          }
+        ]
+      },
+      {
+        "name":"平凉市",
+        "code":"620800",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"620801"
+          },
+          {
+            "name":"崆峒区",
+            "code":"620802"
+          },
+          {
+            "name":"泾川县",
+            "code":"620821"
+          },
+          {
+            "name":"灵台县",
+            "code":"620822"
+          },
+          {
+            "name":"崇信县",
+            "code":"620823"
+          },
+          {
+            "name":"华亭县",
+            "code":"620824"
+          },
+          {
+            "name":"庄浪县",
+            "code":"620825"
+          },
+          {
+            "name":"静宁县",
+            "code":"620826"
+          }
+        ]
+      },
+      {
+        "name":"酒泉市",
+        "code":"620900",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"620901"
+          },
+          {
+            "name":"肃州区",
+            "code":"620902"
+          },
+          {
+            "name":"金塔县",
+            "code":"620921"
+          },
+          {
+            "name":"瓜州县",
+            "code":"620922"
+          },
+          {
+            "name":"肃北蒙古族自治县",
+            "code":"620923"
+          },
+          {
+            "name":"阿克塞哈萨克族自治县",
+            "code":"620924"
+          },
+          {
+            "name":"玉门市",
+            "code":"620981"
+          },
+          {
+            "name":"敦煌市",
+            "code":"620982"
+          }
+        ]
+      },
+      {
+        "name":"庆阳市",
+        "code":"621000",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"621001"
+          },
+          {
+            "name":"西峰区",
+            "code":"621002"
+          },
+          {
+            "name":"庆城县",
+            "code":"621021"
+          },
+          {
+            "name":"环县",
+            "code":"621022"
+          },
+          {
+            "name":"华池县",
+            "code":"621023"
+          },
+          {
+            "name":"合水县",
+            "code":"621024"
+          },
+          {
+            "name":"正宁县",
+            "code":"621025"
+          },
+          {
+            "name":"宁县",
+            "code":"621026"
+          },
+          {
+            "name":"镇原县",
+            "code":"621027"
+          }
+        ]
+      },
+      {
+        "name":"定西市",
+        "code":"621100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"621101"
+          },
+          {
+            "name":"安定区",
+            "code":"621102"
+          },
+          {
+            "name":"通渭县",
+            "code":"621121"
+          },
+          {
+            "name":"陇西县",
+            "code":"621122"
+          },
+          {
+            "name":"渭源县",
+            "code":"621123"
+          },
+          {
+            "name":"临洮县",
+            "code":"621124"
+          },
+          {
+            "name":"漳县",
+            "code":"621125"
+          },
+          {
+            "name":"岷县",
+            "code":"621126"
+          }
+        ]
+      },
+      {
+        "name":"陇南市",
+        "code":"621200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"621201"
+          },
+          {
+            "name":"武都区",
+            "code":"621202"
+          },
+          {
+            "name":"成县",
+            "code":"621221"
+          },
+          {
+            "name":"文县",
+            "code":"621222"
+          },
+          {
+            "name":"宕昌县",
+            "code":"621223"
+          },
+          {
+            "name":"康县",
+            "code":"621224"
+          },
+          {
+            "name":"西和县",
+            "code":"621225"
+          },
+          {
+            "name":"礼县",
+            "code":"621226"
+          },
+          {
+            "name":"徽县",
+            "code":"621227"
+          },
+          {
+            "name":"两当县",
+            "code":"621228"
+          }
+        ]
+      },
+      {
+        "name":"临夏回族自治州",
+        "code":"622900",
+        "sub":[
+          {
+            "name":"临夏市",
+            "code":"622901"
+          },
+          {
+            "name":"临夏县",
+            "code":"622921"
+          },
+          {
+            "name":"康乐县",
+            "code":"622922"
+          },
+          {
+            "name":"永靖县",
+            "code":"622923"
+          },
+          {
+            "name":"广河县",
+            "code":"622924"
+          },
+          {
+            "name":"和政县",
+            "code":"622925"
+          },
+          {
+            "name":"东乡族自治县",
+            "code":"622926"
+          },
+          {
+            "name":"积石山保安族东乡族撒拉族自治县",
+            "code":"622927"
+          }
+        ]
+      },
+      {
+        "name":"甘南藏族自治州",
+        "code":"623000",
+        "sub":[
+          {
+            "name":"合作市",
+            "code":"623001"
+          },
+          {
+            "name":"临潭县",
+            "code":"623021"
+          },
+          {
+            "name":"卓尼县",
+            "code":"623022"
+          },
+          {
+            "name":"舟曲县",
+            "code":"623023"
+          },
+          {
+            "name":"迭部县",
+            "code":"623024"
+          },
+          {
+            "name":"玛曲县",
+            "code":"623025"
+          },
+          {
+            "name":"碌曲县",
+            "code":"623026"
+          },
+          {
+            "name":"夏河县",
+            "code":"623027"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"青海省",
+    "code":"630000",
+    "sub":[
+      {
+        "name":"西宁市",
+        "code":"630100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"630101"
+          },
+          {
+            "name":"城东区",
+            "code":"630102"
+          },
+          {
+            "name":"城中区",
+            "code":"630103"
+          },
+          {
+            "name":"城西区",
+            "code":"630104"
+          },
+          {
+            "name":"城北区",
+            "code":"630105"
+          },
+          {
+            "name":"大通回族土族自治县",
+            "code":"630121"
+          },
+          {
+            "name":"湟中县",
+            "code":"630122"
+          },
+          {
+            "name":"湟源县",
+            "code":"630123"
+          }
+        ]
+      },
+      {
+        "name":"海东市",
+        "code":"630200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"630201"
+          },
+          {
+            "name":"乐都区",
+            "code":"630202"
+          },
+          {
+            "name":"平安县",
+            "code":"630221"
+          },
+          {
+            "name":"民和回族土族自治县",
+            "code":"630222"
+          },
+          {
+            "name":"互助土族自治县",
+            "code":"630223"
+          },
+          {
+            "name":"化隆回族自治县",
+            "code":"630224"
+          },
+          {
+            "name":"循化撒拉族自治县",
+            "code":"630225"
+          }
+        ]
+      },
+      {
+        "name":"海北藏族自治州",
+        "code":"632200",
+        "sub":[
+          {
+            "name":"门源回族自治县",
+            "code":"632221"
+          },
+          {
+            "name":"祁连县",
+            "code":"632222"
+          },
+          {
+            "name":"海晏县",
+            "code":"632223"
+          },
+          {
+            "name":"刚察县",
+            "code":"632224"
+          }
+        ]
+      },
+      {
+        "name":"黄南藏族自治州",
+        "code":"632300",
+        "sub":[
+          {
+            "name":"同仁县",
+            "code":"632321"
+          },
+          {
+            "name":"尖扎县",
+            "code":"632322"
+          },
+          {
+            "name":"泽库县",
+            "code":"632323"
+          },
+          {
+            "name":"河南蒙古族自治县",
+            "code":"632324"
+          }
+        ]
+      },
+      {
+        "name":"海南藏族自治州",
+        "code":"632500",
+        "sub":[
+          {
+            "name":"共和县",
+            "code":"632521"
+          },
+          {
+            "name":"同德县",
+            "code":"632522"
+          },
+          {
+            "name":"贵德县",
+            "code":"632523"
+          },
+          {
+            "name":"兴海县",
+            "code":"632524"
+          },
+          {
+            "name":"贵南县",
+            "code":"632525"
+          }
+        ]
+      },
+      {
+        "name":"果洛藏族自治州",
+        "code":"632600",
+        "sub":[
+          {
+            "name":"玛沁县",
+            "code":"632621"
+          },
+          {
+            "name":"班玛县",
+            "code":"632622"
+          },
+          {
+            "name":"甘德县",
+            "code":"632623"
+          },
+          {
+            "name":"达日县",
+            "code":"632624"
+          },
+          {
+            "name":"久治县",
+            "code":"632625"
+          },
+          {
+            "name":"玛多县",
+            "code":"632626"
+          }
+        ]
+      },
+      {
+        "name":"玉树藏族自治州",
+        "code":"632700",
+        "sub":[
+          {
+            "name":"玉树市",
+            "code":"632701"
+          },
+          {
+            "name":"杂多县",
+            "code":"632722"
+          },
+          {
+            "name":"称多县",
+            "code":"632723"
+          },
+          {
+            "name":"治多县",
+            "code":"632724"
+          },
+          {
+            "name":"囊谦县",
+            "code":"632725"
+          },
+          {
+            "name":"曲麻莱县",
+            "code":"632726"
+          }
+        ]
+      },
+      {
+        "name":"海西蒙古族藏族自治州",
+        "code":"632800",
+        "sub":[
+          {
+            "name":"格尔木市",
+            "code":"632801"
+          },
+          {
+            "name":"德令哈市",
+            "code":"632802"
+          },
+          {
+            "name":"乌兰县",
+            "code":"632821"
+          },
+          {
+            "name":"都兰县",
+            "code":"632822"
+          },
+          {
+            "name":"天峻县",
+            "code":"632823"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"宁夏回族自治区",
+    "code":"640000",
+    "sub":[
+      {
+        "name":"银川市",
+        "code":"640100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"640101"
+          },
+          {
+            "name":"兴庆区",
+            "code":"640104"
+          },
+          {
+            "name":"西夏区",
+            "code":"640105"
+          },
+          {
+            "name":"金凤区",
+            "code":"640106"
+          },
+          {
+            "name":"永宁县",
+            "code":"640121"
+          },
+          {
+            "name":"贺兰县",
+            "code":"640122"
+          },
+          {
+            "name":"灵武市",
+            "code":"640181"
+          }
+        ]
+      },
+      {
+        "name":"石嘴山市",
+        "code":"640200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"640201"
+          },
+          {
+            "name":"大武口区",
+            "code":"640202"
+          },
+          {
+            "name":"惠农区",
+            "code":"640205"
+          },
+          {
+            "name":"平罗县",
+            "code":"640221"
+          }
+        ]
+      },
+      {
+        "name":"吴忠市",
+        "code":"640300",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"640301"
+          },
+          {
+            "name":"利通区",
+            "code":"640302"
+          },
+          {
+            "name":"红寺堡区",
+            "code":"640303"
+          },
+          {
+            "name":"盐池县",
+            "code":"640323"
+          },
+          {
+            "name":"同心县",
+            "code":"640324"
+          },
+          {
+            "name":"青铜峡市",
+            "code":"640381"
+          }
+        ]
+      },
+      {
+        "name":"固原市",
+        "code":"640400",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"640401"
+          },
+          {
+            "name":"原州区",
+            "code":"640402"
+          },
+          {
+            "name":"西吉县",
+            "code":"640422"
+          },
+          {
+            "name":"隆德县",
+            "code":"640423"
+          },
+          {
+            "name":"泾源县",
+            "code":"640424"
+          },
+          {
+            "name":"彭阳县",
+            "code":"640425"
+          }
+        ]
+      },
+      {
+        "name":"中卫市",
+        "code":"640500",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"640501"
+          },
+          {
+            "name":"沙坡头区",
+            "code":"640502"
+          },
+          {
+            "name":"中宁县",
+            "code":"640521"
+          },
+          {
+            "name":"海原县",
+            "code":"640522"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"新疆维吾尔自治区",
+    "code":"650000",
+    "sub":[
+      {
+        "name":"乌鲁木齐市",
+        "code":"650100",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"650101"
+          },
+          {
+            "name":"天山区",
+            "code":"650102"
+          },
+          {
+            "name":"沙依巴克区",
+            "code":"650103"
+          },
+          {
+            "name":"新市区",
+            "code":"650104"
+          },
+          {
+            "name":"水磨沟区",
+            "code":"650105"
+          },
+          {
+            "name":"头屯河区",
+            "code":"650106"
+          },
+          {
+            "name":"达坂城区",
+            "code":"650107"
+          },
+          {
+            "name":"米东区",
+            "code":"650109"
+          },
+          {
+            "name":"乌鲁木齐县",
+            "code":"650121"
+          }
+        ]
+      },
+      {
+        "name":"克拉玛依市",
+        "code":"650200",
+        "sub":[
+          {
+            "name":"市辖区",
+            "code":"650201"
+          },
+          {
+            "name":"独山子区",
+            "code":"650202"
+          },
+          {
+            "name":"克拉玛依区",
+            "code":"650203"
+          },
+          {
+            "name":"白碱滩区",
+            "code":"650204"
+          },
+          {
+            "name":"乌尔禾区",
+            "code":"650205"
+          }
+        ]
+      },
+      {
+        "name":"吐鲁番地区",
+        "code":"652100",
+        "sub":[
+          {
+            "name":"吐鲁番市",
+            "code":"652101"
+          },
+          {
+            "name":"鄯善县",
+            "code":"652122"
+          },
+          {
+            "name":"托克逊县",
+            "code":"652123"
+          }
+        ]
+      },
+      {
+        "name":"哈密地区",
+        "code":"652200",
+        "sub":[
+          {
+            "name":"哈密市",
+            "code":"652201"
+          },
+          {
+            "name":"巴里坤哈萨克自治县",
+            "code":"652222"
+          },
+          {
+            "name":"伊吾县",
+            "code":"652223"
+          }
+        ]
+      },
+      {
+        "name":"昌吉回族自治州",
+        "code":"652300",
+        "sub":[
+          {
+            "name":"昌吉市",
+            "code":"652301"
+          },
+          {
+            "name":"阜康市",
+            "code":"652302"
+          },
+          {
+            "name":"呼图壁县",
+            "code":"652323"
+          },
+          {
+            "name":"玛纳斯县",
+            "code":"652324"
+          },
+          {
+            "name":"奇台县",
+            "code":"652325"
+          },
+          {
+            "name":"吉木萨尔县",
+            "code":"652327"
+          },
+          {
+            "name":"木垒哈萨克自治县",
+            "code":"652328"
+          }
+        ]
+      },
+      {
+        "name":"博尔塔拉蒙古自治州",
+        "code":"652700",
+        "sub":[
+          {
+            "name":"博乐市",
+            "code":"652701"
+          },
+          {
+            "name":"阿拉山口市",
+            "code":"652702"
+          },
+          {
+            "name":"精河县",
+            "code":"652722"
+          },
+          {
+            "name":"温泉县",
+            "code":"652723"
+          }
+        ]
+      },
+      {
+        "name":"巴音郭楞蒙古自治州",
+        "code":"652800",
+        "sub":[
+          {
+            "name":"库尔勒市",
+            "code":"652801"
+          },
+          {
+            "name":"轮台县",
+            "code":"652822"
+          },
+          {
+            "name":"尉犁县",
+            "code":"652823"
+          },
+          {
+            "name":"若羌县",
+            "code":"652824"
+          },
+          {
+            "name":"且末县",
+            "code":"652825"
+          },
+          {
+            "name":"焉耆回族自治县",
+            "code":"652826"
+          },
+          {
+            "name":"和静县",
+            "code":"652827"
+          },
+          {
+            "name":"和硕县",
+            "code":"652828"
+          },
+          {
+            "name":"博湖县",
+            "code":"652829"
+          }
+        ]
+      },
+      {
+        "name":"阿克苏地区",
+        "code":"652900",
+        "sub":[
+          {
+            "name":"阿克苏市",
+            "code":"652901"
+          },
+          {
+            "name":"温宿县",
+            "code":"652922"
+          },
+          {
+            "name":"库车县",
+            "code":"652923"
+          },
+          {
+            "name":"沙雅县",
+            "code":"652924"
+          },
+          {
+            "name":"新和县",
+            "code":"652925"
+          },
+          {
+            "name":"拜城县",
+            "code":"652926"
+          },
+          {
+            "name":"乌什县",
+            "code":"652927"
+          },
+          {
+            "name":"阿瓦提县",
+            "code":"652928"
+          },
+          {
+            "name":"柯坪县",
+            "code":"652929"
+          }
+        ]
+      },
+      {
+        "name":"克孜勒苏柯尔克孜自治州",
+        "code":"653000",
+        "sub":[
+          {
+            "name":"阿图什市",
+            "code":"653001"
+          },
+          {
+            "name":"阿克陶县",
+            "code":"653022"
+          },
+          {
+            "name":"阿合奇县",
+            "code":"653023"
+          },
+          {
+            "name":"乌恰县",
+            "code":"653024"
+          }
+        ]
+      },
+      {
+        "name":"喀什地区",
+        "code":"653100",
+        "sub":[
+          {
+            "name":"喀什市",
+            "code":"653101"
+          },
+          {
+            "name":"疏附县",
+            "code":"653121"
+          },
+          {
+            "name":"疏勒县",
+            "code":"653122"
+          },
+          {
+            "name":"英吉沙县",
+            "code":"653123"
+          },
+          {
+            "name":"泽普县",
+            "code":"653124"
+          },
+          {
+            "name":"莎车县",
+            "code":"653125"
+          },
+          {
+            "name":"叶城县",
+            "code":"653126"
+          },
+          {
+            "name":"麦盖提县",
+            "code":"653127"
+          },
+          {
+            "name":"岳普湖县",
+            "code":"653128"
+          },
+          {
+            "name":"伽师县",
+            "code":"653129"
+          },
+          {
+            "name":"巴楚县",
+            "code":"653130"
+          },
+          {
+            "name":"塔什库尔干塔吉克自治县",
+            "code":"653131"
+          }
+        ]
+      },
+      {
+        "name":"和田地区",
+        "code":"653200",
+        "sub":[
+          {
+            "name":"和田市",
+            "code":"653201"
+          },
+          {
+            "name":"和田县",
+            "code":"653221"
+          },
+          {
+            "name":"墨玉县",
+            "code":"653222"
+          },
+          {
+            "name":"皮山县",
+            "code":"653223"
+          },
+          {
+            "name":"洛浦县",
+            "code":"653224"
+          },
+          {
+            "name":"策勒县",
+            "code":"653225"
+          },
+          {
+            "name":"于田县",
+            "code":"653226"
+          },
+          {
+            "name":"民丰县",
+            "code":"653227"
+          }
+        ]
+      },
+      {
+        "name":"伊犁哈萨克自治州",
+        "code":"654000",
+        "sub":[
+          {
+            "name":"伊宁市",
+            "code":"654002"
+          },
+          {
+            "name":"奎屯市",
+            "code":"654003"
+          },
+          {
+            "name":"霍尔果斯市",
+            "code":"654004"
+          },
+          {
+            "name":"伊宁县",
+            "code":"654021"
+          },
+          {
+            "name":"察布查尔锡伯自治县",
+            "code":"654022"
+          },
+          {
+            "name":"霍城县",
+            "code":"654023"
+          },
+          {
+            "name":"巩留县",
+            "code":"654024"
+          },
+          {
+            "name":"新源县",
+            "code":"654025"
+          },
+          {
+            "name":"昭苏县",
+            "code":"654026"
+          },
+          {
+            "name":"特克斯县",
+            "code":"654027"
+          },
+          {
+            "name":"尼勒克县",
+            "code":"654028"
+          },
+          {
+            "name":"塔城地区",
+            "code":"654200"
+          },
+          {
+            "name":"塔城市",
+            "code":"654201"
+          },
+          {
+            "name":"乌苏市",
+            "code":"654202"
+          },
+          {
+            "name":"额敏县",
+            "code":"654221"
+          },
+          {
+            "name":"沙湾县",
+            "code":"654223"
+          },
+          {
+            "name":"托里县",
+            "code":"654224"
+          },
+          {
+            "name":"裕民县",
+            "code":"654225"
+          },
+          {
+            "name":"和布克赛尔蒙古自治县",
+            "code":"654226"
+          },
+          {
+            "name":"阿勒泰地区",
+            "code":"654300"
+          },
+          {
+            "name":"阿勒泰市",
+            "code":"654301"
+          },
+          {
+            "name":"布尔津县",
+            "code":"654321"
+          },
+          {
+            "name":"富蕴县",
+            "code":"654322"
+          },
+          {
+            "name":"福海县",
+            "code":"654323"
+          },
+          {
+            "name":"哈巴河县",
+            "code":"654324"
+          },
+          {
+            "name":"青河县",
+            "code":"654325"
+          },
+          {
+            "name":"吉木乃县",
+            "code":"654326"
+          }
+        ]
+      },
+      {
+        "name":"自治区直辖县级行政区划",
+        "code":"659000",
+        "sub":[
+          {
+            "name":"石河子市",
+            "code":"659001"
+          },
+          {
+            "name":"阿拉尔市",
+            "code":"659002"
+          },
+          {
+            "name":"图木舒克市",
+            "code":"659003"
+          },
+          {
+            "name":"五家渠市",
+            "code":"659004"
+          },
+          {
+            "name":"北屯市",
+            "code":"659005"
+          },
+          {
+            "name":"铁门关市",
+            "code":"659006"
+          },
+          {
+            "name":"双河市",
+            "code":"659007"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"台湾省",
+    "code":"710000",
+    "sub":[
+      {
+        "name":"台北市",
+        "code":"710100",
+        "sub":[
+          {
+            "name":"松山区",
+            "code":"710101"
+          },
+          {
+            "name":"信义区",
+            "code":"710102"
+          },
+          {
+            "name":"大安区",
+            "code":"710103"
+          },
+          {
+            "name":"中山区",
+            "code":"710104"
+          },
+          {
+            "name":"中正区",
+            "code":"710105"
+          },
+          {
+            "name":"大同区",
+            "code":"710106"
+          },
+          {
+            "name":"万华区",
+            "code":"710107"
+          },
+          {
+            "name":"文山区",
+            "code":"710108"
+          },
+          {
+            "name":"南港区",
+            "code":"710109"
+          },
+          {
+            "name":"内湖区",
+            "code":"710110"
+          },
+          {
+            "name":"士林区",
+            "code":"710111"
+          },
+          {
+            "name":"北投区",
+            "code":"710112"
+          }
+        ]
+      },
+      {
+        "name":"高雄市",
+        "code":"710200",
+        "sub":[
+          {
+            "name":"盐埕区",
+            "code":"710201"
+          },
+          {
+            "name":"鼓山区",
+            "code":"710202"
+          },
+          {
+            "name":"左营区",
+            "code":"710203"
+          },
+          {
+            "name":"楠梓区",
+            "code":"710204"
+          },
+          {
+            "name":"三民区",
+            "code":"710205"
+          },
+          {
+            "name":"新兴区",
+            "code":"710206"
+          },
+          {
+            "name":"前金区",
+            "code":"710207"
+          },
+          {
+            "name":"苓雅区",
+            "code":"710208"
+          },
+          {
+            "name":"前镇区",
+            "code":"710209"
+          },
+          {
+            "name":"旗津区",
+            "code":"710210"
+          },
+          {
+            "name":"小港区",
+            "code":"710211"
+          },
+          {
+            "name":"凤山区",
+            "code":"710212"
+          },
+          {
+            "name":"林园区",
+            "code":"710213"
+          },
+          {
+            "name":"大寮区",
+            "code":"710214"
+          },
+          {
+            "name":"大树区",
+            "code":"710215"
+          },
+          {
+            "name":"大社区",
+            "code":"710216"
+          },
+          {
+            "name":"仁武区",
+            "code":"710217"
+          },
+          {
+            "name":"鸟松区",
+            "code":"710218"
+          },
+          {
+            "name":"冈山区",
+            "code":"710219"
+          },
+          {
+            "name":"桥头区",
+            "code":"710220"
+          },
+          {
+            "name":"燕巢区",
+            "code":"710221"
+          },
+          {
+            "name":"田寮区",
+            "code":"710222"
+          },
+          {
+            "name":"阿莲区",
+            "code":"710223"
+          },
+          {
+            "name":"路竹区",
+            "code":"710224"
+          },
+          {
+            "name":"湖内区",
+            "code":"710225"
+          },
+          {
+            "name":"茄萣区",
+            "code":"710226"
+          },
+          {
+            "name":"永安区",
+            "code":"710227"
+          },
+          {
+            "name":"弥陀区",
+            "code":"710228"
+          },
+          {
+            "name":"梓官区",
+            "code":"710229"
+          },
+          {
+            "name":"旗山区",
+            "code":"710230"
+          },
+          {
+            "name":"美浓区",
+            "code":"710231"
+          },
+          {
+            "name":"六龟区",
+            "code":"710232"
+          },
+          {
+            "name":"甲仙区",
+            "code":"710233"
+          },
+          {
+            "name":"杉林区",
+            "code":"710234"
+          },
+          {
+            "name":"内门区",
+            "code":"710235"
+          },
+          {
+            "name":"茂林区",
+            "code":"710236"
+          },
+          {
+            "name":"桃源区",
+            "code":"710237"
+          },
+          {
+            "name":"那玛夏区",
+            "code":"710238"
+          }
+        ]
+      },
+      {
+        "name":"基隆市",
+        "code":"710300",
+        "sub":[
+          {
+            "name":"中正区",
+            "code":"710301"
+          },
+          {
+            "name":"七堵区",
+            "code":"710302"
+          },
+          {
+            "name":"暖暖区",
+            "code":"710303"
+          },
+          {
+            "name":"仁爱区",
+            "code":"710304"
+          },
+          {
+            "name":"中山区",
+            "code":"710305"
+          },
+          {
+            "name":"安乐区",
+            "code":"710306"
+          },
+          {
+            "name":"信义区",
+            "code":"710307"
+          }
+        ]
+      },
+      {
+        "name":"台中市",
+        "code":"710400",
+        "sub":[
+          {
+            "name":"中区",
+            "code":"710401"
+          },
+          {
+            "name":"东区",
+            "code":"710402"
+          },
+          {
+            "name":"南区",
+            "code":"710403"
+          },
+          {
+            "name":"西区",
+            "code":"710404"
+          },
+          {
+            "name":"北区",
+            "code":"710405"
+          },
+          {
+            "name":"西屯区",
+            "code":"710406"
+          },
+          {
+            "name":"南屯区",
+            "code":"710407"
+          },
+          {
+            "name":"北屯区",
+            "code":"710408"
+          },
+          {
+            "name":"丰原区",
+            "code":"710409"
+          },
+          {
+            "name":"东势区",
+            "code":"710410"
+          },
+          {
+            "name":"大甲区",
+            "code":"710411"
+          },
+          {
+            "name":"清水区",
+            "code":"710412"
+          },
+          {
+            "name":"沙鹿区",
+            "code":"710413"
+          },
+          {
+            "name":"梧栖区",
+            "code":"710414"
+          },
+          {
+            "name":"后里区",
+            "code":"710415"
+          },
+          {
+            "name":"神冈区",
+            "code":"710416"
+          },
+          {
+            "name":"潭子区",
+            "code":"710417"
+          },
+          {
+            "name":"大雅区",
+            "code":"710418"
+          },
+          {
+            "name":"新社区",
+            "code":"710419"
+          },
+          {
+            "name":"石冈区",
+            "code":"710420"
+          },
+          {
+            "name":"外埔区",
+            "code":"710421"
+          },
+          {
+            "name":"大安区",
+            "code":"710422"
+          },
+          {
+            "name":"乌日区",
+            "code":"710423"
+          },
+          {
+            "name":"大肚区",
+            "code":"710424"
+          },
+          {
+            "name":"龙井区",
+            "code":"710425"
+          },
+          {
+            "name":"雾峰区",
+            "code":"710426"
+          },
+          {
+            "name":"太平区",
+            "code":"710427"
+          },
+          {
+            "name":"大里区",
+            "code":"710428"
+          },
+          {
+            "name":"和平区",
+            "code":"710429"
+          }
+        ]
+      },
+      {
+        "name":"台南市",
+        "code":"710500",
+        "sub":[
+          {
+            "name":"东区",
+            "code":"710501"
+          },
+          {
+            "name":"南区",
+            "code":"710502"
+          },
+          {
+            "name":"北区",
+            "code":"710504"
+          },
+          {
+            "name":"安南区",
+            "code":"710506"
+          },
+          {
+            "name":"安平区",
+            "code":"710507"
+          },
+          {
+            "name":"中西区",
+            "code":"710508"
+          },
+          {
+            "name":"新营区",
+            "code":"710509"
+          },
+          {
+            "name":"盐水区",
+            "code":"710510"
+          },
+          {
+            "name":"白河区",
+            "code":"710511"
+          },
+          {
+            "name":"柳营区",
+            "code":"710512"
+          },
+          {
+            "name":"后壁区",
+            "code":"710513"
+          },
+          {
+            "name":"东山区",
+            "code":"710514"
+          },
+          {
+            "name":"麻豆区",
+            "code":"710515"
+          },
+          {
+            "name":"下营区",
+            "code":"710516"
+          },
+          {
+            "name":"六甲区",
+            "code":"710517"
+          },
+          {
+            "name":"官田区",
+            "code":"710518"
+          },
+          {
+            "name":"大内区",
+            "code":"710519"
+          },
+          {
+            "name":"佳里区",
+            "code":"710520"
+          },
+          {
+            "name":"学甲区",
+            "code":"710521"
+          },
+          {
+            "name":"西港区",
+            "code":"710522"
+          },
+          {
+            "name":"七股区",
+            "code":"710523"
+          },
+          {
+            "name":"将军区",
+            "code":"710524"
+          },
+          {
+            "name":"北门区",
+            "code":"710525"
+          },
+          {
+            "name":"新化区",
+            "code":"710526"
+          },
+          {
+            "name":"善化区",
+            "code":"710527"
+          },
+          {
+            "name":"新市区",
+            "code":"710528"
+          },
+          {
+            "name":"安定区",
+            "code":"710529"
+          },
+          {
+            "name":"山上区",
+            "code":"710530"
+          },
+          {
+            "name":"玉井区",
+            "code":"710531"
+          },
+          {
+            "name":"楠西区",
+            "code":"710532"
+          },
+          {
+            "name":"南化区",
+            "code":"710533"
+          },
+          {
+            "name":"左镇区",
+            "code":"710534"
+          },
+          {
+            "name":"仁德区",
+            "code":"710535"
+          },
+          {
+            "name":"归仁区",
+            "code":"710536"
+          },
+          {
+            "name":"关庙区",
+            "code":"710537"
+          },
+          {
+            "name":"龙崎区",
+            "code":"710538"
+          },
+          {
+            "name":"永康区",
+            "code":"710539"
+          }
+        ]
+      },
+      {
+        "name":"新竹市",
+        "code":"710600",
+        "sub":[
+          {
+            "name":"东区",
+            "code":"710601"
+          },
+          {
+            "name":"北区",
+            "code":"710602"
+          },
+          {
+            "name":"香山区",
+            "code":"710603"
+          }
+        ]
+      },
+      {
+        "name":"嘉义市",
+        "code":"710700",
+        "sub":[
+          {
+            "name":"东区",
+            "code":"710701"
+          },
+          {
+            "name":"西区",
+            "code":"710702"
+          }
+        ]
+      },
+      {
+        "name":"新北市",
+        "code":"710800",
+        "sub":[
+          {
+            "name":"板桥区",
+            "code":"710801"
+          },
+          {
+            "name":"三重区",
+            "code":"710802"
+          },
+          {
+            "name":"中和区",
+            "code":"710803"
+          },
+          {
+            "name":"永和区",
+            "code":"710804"
+          },
+          {
+            "name":"新庄区",
+            "code":"710805"
+          },
+          {
+            "name":"新店区",
+            "code":"710806"
+          },
+          {
+            "name":"树林区",
+            "code":"710807"
+          },
+          {
+            "name":"莺歌区",
+            "code":"710808"
+          },
+          {
+            "name":"三峡区",
+            "code":"710809"
+          },
+          {
+            "name":"淡水区",
+            "code":"710810"
+          },
+          {
+            "name":"汐止区",
+            "code":"710811"
+          },
+          {
+            "name":"瑞芳区",
+            "code":"710812"
+          },
+          {
+            "name":"土城区",
+            "code":"710813"
+          },
+          {
+            "name":"芦洲区",
+            "code":"710814"
+          },
+          {
+            "name":"五股区",
+            "code":"710815"
+          },
+          {
+            "name":"泰山区",
+            "code":"710816"
+          },
+          {
+            "name":"林口区",
+            "code":"710817"
+          },
+          {
+            "name":"深坑区",
+            "code":"710818"
+          },
+          {
+            "name":"石碇区",
+            "code":"710819"
+          },
+          {
+            "name":"坪林区",
+            "code":"710820"
+          },
+          {
+            "name":"三芝区",
+            "code":"710821"
+          },
+          {
+            "name":"石门区",
+            "code":"710822"
+          },
+          {
+            "name":"八里区",
+            "code":"710823"
+          },
+          {
+            "name":"平溪区",
+            "code":"710824"
+          },
+          {
+            "name":"双溪区",
+            "code":"710825"
+          },
+          {
+            "name":"贡寮区",
+            "code":"710826"
+          },
+          {
+            "name":"金山区",
+            "code":"710827"
+          },
+          {
+            "name":"万里区",
+            "code":"710828"
+          },
+          {
+            "name":"乌来区",
+            "code":"710829"
+          }
+        ]
+      },
+      {
+        "name":"宜兰县",
+        "code":"712200",
+        "sub":[
+          {
+            "name":"宜兰市",
+            "code":"712201"
+          },
+          {
+            "name":"罗东镇",
+            "code":"712221"
+          },
+          {
+            "name":"苏澳镇",
+            "code":"712222"
+          },
+          {
+            "name":"头城镇",
+            "code":"712223"
+          },
+          {
+            "name":"礁溪乡",
+            "code":"712224"
+          },
+          {
+            "name":"壮围乡",
+            "code":"712225"
+          },
+          {
+            "name":"员山乡",
+            "code":"712226"
+          },
+          {
+            "name":"冬山乡",
+            "code":"712227"
+          },
+          {
+            "name":"五结乡",
+            "code":"712228"
+          },
+          {
+            "name":"三星乡",
+            "code":"712229"
+          },
+          {
+            "name":"大同乡",
+            "code":"712230"
+          },
+          {
+            "name":"南澳乡",
+            "code":"712231"
+          }
+        ]
+      },
+      {
+        "name":"桃园县",
+        "code":"712300",
+        "sub":[
+          {
+            "name":"桃园市",
+            "code":"712301"
+          },
+          {
+            "name":"中坜市",
+            "code":"712302"
+          },
+          {
+            "name":"平镇市",
+            "code":"712303"
+          },
+          {
+            "name":"八德市",
+            "code":"712304"
+          },
+          {
+            "name":"杨梅市",
+            "code":"712305"
+          },
+          {
+            "name":"大溪镇",
+            "code":"712321"
+          },
+          {
+            "name":"芦竹乡",
+            "code":"712323"
+          },
+          {
+            "name":"大园乡",
+            "code":"712324"
+          },
+          {
+            "name":"龟山乡",
+            "code":"712325"
+          },
+          {
+            "name":"龙潭乡",
+            "code":"712327"
+          },
+          {
+            "name":"新屋乡",
+            "code":"712329"
+          },
+          {
+            "name":"观音乡",
+            "code":"712330"
+          },
+          {
+            "name":"复兴乡",
+            "code":"712331"
+          }
+        ]
+      },
+      {
+        "name":"新竹县",
+        "code":"712400",
+        "sub":[
+          {
+            "name":"竹北市",
+            "code":"712401"
+          },
+          {
+            "name":"竹东镇",
+            "code":"712421"
+          },
+          {
+            "name":"新埔镇",
+            "code":"712422"
+          },
+          {
+            "name":"关西镇",
+            "code":"712423"
+          },
+          {
+            "name":"湖口乡",
+            "code":"712424"
+          },
+          {
+            "name":"新丰乡",
+            "code":"712425"
+          },
+          {
+            "name":"芎林乡",
+            "code":"712426"
+          },
+          {
+            "name":"橫山乡",
+            "code":"712427"
+          },
+          {
+            "name":"北埔乡",
+            "code":"712428"
+          },
+          {
+            "name":"宝山乡",
+            "code":"712429"
+          },
+          {
+            "name":"峨眉乡",
+            "code":"712430"
+          },
+          {
+            "name":"尖石乡",
+            "code":"712431"
+          },
+          {
+            "name":"五峰乡",
+            "code":"712432"
+          }
+        ]
+      },
+      {
+        "name":"苗栗县",
+        "code":"712500",
+        "sub":[
+          {
+            "name":"苗栗市",
+            "code":"712501"
+          },
+          {
+            "name":"苑里镇",
+            "code":"712521"
+          },
+          {
+            "name":"通霄镇",
+            "code":"712522"
+          },
+          {
+            "name":"竹南镇",
+            "code":"712523"
+          },
+          {
+            "name":"头份镇",
+            "code":"712524"
+          },
+          {
+            "name":"后龙镇",
+            "code":"712525"
+          },
+          {
+            "name":"卓兰镇",
+            "code":"712526"
+          },
+          {
+            "name":"大湖乡",
+            "code":"712527"
+          },
+          {
+            "name":"公馆乡",
+            "code":"712528"
+          },
+          {
+            "name":"铜锣乡",
+            "code":"712529"
+          },
+          {
+            "name":"南庄乡",
+            "code":"712530"
+          },
+          {
+            "name":"头屋乡",
+            "code":"712531"
+          },
+          {
+            "name":"三义乡",
+            "code":"712532"
+          },
+          {
+            "name":"西湖乡",
+            "code":"712533"
+          },
+          {
+            "name":"造桥乡",
+            "code":"712534"
+          },
+          {
+            "name":"三湾乡",
+            "code":"712535"
+          },
+          {
+            "name":"狮潭乡",
+            "code":"712536"
+          },
+          {
+            "name":"泰安乡",
+            "code":"712537"
+          }
+        ]
+      },
+      {
+        "name":"彰化县",
+        "code":"712700",
+        "sub":[
+          {
+            "name":"彰化市",
+            "code":"712701"
+          },
+          {
+            "name":"鹿港镇",
+            "code":"712721"
+          },
+          {
+            "name":"和美镇",
+            "code":"712722"
+          },
+          {
+            "name":"线西乡",
+            "code":"712723"
+          },
+          {
+            "name":"伸港乡",
+            "code":"712724"
+          },
+          {
+            "name":"福兴乡",
+            "code":"712725"
+          },
+          {
+            "name":"秀水乡",
+            "code":"712726"
+          },
+          {
+            "name":"花坛乡",
+            "code":"712727"
+          },
+          {
+            "name":"芬园乡",
+            "code":"712728"
+          },
+          {
+            "name":"员林镇",
+            "code":"712729"
+          },
+          {
+            "name":"溪湖镇",
+            "code":"712730"
+          },
+          {
+            "name":"田中镇",
+            "code":"712731"
+          },
+          {
+            "name":"大村乡",
+            "code":"712732"
+          },
+          {
+            "name":"埔盐乡",
+            "code":"712733"
+          },
+          {
+            "name":"埔心乡",
+            "code":"712734"
+          },
+          {
+            "name":"永靖乡",
+            "code":"712735"
+          },
+          {
+            "name":"社头乡",
+            "code":"712736"
+          },
+          {
+            "name":"二水乡",
+            "code":"712737"
+          },
+          {
+            "name":"北斗镇",
+            "code":"712738"
+          },
+          {
+            "name":"二林镇",
+            "code":"712739"
+          },
+          {
+            "name":"田尾乡",
+            "code":"712740"
+          },
+          {
+            "name":"埤头乡",
+            "code":"712741"
+          },
+          {
+            "name":"芳苑乡",
+            "code":"712742"
+          },
+          {
+            "name":"大城乡",
+            "code":"712743"
+          },
+          {
+            "name":"竹塘乡",
+            "code":"712744"
+          },
+          {
+            "name":"溪州乡",
+            "code":"712745"
+          }
+        ]
+      },
+      {
+        "name":"南投县",
+        "code":"712800",
+        "sub":[
+          {
+            "name":"南投市",
+            "code":"712801"
+          },
+          {
+            "name":"埔里镇",
+            "code":"712821"
+          },
+          {
+            "name":"草屯镇",
+            "code":"712822"
+          },
+          {
+            "name":"竹山镇",
+            "code":"712823"
+          },
+          {
+            "name":"集集镇",
+            "code":"712824"
+          },
+          {
+            "name":"名间乡",
+            "code":"712825"
+          },
+          {
+            "name":"鹿谷乡",
+            "code":"712826"
+          },
+          {
+            "name":"中寮乡",
+            "code":"712827"
+          },
+          {
+            "name":"鱼池乡",
+            "code":"712828"
+          },
+          {
+            "name":"国姓乡",
+            "code":"712829"
+          },
+          {
+            "name":"水里乡",
+            "code":"712830"
+          },
+          {
+            "name":"信义乡",
+            "code":"712831"
+          },
+          {
+            "name":"仁爱乡",
+            "code":"712832"
+          }
+        ]
+      },
+      {
+        "name":"云林县",
+        "code":"712900",
+        "sub":[
+          {
+            "name":"斗六市",
+            "code":"712901"
+          },
+          {
+            "name":"斗南镇",
+            "code":"712921"
+          },
+          {
+            "name":"虎尾镇",
+            "code":"712922"
+          },
+          {
+            "name":"西螺镇",
+            "code":"712923"
+          },
+          {
+            "name":"土库镇",
+            "code":"712924"
+          },
+          {
+            "name":"北港镇",
+            "code":"712925"
+          },
+          {
+            "name":"古坑乡",
+            "code":"712926"
+          },
+          {
+            "name":"大埤乡",
+            "code":"712927"
+          },
+          {
+            "name":"莿桐乡",
+            "code":"712928"
+          },
+          {
+            "name":"林内乡",
+            "code":"712929"
+          },
+          {
+            "name":"二仑乡",
+            "code":"712930"
+          },
+          {
+            "name":"仑背乡",
+            "code":"712931"
+          },
+          {
+            "name":"麦寮乡",
+            "code":"712932"
+          },
+          {
+            "name":"东势乡",
+            "code":"712933"
+          },
+          {
+            "name":"褒忠乡",
+            "code":"712934"
+          },
+          {
+            "name":"台西乡",
+            "code":"712935"
+          },
+          {
+            "name":"元长乡",
+            "code":"712936"
+          },
+          {
+            "name":"四湖乡",
+            "code":"712937"
+          },
+          {
+            "name":"口湖乡",
+            "code":"712938"
+          },
+          {
+            "name":"水林乡",
+            "code":"712939"
+          }
+        ]
+      },
+      {
+        "name":"嘉义县",
+        "code":"713000",
+        "sub":[
+          {
+            "name":"太保市",
+            "code":"713001"
+          },
+          {
+            "name":"朴子市",
+            "code":"713002"
+          },
+          {
+            "name":"布袋镇",
+            "code":"713023"
+          },
+          {
+            "name":"大林镇",
+            "code":"713024"
+          },
+          {
+            "name":"民雄乡",
+            "code":"713025"
+          },
+          {
+            "name":"溪口乡",
+            "code":"713026"
+          },
+          {
+            "name":"新港乡",
+            "code":"713027"
+          },
+          {
+            "name":"六脚乡",
+            "code":"713028"
+          },
+          {
+            "name":"东石乡",
+            "code":"713029"
+          },
+          {
+            "name":"义竹乡",
+            "code":"713030"
+          },
+          {
+            "name":"鹿草乡",
+            "code":"713031"
+          },
+          {
+            "name":"水上乡",
+            "code":"713032"
+          },
+          {
+            "name":"中埔乡",
+            "code":"713033"
+          },
+          {
+            "name":"竹崎乡",
+            "code":"713034"
+          },
+          {
+            "name":"梅山乡",
+            "code":"713035"
+          },
+          {
+            "name":"番路乡",
+            "code":"713036"
+          },
+          {
+            "name":"大埔乡",
+            "code":"713037"
+          },
+          {
+            "name":"阿里山乡",
+            "code":"713038"
+          }
+        ]
+      },
+      {
+        "name":"屏东县",
+        "code":"713300",
+        "sub":[
+          {
+            "name":"屏东市",
+            "code":"713301"
+          },
+          {
+            "name":"潮州镇",
+            "code":"713321"
+          },
+          {
+            "name":"东港镇",
+            "code":"713322"
+          },
+          {
+            "name":"恒春镇",
+            "code":"713323"
+          },
+          {
+            "name":"万丹乡",
+            "code":"713324"
+          },
+          {
+            "name":"长治乡",
+            "code":"713325"
+          },
+          {
+            "name":"麟洛乡",
+            "code":"713326"
+          },
+          {
+            "name":"九如乡",
+            "code":"713327"
+          },
+          {
+            "name":"里港乡",
+            "code":"713328"
+          },
+          {
+            "name":"盐埔乡",
+            "code":"713329"
+          },
+          {
+            "name":"高树乡",
+            "code":"713330"
+          },
+          {
+            "name":"万峦乡",
+            "code":"713331"
+          },
+          {
+            "name":"内埔乡",
+            "code":"713332"
+          },
+          {
+            "name":"竹田乡",
+            "code":"713333"
+          },
+          {
+            "name":"新埤乡",
+            "code":"713334"
+          },
+          {
+            "name":"枋寮乡",
+            "code":"713335"
+          },
+          {
+            "name":"新园乡",
+            "code":"713336"
+          },
+          {
+            "name":"崁顶乡",
+            "code":"713337"
+          },
+          {
+            "name":"林边乡",
+            "code":"713338"
+          },
+          {
+            "name":"南州乡",
+            "code":"713339"
+          },
+          {
+            "name":"佳冬乡",
+            "code":"713340"
+          },
+          {
+            "name":"琉球乡",
+            "code":"713341"
+          },
+          {
+            "name":"车城乡",
+            "code":"713342"
+          },
+          {
+            "name":"满州乡",
+            "code":"713343"
+          },
+          {
+            "name":"枋山乡",
+            "code":"713344"
+          },
+          {
+            "name":"三地门乡",
+            "code":"713345"
+          },
+          {
+            "name":"雾台乡",
+            "code":"713346"
+          },
+          {
+            "name":"玛家乡",
+            "code":"713347"
+          },
+          {
+            "name":"泰武乡",
+            "code":"713348"
+          },
+          {
+            "name":"来义乡",
+            "code":"713349"
+          },
+          {
+            "name":"春日乡",
+            "code":"713350"
+          },
+          {
+            "name":"狮子乡",
+            "code":"713351"
+          },
+          {
+            "name":"牡丹乡",
+            "code":"713352"
+          }
+        ]
+      },
+      {
+        "name":"台东县",
+        "code":"713400",
+        "sub":[
+          {
+            "name":"台东市",
+            "code":"713401"
+          },
+          {
+            "name":"成功镇",
+            "code":"713421"
+          },
+          {
+            "name":"关山镇",
+            "code":"713422"
+          },
+          {
+            "name":"卑南乡",
+            "code":"713423"
+          },
+          {
+            "name":"鹿野乡",
+            "code":"713424"
+          },
+          {
+            "name":"池上乡",
+            "code":"713425"
+          },
+          {
+            "name":"东河乡",
+            "code":"713426"
+          },
+          {
+            "name":"长滨乡",
+            "code":"713427"
+          },
+          {
+            "name":"太麻里乡",
+            "code":"713428"
+          },
+          {
+            "name":"大武乡",
+            "code":"713429"
+          },
+          {
+            "name":"绿岛乡",
+            "code":"713430"
+          },
+          {
+            "name":"海端乡",
+            "code":"713431"
+          },
+          {
+            "name":"延平乡",
+            "code":"713432"
+          },
+          {
+            "name":"金峰乡",
+            "code":"713433"
+          },
+          {
+            "name":"达仁乡",
+            "code":"713434"
+          },
+          {
+            "name":"兰屿乡",
+            "code":"713435"
+          }
+        ]
+      },
+      {
+        "name":"花莲县",
+        "code":"713500",
+        "sub":[
+          {
+            "name":"花莲市",
+            "code":"713501"
+          },
+          {
+            "name":"凤林镇",
+            "code":"713521"
+          },
+          {
+            "name":"玉里镇",
+            "code":"713522"
+          },
+          {
+            "name":"新城乡",
+            "code":"713523"
+          },
+          {
+            "name":"吉安乡",
+            "code":"713524"
+          },
+          {
+            "name":"寿丰乡",
+            "code":"713525"
+          },
+          {
+            "name":"光复乡",
+            "code":"713526"
+          },
+          {
+            "name":"丰滨乡",
+            "code":"713527"
+          },
+          {
+            "name":"瑞穗乡",
+            "code":"713528"
+          },
+          {
+            "name":"富里乡",
+            "code":"713529"
+          },
+          {
+            "name":"秀林乡",
+            "code":"713530"
+          },
+          {
+            "name":"万荣乡",
+            "code":"713531"
+          },
+          {
+            "name":"卓溪乡",
+            "code":"713532"
+          }
+        ]
+      },
+      {
+        "name":"澎湖县",
+        "code":"713600",
+        "sub":[
+          {
+            "name":"马公市",
+            "code":"713601"
+          },
+          {
+            "name":"湖西乡",
+            "code":"713621"
+          },
+          {
+            "name":"白沙乡",
+            "code":"713622"
+          },
+          {
+            "name":"西屿乡",
+            "code":"713623"
+          },
+          {
+            "name":"望安乡",
+            "code":"713624"
+          },
+          {
+            "name":"七美乡",
+            "code":"713625"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"香港特别行政区",
+    "code":"810000",
+    "sub":[
+      {
+        "name":"香港岛",
+        "code":"810100",
+        "sub":[
+          {
+            "name":"中西区",
+            "code":"810101"
+          },
+          {
+            "name":"湾仔区",
+            "code":"810102"
+          },
+          {
+            "name":"东区",
+            "code":"810103"
+          },
+          {
+            "name":"南区",
+            "code":"810104"
+          }
+        ]
+      },
+      {
+        "name":"九龙",
+        "code":"810200",
+        "sub":[
+          {
+            "name":"油尖旺区",
+            "code":"810201"
+          },
+          {
+            "name":"深水埗区",
+            "code":"810202"
+          },
+          {
+            "name":"九龙城区",
+            "code":"810203"
+          },
+          {
+            "name":"黄大仙区",
+            "code":"810204"
+          },
+          {
+            "name":"观塘区",
+            "code":"810205"
+          }
+        ]
+      },
+      {
+        "name":"新界",
+        "code":"810300",
+        "sub":[
+          {
+            "name":"荃湾区",
+            "code":"810301"
+          },
+          {
+            "name":"屯门区",
+            "code":"810302"
+          },
+          {
+            "name":"元朗区",
+            "code":"810303"
+          },
+          {
+            "name":"北区",
+            "code":"810304"
+          },
+          {
+            "name":"大埔区",
+            "code":"810305"
+          },
+          {
+            "name":"西贡区",
+            "code":"810306"
+          },
+          {
+            "name":"沙田区",
+            "code":"810307"
+          },
+          {
+            "name":"葵青区",
+            "code":"810308"
+          },
+          {
+            "name":"离岛区",
+            "code":"810309"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "name":"澳门特别行政区",
+    "code":"820000",
+    "sub":[
+      {
+        "name":"澳门半岛",
+        "code":"820100",
+        "sub":[
+          {
+            "name":"花地玛堂区",
+            "code":"820101"
+          },
+          {
+            "name":"圣安多尼堂区",
+            "code":"820102"
+          },
+          {
+            "name":"大堂区",
+            "code":"820103"
+          },
+          {
+            "name":"望德堂区",
+            "code":"820104"
+          },
+          {
+            "name":"风顺堂区",
+            "code":"820105"
+          }
+        ]
+      },
+      {
+        "name":"氹仔岛",
+        "code":"820200",
+        "sub":[
+          {
+            "name":"嘉模堂区",
+            "code":"820201"
+          }
+        ]
+      },
+      {
+        "name":"路环岛",
+        "code":"820300",
+        "sub":[
+          {
+            "name":"圣方济各堂区",
+            "code":"820301"
+          }
+        ]
+      }
+    ]
+  }
+
+];
+}($);
+// jshint ignore: end
+
+/* global $:true */
+/* jshint unused:false*/
+
++ function($) {
+  "use strict";
+
+  var defaults;
+  var raw = $.rawCitiesData;
+
+  var format = function(data) {
+    var result = [];
+    for(var i=0;i<data.length;i++) {
+      var d = data[i];
+      if(/^请选择|市辖区/.test(d.name)) continue;
+      result.push(d);
+    }
+    if(result.length) return result;
+    return [];
+  };
+
+  var sub = function(data) {
+    if(!data.sub) return [{ name: '', code: data.code }];  // 有可能某些县级市没有区
+    return format(data.sub);
+  };
+
+  var getCities = function(d) {
+    for(var i=0;i< raw.length;i++) {
+      if(raw[i].code === d || raw[i].name === d) return sub(raw[i]);
+    }
+    return [];
+  };
+
+  var getDistricts = function(p, c) {
+    for(var i=0;i< raw.length;i++) {
+      if(raw[i].code === p || raw[i].name === p) {
+        for(var j=0;j< raw[i].sub.length;j++) {
+          if(raw[i].sub[j].code === c || raw[i].sub[j].name === c) {
+            return sub(raw[i].sub[j]);
+          }
+        }
+      }
+    }
+  };
+
+  var parseInitValue = function (val) {
+    var p = raw[0], c, d;
+    var tokens = val.split(' ');
+    raw.map(function (t) {
+      if (t.name === tokens[0]) p = t;
+    });
+
+    p.sub.map(function (t) {
+      if (t.name === tokens[1]) c = t;
+    })
+
+    if (tokens[2]) {
+      c.sub.map(function (t) {
+        if (t.name === tokens[2]) d = t;
+      })
+    }
+
+    if (d) return [p.code, c.code, d.code];
+    return [p.code, c.code];
+  }
+
+  $.fn.cityPicker = function(params) {
+    params = $.extend({}, defaults, params);
+    return this.each(function() {
+      var self = this;
+      
+      var provincesName = raw.map(function(d) {
+        return d.name;
+      });
+      var provincesCode = raw.map(function(d) {
+        return d.code;
+      });
+      var initCities = sub(raw[0]);
+      var initCitiesName = initCities.map(function (c) {
+        return c.name;
+      });
+      var initCitiesCode = initCities.map(function (c) {
+        return c.code;
+      });
+      var initDistricts = sub(raw[0].sub[0]);
+
+      var initDistrictsName = initDistricts.map(function (c) {
+        return c.name;
+      });
+      var initDistrictsCode = initDistricts.map(function (c) {
+        return c.code;
+      });
+
+      var currentProvince = provincesName[0];
+      var currentCity = initCitiesName[0];
+      var currentDistrict = initDistrictsName[0];
+
+      var cols = [
+          {
+            displayValues: provincesName,
+            values: provincesCode,
+            cssClass: "col-province"
+          },
+          {
+            displayValues: initCitiesName,
+            values: initCitiesCode,
+            cssClass: "col-city"
+          }
+        ];
+
+        if(params.showDistrict) cols.push({
+          values: initDistrictsCode,
+          displayValues: initDistrictsName,
+          cssClass: "col-district"
+        });
+
+      var config = {
+
+        cssClass: "city-picker",
+        rotateEffect: false,  //为了性能
+        formatValue: function (p, values, displayValues) {
+          return displayValues.join(' ');
+        },
+        onChange: function (picker, values, displayValues) {
+          var newProvince = picker.cols[0].displayValue;
+          var newCity;
+          if(newProvince !== currentProvince) {
+            var newCities = getCities(newProvince);
+            newCity = newCities[0].name;
+            var newDistricts = getDistricts(newProvince, newCity);
+            picker.cols[1].replaceValues(newCities.map(function (c) {
+              return c.code;
+            }), newCities.map(function (c) {
+              return c.name;
+            }));
+            if(params.showDistrict) picker.cols[2].replaceValues(newDistricts.map(function (d) {
+              return d.code;
+            }), newDistricts.map(function (d) {
+              return d.name;
+            }));
+            currentProvince = newProvince;
+            currentCity = newCity;
+            picker.updateValue();
+            return false; // 因为数据未更新完,所以这里不进行后序的值的处理
+          } else {
+            if(params.showDistrict) {
+              newCity = picker.cols[1].displayValue;
+              if(newCity !== currentCity) {
+                var districts = getDistricts(newProvince, newCity);
+                picker.cols[2].replaceValues(districts.map(function (d) {
+                  return d.code;
+                }), districts.map(function (d) {
+                  return d.name;
+                }));
+                currentCity = newCity;
+                picker.updateValue();
+                return false; // 因为数据未更新完,所以这里不进行后序的值的处理
+              }
+            }
+          }
+          //如果最后一列是空的,那么取倒数第二列
+          var len = (values[values.length-1] ? values.length - 1 : values.length - 2)
+          $(self).attr('data-code', values[len]);
+          $(self).attr('data-codes', values.join(','));
+          if (params.onChange) {
+            params.onChange.call(self, picker, values, displayValues);
+          }
+        },
+
+        cols: cols
+      };
+
+      if(!this) return;
+      var p = $.extend({}, params, config);
+      //计算value
+      var val = $(this).val();
+      if (!val) val = '北京 北京市 东城区';
+      currentProvince = val.split(" ")[0];
+      currentCity = val.split(" ")[1];
+      currentDistrict= val.split(" ")[2];
+      if(val) {
+        p.value = parseInitValue(val);
+        if(p.value[0]) {
+          var cities = getCities(p.value[0]);
+          p.cols[1].values = cities.map(function (c) {
+            return c.code;
+          });
+          p.cols[1].displayValues = cities.map(function (c) {
+            return c.name;
+          });
+        }
+
+        if(p.value[1]) {
+          if (params.showDistrict) {
+            var dis = getDistricts(p.value[0], p.value[1]);
+            p.cols[2].values = dis.map(function (d) {
+              return d.code;
+            });
+            p.cols[2].displayValues = dis.map(function (d) {
+              return d.name;
+            });
+          }
+        } else {
+          if (params.showDistrict) {
+            var dis = getDistricts(p.value[0], p.cols[1].values[0]);
+            p.cols[2].values = dis.map(function (d) {
+              return d.code;
+            });
+            p.cols[2].displayValues = dis.map(function (d) {
+              return d.name;
+            });
+          }
+        }
+      }
+      $(this).picker(p);
+    });
+  };
+
+  defaults = $.fn.cityPicker.prototype.defaults = {
+    showDistrict: true //是否显示地区选择
+  };
+
+}($);
diff --git a/platforms/android/app/src/main/assets/www/js/lib/city-picker.min.js b/platforms/android/app/src/main/assets/www/js/lib/city-picker.min.js
new file mode 100755
index 0000000..8091f11
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/city-picker.min.js
@@ -0,0 +1,5 @@
+// jshint ignore: start
++function(e){e.rawCitiesData=[{name:"北京",code:"110000",sub:[{name:"北京市",code:"110000",sub:[{name:"东城区",code:"110101"},{name:"西城区",code:"110102"},{name:"朝阳区",code:"110105"},{name:"丰台区",code:"110106"},{name:"石景山区",code:"110107"},{name:"海淀区",code:"110108"},{name:"门头沟区",code:"110109"},{name:"房山区",code:"110111"},{name:"通州区",code:"110112"},{name:"顺义区",code:"110113"},{name:"昌平区",code:"110114"},{name:"大兴区",code:"110115"},{name:"怀柔区",code:"110116"},{name:"平谷区",code:"110117"},{name:"密云县",code:"110228"},{name:"延庆县",code:"110229"}]}]},{name:"天津",code:"120000",sub:[{name:"天津市",code:"120000",sub:[{name:"和平区",code:"120101"},{name:"河东区",code:"120102"},{name:"河西区",code:"120103"},{name:"南开区",code:"120104"},{name:"河北区",code:"120105"},{name:"红桥区",code:"120106"},{name:"东丽区",code:"120110"},{name:"西青区",code:"120111"},{name:"津南区",code:"120112"},{name:"北辰区",code:"120113"},{name:"武清区",code:"120114"},{name:"宝坻区",code:"120115"},{name:"滨海新区",code:"120116"},{name:"宁河县",code:"120221"},{name:"静海县",code:"120223"},{name:"蓟县",code:"120225"}]}]},{name:"河北省",code:"130000",sub:[{name:"石家庄市",code:"130100",sub:[{name:"市辖区",code:"130101"},{name:"长安区",code:"130102"},{name:"桥西区",code:"130104"},{name:"新华区",code:"130105"},{name:"井陉矿区",code:"130107"},{name:"裕华区",code:"130108"},{name:"藁城区",code:"130109"},{name:"鹿泉区",code:"130110"},{name:"栾城区",code:"130111"},{name:"井陉县",code:"130121"},{name:"正定县",code:"130123"},{name:"行唐县",code:"130125"},{name:"灵寿县",code:"130126"},{name:"高邑县",code:"130127"},{name:"深泽县",code:"130128"},{name:"赞皇县",code:"130129"},{name:"无极县",code:"130130"},{name:"平山县",code:"130131"},{name:"元氏县",code:"130132"},{name:"赵县",code:"130133"},{name:"辛集市",code:"130181"},{name:"晋州市",code:"130183"},{name:"新乐市",code:"130184"}]},{name:"唐山市",code:"130200",sub:[{name:"市辖区",code:"130201"},{name:"路南区",code:"130202"},{name:"路北区",code:"130203"},{name:"古冶区",code:"130204"},{name:"开平区",code:"130205"},{name:"丰南区",code:"130207"},{name:"丰润区",code:"130208"},{name:"曹妃甸区",code:"130209"},{name:"滦县",code:"130223"},{name:"滦南县",code:"130224"},{name:"乐亭县",code:"130225"},{name:"迁西县",code:"130227"},{name:"玉田县",code:"130229"},{name:"遵化市",code:"130281"},{name:"迁安市",code:"130283"}]},{name:"秦皇岛市",code:"130300",sub:[{name:"市辖区",code:"130301"},{name:"海港区",code:"130302"},{name:"山海关区",code:"130303"},{name:"北戴河区",code:"130304"},{name:"青龙满族自治县",code:"130321"},{name:"昌黎县",code:"130322"},{name:"抚宁县",code:"130323"},{name:"卢龙县",code:"130324"}]},{name:"邯郸市",code:"130400",sub:[{name:"市辖区",code:"130401"},{name:"邯山区",code:"130402"},{name:"丛台区",code:"130403"},{name:"复兴区",code:"130404"},{name:"峰峰矿区",code:"130406"},{name:"邯郸县",code:"130421"},{name:"临漳县",code:"130423"},{name:"成安县",code:"130424"},{name:"大名县",code:"130425"},{name:"涉县",code:"130426"},{name:"磁县",code:"130427"},{name:"肥乡县",code:"130428"},{name:"永年县",code:"130429"},{name:"邱县",code:"130430"},{name:"鸡泽县",code:"130431"},{name:"广平县",code:"130432"},{name:"馆陶县",code:"130433"},{name:"魏县",code:"130434"},{name:"曲周县",code:"130435"},{name:"武安市",code:"130481"}]},{name:"邢台市",code:"130500",sub:[{name:"市辖区",code:"130501"},{name:"桥东区",code:"130502"},{name:"桥西区",code:"130503"},{name:"邢台县",code:"130521"},{name:"临城县",code:"130522"},{name:"内丘县",code:"130523"},{name:"柏乡县",code:"130524"},{name:"隆尧县",code:"130525"},{name:"任县",code:"130526"},{name:"南和县",code:"130527"},{name:"宁晋县",code:"130528"},{name:"巨鹿县",code:"130529"},{name:"新河县",code:"130530"},{name:"广宗县",code:"130531"},{name:"平乡县",code:"130532"},{name:"威县",code:"130533"},{name:"清河县",code:"130534"},{name:"临西县",code:"130535"},{name:"南宫市",code:"130581"},{name:"沙河市",code:"130582"}]},{name:"保定市",code:"130600",sub:[{name:"市辖区",code:"130601"},{name:"新市区",code:"130602"},{name:"北市区",code:"130603"},{name:"南市区",code:"130604"},{name:"满城县",code:"130621"},{name:"清苑县",code:"130622"},{name:"涞水县",code:"130623"},{name:"阜平县",code:"130624"},{name:"徐水县",code:"130625"},{name:"定兴县",code:"130626"},{name:"唐县",code:"130627"},{name:"高阳县",code:"130628"},{name:"容城县",code:"130629"},{name:"涞源县",code:"130630"},{name:"望都县",code:"130631"},{name:"安新县",code:"130632"},{name:"易县",code:"130633"},{name:"曲阳县",code:"130634"},{name:"蠡县",code:"130635"},{name:"顺平县",code:"130636"},{name:"博野县",code:"130637"},{name:"雄县",code:"130638"},{name:"涿州市",code:"130681"},{name:"定州市",code:"130682"},{name:"安国市",code:"130683"},{name:"高碑店市",code:"130684"}]},{name:"张家口市",code:"130700",sub:[{name:"市辖区",code:"130701"},{name:"桥东区",code:"130702"},{name:"桥西区",code:"130703"},{name:"宣化区",code:"130705"},{name:"下花园区",code:"130706"},{name:"宣化县",code:"130721"},{name:"张北县",code:"130722"},{name:"康保县",code:"130723"},{name:"沽源县",code:"130724"},{name:"尚义县",code:"130725"},{name:"蔚县",code:"130726"},{name:"阳原县",code:"130727"},{name:"怀安县",code:"130728"},{name:"万全县",code:"130729"},{name:"怀来县",code:"130730"},{name:"涿鹿县",code:"130731"},{name:"赤城县",code:"130732"},{name:"崇礼县",code:"130733"}]},{name:"承德市",code:"130800",sub:[{name:"市辖区",code:"130801"},{name:"双桥区",code:"130802"},{name:"双滦区",code:"130803"},{name:"鹰手营子矿区",code:"130804"},{name:"承德县",code:"130821"},{name:"兴隆县",code:"130822"},{name:"平泉县",code:"130823"},{name:"滦平县",code:"130824"},{name:"隆化县",code:"130825"},{name:"丰宁满族自治县",code:"130826"},{name:"宽城满族自治县",code:"130827"},{name:"围场满族蒙古族自治县",code:"130828"}]},{name:"沧州市",code:"130900",sub:[{name:"市辖区",code:"130901"},{name:"新华区",code:"130902"},{name:"运河区",code:"130903"},{name:"沧县",code:"130921"},{name:"青县",code:"130922"},{name:"东光县",code:"130923"},{name:"海兴县",code:"130924"},{name:"盐山县",code:"130925"},{name:"肃宁县",code:"130926"},{name:"南皮县",code:"130927"},{name:"吴桥县",code:"130928"},{name:"献县",code:"130929"},{name:"孟村回族自治县",code:"130930"},{name:"泊头市",code:"130981"},{name:"任丘市",code:"130982"},{name:"黄骅市",code:"130983"},{name:"河间市",code:"130984"}]},{name:"廊坊市",code:"131000",sub:[{name:"市辖区",code:"131001"},{name:"安次区",code:"131002"},{name:"广阳区",code:"131003"},{name:"固安县",code:"131022"},{name:"永清县",code:"131023"},{name:"香河县",code:"131024"},{name:"大城县",code:"131025"},{name:"文安县",code:"131026"},{name:"大厂回族自治县",code:"131028"},{name:"霸州市",code:"131081"},{name:"三河市",code:"131082"}]},{name:"衡水市",code:"131100",sub:[{name:"市辖区",code:"131101"},{name:"桃城区",code:"131102"},{name:"枣强县",code:"131121"},{name:"武邑县",code:"131122"},{name:"武强县",code:"131123"},{name:"饶阳县",code:"131124"},{name:"安平县",code:"131125"},{name:"故城县",code:"131126"},{name:"景县",code:"131127"},{name:"阜城县",code:"131128"},{name:"冀州市",code:"131181"},{name:"深州市",code:"131182"}]}]},{name:"山西省",code:"140000",sub:[{name:"太原市",code:"140100",sub:[{name:"市辖区",code:"140101"},{name:"小店区",code:"140105"},{name:"迎泽区",code:"140106"},{name:"杏花岭区",code:"140107"},{name:"尖草坪区",code:"140108"},{name:"万柏林区",code:"140109"},{name:"晋源区",code:"140110"},{name:"清徐县",code:"140121"},{name:"阳曲县",code:"140122"},{name:"娄烦县",code:"140123"},{name:"古交市",code:"140181"}]},{name:"大同市",code:"140200",sub:[{name:"市辖区",code:"140201"},{name:"城区",code:"140202"},{name:"矿区",code:"140203"},{name:"南郊区",code:"140211"},{name:"新荣区",code:"140212"},{name:"阳高县",code:"140221"},{name:"天镇县",code:"140222"},{name:"广灵县",code:"140223"},{name:"灵丘县",code:"140224"},{name:"浑源县",code:"140225"},{name:"左云县",code:"140226"},{name:"大同县",code:"140227"}]},{name:"阳泉市",code:"140300",sub:[{name:"市辖区",code:"140301"},{name:"城区",code:"140302"},{name:"矿区",code:"140303"},{name:"郊区",code:"140311"},{name:"平定县",code:"140321"},{name:"盂县",code:"140322"}]},{name:"长治市",code:"140400",sub:[{name:"市辖区",code:"140401"},{name:"城区",code:"140402"},{name:"郊区",code:"140411"},{name:"长治县",code:"140421"},{name:"襄垣县",code:"140423"},{name:"屯留县",code:"140424"},{name:"平顺县",code:"140425"},{name:"黎城县",code:"140426"},{name:"壶关县",code:"140427"},{name:"长子县",code:"140428"},{name:"武乡县",code:"140429"},{name:"沁县",code:"140430"},{name:"沁源县",code:"140431"},{name:"潞城市",code:"140481"}]},{name:"晋城市",code:"140500",sub:[{name:"市辖区",code:"140501"},{name:"城区",code:"140502"},{name:"沁水县",code:"140521"},{name:"阳城县",code:"140522"},{name:"陵川县",code:"140524"},{name:"泽州县",code:"140525"},{name:"高平市",code:"140581"}]},{name:"朔州市",code:"140600",sub:[{name:"市辖区",code:"140601"},{name:"朔城区",code:"140602"},{name:"平鲁区",code:"140603"},{name:"山阴县",code:"140621"},{name:"应县",code:"140622"},{name:"右玉县",code:"140623"},{name:"怀仁县",code:"140624"}]},{name:"晋中市",code:"140700",sub:[{name:"市辖区",code:"140701"},{name:"榆次区",code:"140702"},{name:"榆社县",code:"140721"},{name:"左权县",code:"140722"},{name:"和顺县",code:"140723"},{name:"昔阳县",code:"140724"},{name:"寿阳县",code:"140725"},{name:"太谷县",code:"140726"},{name:"祁县",code:"140727"},{name:"平遥县",code:"140728"},{name:"灵石县",code:"140729"},{name:"介休市",code:"140781"}]},{name:"运城市",code:"140800",sub:[{name:"市辖区",code:"140801"},{name:"盐湖区",code:"140802"},{name:"临猗县",code:"140821"},{name:"万荣县",code:"140822"},{name:"闻喜县",code:"140823"},{name:"稷山县",code:"140824"},{name:"新绛县",code:"140825"},{name:"绛县",code:"140826"},{name:"垣曲县",code:"140827"},{name:"夏县",code:"140828"},{name:"平陆县",code:"140829"},{name:"芮城县",code:"140830"},{name:"永济市",code:"140881"},{name:"河津市",code:"140882"}]},{name:"忻州市",code:"140900",sub:[{name:"市辖区",code:"140901"},{name:"忻府区",code:"140902"},{name:"定襄县",code:"140921"},{name:"五台县",code:"140922"},{name:"代县",code:"140923"},{name:"繁峙县",code:"140924"},{name:"宁武县",code:"140925"},{name:"静乐县",code:"140926"},{name:"神池县",code:"140927"},{name:"五寨县",code:"140928"},{name:"岢岚县",code:"140929"},{name:"河曲县",code:"140930"},{name:"保德县",code:"140931"},{name:"偏关县",code:"140932"},{name:"原平市",code:"140981"}]},{name:"临汾市",code:"141000",sub:[{name:"市辖区",code:"141001"},{name:"尧都区",code:"141002"},{name:"曲沃县",code:"141021"},{name:"翼城县",code:"141022"},{name:"襄汾县",code:"141023"},{name:"洪洞县",code:"141024"},{name:"古县",code:"141025"},{name:"安泽县",code:"141026"},{name:"浮山县",code:"141027"},{name:"吉县",code:"141028"},{name:"乡宁县",code:"141029"},{name:"大宁县",code:"141030"},{name:"隰县",code:"141031"},{name:"永和县",code:"141032"},{name:"蒲县",code:"141033"},{name:"汾西县",code:"141034"},{name:"侯马市",code:"141081"},{name:"霍州市",code:"141082"}]},{name:"吕梁市",code:"141100",sub:[{name:"市辖区",code:"141101"},{name:"离石区",code:"141102"},{name:"文水县",code:"141121"},{name:"交城县",code:"141122"},{name:"兴县",code:"141123"},{name:"临县",code:"141124"},{name:"柳林县",code:"141125"},{name:"石楼县",code:"141126"},{name:"岚县",code:"141127"},{name:"方山县",code:"141128"},{name:"中阳县",code:"141129"},{name:"交口县",code:"141130"},{name:"孝义市",code:"141181"},{name:"汾阳市",code:"141182"}]}]},{name:"内蒙古自治区",code:"150000",sub:[{name:"呼和浩特市",code:"150100",sub:[{name:"市辖区",code:"150101"},{name:"新城区",code:"150102"},{name:"回民区",code:"150103"},{name:"玉泉区",code:"150104"},{name:"赛罕区",code:"150105"},{name:"土默特左旗",code:"150121"},{name:"托克托县",code:"150122"},{name:"和林格尔县",code:"150123"},{name:"清水河县",code:"150124"},{name:"武川县",code:"150125"}]},{name:"包头市",code:"150200",sub:[{name:"市辖区",code:"150201"},{name:"东河区",code:"150202"},{name:"昆都仑区",code:"150203"},{name:"青山区",code:"150204"},{name:"石拐区",code:"150205"},{name:"白云鄂博矿区",code:"150206"},{name:"九原区",code:"150207"},{name:"土默特右旗",code:"150221"},{name:"固阳县",code:"150222"},{name:"达尔罕茂明安联合旗",code:"150223"}]},{name:"乌海市",code:"150300",sub:[{name:"市辖区",code:"150301"},{name:"海勃湾区",code:"150302"},{name:"海南区",code:"150303"},{name:"乌达区",code:"150304"}]},{name:"赤峰市",code:"150400",sub:[{name:"市辖区",code:"150401"},{name:"红山区",code:"150402"},{name:"元宝山区",code:"150403"},{name:"松山区",code:"150404"},{name:"阿鲁科尔沁旗",code:"150421"},{name:"巴林左旗",code:"150422"},{name:"巴林右旗",code:"150423"},{name:"林西县",code:"150424"},{name:"克什克腾旗",code:"150425"},{name:"翁牛特旗",code:"150426"},{name:"喀喇沁旗",code:"150428"},{name:"宁城县",code:"150429"},{name:"敖汉旗",code:"150430"}]},{name:"通辽市",code:"150500",sub:[{name:"市辖区",code:"150501"},{name:"科尔沁区",code:"150502"},{name:"科尔沁左翼中旗",code:"150521"},{name:"科尔沁左翼后旗",code:"150522"},{name:"开鲁县",code:"150523"},{name:"库伦旗",code:"150524"},{name:"奈曼旗",code:"150525"},{name:"扎鲁特旗",code:"150526"},{name:"霍林郭勒市",code:"150581"}]},{name:"鄂尔多斯市",code:"150600",sub:[{name:"市辖区",code:"150601"},{name:"东胜区",code:"150602"},{name:"达拉特旗",code:"150621"},{name:"准格尔旗",code:"150622"},{name:"鄂托克前旗",code:"150623"},{name:"鄂托克旗",code:"150624"},{name:"杭锦旗",code:"150625"},{name:"乌审旗",code:"150626"},{name:"伊金霍洛旗",code:"150627"}]},{name:"呼伦贝尔市",code:"150700",sub:[{name:"市辖区",code:"150701"},{name:"海拉尔区",code:"150702"},{name:"扎赉诺尔区",code:"150703"},{name:"阿荣旗",code:"150721"},{name:"莫力达瓦达斡尔族自治旗",code:"150722"},{name:"鄂伦春自治旗",code:"150723"},{name:"鄂温克族自治旗",code:"150724"},{name:"陈巴尔虎旗",code:"150725"},{name:"新巴尔虎左旗",code:"150726"},{name:"新巴尔虎右旗",code:"150727"},{name:"满洲里市",code:"150781"},{name:"牙克石市",code:"150782"},{name:"扎兰屯市",code:"150783"},{name:"额尔古纳市",code:"150784"},{name:"根河市",code:"150785"}]},{name:"巴彦淖尔市",code:"150800",sub:[{name:"市辖区",code:"150801"},{name:"临河区",code:"150802"},{name:"五原县",code:"150821"},{name:"磴口县",code:"150822"},{name:"乌拉特前旗",code:"150823"},{name:"乌拉特中旗",code:"150824"},{name:"乌拉特后旗",code:"150825"},{name:"杭锦后旗",code:"150826"}]},{name:"乌兰察布市",code:"150900",sub:[{name:"市辖区",code:"150901"},{name:"集宁区",code:"150902"},{name:"卓资县",code:"150921"},{name:"化德县",code:"150922"},{name:"商都县",code:"150923"},{name:"兴和县",code:"150924"},{name:"凉城县",code:"150925"},{name:"察哈尔右翼前旗",code:"150926"},{name:"察哈尔右翼中旗",code:"150927"},{name:"察哈尔右翼后旗",code:"150928"},{name:"四子王旗",code:"150929"},{name:"丰镇市",code:"150981"}]},{name:"兴安盟",code:"152200",sub:[{name:"乌兰浩特市",code:"152201"},{name:"阿尔山市",code:"152202"},{name:"科尔沁右翼前旗",code:"152221"},{name:"科尔沁右翼中旗",code:"152222"},{name:"扎赉特旗",code:"152223"},{name:"突泉县",code:"152224"}]},{name:"锡林郭勒盟",code:"152500",sub:[{name:"二连浩特市",code:"152501"},{name:"锡林浩特市",code:"152502"},{name:"阿巴嘎旗",code:"152522"},{name:"苏尼特左旗",code:"152523"},{name:"苏尼特右旗",code:"152524"},{name:"东乌珠穆沁旗",code:"152525"},{name:"西乌珠穆沁旗",code:"152526"},{name:"太仆寺旗",code:"152527"},{name:"镶黄旗",code:"152528"},{name:"正镶白旗",code:"152529"},{name:"正蓝旗",code:"152530"},{name:"多伦县",code:"152531"}]},{name:"阿拉善盟",code:"152900",sub:[{name:"阿拉善左旗",code:"152921"},{name:"阿拉善右旗",code:"152922"},{name:"额济纳旗",code:"152923"}]}]},{name:"辽宁省",code:"210000",sub:[{name:"沈阳市",code:"210100",sub:[{name:"市辖区",code:"210101"},{name:"和平区",code:"210102"},{name:"沈河区",code:"210103"},{name:"大东区",code:"210104"},{name:"皇姑区",code:"210105"},{name:"铁西区",code:"210106"},{name:"苏家屯区",code:"210111"},{name:"浑南区",code:"210112"},{name:"沈北新区",code:"210113"},{name:"于洪区",code:"210114"},{name:"辽中县",code:"210122"},{name:"康平县",code:"210123"},{name:"法库县",code:"210124"},{name:"新民市",code:"210181"}]},{name:"大连市",code:"210200",sub:[{name:"市辖区",code:"210201"},{name:"中山区",code:"210202"},{name:"西岗区",code:"210203"},{name:"沙河口区",code:"210204"},{name:"甘井子区",code:"210211"},{name:"旅顺口区",code:"210212"},{name:"金州区",code:"210213"},{name:"长海县",code:"210224"},{name:"瓦房店市",code:"210281"},{name:"普兰店市",code:"210282"},{name:"庄河市",code:"210283"}]},{name:"鞍山市",code:"210300",sub:[{name:"市辖区",code:"210301"},{name:"铁东区",code:"210302"},{name:"铁西区",code:"210303"},{name:"立山区",code:"210304"},{name:"千山区",code:"210311"},{name:"台安县",code:"210321"},{name:"岫岩满族自治县",code:"210323"},{name:"海城市",code:"210381"}]},{name:"抚顺市",code:"210400",sub:[{name:"市辖区",code:"210401"},{name:"新抚区",code:"210402"},{name:"东洲区",code:"210403"},{name:"望花区",code:"210404"},{name:"顺城区",code:"210411"},{name:"抚顺县",code:"210421"},{name:"新宾满族自治县",code:"210422"},{name:"清原满族自治县",code:"210423"}]},{name:"本溪市",code:"210500",sub:[{name:"市辖区",code:"210501"},{name:"平山区",code:"210502"},{name:"溪湖区",code:"210503"},{name:"明山区",code:"210504"},{name:"南芬区",code:"210505"},{name:"本溪满族自治县",code:"210521"},{name:"桓仁满族自治县",code:"210522"}]},{name:"丹东市",code:"210600",sub:[{name:"市辖区",code:"210601"},{name:"元宝区",code:"210602"},{name:"振兴区",code:"210603"},{name:"振安区",code:"210604"},{name:"宽甸满族自治县",code:"210624"},{name:"东港市",code:"210681"},{name:"凤城市",code:"210682"}]},{name:"锦州市",code:"210700",sub:[{name:"市辖区",code:"210701"},{name:"古塔区",code:"210702"},{name:"凌河区",code:"210703"},{name:"太和区",code:"210711"},{name:"黑山县",code:"210726"},{name:"义县",code:"210727"},{name:"凌海市",code:"210781"},{name:"北镇市",code:"210782"}]},{name:"营口市",code:"210800",sub:[{name:"市辖区",code:"210801"},{name:"站前区",code:"210802"},{name:"西市区",code:"210803"},{name:"鲅鱼圈区",code:"210804"},{name:"老边区",code:"210811"},{name:"盖州市",code:"210881"},{name:"大石桥市",code:"210882"}]},{name:"阜新市",code:"210900",sub:[{name:"市辖区",code:"210901"},{name:"海州区",code:"210902"},{name:"新邱区",code:"210903"},{name:"太平区",code:"210904"},{name:"清河门区",code:"210905"},{name:"细河区",code:"210911"},{name:"阜新蒙古族自治县",code:"210921"},{name:"彰武县",code:"210922"}]},{name:"辽阳市",code:"211000",sub:[{name:"市辖区",code:"211001"},{name:"白塔区",code:"211002"},{name:"文圣区",code:"211003"},{name:"宏伟区",code:"211004"},{name:"弓长岭区",code:"211005"},{name:"太子河区",code:"211011"},{name:"辽阳县",code:"211021"},{name:"灯塔市",code:"211081"}]},{name:"盘锦市",code:"211100",sub:[{name:"市辖区",code:"211101"},{name:"双台子区",code:"211102"},{name:"兴隆台区",code:"211103"},{name:"大洼县",code:"211121"},{name:"盘山县",code:"211122"}]},{name:"铁岭市",code:"211200",sub:[{name:"市辖区",code:"211201"},{name:"银州区",code:"211202"},{name:"清河区",code:"211204"},{name:"铁岭县",code:"211221"},{name:"西丰县",code:"211223"},{name:"昌图县",code:"211224"},{name:"调兵山市",code:"211281"},{name:"开原市",code:"211282"}]},{name:"朝阳市",code:"211300",sub:[{name:"市辖区",code:"211301"},{name:"双塔区",code:"211302"},{name:"龙城区",code:"211303"},{name:"朝阳县",code:"211321"},{name:"建平县",code:"211322"},{name:"喀喇沁左翼蒙古族自治县",code:"211324"},{name:"北票市",code:"211381"},{name:"凌源市",code:"211382"}]},{name:"葫芦岛市",code:"211400",sub:[{name:"市辖区",code:"211401"},{name:"连山区",code:"211402"},{name:"龙港区",code:"211403"},{name:"南票区",code:"211404"},{name:"绥中县",code:"211421"},{name:"建昌县",code:"211422"},{name:"兴城市",code:"211481"}]}]},{name:"吉林省",code:"220000",sub:[{name:"长春市",code:"220100",sub:[{name:"市辖区",code:"220101"},{name:"南关区",code:"220102"},{name:"宽城区",code:"220103"},{name:"朝阳区",code:"220104"},{name:"二道区",code:"220105"},{name:"绿园区",code:"220106"},{name:"双阳区",code:"220112"},{name:"九台区",code:"220113"},{name:"农安县",code:"220122"},{name:"榆树市",code:"220182"},{name:"德惠市",code:"220183"}]},{name:"吉林市",code:"220200",sub:[{name:"市辖区",code:"220201"},{name:"昌邑区",code:"220202"},{name:"龙潭区",code:"220203"},{name:"船营区",code:"220204"},{name:"丰满区",code:"220211"},{name:"永吉县",code:"220221"},{name:"蛟河市",code:"220281"},{name:"桦甸市",code:"220282"},{name:"舒兰市",code:"220283"},{name:"磐石市",code:"220284"}]},{name:"四平市",code:"220300",sub:[{name:"市辖区",code:"220301"},{name:"铁西区",code:"220302"},{name:"铁东区",code:"220303"},{name:"梨树县",code:"220322"},{name:"伊通满族自治县",code:"220323"},{name:"公主岭市",code:"220381"},{name:"双辽市",code:"220382"}]},{name:"辽源市",code:"220400",sub:[{name:"市辖区",code:"220401"},{name:"龙山区",code:"220402"},{name:"西安区",code:"220403"},{name:"东丰县",code:"220421"},{name:"东辽县",code:"220422"}]},{name:"通化市",code:"220500",sub:[{name:"市辖区",code:"220501"},{name:"东昌区",code:"220502"},{name:"二道江区",code:"220503"},{name:"通化县",code:"220521"},{name:"辉南县",code:"220523"},{name:"柳河县",code:"220524"},{name:"梅河口市",code:"220581"},{name:"集安市",code:"220582"}]},{name:"白山市",code:"220600",sub:[{name:"市辖区",code:"220601"},{name:"浑江区",code:"220602"},{name:"江源区",code:"220605"},{name:"抚松县",code:"220621"},{name:"靖宇县",code:"220622"},{name:"长白朝鲜族自治县",code:"220623"},{name:"临江市",code:"220681"}]},{name:"松原市",code:"220700",sub:[{name:"市辖区",code:"220701"},{name:"宁江区",code:"220702"},{name:"前郭尔罗斯蒙古族自治县",code:"220721"},{name:"长岭县",code:"220722"},{name:"乾安县",code:"220723"},{name:"扶余市",code:"220781"}]},{name:"白城市",code:"220800",sub:[{name:"市辖区",code:"220801"},{name:"洮北区",code:"220802"},{name:"镇赉县",code:"220821"},{name:"通榆县",code:"220822"},{name:"洮南市",code:"220881"},{name:"大安市",code:"220882"}]},{name:"延边朝鲜族自治州",code:"222400",sub:[{name:"延吉市",code:"222401"},{name:"图们市",code:"222402"},{name:"敦化市",code:"222403"},{name:"珲春市",code:"222404"},{name:"龙井市",code:"222405"},{name:"和龙市",code:"222406"},{name:"汪清县",code:"222424"},{name:"安图县",code:"222426"}]}]},{name:"黑龙江省",code:"230000",sub:[{name:"哈尔滨市",code:"230100",sub:[{name:"市辖区",code:"230101"},{name:"道里区",code:"230102"},{name:"南岗区",code:"230103"},{name:"道外区",code:"230104"},{name:"平房区",code:"230108"},{name:"松北区",code:"230109"},{name:"香坊区",code:"230110"},{name:"呼兰区",code:"230111"},{name:"阿城区",code:"230112"},{name:"双城区",code:"230113"},{name:"依兰县",code:"230123"},{name:"方正县",code:"230124"},{name:"宾县",code:"230125"},{name:"巴彦县",code:"230126"},{name:"木兰县",code:"230127"},{name:"通河县",code:"230128"},{name:"延寿县",code:"230129"},{name:"尚志市",code:"230183"},{name:"五常市",code:"230184"}]},{name:"齐齐哈尔市",code:"230200",sub:[{name:"市辖区",code:"230201"},{name:"龙沙区",code:"230202"},{name:"建华区",code:"230203"},{name:"铁锋区",code:"230204"},{name:"昂昂溪区",code:"230205"},{name:"富拉尔基区",code:"230206"},{name:"碾子山区",code:"230207"},{name:"梅里斯达斡尔族区",code:"230208"},{name:"龙江县",code:"230221"},{name:"依安县",code:"230223"},{name:"泰来县",code:"230224"},{name:"甘南县",code:"230225"},{name:"富裕县",code:"230227"},{name:"克山县",code:"230229"},{name:"克东县",code:"230230"},{name:"拜泉县",code:"230231"},{name:"讷河市",code:"230281"}]},{name:"鸡西市",code:"230300",sub:[{name:"市辖区",code:"230301"},{name:"鸡冠区",code:"230302"},{name:"恒山区",code:"230303"},{name:"滴道区",code:"230304"},{name:"梨树区",code:"230305"},{name:"城子河区",code:"230306"},{name:"麻山区",code:"230307"},{name:"鸡东县",code:"230321"},{name:"虎林市",code:"230381"},{name:"密山市",code:"230382"}]},{name:"鹤岗市",code:"230400",sub:[{name:"市辖区",code:"230401"},{name:"向阳区",code:"230402"},{name:"工农区",code:"230403"},{name:"南山区",code:"230404"},{name:"兴安区",code:"230405"},{name:"东山区",code:"230406"},{name:"兴山区",code:"230407"},{name:"萝北县",code:"230421"},{name:"绥滨县",code:"230422"}]},{name:"双鸭山市",code:"230500",sub:[{name:"市辖区",code:"230501"},{name:"尖山区",code:"230502"},{name:"岭东区",code:"230503"},{name:"四方台区",code:"230505"},{name:"宝山区",code:"230506"},{name:"集贤县",code:"230521"},{name:"友谊县",code:"230522"},{name:"宝清县",code:"230523"},{name:"饶河县",code:"230524"}]},{name:"大庆市",code:"230600",sub:[{name:"市辖区",code:"230601"},{name:"萨尔图区",code:"230602"},{name:"龙凤区",code:"230603"},{name:"让胡路区",code:"230604"},{name:"红岗区",code:"230605"},{name:"大同区",code:"230606"},{name:"肇州县",code:"230621"},{name:"肇源县",code:"230622"},{name:"林甸县",code:"230623"},{name:"杜尔伯特蒙古族自治县",code:"230624"}]},{name:"伊春市",code:"230700",sub:[{name:"市辖区",code:"230701"},{name:"伊春区",code:"230702"},{name:"南岔区",code:"230703"},{name:"友好区",code:"230704"},{name:"西林区",code:"230705"},{name:"翠峦区",code:"230706"},{name:"新青区",code:"230707"},{name:"美溪区",code:"230708"},{name:"金山屯区",code:"230709"},{name:"五营区",code:"230710"},{name:"乌马河区",code:"230711"},{name:"汤旺河区",code:"230712"},{name:"带岭区",code:"230713"},{name:"乌伊岭区",code:"230714"},{name:"红星区",code:"230715"},{name:"上甘岭区",code:"230716"},{name:"嘉荫县",code:"230722"},{name:"铁力市",code:"230781"}]},{name:"佳木斯市",code:"230800",sub:[{name:"市辖区",code:"230801"},{name:"向阳区",code:"230803"},{name:"前进区",code:"230804"},{name:"东风区",code:"230805"},{name:"郊区",code:"230811"},{name:"桦南县",code:"230822"},{name:"桦川县",code:"230826"},{name:"汤原县",code:"230828"},{name:"抚远县",code:"230833"},{name:"同江市",code:"230881"},{name:"富锦市",code:"230882"}]},{name:"七台河市",code:"230900",sub:[{name:"市辖区",code:"230901"},{name:"新兴区",code:"230902"},{name:"桃山区",code:"230903"},{name:"茄子河区",code:"230904"},{name:"勃利县",code:"230921"}]},{name:"牡丹江市",code:"231000",sub:[{name:"市辖区",code:"231001"},{name:"东安区",code:"231002"},{name:"阳明区",code:"231003"},{name:"爱民区",code:"231004"},{name:"西安区",code:"231005"},{name:"东宁县",code:"231024"},{name:"林口县",code:"231025"},{name:"绥芬河市",code:"231081"},{name:"海林市",code:"231083"},{name:"宁安市",code:"231084"},{name:"穆棱市",code:"231085"}]},{name:"黑河市",code:"231100",sub:[{name:"市辖区",code:"231101"},{name:"爱辉区",code:"231102"},{name:"嫩江县",code:"231121"},{name:"逊克县",code:"231123"},{name:"孙吴县",code:"231124"},{name:"北安市",code:"231181"},{name:"五大连池市",code:"231182"}]},{name:"绥化市",code:"231200",sub:[{name:"市辖区",code:"231201"},{name:"北林区",code:"231202"},{name:"望奎县",code:"231221"},{name:"兰西县",code:"231222"},{name:"青冈县",code:"231223"},{name:"庆安县",code:"231224"},{name:"明水县",code:"231225"},{name:"绥棱县",code:"231226"},{name:"安达市",code:"231281"},{name:"肇东市",code:"231282"},{name:"海伦市",code:"231283"}]},{name:"大兴安岭地区",code:"232700",sub:[{name:"呼玛县",code:"232721"},{name:"塔河县",code:"232722"},{name:"漠河县",code:"232723"}]}]},{name:"上海",code:"310000",sub:[{name:"上海市",code:"310000",sub:[{name:"黄浦区",code:"310101"},{name:"徐汇区",code:"310104"},{name:"长宁区",code:"310105"},{name:"静安区",code:"310106"},{name:"普陀区",code:"310107"},{name:"闸北区",code:"310108"},{name:"虹口区",code:"310109"},{name:"杨浦区",code:"310110"},{name:"闵行区",code:"310112"},{name:"宝山区",code:"310113"},{name:"嘉定区",code:"310114"},{name:"浦东新区",code:"310115"},{name:"金山区",code:"310116"},{name:"松江区",code:"310117"},{name:"青浦区",code:"310118"},{name:"奉贤区",code:"310120"},{name:"崇明县",code:"310230"}]}]},{name:"江苏省",code:"320000",sub:[{name:"南京市",code:"320100",sub:[{name:"市辖区",code:"320101"},{name:"玄武区",code:"320102"},{name:"秦淮区",code:"320104"},{name:"建邺区",code:"320105"},{name:"鼓楼区",code:"320106"},{name:"浦口区",code:"320111"},{name:"栖霞区",code:"320113"},{name:"雨花台区",code:"320114"},{name:"江宁区",code:"320115"},{name:"六合区",code:"320116"},{name:"溧水区",code:"320117"},{name:"高淳区",code:"320118"}]},{name:"无锡市",code:"320200",sub:[{name:"市辖区",code:"320201"},{name:"崇安区",code:"320202"},{name:"南长区",code:"320203"},{name:"北塘区",code:"320204"},{name:"锡山区",code:"320205"},{name:"惠山区",code:"320206"},{name:"滨湖区",code:"320211"},{name:"江阴市",code:"320281"},{name:"宜兴市",code:"320282"}]},{name:"徐州市",code:"320300",sub:[{name:"市辖区",code:"320301"},{name:"鼓楼区",code:"320302"},{name:"云龙区",code:"320303"},{name:"贾汪区",code:"320305"},{name:"泉山区",code:"320311"},{name:"铜山区",code:"320312"},{name:"丰县",code:"320321"},{name:"沛县",code:"320322"},{name:"睢宁县",code:"320324"},{name:"新沂市",code:"320381"},{name:"邳州市",code:"320382"}]},{name:"常州市",code:"320400",sub:[{name:"市辖区",code:"320401"},{name:"天宁区",code:"320402"},{name:"钟楼区",code:"320404"},{name:"戚墅堰区",code:"320405"},{name:"新北区",code:"320411"},{name:"武进区",code:"320412"},{name:"溧阳市",code:"320481"},{name:"金坛市",code:"320482"}]},{name:"苏州市",code:"320500",sub:[{name:"市辖区",code:"320501"},{name:"虎丘区",code:"320505"},{name:"吴中区",code:"320506"},{name:"相城区",code:"320507"},{name:"姑苏区",code:"320508"},{name:"吴江区",code:"320509"},{name:"常熟市",code:"320581"},{name:"张家港市",code:"320582"},{name:"昆山市",code:"320583"},{name:"太仓市",code:"320585"}]},{name:"南通市",code:"320600",sub:[{name:"市辖区",code:"320601"},{name:"崇川区",code:"320602"},{name:"港闸区",code:"320611"},{name:"通州区",code:"320612"},{name:"海安县",code:"320621"},{name:"如东县",code:"320623"},{name:"启东市",code:"320681"},{name:"如皋市",code:"320682"},{name:"海门市",code:"320684"}]},{name:"连云港市",code:"320700",sub:[{name:"市辖区",code:"320701"},{name:"连云区",code:"320703"},{name:"海州区",code:"320706"},{name:"赣榆区",code:"320707"},{name:"东海县",code:"320722"},{name:"灌云县",code:"320723"},{name:"灌南县",code:"320724"}]},{name:"淮安市",code:"320800",sub:[{name:"市辖区",code:"320801"},{name:"清河区",code:"320802"},{name:"淮安区",code:"320803"},{name:"淮阴区",code:"320804"},{name:"清浦区",code:"320811"},{name:"涟水县",code:"320826"},{name:"洪泽县",code:"320829"},{name:"盱眙县",code:"320830"},{name:"金湖县",code:"320831"}]},{name:"盐城市",code:"320900",sub:[{name:"市辖区",code:"320901"},{name:"亭湖区",code:"320902"},{name:"盐都区",code:"320903"},{name:"响水县",code:"320921"},{name:"滨海县",code:"320922"},{name:"阜宁县",code:"320923"},{name:"射阳县",code:"320924"},{name:"建湖县",code:"320925"},{name:"东台市",code:"320981"},{name:"大丰市",code:"320982"}]},{name:"扬州市",code:"321000",sub:[{name:"市辖区",code:"321001"},{name:"广陵区",code:"321002"},{name:"邗江区",code:"321003"},{name:"江都区",code:"321012"},{name:"宝应县",code:"321023"},{name:"仪征市",code:"321081"},{name:"高邮市",code:"321084"}]},{name:"镇江市",code:"321100",sub:[{name:"市辖区",code:"321101"},{name:"京口区",code:"321102"},{name:"润州区",code:"321111"},{name:"丹徒区",code:"321112"},{name:"丹阳市",code:"321181"},{name:"扬中市",code:"321182"},{name:"句容市",code:"321183"}]},{name:"泰州市",code:"321200",sub:[{name:"市辖区",code:"321201"},{name:"海陵区",code:"321202"},{name:"高港区",code:"321203"},{name:"姜堰区",code:"321204"},{name:"兴化市",code:"321281"},{name:"靖江市",code:"321282"},{name:"泰兴市",code:"321283"}]},{name:"宿迁市",code:"321300",sub:[{name:"市辖区",code:"321301"},{name:"宿城区",code:"321302"},{name:"宿豫区",code:"321311"},{name:"沭阳县",code:"321322"},{name:"泗阳县",code:"321323"},{name:"泗洪县",code:"321324"}]}]},{name:"浙江省",code:"330000",sub:[{name:"杭州市",code:"330100",sub:[{name:"市辖区",code:"330101"},{name:"上城区",code:"330102"},{name:"下城区",code:"330103"},{name:"江干区",code:"330104"},{name:"拱墅区",code:"330105"},{name:"西湖区",code:"330106"},{name:"滨江区",code:"330108"},{name:"萧山区",code:"330109"},{name:"余杭区",code:"330110"},{name:"富阳区",code:"330111"},{name:"桐庐县",code:"330122"},{name:"淳安县",code:"330127"},{name:"建德市",code:"330182"},{name:"临安市",code:"330185"}]},{name:"宁波市",code:"330200",sub:[{name:"市辖区",code:"330201"},{name:"海曙区",code:"330203"},{name:"江东区",code:"330204"},{name:"江北区",code:"330205"},{name:"北仑区",code:"330206"},{name:"镇海区",code:"330211"},{name:"鄞州区",code:"330212"},{name:"象山县",code:"330225"},{name:"宁海县",code:"330226"},{name:"余姚市",code:"330281"},{name:"慈溪市",code:"330282"},{name:"奉化市",code:"330283"}]},{name:"温州市",code:"330300",sub:[{name:"市辖区",code:"330301"},{name:"鹿城区",code:"330302"},{name:"龙湾区",code:"330303"},{name:"瓯海区",code:"330304"},{name:"洞头县",code:"330322"},{name:"永嘉县",code:"330324"},{name:"平阳县",code:"330326"},{name:"苍南县",code:"330327"},{name:"文成县",code:"330328"},{name:"泰顺县",code:"330329"},{name:"瑞安市",code:"330381"},{name:"乐清市",code:"330382"}]},{name:"嘉兴市",code:"330400",sub:[{name:"市辖区",code:"330401"},{name:"南湖区",code:"330402"},{name:"秀洲区",code:"330411"},{name:"嘉善县",code:"330421"},{name:"海盐县",code:"330424"},{name:"海宁市",code:"330481"},{name:"平湖市",code:"330482"},{name:"桐乡市",code:"330483"}]},{name:"湖州市",code:"330500",sub:[{name:"市辖区",code:"330501"},{name:"吴兴区",code:"330502"},{name:"南浔区",code:"330503"},{name:"德清县",code:"330521"},{name:"长兴县",code:"330522"},{name:"安吉县",code:"330523"}]},{name:"绍兴市",code:"330600",sub:[{name:"市辖区",code:"330601"},{name:"越城区",code:"330602"},{name:"柯桥区",code:"330603"},{name:"上虞区",code:"330604"},{name:"新昌县",code:"330624"},{name:"诸暨市",code:"330681"},{name:"嵊州市",code:"330683"}]},{name:"金华市",code:"330700",sub:[{name:"市辖区",code:"330701"},{name:"婺城区",code:"330702"},{name:"金东区",code:"330703"},{name:"武义县",code:"330723"},{name:"浦江县",code:"330726"},{name:"磐安县",code:"330727"},{name:"兰溪市",code:"330781"},{name:"义乌市",code:"330782"},{name:"东阳市",code:"330783"},{name:"永康市",code:"330784"}]},{name:"衢州市",code:"330800",sub:[{name:"市辖区",code:"330801"},{name:"柯城区",code:"330802"},{name:"衢江区",code:"330803"},{name:"常山县",code:"330822"},{name:"开化县",code:"330824"},{name:"龙游县",code:"330825"},{name:"江山市",code:"330881"}]},{name:"舟山市",code:"330900",sub:[{name:"市辖区",code:"330901"},{name:"定海区",code:"330902"},{name:"普陀区",code:"330903"},{name:"岱山县",code:"330921"},{name:"嵊泗县",code:"330922"}]},{name:"台州市",code:"331000",sub:[{name:"市辖区",code:"331001"},{name:"椒江区",code:"331002"},{name:"黄岩区",code:"331003"},{name:"路桥区",code:"331004"},{name:"玉环县",code:"331021"},{name:"三门县",code:"331022"},{name:"天台县",code:"331023"},{name:"仙居县",code:"331024"},{name:"温岭市",code:"331081"},{name:"临海市",code:"331082"}]},{name:"丽水市",code:"331100",sub:[{name:"市辖区",code:"331101"},{name:"莲都区",code:"331102"},{name:"青田县",code:"331121"},{name:"缙云县",code:"331122"},{name:"遂昌县",code:"331123"},{name:"松阳县",code:"331124"},{name:"云和县",code:"331125"},{name:"庆元县",code:"331126"},{name:"景宁畲族自治县",code:"331127"},{name:"龙泉市",code:"331181"}]}]},{name:"安徽省",code:"340000",sub:[{name:"合肥市",code:"340100",sub:[{name:"市辖区",code:"340101"},{name:"瑶海区",code:"340102"},{name:"庐阳区",code:"340103"},{name:"蜀山区",code:"340104"},{name:"包河区",code:"340111"},{name:"长丰县",code:"340121"},{name:"肥东县",code:"340122"},{name:"肥西县",code:"340123"},{name:"庐江县",code:"340124"},{name:"巢湖市",code:"340181"}]},{name:"芜湖市",code:"340200",sub:[{name:"市辖区",code:"340201"},{name:"镜湖区",code:"340202"},{name:"弋江区",code:"340203"},{name:"鸠江区",code:"340207"},{name:"三山区",code:"340208"},{name:"芜湖县",code:"340221"},{name:"繁昌县",code:"340222"},{name:"南陵县",code:"340223"},{name:"无为县",code:"340225"}]},{name:"蚌埠市",code:"340300",sub:[{name:"市辖区",code:"340301"},{name:"龙子湖区",code:"340302"},{name:"蚌山区",code:"340303"},{name:"禹会区",code:"340304"},{name:"淮上区",code:"340311"},{name:"怀远县",code:"340321"},{name:"五河县",code:"340322"},{name:"固镇县",code:"340323"}]},{name:"淮南市",code:"340400",sub:[{name:"市辖区",code:"340401"},{name:"大通区",code:"340402"},{
+name:"田家庵区",code:"340403"},{name:"谢家集区",code:"340404"},{name:"八公山区",code:"340405"},{name:"潘集区",code:"340406"},{name:"凤台县",code:"340421"}]},{name:"马鞍山市",code:"340500",sub:[{name:"市辖区",code:"340501"},{name:"花山区",code:"340503"},{name:"雨山区",code:"340504"},{name:"博望区",code:"340506"},{name:"当涂县",code:"340521"},{name:"含山县",code:"340522"},{name:"和县",code:"340523"}]},{name:"淮北市",code:"340600",sub:[{name:"市辖区",code:"340601"},{name:"杜集区",code:"340602"},{name:"相山区",code:"340603"},{name:"烈山区",code:"340604"},{name:"濉溪县",code:"340621"}]},{name:"铜陵市",code:"340700",sub:[{name:"市辖区",code:"340701"},{name:"铜官山区",code:"340702"},{name:"狮子山区",code:"340703"},{name:"郊区",code:"340711"},{name:"铜陵县",code:"340721"}]},{name:"安庆市",code:"340800",sub:[{name:"市辖区",code:"340801"},{name:"迎江区",code:"340802"},{name:"大观区",code:"340803"},{name:"宜秀区",code:"340811"},{name:"怀宁县",code:"340822"},{name:"枞阳县",code:"340823"},{name:"潜山县",code:"340824"},{name:"太湖县",code:"340825"},{name:"宿松县",code:"340826"},{name:"望江县",code:"340827"},{name:"岳西县",code:"340828"},{name:"桐城市",code:"340881"}]},{name:"黄山市",code:"341000",sub:[{name:"市辖区",code:"341001"},{name:"屯溪区",code:"341002"},{name:"黄山区",code:"341003"},{name:"徽州区",code:"341004"},{name:"歙县",code:"341021"},{name:"休宁县",code:"341022"},{name:"黟县",code:"341023"},{name:"祁门县",code:"341024"}]},{name:"滁州市",code:"341100",sub:[{name:"市辖区",code:"341101"},{name:"琅琊区",code:"341102"},{name:"南谯区",code:"341103"},{name:"来安县",code:"341122"},{name:"全椒县",code:"341124"},{name:"定远县",code:"341125"},{name:"凤阳县",code:"341126"},{name:"天长市",code:"341181"},{name:"明光市",code:"341182"}]},{name:"阜阳市",code:"341200",sub:[{name:"市辖区",code:"341201"},{name:"颍州区",code:"341202"},{name:"颍东区",code:"341203"},{name:"颍泉区",code:"341204"},{name:"临泉县",code:"341221"},{name:"太和县",code:"341222"},{name:"阜南县",code:"341225"},{name:"颍上县",code:"341226"},{name:"界首市",code:"341282"}]},{name:"宿州市",code:"341300",sub:[{name:"市辖区",code:"341301"},{name:"埇桥区",code:"341302"},{name:"砀山县",code:"341321"},{name:"萧县",code:"341322"},{name:"灵璧县",code:"341323"},{name:"泗县",code:"341324"}]},{name:"六安市",code:"341500",sub:[{name:"市辖区",code:"341501"},{name:"金安区",code:"341502"},{name:"裕安区",code:"341503"},{name:"寿县",code:"341521"},{name:"霍邱县",code:"341522"},{name:"舒城县",code:"341523"},{name:"金寨县",code:"341524"},{name:"霍山县",code:"341525"}]},{name:"亳州市",code:"341600",sub:[{name:"市辖区",code:"341601"},{name:"谯城区",code:"341602"},{name:"涡阳县",code:"341621"},{name:"蒙城县",code:"341622"},{name:"利辛县",code:"341623"}]},{name:"池州市",code:"341700",sub:[{name:"市辖区",code:"341701"},{name:"贵池区",code:"341702"},{name:"东至县",code:"341721"},{name:"石台县",code:"341722"},{name:"青阳县",code:"341723"}]},{name:"宣城市",code:"341800",sub:[{name:"市辖区",code:"341801"},{name:"宣州区",code:"341802"},{name:"郎溪县",code:"341821"},{name:"广德县",code:"341822"},{name:"泾县",code:"341823"},{name:"绩溪县",code:"341824"},{name:"旌德县",code:"341825"},{name:"宁国市",code:"341881"}]}]},{name:"福建省",code:"350000",sub:[{name:"福州市",code:"350100",sub:[{name:"市辖区",code:"350101"},{name:"鼓楼区",code:"350102"},{name:"台江区",code:"350103"},{name:"仓山区",code:"350104"},{name:"马尾区",code:"350105"},{name:"晋安区",code:"350111"},{name:"闽侯县",code:"350121"},{name:"连江县",code:"350122"},{name:"罗源县",code:"350123"},{name:"闽清县",code:"350124"},{name:"永泰县",code:"350125"},{name:"平潭县",code:"350128"},{name:"福清市",code:"350181"},{name:"长乐市",code:"350182"}]},{name:"厦门市",code:"350200",sub:[{name:"市辖区",code:"350201"},{name:"思明区",code:"350203"},{name:"海沧区",code:"350205"},{name:"湖里区",code:"350206"},{name:"集美区",code:"350211"},{name:"同安区",code:"350212"},{name:"翔安区",code:"350213"}]},{name:"莆田市",code:"350300",sub:[{name:"市辖区",code:"350301"},{name:"城厢区",code:"350302"},{name:"涵江区",code:"350303"},{name:"荔城区",code:"350304"},{name:"秀屿区",code:"350305"},{name:"仙游县",code:"350322"}]},{name:"三明市",code:"350400",sub:[{name:"市辖区",code:"350401"},{name:"梅列区",code:"350402"},{name:"三元区",code:"350403"},{name:"明溪县",code:"350421"},{name:"清流县",code:"350423"},{name:"宁化县",code:"350424"},{name:"大田县",code:"350425"},{name:"尤溪县",code:"350426"},{name:"沙县",code:"350427"},{name:"将乐县",code:"350428"},{name:"泰宁县",code:"350429"},{name:"建宁县",code:"350430"},{name:"永安市",code:"350481"}]},{name:"泉州市",code:"350500",sub:[{name:"市辖区",code:"350501"},{name:"鲤城区",code:"350502"},{name:"丰泽区",code:"350503"},{name:"洛江区",code:"350504"},{name:"泉港区",code:"350505"},{name:"惠安县",code:"350521"},{name:"安溪县",code:"350524"},{name:"永春县",code:"350525"},{name:"德化县",code:"350526"},{name:"金门县",code:"350527"},{name:"石狮市",code:"350581"},{name:"晋江市",code:"350582"},{name:"南安市",code:"350583"}]},{name:"漳州市",code:"350600",sub:[{name:"市辖区",code:"350601"},{name:"芗城区",code:"350602"},{name:"龙文区",code:"350603"},{name:"云霄县",code:"350622"},{name:"漳浦县",code:"350623"},{name:"诏安县",code:"350624"},{name:"长泰县",code:"350625"},{name:"东山县",code:"350626"},{name:"南靖县",code:"350627"},{name:"平和县",code:"350628"},{name:"华安县",code:"350629"},{name:"龙海市",code:"350681"}]},{name:"南平市",code:"350700",sub:[{name:"市辖区",code:"350701"},{name:"延平区",code:"350702"},{name:"建阳区",code:"350703"},{name:"顺昌县",code:"350721"},{name:"浦城县",code:"350722"},{name:"光泽县",code:"350723"},{name:"松溪县",code:"350724"},{name:"政和县",code:"350725"},{name:"邵武市",code:"350781"},{name:"武夷山市",code:"350782"},{name:"建瓯市",code:"350783"}]},{name:"龙岩市",code:"350800",sub:[{name:"市辖区",code:"350801"},{name:"新罗区",code:"350802"},{name:"永定区",code:"350803"},{name:"长汀县",code:"350821"},{name:"上杭县",code:"350823"},{name:"武平县",code:"350824"},{name:"连城县",code:"350825"},{name:"漳平市",code:"350881"}]},{name:"宁德市",code:"350900",sub:[{name:"市辖区",code:"350901"},{name:"蕉城区",code:"350902"},{name:"霞浦县",code:"350921"},{name:"古田县",code:"350922"},{name:"屏南县",code:"350923"},{name:"寿宁县",code:"350924"},{name:"周宁县",code:"350925"},{name:"柘荣县",code:"350926"},{name:"福安市",code:"350981"},{name:"福鼎市",code:"350982"}]}]},{name:"江西省",code:"360000",sub:[{name:"南昌市",code:"360100",sub:[{name:"市辖区",code:"360101"},{name:"东湖区",code:"360102"},{name:"西湖区",code:"360103"},{name:"青云谱区",code:"360104"},{name:"湾里区",code:"360105"},{name:"青山湖区",code:"360111"},{name:"南昌县",code:"360121"},{name:"新建县",code:"360122"},{name:"安义县",code:"360123"},{name:"进贤县",code:"360124"}]},{name:"景德镇市",code:"360200",sub:[{name:"市辖区",code:"360201"},{name:"昌江区",code:"360202"},{name:"珠山区",code:"360203"},{name:"浮梁县",code:"360222"},{name:"乐平市",code:"360281"}]},{name:"萍乡市",code:"360300",sub:[{name:"市辖区",code:"360301"},{name:"安源区",code:"360302"},{name:"湘东区",code:"360313"},{name:"莲花县",code:"360321"},{name:"上栗县",code:"360322"},{name:"芦溪县",code:"360323"}]},{name:"九江市",code:"360400",sub:[{name:"市辖区",code:"360401"},{name:"庐山区",code:"360402"},{name:"浔阳区",code:"360403"},{name:"九江县",code:"360421"},{name:"武宁县",code:"360423"},{name:"修水县",code:"360424"},{name:"永修县",code:"360425"},{name:"德安县",code:"360426"},{name:"星子县",code:"360427"},{name:"都昌县",code:"360428"},{name:"湖口县",code:"360429"},{name:"彭泽县",code:"360430"},{name:"瑞昌市",code:"360481"},{name:"共青城市",code:"360482"}]},{name:"新余市",code:"360500",sub:[{name:"市辖区",code:"360501"},{name:"渝水区",code:"360502"},{name:"分宜县",code:"360521"}]},{name:"鹰潭市",code:"360600",sub:[{name:"市辖区",code:"360601"},{name:"月湖区",code:"360602"},{name:"余江县",code:"360622"},{name:"贵溪市",code:"360681"}]},{name:"赣州市",code:"360700",sub:[{name:"市辖区",code:"360701"},{name:"章贡区",code:"360702"},{name:"南康区",code:"360703"},{name:"赣县",code:"360721"},{name:"信丰县",code:"360722"},{name:"大余县",code:"360723"},{name:"上犹县",code:"360724"},{name:"崇义县",code:"360725"},{name:"安远县",code:"360726"},{name:"龙南县",code:"360727"},{name:"定南县",code:"360728"},{name:"全南县",code:"360729"},{name:"宁都县",code:"360730"},{name:"于都县",code:"360731"},{name:"兴国县",code:"360732"},{name:"会昌县",code:"360733"},{name:"寻乌县",code:"360734"},{name:"石城县",code:"360735"},{name:"瑞金市",code:"360781"}]},{name:"吉安市",code:"360800",sub:[{name:"市辖区",code:"360801"},{name:"吉州区",code:"360802"},{name:"青原区",code:"360803"},{name:"吉安县",code:"360821"},{name:"吉水县",code:"360822"},{name:"峡江县",code:"360823"},{name:"新干县",code:"360824"},{name:"永丰县",code:"360825"},{name:"泰和县",code:"360826"},{name:"遂川县",code:"360827"},{name:"万安县",code:"360828"},{name:"安福县",code:"360829"},{name:"永新县",code:"360830"},{name:"井冈山市",code:"360881"}]},{name:"宜春市",code:"360900",sub:[{name:"市辖区",code:"360901"},{name:"袁州区",code:"360902"},{name:"奉新县",code:"360921"},{name:"万载县",code:"360922"},{name:"上高县",code:"360923"},{name:"宜丰县",code:"360924"},{name:"靖安县",code:"360925"},{name:"铜鼓县",code:"360926"},{name:"丰城市",code:"360981"},{name:"樟树市",code:"360982"},{name:"高安市",code:"360983"}]},{name:"抚州市",code:"361000",sub:[{name:"市辖区",code:"361001"},{name:"临川区",code:"361002"},{name:"南城县",code:"361021"},{name:"黎川县",code:"361022"},{name:"南丰县",code:"361023"},{name:"崇仁县",code:"361024"},{name:"乐安县",code:"361025"},{name:"宜黄县",code:"361026"},{name:"金溪县",code:"361027"},{name:"资溪县",code:"361028"},{name:"东乡县",code:"361029"},{name:"广昌县",code:"361030"}]},{name:"上饶市",code:"361100",sub:[{name:"市辖区",code:"361101"},{name:"信州区",code:"361102"},{name:"上饶县",code:"361121"},{name:"广丰县",code:"361122"},{name:"玉山县",code:"361123"},{name:"铅山县",code:"361124"},{name:"横峰县",code:"361125"},{name:"弋阳县",code:"361126"},{name:"余干县",code:"361127"},{name:"鄱阳县",code:"361128"},{name:"万年县",code:"361129"},{name:"婺源县",code:"361130"},{name:"德兴市",code:"361181"}]}]},{name:"山东省",code:"370000",sub:[{name:"济南市",code:"370100",sub:[{name:"市辖区",code:"370101"},{name:"历下区",code:"370102"},{name:"市中区",code:"370103"},{name:"槐荫区",code:"370104"},{name:"天桥区",code:"370105"},{name:"历城区",code:"370112"},{name:"长清区",code:"370113"},{name:"平阴县",code:"370124"},{name:"济阳县",code:"370125"},{name:"商河县",code:"370126"},{name:"章丘市",code:"370181"}]},{name:"青岛市",code:"370200",sub:[{name:"市辖区",code:"370201"},{name:"市南区",code:"370202"},{name:"市北区",code:"370203"},{name:"黄岛区",code:"370211"},{name:"崂山区",code:"370212"},{name:"李沧区",code:"370213"},{name:"城阳区",code:"370214"},{name:"胶州市",code:"370281"},{name:"即墨市",code:"370282"},{name:"平度市",code:"370283"},{name:"莱西市",code:"370285"}]},{name:"淄博市",code:"370300",sub:[{name:"市辖区",code:"370301"},{name:"淄川区",code:"370302"},{name:"张店区",code:"370303"},{name:"博山区",code:"370304"},{name:"临淄区",code:"370305"},{name:"周村区",code:"370306"},{name:"桓台县",code:"370321"},{name:"高青县",code:"370322"},{name:"沂源县",code:"370323"}]},{name:"枣庄市",code:"370400",sub:[{name:"市辖区",code:"370401"},{name:"市中区",code:"370402"},{name:"薛城区",code:"370403"},{name:"峄城区",code:"370404"},{name:"台儿庄区",code:"370405"},{name:"山亭区",code:"370406"},{name:"滕州市",code:"370481"}]},{name:"东营市",code:"370500",sub:[{name:"市辖区",code:"370501"},{name:"东营区",code:"370502"},{name:"河口区",code:"370503"},{name:"垦利县",code:"370521"},{name:"利津县",code:"370522"},{name:"广饶县",code:"370523"}]},{name:"烟台市",code:"370600",sub:[{name:"市辖区",code:"370601"},{name:"芝罘区",code:"370602"},{name:"福山区",code:"370611"},{name:"牟平区",code:"370612"},{name:"莱山区",code:"370613"},{name:"长岛县",code:"370634"},{name:"龙口市",code:"370681"},{name:"莱阳市",code:"370682"},{name:"莱州市",code:"370683"},{name:"蓬莱市",code:"370684"},{name:"招远市",code:"370685"},{name:"栖霞市",code:"370686"},{name:"海阳市",code:"370687"}]},{name:"潍坊市",code:"370700",sub:[{name:"市辖区",code:"370701"},{name:"潍城区",code:"370702"},{name:"寒亭区",code:"370703"},{name:"坊子区",code:"370704"},{name:"奎文区",code:"370705"},{name:"临朐县",code:"370724"},{name:"昌乐县",code:"370725"},{name:"青州市",code:"370781"},{name:"诸城市",code:"370782"},{name:"寿光市",code:"370783"},{name:"安丘市",code:"370784"},{name:"高密市",code:"370785"},{name:"昌邑市",code:"370786"}]},{name:"济宁市",code:"370800",sub:[{name:"市辖区",code:"370801"},{name:"任城区",code:"370811"},{name:"兖州区",code:"370812"},{name:"微山县",code:"370826"},{name:"鱼台县",code:"370827"},{name:"金乡县",code:"370828"},{name:"嘉祥县",code:"370829"},{name:"汶上县",code:"370830"},{name:"泗水县",code:"370831"},{name:"梁山县",code:"370832"},{name:"曲阜市",code:"370881"},{name:"邹城市",code:"370883"}]},{name:"泰安市",code:"370900",sub:[{name:"市辖区",code:"370901"},{name:"泰山区",code:"370902"},{name:"岱岳区",code:"370911"},{name:"宁阳县",code:"370921"},{name:"东平县",code:"370923"},{name:"新泰市",code:"370982"},{name:"肥城市",code:"370983"}]},{name:"威海市",code:"371000",sub:[{name:"市辖区",code:"371001"},{name:"环翠区",code:"371002"},{name:"文登市",code:"371081"},{name:"荣成市",code:"371082"},{name:"乳山市",code:"371083"}]},{name:"日照市",code:"371100",sub:[{name:"市辖区",code:"371101"},{name:"东港区",code:"371102"},{name:"岚山区",code:"371103"},{name:"五莲县",code:"371121"},{name:"莒县",code:"371122"}]},{name:"莱芜市",code:"371200",sub:[{name:"市辖区",code:"371201"},{name:"莱城区",code:"371202"},{name:"钢城区",code:"371203"}]},{name:"临沂市",code:"371300",sub:[{name:"市辖区",code:"371301"},{name:"兰山区",code:"371302"},{name:"罗庄区",code:"371311"},{name:"河东区",code:"371312"},{name:"沂南县",code:"371321"},{name:"郯城县",code:"371322"},{name:"沂水县",code:"371323"},{name:"兰陵县",code:"371324"},{name:"费县",code:"371325"},{name:"平邑县",code:"371326"},{name:"莒南县",code:"371327"},{name:"蒙阴县",code:"371328"},{name:"临沭县",code:"371329"}]},{name:"德州市",code:"371400",sub:[{name:"市辖区",code:"371401"},{name:"德城区",code:"371402"},{name:"陵城区",code:"371403"},{name:"宁津县",code:"371422"},{name:"庆云县",code:"371423"},{name:"临邑县",code:"371424"},{name:"齐河县",code:"371425"},{name:"平原县",code:"371426"},{name:"夏津县",code:"371427"},{name:"武城县",code:"371428"},{name:"乐陵市",code:"371481"},{name:"禹城市",code:"371482"}]},{name:"聊城市",code:"371500",sub:[{name:"市辖区",code:"371501"},{name:"东昌府区",code:"371502"},{name:"阳谷县",code:"371521"},{name:"莘县",code:"371522"},{name:"茌平县",code:"371523"},{name:"东阿县",code:"371524"},{name:"冠县",code:"371525"},{name:"高唐县",code:"371526"},{name:"临清市",code:"371581"}]},{name:"滨州市",code:"371600",sub:[{name:"市辖区",code:"371601"},{name:"滨城区",code:"371602"},{name:"沾化区",code:"371603"},{name:"惠民县",code:"371621"},{name:"阳信县",code:"371622"},{name:"无棣县",code:"371623"},{name:"博兴县",code:"371625"},{name:"邹平县",code:"371626"}]},{name:"菏泽市",code:"371700",sub:[{name:"市辖区",code:"371701"},{name:"牡丹区",code:"371702"},{name:"曹县",code:"371721"},{name:"单县",code:"371722"},{name:"成武县",code:"371723"},{name:"巨野县",code:"371724"},{name:"郓城县",code:"371725"},{name:"鄄城县",code:"371726"},{name:"定陶县",code:"371727"},{name:"东明县",code:"371728"}]}]},{name:"河南省",code:"410000",sub:[{name:"郑州市",code:"410100",sub:[{name:"市辖区",code:"410101"},{name:"中原区",code:"410102"},{name:"二七区",code:"410103"},{name:"管城回族区",code:"410104"},{name:"金水区",code:"410105"},{name:"上街区",code:"410106"},{name:"惠济区",code:"410108"},{name:"中牟县",code:"410122"},{name:"巩义市",code:"410181"},{name:"荥阳市",code:"410182"},{name:"新密市",code:"410183"},{name:"新郑市",code:"410184"},{name:"登封市",code:"410185"}]},{name:"开封市",code:"410200",sub:[{name:"市辖区",code:"410201"},{name:"龙亭区",code:"410202"},{name:"顺河回族区",code:"410203"},{name:"鼓楼区",code:"410204"},{name:"禹王台区",code:"410205"},{name:"祥符区",code:"410212"},{name:"杞县",code:"410221"},{name:"通许县",code:"410222"},{name:"尉氏县",code:"410223"},{name:"兰考县",code:"410225"}]},{name:"洛阳市",code:"410300",sub:[{name:"市辖区",code:"410301"},{name:"老城区",code:"410302"},{name:"西工区",code:"410303"},{name:"瀍河回族区",code:"410304"},{name:"涧西区",code:"410305"},{name:"吉利区",code:"410306"},{name:"洛龙区",code:"410311"},{name:"孟津县",code:"410322"},{name:"新安县",code:"410323"},{name:"栾川县",code:"410324"},{name:"嵩县",code:"410325"},{name:"汝阳县",code:"410326"},{name:"宜阳县",code:"410327"},{name:"洛宁县",code:"410328"},{name:"伊川县",code:"410329"},{name:"偃师市",code:"410381"}]},{name:"平顶山市",code:"410400",sub:[{name:"市辖区",code:"410401"},{name:"新华区",code:"410402"},{name:"卫东区",code:"410403"},{name:"石龙区",code:"410404"},{name:"湛河区",code:"410411"},{name:"宝丰县",code:"410421"},{name:"叶县",code:"410422"},{name:"鲁山县",code:"410423"},{name:"郏县",code:"410425"},{name:"舞钢市",code:"410481"},{name:"汝州市",code:"410482"}]},{name:"安阳市",code:"410500",sub:[{name:"市辖区",code:"410501"},{name:"文峰区",code:"410502"},{name:"北关区",code:"410503"},{name:"殷都区",code:"410505"},{name:"龙安区",code:"410506"},{name:"安阳县",code:"410522"},{name:"汤阴县",code:"410523"},{name:"滑县",code:"410526"},{name:"内黄县",code:"410527"},{name:"林州市",code:"410581"}]},{name:"鹤壁市",code:"410600",sub:[{name:"市辖区",code:"410601"},{name:"鹤山区",code:"410602"},{name:"山城区",code:"410603"},{name:"淇滨区",code:"410611"},{name:"浚县",code:"410621"},{name:"淇县",code:"410622"}]},{name:"新乡市",code:"410700",sub:[{name:"市辖区",code:"410701"},{name:"红旗区",code:"410702"},{name:"卫滨区",code:"410703"},{name:"凤泉区",code:"410704"},{name:"牧野区",code:"410711"},{name:"新乡县",code:"410721"},{name:"获嘉县",code:"410724"},{name:"原阳县",code:"410725"},{name:"延津县",code:"410726"},{name:"封丘县",code:"410727"},{name:"长垣县",code:"410728"},{name:"卫辉市",code:"410781"},{name:"辉县市",code:"410782"}]},{name:"焦作市",code:"410800",sub:[{name:"市辖区",code:"410801"},{name:"解放区",code:"410802"},{name:"中站区",code:"410803"},{name:"马村区",code:"410804"},{name:"山阳区",code:"410811"},{name:"修武县",code:"410821"},{name:"博爱县",code:"410822"},{name:"武陟县",code:"410823"},{name:"温县",code:"410825"},{name:"沁阳市",code:"410882"},{name:"孟州市",code:"410883"}]},{name:"濮阳市",code:"410900",sub:[{name:"市辖区",code:"410901"},{name:"华龙区",code:"410902"},{name:"清丰县",code:"410922"},{name:"南乐县",code:"410923"},{name:"范县",code:"410926"},{name:"台前县",code:"410927"},{name:"濮阳县",code:"410928"}]},{name:"许昌市",code:"411000",sub:[{name:"市辖区",code:"411001"},{name:"魏都区",code:"411002"},{name:"许昌县",code:"411023"},{name:"鄢陵县",code:"411024"},{name:"襄城县",code:"411025"},{name:"禹州市",code:"411081"},{name:"长葛市",code:"411082"}]},{name:"漯河市",code:"411100",sub:[{name:"市辖区",code:"411101"},{name:"源汇区",code:"411102"},{name:"郾城区",code:"411103"},{name:"召陵区",code:"411104"},{name:"舞阳县",code:"411121"},{name:"临颍县",code:"411122"}]},{name:"三门峡市",code:"411200",sub:[{name:"市辖区",code:"411201"},{name:"湖滨区",code:"411202"},{name:"渑池县",code:"411221"},{name:"陕县",code:"411222"},{name:"卢氏县",code:"411224"},{name:"义马市",code:"411281"},{name:"灵宝市",code:"411282"}]},{name:"南阳市",code:"411300",sub:[{name:"市辖区",code:"411301"},{name:"宛城区",code:"411302"},{name:"卧龙区",code:"411303"},{name:"南召县",code:"411321"},{name:"方城县",code:"411322"},{name:"西峡县",code:"411323"},{name:"镇平县",code:"411324"},{name:"内乡县",code:"411325"},{name:"淅川县",code:"411326"},{name:"社旗县",code:"411327"},{name:"唐河县",code:"411328"},{name:"新野县",code:"411329"},{name:"桐柏县",code:"411330"},{name:"邓州市",code:"411381"}]},{name:"商丘市",code:"411400",sub:[{name:"市辖区",code:"411401"},{name:"梁园区",code:"411402"},{name:"睢阳区",code:"411403"},{name:"民权县",code:"411421"},{name:"睢县",code:"411422"},{name:"宁陵县",code:"411423"},{name:"柘城县",code:"411424"},{name:"虞城县",code:"411425"},{name:"夏邑县",code:"411426"},{name:"永城市",code:"411481"}]},{name:"信阳市",code:"411500",sub:[{name:"市辖区",code:"411501"},{name:"浉河区",code:"411502"},{name:"平桥区",code:"411503"},{name:"罗山县",code:"411521"},{name:"光山县",code:"411522"},{name:"新县",code:"411523"},{name:"商城县",code:"411524"},{name:"固始县",code:"411525"},{name:"潢川县",code:"411526"},{name:"淮滨县",code:"411527"},{name:"息县",code:"411528"}]},{name:"周口市",code:"411600",sub:[{name:"市辖区",code:"411601"},{name:"川汇区",code:"411602"},{name:"扶沟县",code:"411621"},{name:"西华县",code:"411622"},{name:"商水县",code:"411623"},{name:"沈丘县",code:"411624"},{name:"郸城县",code:"411625"},{name:"淮阳县",code:"411626"},{name:"太康县",code:"411627"},{name:"鹿邑县",code:"411628"},{name:"项城市",code:"411681"}]},{name:"驻马店市",code:"411700",sub:[{name:"市辖区",code:"411701"},{name:"驿城区",code:"411702"},{name:"西平县",code:"411721"},{name:"上蔡县",code:"411722"},{name:"平舆县",code:"411723"},{name:"正阳县",code:"411724"},{name:"确山县",code:"411725"},{name:"泌阳县",code:"411726"},{name:"汝南县",code:"411727"},{name:"遂平县",code:"411728"},{name:"新蔡县",code:"411729"}]},{name:"济源市",code:"419001"}]},{name:"湖北省",code:"420000",sub:[{name:"武汉市",code:"420100",sub:[{name:"市辖区",code:"420101"},{name:"江岸区",code:"420102"},{name:"江汉区",code:"420103"},{name:"硚口区",code:"420104"},{name:"汉阳区",code:"420105"},{name:"武昌区",code:"420106"},{name:"青山区",code:"420107"},{name:"洪山区",code:"420111"},{name:"东西湖区",code:"420112"},{name:"汉南区",code:"420113"},{name:"蔡甸区",code:"420114"},{name:"江夏区",code:"420115"},{name:"黄陂区",code:"420116"},{name:"新洲区",code:"420117"}]},{name:"黄石市",code:"420200",sub:[{name:"市辖区",code:"420201"},{name:"黄石港区",code:"420202"},{name:"西塞山区",code:"420203"},{name:"下陆区",code:"420204"},{name:"铁山区",code:"420205"},{name:"阳新县",code:"420222"},{name:"大冶市",code:"420281"}]},{name:"十堰市",code:"420300",sub:[{name:"市辖区",code:"420301"},{name:"茅箭区",code:"420302"},{name:"张湾区",code:"420303"},{name:"郧阳区",code:"420304"},{name:"郧西县",code:"420322"},{name:"竹山县",code:"420323"},{name:"竹溪县",code:"420324"},{name:"房县",code:"420325"},{name:"丹江口市",code:"420381"}]},{name:"宜昌市",code:"420500",sub:[{name:"市辖区",code:"420501"},{name:"西陵区",code:"420502"},{name:"伍家岗区",code:"420503"},{name:"点军区",code:"420504"},{name:"猇亭区",code:"420505"},{name:"夷陵区",code:"420506"},{name:"远安县",code:"420525"},{name:"兴山县",code:"420526"},{name:"秭归县",code:"420527"},{name:"长阳土家族自治县",code:"420528"},{name:"五峰土家族自治县",code:"420529"},{name:"宜都市",code:"420581"},{name:"当阳市",code:"420582"},{name:"枝江市",code:"420583"}]},{name:"襄阳市",code:"420600",sub:[{name:"市辖区",code:"420601"},{name:"襄城区",code:"420602"},{name:"樊城区",code:"420606"},{name:"襄州区",code:"420607"},{name:"南漳县",code:"420624"},{name:"谷城县",code:"420625"},{name:"保康县",code:"420626"},{name:"老河口市",code:"420682"},{name:"枣阳市",code:"420683"},{name:"宜城市",code:"420684"}]},{name:"鄂州市",code:"420700",sub:[{name:"市辖区",code:"420701"},{name:"梁子湖区",code:"420702"},{name:"华容区",code:"420703"},{name:"鄂城区",code:"420704"}]},{name:"荆门市",code:"420800",sub:[{name:"市辖区",code:"420801"},{name:"东宝区",code:"420802"},{name:"掇刀区",code:"420804"},{name:"京山县",code:"420821"},{name:"沙洋县",code:"420822"},{name:"钟祥市",code:"420881"}]},{name:"孝感市",code:"420900",sub:[{name:"市辖区",code:"420901"},{name:"孝南区",code:"420902"},{name:"孝昌县",code:"420921"},{name:"大悟县",code:"420922"},{name:"云梦县",code:"420923"},{name:"应城市",code:"420981"},{name:"安陆市",code:"420982"},{name:"汉川市",code:"420984"}]},{name:"荆州市",code:"421000",sub:[{name:"市辖区",code:"421001"},{name:"沙市区",code:"421002"},{name:"荆州区",code:"421003"},{name:"公安县",code:"421022"},{name:"监利县",code:"421023"},{name:"江陵县",code:"421024"},{name:"石首市",code:"421081"},{name:"洪湖市",code:"421083"},{name:"松滋市",code:"421087"}]},{name:"黄冈市",code:"421100",sub:[{name:"市辖区",code:"421101"},{name:"黄州区",code:"421102"},{name:"团风县",code:"421121"},{name:"红安县",code:"421122"},{name:"罗田县",code:"421123"},{name:"英山县",code:"421124"},{name:"浠水县",code:"421125"},{name:"蕲春县",code:"421126"},{name:"黄梅县",code:"421127"},{name:"麻城市",code:"421181"},{name:"武穴市",code:"421182"}]},{name:"咸宁市",code:"421200",sub:[{name:"市辖区",code:"421201"},{name:"咸安区",code:"421202"},{name:"嘉鱼县",code:"421221"},{name:"通城县",code:"421222"},{name:"崇阳县",code:"421223"},{name:"通山县",code:"421224"},{name:"赤壁市",code:"421281"}]},{name:"随州市",code:"421300",sub:[{name:"市辖区",code:"421301"},{name:"曾都区",code:"421303"},{name:"随县",code:"421321"},{name:"广水市",code:"421381"}]},{name:"恩施土家族苗族自治州",code:"422800",sub:[{name:"恩施市",code:"422801"},{name:"利川市",code:"422802"},{name:"建始县",code:"422822"},{name:"巴东县",code:"422823"},{name:"宣恩县",code:"422825"},{name:"咸丰县",code:"422826"},{name:"来凤县",code:"422827"},{name:"鹤峰县",code:"422828"}]},{name:"仙桃市",code:"429004"},{name:"潜江市",code:"429005"},{name:"天门市",code:"429006"},{name:"神农架林区",code:"429021"}]},{name:"湖南省",code:"430000",sub:[{name:"长沙市",code:"430100",sub:[{name:"市辖区",code:"430101"},{name:"芙蓉区",code:"430102"},{name:"天心区",code:"430103"},{name:"岳麓区",code:"430104"},{name:"开福区",code:"430105"},{name:"雨花区",code:"430111"},{name:"望城区",code:"430112"},{name:"长沙县",code:"430121"},{name:"宁乡县",code:"430124"},{name:"浏阳市",code:"430181"}]},{name:"株洲市",code:"430200",sub:[{name:"市辖区",code:"430201"},{name:"荷塘区",code:"430202"},{name:"芦淞区",code:"430203"},{name:"石峰区",code:"430204"},{name:"天元区",code:"430211"},{name:"株洲县",code:"430221"},{name:"攸县",code:"430223"},{name:"茶陵县",code:"430224"},{name:"炎陵县",code:"430225"},{name:"醴陵市",code:"430281"}]},{name:"湘潭市",code:"430300",sub:[{name:"市辖区",code:"430301"},{name:"雨湖区",code:"430302"},{name:"岳塘区",code:"430304"},{name:"湘潭县",code:"430321"},{name:"湘乡市",code:"430381"},{name:"韶山市",code:"430382"}]},{name:"衡阳市",code:"430400",sub:[{name:"市辖区",code:"430401"},{name:"珠晖区",code:"430405"},{name:"雁峰区",code:"430406"},{name:"石鼓区",code:"430407"},{name:"蒸湘区",code:"430408"},{name:"南岳区",code:"430412"},{name:"衡阳县",code:"430421"},{name:"衡南县",code:"430422"},{name:"衡山县",code:"430423"},{name:"衡东县",code:"430424"},{name:"祁东县",code:"430426"},{name:"耒阳市",code:"430481"},{name:"常宁市",code:"430482"}]},{name:"邵阳市",code:"430500",sub:[{name:"市辖区",code:"430501"},{name:"双清区",code:"430502"},{name:"大祥区",code:"430503"},{name:"北塔区",code:"430511"},{name:"邵东县",code:"430521"},{name:"新邵县",code:"430522"},{name:"邵阳县",code:"430523"},{name:"隆回县",code:"430524"},{name:"洞口县",code:"430525"},{name:"绥宁县",code:"430527"},{name:"新宁县",code:"430528"},{name:"城步苗族自治县",code:"430529"},{name:"武冈市",code:"430581"}]},{name:"岳阳市",code:"430600",sub:[{name:"市辖区",code:"430601"},{name:"岳阳楼区",code:"430602"},{name:"云溪区",code:"430603"},{name:"君山区",code:"430611"},{name:"岳阳县",code:"430621"},{name:"华容县",code:"430623"},{name:"湘阴县",code:"430624"},{name:"平江县",code:"430626"},{name:"汨罗市",code:"430681"},{name:"临湘市",code:"430682"}]},{name:"常德市",code:"430700",sub:[{name:"市辖区",code:"430701"},{name:"武陵区",code:"430702"},{name:"鼎城区",code:"430703"},{name:"安乡县",code:"430721"},{name:"汉寿县",code:"430722"},{name:"澧县",code:"430723"},{name:"临澧县",code:"430724"},{name:"桃源县",code:"430725"},{name:"石门县",code:"430726"},{name:"津市市",code:"430781"}]},{name:"张家界市",code:"430800",sub:[{name:"市辖区",code:"430801"},{name:"永定区",code:"430802"},{name:"武陵源区",code:"430811"},{name:"慈利县",code:"430821"},{name:"桑植县",code:"430822"}]},{name:"益阳市",code:"430900",sub:[{name:"市辖区",code:"430901"},{name:"资阳区",code:"430902"},{name:"赫山区",code:"430903"},{name:"南县",code:"430921"},{name:"桃江县",code:"430922"},{name:"安化县",code:"430923"},{name:"沅江市",code:"430981"}]},{name:"郴州市",code:"431000",sub:[{name:"市辖区",code:"431001"},{name:"北湖区",code:"431002"},{name:"苏仙区",code:"431003"},{name:"桂阳县",code:"431021"},{name:"宜章县",code:"431022"},{name:"永兴县",code:"431023"},{name:"嘉禾县",code:"431024"},{name:"临武县",code:"431025"},{name:"汝城县",code:"431026"},{name:"桂东县",code:"431027"},{name:"安仁县",code:"431028"},{name:"资兴市",code:"431081"}]},{name:"永州市",code:"431100",sub:[{name:"市辖区",code:"431101"},{name:"零陵区",code:"431102"},{name:"冷水滩区",code:"431103"},{name:"祁阳县",code:"431121"},{name:"东安县",code:"431122"},{name:"双牌县",code:"431123"},{name:"道县",code:"431124"},{name:"江永县",code:"431125"},{name:"宁远县",code:"431126"},{name:"蓝山县",code:"431127"},{name:"新田县",code:"431128"},{name:"江华瑶族自治县",code:"431129"}]},{name:"怀化市",code:"431200",sub:[{name:"市辖区",code:"431201"},{name:"鹤城区",code:"431202"},{name:"中方县",code:"431221"},{name:"沅陵县",code:"431222"},{name:"辰溪县",code:"431223"},{name:"溆浦县",code:"431224"},{name:"会同县",code:"431225"},{name:"麻阳苗族自治县",code:"431226"},{name:"新晃侗族自治县",code:"431227"},{name:"芷江侗族自治县",code:"431228"},{name:"靖州苗族侗族自治县",code:"431229"},{name:"通道侗族自治县",code:"431230"},{name:"洪江市",code:"431281"}]},{name:"娄底市",code:"431300",sub:[{name:"市辖区",code:"431301"},{name:"娄星区",code:"431302"},{name:"双峰县",code:"431321"},{name:"新化县",code:"431322"},{name:"冷水江市",code:"431381"},{name:"涟源市",code:"431382"}]},{name:"湘西土家族苗族自治州",code:"433100",sub:[{name:"吉首市",code:"433101"},{name:"泸溪县",code:"433122"},{name:"凤凰县",code:"433123"},{name:"花垣县",code:"433124"},{name:"保靖县",code:"433125"},{name:"古丈县",code:"433126"},{name:"永顺县",code:"433127"},{name:"龙山县",code:"433130"}]}]},{name:"广东省",code:"440000",sub:[{name:"广州市",code:"440100",sub:[{name:"市辖区",code:"440101"},{name:"荔湾区",code:"440103"},{name:"越秀区",code:"440104"},{name:"海珠区",code:"440105"},{name:"天河区",code:"440106"},{name:"白云区",code:"440111"},{name:"黄埔区",code:"440112"},{name:"番禺区",code:"440113"},{name:"花都区",code:"440114"},{name:"南沙区",code:"440115"},{name:"从化区",code:"440117"},{name:"增城区",code:"440118"}]},{name:"韶关市",code:"440200",sub:[{name:"市辖区",code:"440201"},{name:"武江区",code:"440203"},{name:"浈江区",code:"440204"},{name:"曲江区",code:"440205"},{name:"始兴县",code:"440222"},{name:"仁化县",code:"440224"},{name:"翁源县",code:"440229"},{name:"乳源瑶族自治县",code:"440232"},{name:"新丰县",code:"440233"},{name:"乐昌市",code:"440281"},{name:"南雄市",code:"440282"}]},{name:"深圳市",code:"440300",sub:[{name:"市辖区",code:"440301"},{name:"罗湖区",code:"440303"},{name:"福田区",code:"440304"},{name:"南山区",code:"440305"},{name:"宝安区",code:"440306"},{name:"龙岗区",code:"440307"},{name:"盐田区",code:"440308"}]},{name:"珠海市",code:"440400",sub:[{name:"市辖区",code:"440401"},{name:"香洲区",code:"440402"},{name:"斗门区",code:"440403"},{name:"金湾区",code:"440404"}]},{name:"汕头市",code:"440500",sub:[{name:"市辖区",code:"440501"},{name:"龙湖区",code:"440507"},{name:"金平区",code:"440511"},{name:"濠江区",code:"440512"},{name:"潮阳区",code:"440513"},{name:"潮南区",code:"440514"},{name:"澄海区",code:"440515"},{name:"南澳县",code:"440523"}]},{name:"佛山市",code:"440600",sub:[{name:"市辖区",code:"440601"},{name:"禅城区",code:"440604"},{name:"南海区",code:"440605"},{name:"顺德区",code:"440606"},{name:"三水区",code:"440607"},{name:"高明区",code:"440608"}]},{name:"江门市",code:"440700",sub:[{name:"市辖区",code:"440701"},{name:"蓬江区",code:"440703"},{name:"江海区",code:"440704"},{name:"新会区",code:"440705"},{name:"台山市",code:"440781"},{name:"开平市",code:"440783"},{name:"鹤山市",code:"440784"},{name:"恩平市",code:"440785"}]},{name:"湛江市",code:"440800",sub:[{name:"市辖区",code:"440801"},{name:"赤坎区",code:"440802"},{name:"霞山区",code:"440803"},{name:"坡头区",code:"440804"},{name:"麻章区",code:"440811"},{name:"遂溪县",code:"440823"},{name:"徐闻县",code:"440825"},{name:"廉江市",code:"440881"},{name:"雷州市",code:"440882"},{name:"吴川市",code:"440883"}]},{name:"茂名市",code:"440900",sub:[{name:"市辖区",code:"440901"},{name:"茂南区",code:"440902"},{name:"电白区",code:"440904"},{name:"高州市",code:"440981"},{name:"化州市",code:"440982"},{name:"信宜市",code:"440983"}]},{name:"肇庆市",code:"441200",sub:[{name:"市辖区",code:"441201"},{name:"端州区",code:"441202"},{name:"鼎湖区",code:"441203"},{name:"广宁县",code:"441223"},{name:"怀集县",code:"441224"},{name:"封开县",code:"441225"},{name:"德庆县",code:"441226"},{name:"高要市",code:"441283"},{name:"四会市",code:"441284"}]},{name:"惠州市",code:"441300",sub:[{name:"市辖区",code:"441301"},{name:"惠城区",code:"441302"},{name:"惠阳区",code:"441303"},{name:"博罗县",code:"441322"},{name:"惠东县",code:"441323"},{name:"龙门县",code:"441324"}]},{name:"梅州市",code:"441400",sub:[{name:"市辖区",code:"441401"},{name:"梅江区",code:"441402"},{name:"梅县区",code:"441403"},{name:"大埔县",code:"441422"},{name:"丰顺县",code:"441423"},{name:"五华县",code:"441424"},{name:"平远县",code:"441426"},{name:"蕉岭县",code:"441427"},{name:"兴宁市",code:"441481"}]},{name:"汕尾市",code:"441500",sub:[{name:"市辖区",code:"441501"},{name:"城区",code:"441502"},{name:"海丰县",code:"441521"},{name:"陆河县",code:"441523"},{name:"陆丰市",code:"441581"}]},{name:"河源市",code:"441600",sub:[{name:"市辖区",code:"441601"},{name:"源城区",code:"441602"},{name:"紫金县",code:"441621"},{name:"龙川县",code:"441622"},{name:"连平县",code:"441623"},{name:"和平县",code:"441624"},{name:"东源县",code:"441625"}]},{name:"阳江市",code:"441700",sub:[{name:"市辖区",code:"441701"},{name:"江城区",code:"441702"},{name:"阳东区",code:"441704"},{name:"阳西县",code:"441721"},{name:"阳春市",code:"441781"}]},{name:"清远市",code:"441800",sub:[{name:"市辖区",code:"441801"},{name:"清城区",code:"441802"},{name:"清新区",code:"441803"},{name:"佛冈县",code:"441821"},{name:"阳山县",code:"441823"},{name:"连山壮族瑶族自治县",code:"441825"},{name:"连南瑶族自治县",code:"441826"},{name:"英德市",code:"441881"},{name:"连州市",code:"441882"}]},{name:"东莞市",code:"441900",sub:[]},{name:"中山市",code:"442000",sub:[]},{name:"潮州市",code:"445100",sub:[{name:"市辖区",code:"445101"},{name:"湘桥区",code:"445102"},{name:"潮安区",code:"445103"},{name:"饶平县",code:"445122"}]},{name:"揭阳市",code:"445200",sub:[{name:"市辖区",code:"445201"},{name:"榕城区",code:"445202"},{name:"揭东区",code:"445203"},{name:"揭西县",code:"445222"},{name:"惠来县",code:"445224"},{name:"普宁市",code:"445281"}]},{name:"云浮市",code:"445300",sub:[{name:"市辖区",code:"445301"},{name:"云城区",code:"445302"},{name:"云安区",code:"445303"},{name:"新兴县",code:"445321"},{name:"郁南县",code:"445322"},{name:"罗定市",code:"445381"}]}]},{name:"广西壮族自治区",code:"450000",sub:[{name:"南宁市",code:"450100",sub:[{name:"市辖区",code:"450101"},{name:"兴宁区",code:"450102"},{name:"青秀区",code:"450103"},{name:"江南区",code:"450105"},{name:"西乡塘区",code:"450107"},{name:"良庆区",code:"450108"},{name:"邕宁区",code:"450109"},{name:"武鸣县",code:"450122"},{name:"隆安县",code:"450123"},{name:"马山县",code:"450124"},{name:"上林县",code:"450125"},{name:"宾阳县",code:"450126"},{name:"横县",code:"450127"}]},{name:"柳州市",code:"450200",sub:[{name:"市辖区",code:"450201"},{name:"城中区",code:"450202"},{name:"鱼峰区",code:"450203"},{name:"柳南区",code:"450204"
+},{name:"柳北区",code:"450205"},{name:"柳江县",code:"450221"},{name:"柳城县",code:"450222"},{name:"鹿寨县",code:"450223"},{name:"融安县",code:"450224"},{name:"融水苗族自治县",code:"450225"},{name:"三江侗族自治县",code:"450226"}]},{name:"桂林市",code:"450300",sub:[{name:"市辖区",code:"450301"},{name:"秀峰区",code:"450302"},{name:"叠彩区",code:"450303"},{name:"象山区",code:"450304"},{name:"七星区",code:"450305"},{name:"雁山区",code:"450311"},{name:"临桂区",code:"450312"},{name:"阳朔县",code:"450321"},{name:"灵川县",code:"450323"},{name:"全州县",code:"450324"},{name:"兴安县",code:"450325"},{name:"永福县",code:"450326"},{name:"灌阳县",code:"450327"},{name:"龙胜各族自治县",code:"450328"},{name:"资源县",code:"450329"},{name:"平乐县",code:"450330"},{name:"荔浦县",code:"450331"},{name:"恭城瑶族自治县",code:"450332"}]},{name:"梧州市",code:"450400",sub:[{name:"市辖区",code:"450401"},{name:"万秀区",code:"450403"},{name:"长洲区",code:"450405"},{name:"龙圩区",code:"450406"},{name:"苍梧县",code:"450421"},{name:"藤县",code:"450422"},{name:"蒙山县",code:"450423"},{name:"岑溪市",code:"450481"}]},{name:"北海市",code:"450500",sub:[{name:"市辖区",code:"450501"},{name:"海城区",code:"450502"},{name:"银海区",code:"450503"},{name:"铁山港区",code:"450512"},{name:"合浦县",code:"450521"}]},{name:"防城港市",code:"450600",sub:[{name:"市辖区",code:"450601"},{name:"港口区",code:"450602"},{name:"防城区",code:"450603"},{name:"上思县",code:"450621"},{name:"东兴市",code:"450681"}]},{name:"钦州市",code:"450700",sub:[{name:"市辖区",code:"450701"},{name:"钦南区",code:"450702"},{name:"钦北区",code:"450703"},{name:"灵山县",code:"450721"},{name:"浦北县",code:"450722"}]},{name:"贵港市",code:"450800",sub:[{name:"市辖区",code:"450801"},{name:"港北区",code:"450802"},{name:"港南区",code:"450803"},{name:"覃塘区",code:"450804"},{name:"平南县",code:"450821"},{name:"桂平市",code:"450881"}]},{name:"玉林市",code:"450900",sub:[{name:"市辖区",code:"450901"},{name:"玉州区",code:"450902"},{name:"福绵区",code:"450903"},{name:"容县",code:"450921"},{name:"陆川县",code:"450922"},{name:"博白县",code:"450923"},{name:"兴业县",code:"450924"},{name:"北流市",code:"450981"}]},{name:"百色市",code:"451000",sub:[{name:"市辖区",code:"451001"},{name:"右江区",code:"451002"},{name:"田阳县",code:"451021"},{name:"田东县",code:"451022"},{name:"平果县",code:"451023"},{name:"德保县",code:"451024"},{name:"靖西县",code:"451025"},{name:"那坡县",code:"451026"},{name:"凌云县",code:"451027"},{name:"乐业县",code:"451028"},{name:"田林县",code:"451029"},{name:"西林县",code:"451030"},{name:"隆林各族自治县",code:"451031"}]},{name:"贺州市",code:"451100",sub:[{name:"市辖区",code:"451101"},{name:"八步区",code:"451102"},{name:"平桂管理区",code:"451119"},{name:"昭平县",code:"451121"},{name:"钟山县",code:"451122"},{name:"富川瑶族自治县",code:"451123"}]},{name:"河池市",code:"451200",sub:[{name:"市辖区",code:"451201"},{name:"金城江区",code:"451202"},{name:"南丹县",code:"451221"},{name:"天峨县",code:"451222"},{name:"凤山县",code:"451223"},{name:"东兰县",code:"451224"},{name:"罗城仫佬族自治县",code:"451225"},{name:"环江毛南族自治县",code:"451226"},{name:"巴马瑶族自治县",code:"451227"},{name:"都安瑶族自治县",code:"451228"},{name:"大化瑶族自治县",code:"451229"},{name:"宜州市",code:"451281"}]},{name:"来宾市",code:"451300",sub:[{name:"市辖区",code:"451301"},{name:"兴宾区",code:"451302"},{name:"忻城县",code:"451321"},{name:"象州县",code:"451322"},{name:"武宣县",code:"451323"},{name:"金秀瑶族自治县",code:"451324"},{name:"合山市",code:"451381"}]},{name:"崇左市",code:"451400",sub:[{name:"市辖区",code:"451401"},{name:"江州区",code:"451402"},{name:"扶绥县",code:"451421"},{name:"宁明县",code:"451422"},{name:"龙州县",code:"451423"},{name:"大新县",code:"451424"},{name:"天等县",code:"451425"},{name:"凭祥市",code:"451481"}]}]},{name:"海南省",code:"460000",sub:[{name:"海口市",code:"460100",sub:[{name:"市辖区",code:"460101"},{name:"秀英区",code:"460105"},{name:"龙华区",code:"460106"},{name:"琼山区",code:"460107"},{name:"美兰区",code:"460108"}]},{name:"三亚市",code:"460200",sub:[{name:"市辖区",code:"460201"},{name:"海棠区",code:"460202"},{name:"吉阳区",code:"460203"},{name:"天涯区",code:"460204"},{name:"崖州区",code:"460205"}]},{name:"三沙市",code:"460300",sub:[{name:"西沙群岛",code:"460321"},{name:"南沙群岛",code:"460322"},{name:"中沙群岛的岛礁及其海域",code:"460323"}]},{name:"五指山市",code:"469001"},{name:"琼海市",code:"469002"},{name:"儋州市",code:"469003"},{name:"文昌市",code:"469005"},{name:"万宁市",code:"469006"},{name:"东方市",code:"469007"},{name:"定安县",code:"469021"},{name:"屯昌县",code:"469022"},{name:"澄迈县",code:"469023"},{name:"临高县",code:"469024"},{name:"白沙黎族自治县",code:"469025"},{name:"昌江黎族自治县",code:"469026"},{name:"乐东黎族自治县",code:"469027"},{name:"陵水黎族自治县",code:"469028"},{name:"保亭黎族苗族自治县",code:"469029"},{name:"琼中黎族苗族自治县",code:"469030"}]},{name:"重庆",code:"500000",sub:[{name:"重庆市",code:"500000",sub:[{name:"万州区",code:"500101"},{name:"涪陵区",code:"500102"},{name:"渝中区",code:"500103"},{name:"大渡口区",code:"500104"},{name:"江北区",code:"500105"},{name:"沙坪坝区",code:"500106"},{name:"九龙坡区",code:"500107"},{name:"南岸区",code:"500108"},{name:"北碚区",code:"500109"},{name:"綦江区",code:"500110"},{name:"大足区",code:"500111"},{name:"渝北区",code:"500112"},{name:"巴南区",code:"500113"},{name:"黔江区",code:"500114"},{name:"长寿区",code:"500115"},{name:"江津区",code:"500116"},{name:"合川区",code:"500117"},{name:"永川区",code:"500118"},{name:"南川区",code:"500119"},{name:"璧山区",code:"500120"},{name:"铜梁区",code:"500151"},{name:"潼南县",code:"500223"},{name:"荣昌县",code:"500226"},{name:"梁平县",code:"500228"},{name:"城口县",code:"500229"},{name:"丰都县",code:"500230"},{name:"垫江县",code:"500231"},{name:"武隆县",code:"500232"},{name:"忠县",code:"500233"},{name:"开县",code:"500234"},{name:"云阳县",code:"500235"},{name:"奉节县",code:"500236"},{name:"巫山县",code:"500237"},{name:"巫溪县",code:"500238"},{name:"石柱土家族自治县",code:"500240"},{name:"秀山土家族苗族自治县",code:"500241"},{name:"酉阳土家族苗族自治县",code:"500242"},{name:"彭水苗族土家族自治县",code:"500243"}]}]},{name:"四川省",code:"510000",sub:[{name:"成都市",code:"510100",sub:[{name:"市辖区",code:"510101"},{name:"锦江区",code:"510104"},{name:"青羊区",code:"510105"},{name:"金牛区",code:"510106"},{name:"武侯区",code:"510107"},{name:"成华区",code:"510108"},{name:"龙泉驿区",code:"510112"},{name:"青白江区",code:"510113"},{name:"新都区",code:"510114"},{name:"温江区",code:"510115"},{name:"金堂县",code:"510121"},{name:"双流县",code:"510122"},{name:"郫县",code:"510124"},{name:"大邑县",code:"510129"},{name:"蒲江县",code:"510131"},{name:"新津县",code:"510132"},{name:"都江堰市",code:"510181"},{name:"彭州市",code:"510182"},{name:"邛崃市",code:"510183"},{name:"崇州市",code:"510184"}]},{name:"自贡市",code:"510300",sub:[{name:"市辖区",code:"510301"},{name:"自流井区",code:"510302"},{name:"贡井区",code:"510303"},{name:"大安区",code:"510304"},{name:"沿滩区",code:"510311"},{name:"荣县",code:"510321"},{name:"富顺县",code:"510322"}]},{name:"攀枝花市",code:"510400",sub:[{name:"市辖区",code:"510401"},{name:"东区",code:"510402"},{name:"西区",code:"510403"},{name:"仁和区",code:"510411"},{name:"米易县",code:"510421"},{name:"盐边县",code:"510422"}]},{name:"泸州市",code:"510500",sub:[{name:"市辖区",code:"510501"},{name:"江阳区",code:"510502"},{name:"纳溪区",code:"510503"},{name:"龙马潭区",code:"510504"},{name:"泸县",code:"510521"},{name:"合江县",code:"510522"},{name:"叙永县",code:"510524"},{name:"古蔺县",code:"510525"}]},{name:"德阳市",code:"510600",sub:[{name:"市辖区",code:"510601"},{name:"旌阳区",code:"510603"},{name:"中江县",code:"510623"},{name:"罗江县",code:"510626"},{name:"广汉市",code:"510681"},{name:"什邡市",code:"510682"},{name:"绵竹市",code:"510683"}]},{name:"绵阳市",code:"510700",sub:[{name:"市辖区",code:"510701"},{name:"涪城区",code:"510703"},{name:"游仙区",code:"510704"},{name:"三台县",code:"510722"},{name:"盐亭县",code:"510723"},{name:"安县",code:"510724"},{name:"梓潼县",code:"510725"},{name:"北川羌族自治县",code:"510726"},{name:"平武县",code:"510727"},{name:"江油市",code:"510781"}]},{name:"广元市",code:"510800",sub:[{name:"市辖区",code:"510801"},{name:"利州区",code:"510802"},{name:"昭化区",code:"510811"},{name:"朝天区",code:"510812"},{name:"旺苍县",code:"510821"},{name:"青川县",code:"510822"},{name:"剑阁县",code:"510823"},{name:"苍溪县",code:"510824"}]},{name:"遂宁市",code:"510900",sub:[{name:"市辖区",code:"510901"},{name:"船山区",code:"510903"},{name:"安居区",code:"510904"},{name:"蓬溪县",code:"510921"},{name:"射洪县",code:"510922"},{name:"大英县",code:"510923"}]},{name:"内江市",code:"511000",sub:[{name:"市辖区",code:"511001"},{name:"市中区",code:"511002"},{name:"东兴区",code:"511011"},{name:"威远县",code:"511024"},{name:"资中县",code:"511025"},{name:"隆昌县",code:"511028"}]},{name:"乐山市",code:"511100",sub:[{name:"市辖区",code:"511101"},{name:"市中区",code:"511102"},{name:"沙湾区",code:"511111"},{name:"五通桥区",code:"511112"},{name:"金口河区",code:"511113"},{name:"犍为县",code:"511123"},{name:"井研县",code:"511124"},{name:"夹江县",code:"511126"},{name:"沐川县",code:"511129"},{name:"峨边彝族自治县",code:"511132"},{name:"马边彝族自治县",code:"511133"},{name:"峨眉山市",code:"511181"}]},{name:"南充市",code:"511300",sub:[{name:"市辖区",code:"511301"},{name:"顺庆区",code:"511302"},{name:"高坪区",code:"511303"},{name:"嘉陵区",code:"511304"},{name:"南部县",code:"511321"},{name:"营山县",code:"511322"},{name:"蓬安县",code:"511323"},{name:"仪陇县",code:"511324"},{name:"西充县",code:"511325"},{name:"阆中市",code:"511381"}]},{name:"眉山市",code:"511400",sub:[{name:"市辖区",code:"511401"},{name:"东坡区",code:"511402"},{name:"彭山区",code:"511403"},{name:"仁寿县",code:"511421"},{name:"洪雅县",code:"511423"},{name:"丹棱县",code:"511424"},{name:"青神县",code:"511425"}]},{name:"宜宾市",code:"511500",sub:[{name:"市辖区",code:"511501"},{name:"翠屏区",code:"511502"},{name:"南溪区",code:"511503"},{name:"宜宾县",code:"511521"},{name:"江安县",code:"511523"},{name:"长宁县",code:"511524"},{name:"高县",code:"511525"},{name:"珙县",code:"511526"},{name:"筠连县",code:"511527"},{name:"兴文县",code:"511528"},{name:"屏山县",code:"511529"}]},{name:"广安市",code:"511600",sub:[{name:"市辖区",code:"511601"},{name:"广安区",code:"511602"},{name:"前锋区",code:"511603"},{name:"岳池县",code:"511621"},{name:"武胜县",code:"511622"},{name:"邻水县",code:"511623"},{name:"华蓥市",code:"511681"}]},{name:"达州市",code:"511700",sub:[{name:"市辖区",code:"511701"},{name:"通川区",code:"511702"},{name:"达川区",code:"511703"},{name:"宣汉县",code:"511722"},{name:"开江县",code:"511723"},{name:"大竹县",code:"511724"},{name:"渠县",code:"511725"},{name:"万源市",code:"511781"}]},{name:"雅安市",code:"511800",sub:[{name:"市辖区",code:"511801"},{name:"雨城区",code:"511802"},{name:"名山区",code:"511803"},{name:"荥经县",code:"511822"},{name:"汉源县",code:"511823"},{name:"石棉县",code:"511824"},{name:"天全县",code:"511825"},{name:"芦山县",code:"511826"},{name:"宝兴县",code:"511827"}]},{name:"巴中市",code:"511900",sub:[{name:"市辖区",code:"511901"},{name:"巴州区",code:"511902"},{name:"恩阳区",code:"511903"},{name:"通江县",code:"511921"},{name:"南江县",code:"511922"},{name:"平昌县",code:"511923"}]},{name:"资阳市",code:"512000",sub:[{name:"市辖区",code:"512001"},{name:"雁江区",code:"512002"},{name:"安岳县",code:"512021"},{name:"乐至县",code:"512022"},{name:"简阳市",code:"512081"}]},{name:"阿坝藏族羌族自治州",code:"513200",sub:[{name:"汶川县",code:"513221"},{name:"理县",code:"513222"},{name:"茂县",code:"513223"},{name:"松潘县",code:"513224"},{name:"九寨沟县",code:"513225"},{name:"金川县",code:"513226"},{name:"小金县",code:"513227"},{name:"黑水县",code:"513228"},{name:"马尔康县",code:"513229"},{name:"壤塘县",code:"513230"},{name:"阿坝县",code:"513231"},{name:"若尔盖县",code:"513232"},{name:"红原县",code:"513233"}]},{name:"甘孜藏族自治州",code:"513300",sub:[{name:"康定县",code:"513321"},{name:"泸定县",code:"513322"},{name:"丹巴县",code:"513323"},{name:"九龙县",code:"513324"},{name:"雅江县",code:"513325"},{name:"道孚县",code:"513326"},{name:"炉霍县",code:"513327"},{name:"甘孜县",code:"513328"},{name:"新龙县",code:"513329"},{name:"德格县",code:"513330"},{name:"白玉县",code:"513331"},{name:"石渠县",code:"513332"},{name:"色达县",code:"513333"},{name:"理塘县",code:"513334"},{name:"巴塘县",code:"513335"},{name:"乡城县",code:"513336"},{name:"稻城县",code:"513337"},{name:"得荣县",code:"513338"}]},{name:"凉山彝族自治州",code:"513400",sub:[{name:"西昌市",code:"513401"},{name:"木里藏族自治县",code:"513422"},{name:"盐源县",code:"513423"},{name:"德昌县",code:"513424"},{name:"会理县",code:"513425"},{name:"会东县",code:"513426"},{name:"宁南县",code:"513427"},{name:"普格县",code:"513428"},{name:"布拖县",code:"513429"},{name:"金阳县",code:"513430"},{name:"昭觉县",code:"513431"},{name:"喜德县",code:"513432"},{name:"冕宁县",code:"513433"},{name:"越西县",code:"513434"},{name:"甘洛县",code:"513435"},{name:"美姑县",code:"513436"},{name:"雷波县",code:"513437"}]}]},{name:"贵州省",code:"520000",sub:[{name:"贵阳市",code:"520100",sub:[{name:"市辖区",code:"520101"},{name:"南明区",code:"520102"},{name:"云岩区",code:"520103"},{name:"花溪区",code:"520111"},{name:"乌当区",code:"520112"},{name:"白云区",code:"520113"},{name:"观山湖区",code:"520115"},{name:"开阳县",code:"520121"},{name:"息烽县",code:"520122"},{name:"修文县",code:"520123"},{name:"清镇市",code:"520181"}]},{name:"六盘水市",code:"520200",sub:[{name:"钟山区",code:"520201"},{name:"六枝特区",code:"520203"},{name:"水城县",code:"520221"},{name:"盘县",code:"520222"}]},{name:"遵义市",code:"520300",sub:[{name:"市辖区",code:"520301"},{name:"红花岗区",code:"520302"},{name:"汇川区",code:"520303"},{name:"遵义县",code:"520321"},{name:"桐梓县",code:"520322"},{name:"绥阳县",code:"520323"},{name:"正安县",code:"520324"},{name:"道真仡佬族苗族自治县",code:"520325"},{name:"务川仡佬族苗族自治县",code:"520326"},{name:"凤冈县",code:"520327"},{name:"湄潭县",code:"520328"},{name:"余庆县",code:"520329"},{name:"习水县",code:"520330"},{name:"赤水市",code:"520381"},{name:"仁怀市",code:"520382"}]},{name:"安顺市",code:"520400",sub:[{name:"市辖区",code:"520401"},{name:"西秀区",code:"520402"},{name:"平坝区",code:"520403"},{name:"普定县",code:"520422"},{name:"镇宁布依族苗族自治县",code:"520423"},{name:"关岭布依族苗族自治县",code:"520424"},{name:"紫云苗族布依族自治县",code:"520425"}]},{name:"毕节市",code:"520500",sub:[{name:"市辖区",code:"520501"},{name:"七星关区",code:"520502"},{name:"大方县",code:"520521"},{name:"黔西县",code:"520522"},{name:"金沙县",code:"520523"},{name:"织金县",code:"520524"},{name:"纳雍县",code:"520525"},{name:"威宁彝族回族苗族自治县",code:"520526"},{name:"赫章县",code:"520527"}]},{name:"铜仁市",code:"520600",sub:[{name:"市辖区",code:"520601"},{name:"碧江区",code:"520602"},{name:"万山区",code:"520603"},{name:"江口县",code:"520621"},{name:"玉屏侗族自治县",code:"520622"},{name:"石阡县",code:"520623"},{name:"思南县",code:"520624"},{name:"印江土家族苗族自治县",code:"520625"},{name:"德江县",code:"520626"},{name:"沿河土家族自治县",code:"520627"},{name:"松桃苗族自治县",code:"520628"}]},{name:"黔西南布依族苗族自治州",code:"522300",sub:[{name:"兴义市",code:"522301"},{name:"兴仁县",code:"522322"},{name:"普安县",code:"522323"},{name:"晴隆县",code:"522324"},{name:"贞丰县",code:"522325"},{name:"望谟县",code:"522326"},{name:"册亨县",code:"522327"},{name:"安龙县",code:"522328"}]},{name:"黔东南苗族侗族自治州",code:"522600",sub:[{name:"凯里市",code:"522601"},{name:"黄平县",code:"522622"},{name:"施秉县",code:"522623"},{name:"三穗县",code:"522624"},{name:"镇远县",code:"522625"},{name:"岑巩县",code:"522626"},{name:"天柱县",code:"522627"},{name:"锦屏县",code:"522628"},{name:"剑河县",code:"522629"},{name:"台江县",code:"522630"},{name:"黎平县",code:"522631"},{name:"榕江县",code:"522632"},{name:"从江县",code:"522633"},{name:"雷山县",code:"522634"},{name:"麻江县",code:"522635"},{name:"丹寨县",code:"522636"}]},{name:"黔南布依族苗族自治州",code:"522700",sub:[{name:"都匀市",code:"522701"},{name:"福泉市",code:"522702"},{name:"荔波县",code:"522722"},{name:"贵定县",code:"522723"},{name:"瓮安县",code:"522725"},{name:"独山县",code:"522726"},{name:"平塘县",code:"522727"},{name:"罗甸县",code:"522728"},{name:"长顺县",code:"522729"},{name:"龙里县",code:"522730"},{name:"惠水县",code:"522731"},{name:"三都水族自治县",code:"522732"}]}]},{name:"云南省",code:"530000",sub:[{name:"昆明市",code:"530100",sub:[{name:"市辖区",code:"530101"},{name:"五华区",code:"530102"},{name:"盘龙区",code:"530103"},{name:"官渡区",code:"530111"},{name:"西山区",code:"530112"},{name:"东川区",code:"530113"},{name:"呈贡区",code:"530114"},{name:"晋宁县",code:"530122"},{name:"富民县",code:"530124"},{name:"宜良县",code:"530125"},{name:"石林彝族自治县",code:"530126"},{name:"嵩明县",code:"530127"},{name:"禄劝彝族苗族自治县",code:"530128"},{name:"寻甸回族彝族自治县",code:"530129"},{name:"安宁市",code:"530181"}]},{name:"曲靖市",code:"530300",sub:[{name:"市辖区",code:"530301"},{name:"麒麟区",code:"530302"},{name:"马龙县",code:"530321"},{name:"陆良县",code:"530322"},{name:"师宗县",code:"530323"},{name:"罗平县",code:"530324"},{name:"富源县",code:"530325"},{name:"会泽县",code:"530326"},{name:"沾益县",code:"530328"},{name:"宣威市",code:"530381"}]},{name:"玉溪市",code:"530400",sub:[{name:"市辖区",code:"530401"},{name:"红塔区",code:"530402"},{name:"江川县",code:"530421"},{name:"澄江县",code:"530422"},{name:"通海县",code:"530423"},{name:"华宁县",code:"530424"},{name:"易门县",code:"530425"},{name:"峨山彝族自治县",code:"530426"},{name:"新平彝族傣族自治县",code:"530427"},{name:"元江哈尼族彝族傣族自治县",code:"530428"}]},{name:"保山市",code:"530500",sub:[{name:"市辖区",code:"530501"},{name:"隆阳区",code:"530502"},{name:"施甸县",code:"530521"},{name:"腾冲县",code:"530522"},{name:"龙陵县",code:"530523"},{name:"昌宁县",code:"530524"}]},{name:"昭通市",code:"530600",sub:[{name:"市辖区",code:"530601"},{name:"昭阳区",code:"530602"},{name:"鲁甸县",code:"530621"},{name:"巧家县",code:"530622"},{name:"盐津县",code:"530623"},{name:"大关县",code:"530624"},{name:"永善县",code:"530625"},{name:"绥江县",code:"530626"},{name:"镇雄县",code:"530627"},{name:"彝良县",code:"530628"},{name:"威信县",code:"530629"},{name:"水富县",code:"530630"}]},{name:"丽江市",code:"530700",sub:[{name:"市辖区",code:"530701"},{name:"古城区",code:"530702"},{name:"玉龙纳西族自治县",code:"530721"},{name:"永胜县",code:"530722"},{name:"华坪县",code:"530723"},{name:"宁蒗彝族自治县",code:"530724"}]},{name:"普洱市",code:"530800",sub:[{name:"市辖区",code:"530801"},{name:"思茅区",code:"530802"},{name:"宁洱哈尼族彝族自治县",code:"530821"},{name:"墨江哈尼族自治县",code:"530822"},{name:"景东彝族自治县",code:"530823"},{name:"景谷傣族彝族自治县",code:"530824"},{name:"镇沅彝族哈尼族拉祜族自治县",code:"530825"},{name:"江城哈尼族彝族自治县",code:"530826"},{name:"孟连傣族拉祜族佤族自治县",code:"530827"},{name:"澜沧拉祜族自治县",code:"530828"},{name:"西盟佤族自治县",code:"530829"}]},{name:"临沧市",code:"530900",sub:[{name:"市辖区",code:"530901"},{name:"临翔区",code:"530902"},{name:"凤庆县",code:"530921"},{name:"云县",code:"530922"},{name:"永德县",code:"530923"},{name:"镇康县",code:"530924"},{name:"双江拉祜族佤族布朗族傣族自治县",code:"530925"},{name:"耿马傣族佤族自治县",code:"530926"},{name:"沧源佤族自治县",code:"530927"}]},{name:"楚雄彝族自治州",code:"532300",sub:[{name:"楚雄市",code:"532301"},{name:"双柏县",code:"532322"},{name:"牟定县",code:"532323"},{name:"南华县",code:"532324"},{name:"姚安县",code:"532325"},{name:"大姚县",code:"532326"},{name:"永仁县",code:"532327"},{name:"元谋县",code:"532328"},{name:"武定县",code:"532329"},{name:"禄丰县",code:"532331"}]},{name:"红河哈尼族彝族自治州",code:"532500",sub:[{name:"个旧市",code:"532501"},{name:"开远市",code:"532502"},{name:"蒙自市",code:"532503"},{name:"弥勒市",code:"532504"},{name:"屏边苗族自治县",code:"532523"},{name:"建水县",code:"532524"},{name:"石屏县",code:"532525"},{name:"泸西县",code:"532527"},{name:"元阳县",code:"532528"},{name:"红河县",code:"532529"},{name:"金平苗族瑶族傣族自治县",code:"532530"},{name:"绿春县",code:"532531"},{name:"河口瑶族自治县",code:"532532"}]},{name:"文山壮族苗族自治州",code:"532600",sub:[{name:"文山市",code:"532601"},{name:"砚山县",code:"532622"},{name:"西畴县",code:"532623"},{name:"麻栗坡县",code:"532624"},{name:"马关县",code:"532625"},{name:"丘北县",code:"532626"},{name:"广南县",code:"532627"},{name:"富宁县",code:"532628"}]},{name:"西双版纳傣族自治州",code:"532800",sub:[{name:"景洪市",code:"532801"},{name:"勐海县",code:"532822"},{name:"勐腊县",code:"532823"}]},{name:"大理白族自治州",code:"532900",sub:[{name:"大理市",code:"532901"},{name:"漾濞彝族自治县",code:"532922"},{name:"祥云县",code:"532923"},{name:"宾川县",code:"532924"},{name:"弥渡县",code:"532925"},{name:"南涧彝族自治县",code:"532926"},{name:"巍山彝族回族自治县",code:"532927"},{name:"永平县",code:"532928"},{name:"云龙县",code:"532929"},{name:"洱源县",code:"532930"},{name:"剑川县",code:"532931"},{name:"鹤庆县",code:"532932"}]},{name:"德宏傣族景颇族自治州",code:"533100",sub:[{name:"瑞丽市",code:"533102"},{name:"芒市",code:"533103"},{name:"梁河县",code:"533122"},{name:"盈江县",code:"533123"},{name:"陇川县",code:"533124"}]},{name:"怒江傈僳族自治州",code:"533300",sub:[{name:"泸水县",code:"533321"},{name:"福贡县",code:"533323"},{name:"贡山独龙族怒族自治县",code:"533324"},{name:"兰坪白族普米族自治县",code:"533325"}]},{name:"迪庆藏族自治州",code:"533400",sub:[{name:"香格里拉市",code:"533401"},{name:"德钦县",code:"533422"},{name:"维西傈僳族自治县",code:"533423"}]}]},{name:"西藏自治区",code:"540000",sub:[{name:"拉萨市",code:"540100",sub:[{name:"市辖区",code:"540101"},{name:"城关区",code:"540102"},{name:"林周县",code:"540121"},{name:"当雄县",code:"540122"},{name:"尼木县",code:"540123"},{name:"曲水县",code:"540124"},{name:"堆龙德庆县",code:"540125"},{name:"达孜县",code:"540126"},{name:"墨竹工卡县",code:"540127"}]},{name:"日喀则市",code:"540200",sub:[{name:"市辖区",code:"540201"},{name:"桑珠孜区",code:"540202"},{name:"南木林县",code:"540221"},{name:"江孜县",code:"540222"},{name:"定日县",code:"540223"},{name:"萨迦县",code:"540224"},{name:"拉孜县",code:"540225"},{name:"昂仁县",code:"540226"},{name:"谢通门县",code:"540227"},{name:"白朗县",code:"540228"},{name:"仁布县",code:"540229"},{name:"康马县",code:"540230"},{name:"定结县",code:"540231"},{name:"仲巴县",code:"540232"},{name:"亚东县",code:"540233"},{name:"吉隆县",code:"540234"},{name:"聂拉木县",code:"540235"},{name:"萨嘎县",code:"540236"},{name:"岗巴县",code:"540237"}]},{name:"昌都市",code:"540300",sub:[{name:"市辖区",code:"540301"},{name:"卡若区",code:"540302"},{name:"江达县",code:"540321"},{name:"贡觉县",code:"540322"},{name:"类乌齐县",code:"540323"},{name:"丁青县",code:"540324"},{name:"察雅县",code:"540325"},{name:"八宿县",code:"540326"},{name:"左贡县",code:"540327"},{name:"芒康县",code:"540328"},{name:"洛隆县",code:"540329"},{name:"边坝县",code:"540330"}]},{name:"山南地区",code:"542200",sub:[{name:"乃东县",code:"542221"},{name:"扎囊县",code:"542222"},{name:"贡嘎县",code:"542223"},{name:"桑日县",code:"542224"},{name:"琼结县",code:"542225"},{name:"曲松县",code:"542226"},{name:"措美县",code:"542227"},{name:"洛扎县",code:"542228"},{name:"加查县",code:"542229"},{name:"隆子县",code:"542231"},{name:"错那县",code:"542232"},{name:"浪卡子县",code:"542233"}]},{name:"那曲地区",code:"542400",sub:[{name:"那曲县",code:"542421"},{name:"嘉黎县",code:"542422"},{name:"比如县",code:"542423"},{name:"聂荣县",code:"542424"},{name:"安多县",code:"542425"},{name:"申扎县",code:"542426"},{name:"索县",code:"542427"},{name:"班戈县",code:"542428"},{name:"巴青县",code:"542429"},{name:"尼玛县",code:"542430"},{name:"双湖县",code:"542431"}]},{name:"阿里地区",code:"542500",sub:[{name:"普兰县",code:"542521"},{name:"札达县",code:"542522"},{name:"噶尔县",code:"542523"},{name:"日土县",code:"542524"},{name:"革吉县",code:"542525"},{name:"改则县",code:"542526"},{name:"措勤县",code:"542527"}]},{name:"林芝地区",code:"542600",sub:[{name:"林芝县",code:"542621"},{name:"工布江达县",code:"542622"},{name:"米林县",code:"542623"},{name:"墨脱县",code:"542624"},{name:"波密县",code:"542625"},{name:"察隅县",code:"542626"},{name:"朗县",code:"542627"}]}]},{name:"陕西省",code:"610000",sub:[{name:"西安市",code:"610100",sub:[{name:"市辖区",code:"610101"},{name:"新城区",code:"610102"},{name:"碑林区",code:"610103"},{name:"莲湖区",code:"610104"},{name:"灞桥区",code:"610111"},{name:"未央区",code:"610112"},{name:"雁塔区",code:"610113"},{name:"阎良区",code:"610114"},{name:"临潼区",code:"610115"},{name:"长安区",code:"610116"},{name:"高陵区",code:"610117"},{name:"蓝田县",code:"610122"},{name:"周至县",code:"610124"},{name:"户县",code:"610125"}]},{name:"铜川市",code:"610200",sub:[{name:"市辖区",code:"610201"},{name:"王益区",code:"610202"},{name:"印台区",code:"610203"},{name:"耀州区",code:"610204"},{name:"宜君县",code:"610222"}]},{name:"宝鸡市",code:"610300",sub:[{name:"市辖区",code:"610301"},{name:"渭滨区",code:"610302"},{name:"金台区",code:"610303"},{name:"陈仓区",code:"610304"},{name:"凤翔县",code:"610322"},{name:"岐山县",code:"610323"},{name:"扶风县",code:"610324"},{name:"眉县",code:"610326"},{name:"陇县",code:"610327"},{name:"千阳县",code:"610328"},{name:"麟游县",code:"610329"},{name:"凤县",code:"610330"},{name:"太白县",code:"610331"}]},{name:"咸阳市",code:"610400",sub:[{name:"市辖区",code:"610401"},{name:"秦都区",code:"610402"},{name:"杨陵区",code:"610403"},{name:"渭城区",code:"610404"},{name:"三原县",code:"610422"},{name:"泾阳县",code:"610423"},{name:"乾县",code:"610424"},{name:"礼泉县",code:"610425"},{name:"永寿县",code:"610426"},{name:"彬县",code:"610427"},{name:"长武县",code:"610428"},{name:"旬邑县",code:"610429"},{name:"淳化县",code:"610430"},{name:"武功县",code:"610431"},{name:"兴平市",code:"610481"}]},{name:"渭南市",code:"610500",sub:[{name:"市辖区",code:"610501"},{name:"临渭区",code:"610502"},{name:"华县",code:"610521"},{name:"潼关县",code:"610522"},{name:"大荔县",code:"610523"},{name:"合阳县",code:"610524"},{name:"澄城县",code:"610525"},{name:"蒲城县",code:"610526"},{name:"白水县",code:"610527"},{name:"富平县",code:"610528"},{name:"韩城市",code:"610581"},{name:"华阴市",code:"610582"}]},{name:"延安市",code:"610600",sub:[{name:"市辖区",code:"610601"},{name:"宝塔区",code:"610602"},{name:"延长县",code:"610621"},{name:"延川县",code:"610622"},{name:"子长县",code:"610623"},{name:"安塞县",code:"610624"},{name:"志丹县",code:"610625"},{name:"吴起县",code:"610626"},{name:"甘泉县",code:"610627"},{name:"富县",code:"610628"},{name:"洛川县",code:"610629"},{name:"宜川县",code:"610630"},{name:"黄龙县",code:"610631"},{name:"黄陵县",code:"610632"}]},{name:"汉中市",code:"610700",sub:[{name:"市辖区",code:"610701"},{name:"汉台区",code:"610702"},{name:"南郑县",code:"610721"},{name:"城固县",code:"610722"},{name:"洋县",code:"610723"},{name:"西乡县",code:"610724"},{name:"勉县",code:"610725"},{name:"宁强县",code:"610726"},{name:"略阳县",code:"610727"},{name:"镇巴县",code:"610728"},{name:"留坝县",code:"610729"},{name:"佛坪县",code:"610730"}]},{name:"榆林市",code:"610800",sub:[{name:"市辖区",code:"610801"},{name:"榆阳区",code:"610802"},{name:"神木县",code:"610821"},{name:"府谷县",code:"610822"},{name:"横山县",code:"610823"},{name:"靖边县",code:"610824"},{name:"定边县",code:"610825"},{name:"绥德县",code:"610826"},{name:"米脂县",code:"610827"},{name:"佳县",code:"610828"},{name:"吴堡县",code:"610829"},{name:"清涧县",code:"610830"},{name:"子洲县",code:"610831"}]},{name:"安康市",code:"610900",sub:[{name:"市辖区",code:"610901"},{name:"汉阴县",code:"610921"},{name:"石泉县",code:"610922"},{name:"宁陕县",code:"610923"},{name:"紫阳县",code:"610924"},{name:"岚皋县",code:"610925"},{name:"平利县",code:"610926"},{name:"镇坪县",code:"610927"},{name:"旬阳县",code:"610928"},{name:"白河县",code:"610929"}]},{name:"商洛市",code:"611000",sub:[{name:"市辖区",code:"611001"},{name:"商州区",code:"611002"},{name:"洛南县",code:"611021"},{name:"丹凤县",code:"611022"},{name:"商南县",code:"611023"},{name:"山阳县",code:"611024"},{name:"镇安县",code:"611025"},{name:"柞水县",code:"611026"}]}]},{name:"甘肃省",code:"620000",sub:[{name:"兰州市",code:"620100",sub:[{name:"市辖区",code:"620101"},{name:"城关区",code:"620102"},{name:"七里河区",code:"620103"},{name:"西固区",code:"620104"},{name:"安宁区",code:"620105"},{name:"红古区",code:"620111"},{name:"永登县",code:"620121"},{name:"皋兰县",code:"620122"},{name:"榆中县",code:"620123"}]},{name:"嘉峪关市",code:"620200",sub:[{name:"市辖区",code:"620201"}]},{name:"金昌市",code:"620300",sub:[{name:"市辖区",code:"620301"},{name:"金川区",code:"620302"},{name:"永昌县",code:"620321"}]},{name:"白银市",code:"620400",sub:[{name:"市辖区",code:"620401"},{name:"白银区",code:"620402"},{name:"平川区",code:"620403"},{name:"靖远县",code:"620421"},{name:"会宁县",code:"620422"},{name:"景泰县",code:"620423"}]},{name:"天水市",code:"620500",sub:[{name:"市辖区",code:"620501"},{name:"秦州区",code:"620502"},{name:"麦积区",code:"620503"},{name:"清水县",code:"620521"},{name:"秦安县",code:"620522"},{name:"甘谷县",code:"620523"},{name:"武山县",code:"620524"},{name:"张家川回族自治县",code:"620525"}]},{name:"武威市",code:"620600",sub:[{name:"市辖区",code:"620601"},{name:"凉州区",code:"620602"},{name:"民勤县",code:"620621"},{name:"古浪县",code:"620622"},{name:"天祝藏族自治县",code:"620623"}]},{name:"张掖市",code:"620700",sub:[{name:"市辖区",code:"620701"},{name:"甘州区",code:"620702"},{name:"肃南裕固族自治县",code:"620721"},{name:"民乐县",code:"620722"},{name:"临泽县",code:"620723"},{name:"高台县",code:"620724"},{name:"山丹县",code:"620725"}]},{name:"平凉市",code:"620800",sub:[{name:"市辖区",code:"620801"},{name:"崆峒区",code:"620802"},{name:"泾川县",code:"620821"},{name:"灵台县",code:"620822"},{name:"崇信县",code:"620823"},{name:"华亭县",code:"620824"},{name:"庄浪县",code:"620825"},{name:"静宁县",code:"620826"}]},{name:"酒泉市",code:"620900",sub:[{name:"市辖区",code:"620901"},{name:"肃州区",code:"620902"},{name:"金塔县",code:"620921"},{name:"瓜州县",code:"620922"},{name:"肃北蒙古族自治县",code:"620923"},{name:"阿克塞哈萨克族自治县",code:"620924"},{name:"玉门市",code:"620981"},{name:"敦煌市",code:"620982"}]},{name:"庆阳市",code:"621000",sub:[{name:"市辖区",code:"621001"},{name:"西峰区",code:"621002"},{name:"庆城县",code:"621021"},{name:"环县",code:"621022"},{name:"华池县",code:"621023"},{name:"合水县",code:"621024"},{name:"正宁县",code:"621025"},{name:"宁县",code:"621026"},{name:"镇原县",code:"621027"}]},{name:"定西市",code:"621100",sub:[{name:"市辖区",code:"621101"},{name:"安定区",code:"621102"},{name:"通渭县",code:"621121"},{name:"陇西县",code:"621122"},{name:"渭源县",code:"621123"},{name:"临洮县",code:"621124"},{name:"漳县",code:"621125"},{name:"岷县",code:"621126"}]},{name:"陇南市",code:"621200",sub:[{name:"市辖区",code:"621201"},{name:"武都区",code:"621202"},{name:"成县",code:"621221"},{name:"文县",code:"621222"},{name:"宕昌县",code:"621223"},{name:"康县",code:"621224"},{name:"西和县",code:"621225"},{name:"礼县",code:"621226"},{name:"徽县",code:"621227"},{name:"两当县",code:"621228"}]},{name:"临夏回族自治州",code:"622900",sub:[{name:"临夏市",code:"622901"},{name:"临夏县",code:"622921"},{name:"康乐县",code:"622922"},{name:"永靖县",code:"622923"},{name:"广河县",code:"622924"},{name:"和政县",code:"622925"},{name:"东乡族自治县",code:"622926"},{name:"积石山保安族东乡族撒拉族自治县",code:"622927"}]},{name:"甘南藏族自治州",code:"623000",sub:[{name:"合作市",code:"623001"},{name:"临潭县",code:"623021"},{name:"卓尼县",code:"623022"},{name:"舟曲县",code:"623023"},{name:"迭部县",code:"623024"},{name:"玛曲县",code:"623025"},{name:"碌曲县",code:"623026"},{name:"夏河县",code:"623027"}]}]},{name:"青海省",code:"630000",sub:[{name:"西宁市",code:"630100",sub:[{name:"市辖区",code:"630101"},{name:"城东区",code:"630102"},{name:"城中区",code:"630103"},{name:"城西区",code:"630104"},{name:"城北区",code:"630105"},{name:"大通回族土族自治县",code:"630121"},{name:"湟中县",code:"630122"},{name:"湟源县",code:"630123"}]},{name:"海东市",code:"630200",sub:[{name:"市辖区",code:"630201"},{name:"乐都区",code:"630202"},{name:"平安县",code:"630221"},{name:"民和回族土族自治县",code:"630222"},{name:"互助土族自治县",code:"630223"},{name:"化隆回族自治县",code:"630224"},{name:"循化撒拉族自治县",code:"630225"}]},{name:"海北藏族自治州",code:"632200",sub:[{name:"门源回族自治县",code:"632221"},{name:"祁连县",code:"632222"},{name:"海晏县",code:"632223"},{name:"刚察县",code:"632224"}]},{name:"黄南藏族自治州",code:"632300",sub:[{name:"同仁县",code:"632321"},{name:"尖扎县",code:"632322"},{name:"泽库县",code:"632323"},{name:"河南蒙古族自治县",code:"632324"}]},{name:"海南藏族自治州",code:"632500",sub:[{name:"共和县",code:"632521"},{name:"同德县",code:"632522"},{name:"贵德县",code:"632523"},{name:"兴海县",code:"632524"},{name:"贵南县",code:"632525"}]},{name:"果洛藏族自治州",code:"632600",sub:[{name:"玛沁县",code:"632621"},{name:"班玛县",code:"632622"},{name:"甘德县",code:"632623"},{name:"达日县",code:"632624"},{name:"久治县",code:"632625"},{name:"玛多县",code:"632626"}]},{name:"玉树藏族自治州",code:"632700",sub:[{name:"玉树市",code:"632701"},{name:"杂多县",code:"632722"},{name:"称多县",code:"632723"},{name:"治多县",code:"632724"},{name:"囊谦县",code:"632725"},{name:"曲麻莱县",code:"632726"}]},{name:"海西蒙古族藏族自治州",code:"632800",sub:[{name:"格尔木市",code:"632801"},{name:"德令哈市",code:"632802"},{name:"乌兰县",code:"632821"},{name:"都兰县",code:"632822"},{name:"天峻县",code:"632823"}]}]},{name:"宁夏回族自治区",code:"640000",sub:[{name:"银川市",code:"640100",sub:[{name:"市辖区",code:"640101"},{name:"兴庆区",code:"640104"},{name:"西夏区",code:"640105"},{name:"金凤区",code:"640106"},{name:"永宁县",code:"640121"},{name:"贺兰县",code:"640122"},{name:"灵武市",code:"640181"}]},{name:"石嘴山市",code:"640200",sub:[{name:"市辖区",code:"640201"},{name:"大武口区",code:"640202"},{name:"惠农区",code:"640205"},{name:"平罗县",code:"640221"}]},{name:"吴忠市",code:"640300",sub:[{name:"市辖区",code:"640301"},{name:"利通区",code:"640302"},{name:"红寺堡区",code:"640303"},{name:"盐池县",code:"640323"},{name:"同心县",code:"640324"},{name:"青铜峡市",code:"640381"}]},{name:"固原市",code:"640400",sub:[{name:"市辖区",code:"640401"},{name:"原州区",code:"640402"},{name:"西吉县",code:"640422"},{name:"隆德县",code:"640423"},{name:"泾源县",code:"640424"},{name:"彭阳县",code:"640425"}]},{name:"中卫市",code:"640500",sub:[{name:"市辖区",code:"640501"},{name:"沙坡头区",code:"640502"},{name:"中宁县",code:"640521"},{name:"海原县",code:"640522"}]}]},{name:"新疆维吾尔自治区",code:"650000",sub:[{name:"乌鲁木齐市",code:"650100",sub:[{name:"市辖区",code:"650101"},{name:"天山区",code:"650102"},{name:"沙依巴克区",code:"650103"},{name:"新市区",code:"650104"},{name:"水磨沟区",code:"650105"},{name:"头屯河区",code:"650106"},{name:"达坂城区",code:"650107"},{name:"米东区",code:"650109"},{name:"乌鲁木齐县",code:"650121"}]},{name:"克拉玛依市",code:"650200",sub:[{name:"市辖区",code:"650201"},{name:"独山子区",code:"650202"},{name:"克拉玛依区",code:"650203"},{name:"白碱滩区",code:"650204"},{name:"乌尔禾区",code:"650205"}]},{name:"吐鲁番地区",code:"652100",sub:[{name:"吐鲁番市",code:"652101"},{name:"鄯善县",code:"652122"},{name:"托克逊县",code:"652123"}]},{name:"哈密地区",code:"652200",sub:[{name:"哈密市",code:"652201"},{name:"巴里坤哈萨克自治县",code:"652222"},{name:"伊吾县",code:"652223"}]},{name:"昌吉回族自治州",code:"652300",sub:[{name:"昌吉市",code:"652301"},{name:"阜康市",code:"652302"},{name:"呼图壁县",code:"652323"},{name:"玛纳斯县",code:"652324"},{name:"奇台县",code:"652325"},{name:"吉木萨尔县",code:"652327"},{name:"木垒哈萨克自治县",code:"652328"}]},{name:"博尔塔拉蒙古自治州",code:"652700",sub:[{name:"博乐市",code:"652701"},{name:"阿拉山口市",code:"652702"},{name:"精河县",code:"652722"},{name:"温泉县",code:"652723"}]},{name:"巴音郭楞蒙古自治州",code:"652800",sub:[{name:"库尔勒市",code:"652801"},{name:"轮台县",code:"652822"},{name:"尉犁县",code:"652823"},{name:"若羌县",code:"652824"},{name:"且末县",code:"652825"},{name:"焉耆回族自治县",code:"652826"},{name:"和静县",code:"652827"},{name:"和硕县",code:"652828"},{name:"博湖县",code:"652829"}]},{name:"阿克苏地区",code:"652900",
+sub:[{name:"阿克苏市",code:"652901"},{name:"温宿县",code:"652922"},{name:"库车县",code:"652923"},{name:"沙雅县",code:"652924"},{name:"新和县",code:"652925"},{name:"拜城县",code:"652926"},{name:"乌什县",code:"652927"},{name:"阿瓦提县",code:"652928"},{name:"柯坪县",code:"652929"}]},{name:"克孜勒苏柯尔克孜自治州",code:"653000",sub:[{name:"阿图什市",code:"653001"},{name:"阿克陶县",code:"653022"},{name:"阿合奇县",code:"653023"},{name:"乌恰县",code:"653024"}]},{name:"喀什地区",code:"653100",sub:[{name:"喀什市",code:"653101"},{name:"疏附县",code:"653121"},{name:"疏勒县",code:"653122"},{name:"英吉沙县",code:"653123"},{name:"泽普县",code:"653124"},{name:"莎车县",code:"653125"},{name:"叶城县",code:"653126"},{name:"麦盖提县",code:"653127"},{name:"岳普湖县",code:"653128"},{name:"伽师县",code:"653129"},{name:"巴楚县",code:"653130"},{name:"塔什库尔干塔吉克自治县",code:"653131"}]},{name:"和田地区",code:"653200",sub:[{name:"和田市",code:"653201"},{name:"和田县",code:"653221"},{name:"墨玉县",code:"653222"},{name:"皮山县",code:"653223"},{name:"洛浦县",code:"653224"},{name:"策勒县",code:"653225"},{name:"于田县",code:"653226"},{name:"民丰县",code:"653227"}]},{name:"伊犁哈萨克自治州",code:"654000",sub:[{name:"伊宁市",code:"654002"},{name:"奎屯市",code:"654003"},{name:"霍尔果斯市",code:"654004"},{name:"伊宁县",code:"654021"},{name:"察布查尔锡伯自治县",code:"654022"},{name:"霍城县",code:"654023"},{name:"巩留县",code:"654024"},{name:"新源县",code:"654025"},{name:"昭苏县",code:"654026"},{name:"特克斯县",code:"654027"},{name:"尼勒克县",code:"654028"},{name:"塔城地区",code:"654200"},{name:"塔城市",code:"654201"},{name:"乌苏市",code:"654202"},{name:"额敏县",code:"654221"},{name:"沙湾县",code:"654223"},{name:"托里县",code:"654224"},{name:"裕民县",code:"654225"},{name:"和布克赛尔蒙古自治县",code:"654226"},{name:"阿勒泰地区",code:"654300"},{name:"阿勒泰市",code:"654301"},{name:"布尔津县",code:"654321"},{name:"富蕴县",code:"654322"},{name:"福海县",code:"654323"},{name:"哈巴河县",code:"654324"},{name:"青河县",code:"654325"},{name:"吉木乃县",code:"654326"}]},{name:"自治区直辖县级行政区划",code:"659000",sub:[{name:"石河子市",code:"659001"},{name:"阿拉尔市",code:"659002"},{name:"图木舒克市",code:"659003"},{name:"五家渠市",code:"659004"},{name:"北屯市",code:"659005"},{name:"铁门关市",code:"659006"},{name:"双河市",code:"659007"}]}]},{name:"台湾省",code:"710000",sub:[{name:"台北市",code:"710100",sub:[{name:"松山区",code:"710101"},{name:"信义区",code:"710102"},{name:"大安区",code:"710103"},{name:"中山区",code:"710104"},{name:"中正区",code:"710105"},{name:"大同区",code:"710106"},{name:"万华区",code:"710107"},{name:"文山区",code:"710108"},{name:"南港区",code:"710109"},{name:"内湖区",code:"710110"},{name:"士林区",code:"710111"},{name:"北投区",code:"710112"}]},{name:"高雄市",code:"710200",sub:[{name:"盐埕区",code:"710201"},{name:"鼓山区",code:"710202"},{name:"左营区",code:"710203"},{name:"楠梓区",code:"710204"},{name:"三民区",code:"710205"},{name:"新兴区",code:"710206"},{name:"前金区",code:"710207"},{name:"苓雅区",code:"710208"},{name:"前镇区",code:"710209"},{name:"旗津区",code:"710210"},{name:"小港区",code:"710211"},{name:"凤山区",code:"710212"},{name:"林园区",code:"710213"},{name:"大寮区",code:"710214"},{name:"大树区",code:"710215"},{name:"大社区",code:"710216"},{name:"仁武区",code:"710217"},{name:"鸟松区",code:"710218"},{name:"冈山区",code:"710219"},{name:"桥头区",code:"710220"},{name:"燕巢区",code:"710221"},{name:"田寮区",code:"710222"},{name:"阿莲区",code:"710223"},{name:"路竹区",code:"710224"},{name:"湖内区",code:"710225"},{name:"茄萣区",code:"710226"},{name:"永安区",code:"710227"},{name:"弥陀区",code:"710228"},{name:"梓官区",code:"710229"},{name:"旗山区",code:"710230"},{name:"美浓区",code:"710231"},{name:"六龟区",code:"710232"},{name:"甲仙区",code:"710233"},{name:"杉林区",code:"710234"},{name:"内门区",code:"710235"},{name:"茂林区",code:"710236"},{name:"桃源区",code:"710237"},{name:"那玛夏区",code:"710238"}]},{name:"基隆市",code:"710300",sub:[{name:"中正区",code:"710301"},{name:"七堵区",code:"710302"},{name:"暖暖区",code:"710303"},{name:"仁爱区",code:"710304"},{name:"中山区",code:"710305"},{name:"安乐区",code:"710306"},{name:"信义区",code:"710307"}]},{name:"台中市",code:"710400",sub:[{name:"中区",code:"710401"},{name:"东区",code:"710402"},{name:"南区",code:"710403"},{name:"西区",code:"710404"},{name:"北区",code:"710405"},{name:"西屯区",code:"710406"},{name:"南屯区",code:"710407"},{name:"北屯区",code:"710408"},{name:"丰原区",code:"710409"},{name:"东势区",code:"710410"},{name:"大甲区",code:"710411"},{name:"清水区",code:"710412"},{name:"沙鹿区",code:"710413"},{name:"梧栖区",code:"710414"},{name:"后里区",code:"710415"},{name:"神冈区",code:"710416"},{name:"潭子区",code:"710417"},{name:"大雅区",code:"710418"},{name:"新社区",code:"710419"},{name:"石冈区",code:"710420"},{name:"外埔区",code:"710421"},{name:"大安区",code:"710422"},{name:"乌日区",code:"710423"},{name:"大肚区",code:"710424"},{name:"龙井区",code:"710425"},{name:"雾峰区",code:"710426"},{name:"太平区",code:"710427"},{name:"大里区",code:"710428"},{name:"和平区",code:"710429"}]},{name:"台南市",code:"710500",sub:[{name:"东区",code:"710501"},{name:"南区",code:"710502"},{name:"北区",code:"710504"},{name:"安南区",code:"710506"},{name:"安平区",code:"710507"},{name:"中西区",code:"710508"},{name:"新营区",code:"710509"},{name:"盐水区",code:"710510"},{name:"白河区",code:"710511"},{name:"柳营区",code:"710512"},{name:"后壁区",code:"710513"},{name:"东山区",code:"710514"},{name:"麻豆区",code:"710515"},{name:"下营区",code:"710516"},{name:"六甲区",code:"710517"},{name:"官田区",code:"710518"},{name:"大内区",code:"710519"},{name:"佳里区",code:"710520"},{name:"学甲区",code:"710521"},{name:"西港区",code:"710522"},{name:"七股区",code:"710523"},{name:"将军区",code:"710524"},{name:"北门区",code:"710525"},{name:"新化区",code:"710526"},{name:"善化区",code:"710527"},{name:"新市区",code:"710528"},{name:"安定区",code:"710529"},{name:"山上区",code:"710530"},{name:"玉井区",code:"710531"},{name:"楠西区",code:"710532"},{name:"南化区",code:"710533"},{name:"左镇区",code:"710534"},{name:"仁德区",code:"710535"},{name:"归仁区",code:"710536"},{name:"关庙区",code:"710537"},{name:"龙崎区",code:"710538"},{name:"永康区",code:"710539"}]},{name:"新竹市",code:"710600",sub:[{name:"东区",code:"710601"},{name:"北区",code:"710602"},{name:"香山区",code:"710603"}]},{name:"嘉义市",code:"710700",sub:[{name:"东区",code:"710701"},{name:"西区",code:"710702"}]},{name:"新北市",code:"710800",sub:[{name:"板桥区",code:"710801"},{name:"三重区",code:"710802"},{name:"中和区",code:"710803"},{name:"永和区",code:"710804"},{name:"新庄区",code:"710805"},{name:"新店区",code:"710806"},{name:"树林区",code:"710807"},{name:"莺歌区",code:"710808"},{name:"三峡区",code:"710809"},{name:"淡水区",code:"710810"},{name:"汐止区",code:"710811"},{name:"瑞芳区",code:"710812"},{name:"土城区",code:"710813"},{name:"芦洲区",code:"710814"},{name:"五股区",code:"710815"},{name:"泰山区",code:"710816"},{name:"林口区",code:"710817"},{name:"深坑区",code:"710818"},{name:"石碇区",code:"710819"},{name:"坪林区",code:"710820"},{name:"三芝区",code:"710821"},{name:"石门区",code:"710822"},{name:"八里区",code:"710823"},{name:"平溪区",code:"710824"},{name:"双溪区",code:"710825"},{name:"贡寮区",code:"710826"},{name:"金山区",code:"710827"},{name:"万里区",code:"710828"},{name:"乌来区",code:"710829"}]},{name:"宜兰县",code:"712200",sub:[{name:"宜兰市",code:"712201"},{name:"罗东镇",code:"712221"},{name:"苏澳镇",code:"712222"},{name:"头城镇",code:"712223"},{name:"礁溪乡",code:"712224"},{name:"壮围乡",code:"712225"},{name:"员山乡",code:"712226"},{name:"冬山乡",code:"712227"},{name:"五结乡",code:"712228"},{name:"三星乡",code:"712229"},{name:"大同乡",code:"712230"},{name:"南澳乡",code:"712231"}]},{name:"桃园县",code:"712300",sub:[{name:"桃园市",code:"712301"},{name:"中坜市",code:"712302"},{name:"平镇市",code:"712303"},{name:"八德市",code:"712304"},{name:"杨梅市",code:"712305"},{name:"大溪镇",code:"712321"},{name:"芦竹乡",code:"712323"},{name:"大园乡",code:"712324"},{name:"龟山乡",code:"712325"},{name:"龙潭乡",code:"712327"},{name:"新屋乡",code:"712329"},{name:"观音乡",code:"712330"},{name:"复兴乡",code:"712331"}]},{name:"新竹县",code:"712400",sub:[{name:"竹北市",code:"712401"},{name:"竹东镇",code:"712421"},{name:"新埔镇",code:"712422"},{name:"关西镇",code:"712423"},{name:"湖口乡",code:"712424"},{name:"新丰乡",code:"712425"},{name:"芎林乡",code:"712426"},{name:"橫山乡",code:"712427"},{name:"北埔乡",code:"712428"},{name:"宝山乡",code:"712429"},{name:"峨眉乡",code:"712430"},{name:"尖石乡",code:"712431"},{name:"五峰乡",code:"712432"}]},{name:"苗栗县",code:"712500",sub:[{name:"苗栗市",code:"712501"},{name:"苑里镇",code:"712521"},{name:"通霄镇",code:"712522"},{name:"竹南镇",code:"712523"},{name:"头份镇",code:"712524"},{name:"后龙镇",code:"712525"},{name:"卓兰镇",code:"712526"},{name:"大湖乡",code:"712527"},{name:"公馆乡",code:"712528"},{name:"铜锣乡",code:"712529"},{name:"南庄乡",code:"712530"},{name:"头屋乡",code:"712531"},{name:"三义乡",code:"712532"},{name:"西湖乡",code:"712533"},{name:"造桥乡",code:"712534"},{name:"三湾乡",code:"712535"},{name:"狮潭乡",code:"712536"},{name:"泰安乡",code:"712537"}]},{name:"彰化县",code:"712700",sub:[{name:"彰化市",code:"712701"},{name:"鹿港镇",code:"712721"},{name:"和美镇",code:"712722"},{name:"线西乡",code:"712723"},{name:"伸港乡",code:"712724"},{name:"福兴乡",code:"712725"},{name:"秀水乡",code:"712726"},{name:"花坛乡",code:"712727"},{name:"芬园乡",code:"712728"},{name:"员林镇",code:"712729"},{name:"溪湖镇",code:"712730"},{name:"田中镇",code:"712731"},{name:"大村乡",code:"712732"},{name:"埔盐乡",code:"712733"},{name:"埔心乡",code:"712734"},{name:"永靖乡",code:"712735"},{name:"社头乡",code:"712736"},{name:"二水乡",code:"712737"},{name:"北斗镇",code:"712738"},{name:"二林镇",code:"712739"},{name:"田尾乡",code:"712740"},{name:"埤头乡",code:"712741"},{name:"芳苑乡",code:"712742"},{name:"大城乡",code:"712743"},{name:"竹塘乡",code:"712744"},{name:"溪州乡",code:"712745"}]},{name:"南投县",code:"712800",sub:[{name:"南投市",code:"712801"},{name:"埔里镇",code:"712821"},{name:"草屯镇",code:"712822"},{name:"竹山镇",code:"712823"},{name:"集集镇",code:"712824"},{name:"名间乡",code:"712825"},{name:"鹿谷乡",code:"712826"},{name:"中寮乡",code:"712827"},{name:"鱼池乡",code:"712828"},{name:"国姓乡",code:"712829"},{name:"水里乡",code:"712830"},{name:"信义乡",code:"712831"},{name:"仁爱乡",code:"712832"}]},{name:"云林县",code:"712900",sub:[{name:"斗六市",code:"712901"},{name:"斗南镇",code:"712921"},{name:"虎尾镇",code:"712922"},{name:"西螺镇",code:"712923"},{name:"土库镇",code:"712924"},{name:"北港镇",code:"712925"},{name:"古坑乡",code:"712926"},{name:"大埤乡",code:"712927"},{name:"莿桐乡",code:"712928"},{name:"林内乡",code:"712929"},{name:"二仑乡",code:"712930"},{name:"仑背乡",code:"712931"},{name:"麦寮乡",code:"712932"},{name:"东势乡",code:"712933"},{name:"褒忠乡",code:"712934"},{name:"台西乡",code:"712935"},{name:"元长乡",code:"712936"},{name:"四湖乡",code:"712937"},{name:"口湖乡",code:"712938"},{name:"水林乡",code:"712939"}]},{name:"嘉义县",code:"713000",sub:[{name:"太保市",code:"713001"},{name:"朴子市",code:"713002"},{name:"布袋镇",code:"713023"},{name:"大林镇",code:"713024"},{name:"民雄乡",code:"713025"},{name:"溪口乡",code:"713026"},{name:"新港乡",code:"713027"},{name:"六脚乡",code:"713028"},{name:"东石乡",code:"713029"},{name:"义竹乡",code:"713030"},{name:"鹿草乡",code:"713031"},{name:"水上乡",code:"713032"},{name:"中埔乡",code:"713033"},{name:"竹崎乡",code:"713034"},{name:"梅山乡",code:"713035"},{name:"番路乡",code:"713036"},{name:"大埔乡",code:"713037"},{name:"阿里山乡",code:"713038"}]},{name:"屏东县",code:"713300",sub:[{name:"屏东市",code:"713301"},{name:"潮州镇",code:"713321"},{name:"东港镇",code:"713322"},{name:"恒春镇",code:"713323"},{name:"万丹乡",code:"713324"},{name:"长治乡",code:"713325"},{name:"麟洛乡",code:"713326"},{name:"九如乡",code:"713327"},{name:"里港乡",code:"713328"},{name:"盐埔乡",code:"713329"},{name:"高树乡",code:"713330"},{name:"万峦乡",code:"713331"},{name:"内埔乡",code:"713332"},{name:"竹田乡",code:"713333"},{name:"新埤乡",code:"713334"},{name:"枋寮乡",code:"713335"},{name:"新园乡",code:"713336"},{name:"崁顶乡",code:"713337"},{name:"林边乡",code:"713338"},{name:"南州乡",code:"713339"},{name:"佳冬乡",code:"713340"},{name:"琉球乡",code:"713341"},{name:"车城乡",code:"713342"},{name:"满州乡",code:"713343"},{name:"枋山乡",code:"713344"},{name:"三地门乡",code:"713345"},{name:"雾台乡",code:"713346"},{name:"玛家乡",code:"713347"},{name:"泰武乡",code:"713348"},{name:"来义乡",code:"713349"},{name:"春日乡",code:"713350"},{name:"狮子乡",code:"713351"},{name:"牡丹乡",code:"713352"}]},{name:"台东县",code:"713400",sub:[{name:"台东市",code:"713401"},{name:"成功镇",code:"713421"},{name:"关山镇",code:"713422"},{name:"卑南乡",code:"713423"},{name:"鹿野乡",code:"713424"},{name:"池上乡",code:"713425"},{name:"东河乡",code:"713426"},{name:"长滨乡",code:"713427"},{name:"太麻里乡",code:"713428"},{name:"大武乡",code:"713429"},{name:"绿岛乡",code:"713430"},{name:"海端乡",code:"713431"},{name:"延平乡",code:"713432"},{name:"金峰乡",code:"713433"},{name:"达仁乡",code:"713434"},{name:"兰屿乡",code:"713435"}]},{name:"花莲县",code:"713500",sub:[{name:"花莲市",code:"713501"},{name:"凤林镇",code:"713521"},{name:"玉里镇",code:"713522"},{name:"新城乡",code:"713523"},{name:"吉安乡",code:"713524"},{name:"寿丰乡",code:"713525"},{name:"光复乡",code:"713526"},{name:"丰滨乡",code:"713527"},{name:"瑞穗乡",code:"713528"},{name:"富里乡",code:"713529"},{name:"秀林乡",code:"713530"},{name:"万荣乡",code:"713531"},{name:"卓溪乡",code:"713532"}]},{name:"澎湖县",code:"713600",sub:[{name:"马公市",code:"713601"},{name:"湖西乡",code:"713621"},{name:"白沙乡",code:"713622"},{name:"西屿乡",code:"713623"},{name:"望安乡",code:"713624"},{name:"七美乡",code:"713625"}]}]},{name:"香港特别行政区",code:"810000",sub:[{name:"香港岛",code:"810100",sub:[{name:"中西区",code:"810101"},{name:"湾仔区",code:"810102"},{name:"东区",code:"810103"},{name:"南区",code:"810104"}]},{name:"九龙",code:"810200",sub:[{name:"油尖旺区",code:"810201"},{name:"深水埗区",code:"810202"},{name:"九龙城区",code:"810203"},{name:"黄大仙区",code:"810204"},{name:"观塘区",code:"810205"}]},{name:"新界",code:"810300",sub:[{name:"荃湾区",code:"810301"},{name:"屯门区",code:"810302"},{name:"元朗区",code:"810303"},{name:"北区",code:"810304"},{name:"大埔区",code:"810305"},{name:"西贡区",code:"810306"},{name:"沙田区",code:"810307"},{name:"葵青区",code:"810308"},{name:"离岛区",code:"810309"}]}]},{name:"澳门特别行政区",code:"820000",sub:[{name:"澳门半岛",code:"820100",sub:[{name:"花地玛堂区",code:"820101"},{name:"圣安多尼堂区",code:"820102"},{name:"大堂区",code:"820103"},{name:"望德堂区",code:"820104"},{name:"风顺堂区",code:"820105"}]},{name:"氹仔岛",code:"820200",sub:[{name:"嘉模堂区",code:"820201"}]},{name:"路环岛",code:"820300",sub:[{name:"圣方济各堂区",code:"820301"}]}]}]}($),+function(e){"use strict";var n,a=e.rawCitiesData,c=function(e){for(var n=[],a=0;a<e.length;a++){var c=e[a];/^请选择|市辖区/.test(c.name)||n.push(c)}return n.length?n:[]},o=function(e){return e.sub?c(e.sub):[{name:"",code:e.code}]},m=function(e){for(var n=0;n<a.length;n++)if(a[n].code===e||a[n].name===e)return o(a[n]);return[]},d=function(e,n){for(var c=0;c<a.length;c++)if(a[c].code===e||a[c].name===e)for(var m=0;m<a[c].sub.length;m++)if(a[c].sub[m].code===n||a[c].sub[m].name===n)return o(a[c].sub[m])},u=function(e){var n,c,o=a[0],m=e.split(" ");return a.map(function(e){e.name===m[0]&&(o=e)}),o.sub.map(function(e){e.name===m[1]&&(n=e)}),m[2]&&n.sub.map(function(e){e.name===m[2]&&(c=e)}),c?[o.code,n.code,c.code]:[o.code,n.code]};e.fn.cityPicker=function(c){return c=e.extend({},n,c),this.each(function(){var n=this,s=a.map(function(e){return e.name}),b=a.map(function(e){return e.code}),t=o(a[0]),r=t.map(function(e){return e.name}),i=t.map(function(e){return e.code}),l=o(a[0].sub[0]),f=l.map(function(e){return e.name}),p=l.map(function(e){return e.code}),v=s[0],h=r[0],V=f[0],y=[{displayValues:s,values:b,cssClass:"col-province"},{displayValues:r,values:i,cssClass:"col-city"}];c.showDistrict&&y.push({values:p,displayValues:f,cssClass:"col-district"});var g={cssClass:"city-picker",rotateEffect:!1,formatValue:function(e,n,a){return a.join(" ")},onChange:function(a,o,u){var s,b=a.cols[0].displayValue;if(b!==v){var t=m(b);s=t[0].name;var r=d(b,s);return a.cols[1].replaceValues(t.map(function(e){return e.code}),t.map(function(e){return e.name})),c.showDistrict&&a.cols[2].replaceValues(r.map(function(e){return e.code}),r.map(function(e){return e.name})),v=b,h=s,a.updateValue(),!1}if(c.showDistrict&&(s=a.cols[1].displayValue,s!==h)){var i=d(b,s);return a.cols[2].replaceValues(i.map(function(e){return e.code}),i.map(function(e){return e.name})),h=s,a.updateValue(),!1}var l=o[o.length-1]?o.length-1:o.length-2;e(n).attr("data-code",o[l]),e(n).attr("data-codes",o.join(",")),c.onChange&&c.onChange.call(n,a,o,u)},cols:y};if(this){var C=e.extend({},c,g),w=e(this).val();if(w||(w="北京 北京市 东城区"),v=w.split(" ")[0],h=w.split(" ")[1],V=w.split(" ")[2],w){if(C.value=u(w),C.value[0]){var D=m(C.value[0]);C.cols[1].values=D.map(function(e){return e.code}),C.cols[1].displayValues=D.map(function(e){return e.name})}if(C.value[1]){if(c.showDistrict){var k=d(C.value[0],C.value[1]);C.cols[2].values=k.map(function(e){return e.code}),C.cols[2].displayValues=k.map(function(e){return e.name})}}else if(c.showDistrict){var k=d(C.value[0],C.cols[1].values[0]);C.cols[2].values=k.map(function(e){return e.code}),C.cols[2].displayValues=k.map(function(e){return e.name})}}e(this).picker(C)}})},n=e.fn.cityPicker.prototype.defaults={showDistrict:!0}}($);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/jquery-2.1.4.js b/platforms/android/app/src/main/assets/www/js/lib/jquery-2.1.4.js
new file mode 100644
index 0000000..eed1777
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/jquery-2.1.4.js
@@ -0,0 +1,9210 @@
+/*!
+ * jQuery JavaScript Library v2.1.4
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2015-04-28T16:01Z
+ */
+
+(function( global, factory ) {
+
+	if ( typeof module === "object" && typeof module.exports === "object" ) {
+		// For CommonJS and CommonJS-like environments where a proper `window`
+		// is present, execute the factory and get jQuery.
+		// For environments that do not have a `window` with a `document`
+		// (such as Node.js), expose a factory as module.exports.
+		// This accentuates the need for the creation of a real `window`.
+		// e.g. var jQuery = require("jquery")(window);
+		// See ticket #14549 for more info.
+		module.exports = global.document ?
+			factory( global, true ) :
+			function( w ) {
+				if ( !w.document ) {
+					throw new Error( "jQuery requires a window with a document" );
+				}
+				return factory( w );
+			};
+	} else {
+		factory( global );
+	}
+
+// Pass this if window is not defined yet
+}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+
+// Support: Firefox 18+
+// Can't be in strict mode, several libs including ASP.NET trace
+// the stack via arguments.caller.callee and Firefox dies if
+// you try to trace through "use strict" call chains. (#13335)
+//
+
+var arr = [];
+
+var slice = arr.slice;
+
+var concat = arr.concat;
+
+var push = arr.push;
+
+var indexOf = arr.indexOf;
+
+var class2type = {};
+
+var toString = class2type.toString;
+
+var hasOwn = class2type.hasOwnProperty;
+
+var support = {};
+
+
+
+var
+	// Use the correct document accordingly with window argument (sandbox)
+	document = window.document,
+
+	version = "2.1.4",
+
+	// Define a local copy of jQuery
+	jQuery = function( selector, context ) {
+		// The jQuery object is actually just the init constructor 'enhanced'
+		// Need init if jQuery is called (just allow error to be thrown if not included)
+		return new jQuery.fn.init( selector, context );
+	},
+
+	// Support: Android<4.1
+	// Make sure we trim BOM and NBSP
+	rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+	// Matches dashed string for camelizing
+	rmsPrefix = /^-ms-/,
+	rdashAlpha = /-([\da-z])/gi,
+
+	// Used by jQuery.camelCase as callback to replace()
+	fcamelCase = function( all, letter ) {
+		return letter.toUpperCase();
+	};
+
+jQuery.fn = jQuery.prototype = {
+	// The current version of jQuery being used
+	jquery: version,
+
+	constructor: jQuery,
+
+	// Start with an empty selector
+	selector: "",
+
+	// The default length of a jQuery object is 0
+	length: 0,
+
+	toArray: function() {
+		return slice.call( this );
+	},
+
+	// Get the Nth element in the matched element set OR
+	// Get the whole matched element set as a clean array
+	get: function( num ) {
+		return num != null ?
+
+			// Return just the one element from the set
+			( num < 0 ? this[ num + this.length ] : this[ num ] ) :
+
+			// Return all the elements in a clean array
+			slice.call( this );
+	},
+
+	// Take an array of elements and push it onto the stack
+	// (returning the new matched element set)
+	pushStack: function( elems ) {
+
+		// Build a new jQuery matched element set
+		var ret = jQuery.merge( this.constructor(), elems );
+
+		// Add the old object onto the stack (as a reference)
+		ret.prevObject = this;
+		ret.context = this.context;
+
+		// Return the newly-formed element set
+		return ret;
+	},
+
+	// Execute a callback for every element in the matched set.
+	// (You can seed the arguments with an array of args, but this is
+	// only used internally.)
+	each: function( callback, args ) {
+		return jQuery.each( this, callback, args );
+	},
+
+	map: function( callback ) {
+		return this.pushStack( jQuery.map(this, function( elem, i ) {
+			return callback.call( elem, i, elem );
+		}));
+	},
+
+	slice: function() {
+		return this.pushStack( slice.apply( this, arguments ) );
+	},
+
+	first: function() {
+		return this.eq( 0 );
+	},
+
+	last: function() {
+		return this.eq( -1 );
+	},
+
+	eq: function( i ) {
+		var len = this.length,
+			j = +i + ( i < 0 ? len : 0 );
+		return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
+	},
+
+	end: function() {
+		return this.prevObject || this.constructor(null);
+	},
+
+	// For internal use only.
+	// Behaves like an Array's method, not like a jQuery method.
+	push: push,
+	sort: arr.sort,
+	splice: arr.splice
+};
+
+jQuery.extend = jQuery.fn.extend = function() {
+	var options, name, src, copy, copyIsArray, clone,
+		target = arguments[0] || {},
+		i = 1,
+		length = arguments.length,
+		deep = false;
+
+	// Handle a deep copy situation
+	if ( typeof target === "boolean" ) {
+		deep = target;
+
+		// Skip the boolean and the target
+		target = arguments[ i ] || {};
+		i++;
+	}
+
+	// Handle case when target is a string or something (possible in deep copy)
+	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+		target = {};
+	}
+
+	// Extend jQuery itself if only one argument is passed
+	if ( i === length ) {
+		target = this;
+		i--;
+	}
+
+	for ( ; i < length; i++ ) {
+		// Only deal with non-null/undefined values
+		if ( (options = arguments[ i ]) != null ) {
+			// Extend the base object
+			for ( name in options ) {
+				src = target[ name ];
+				copy = options[ name ];
+
+				// Prevent never-ending loop
+				if ( target === copy ) {
+					continue;
+				}
+
+				// Recurse if we're merging plain objects or arrays
+				if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+					if ( copyIsArray ) {
+						copyIsArray = false;
+						clone = src && jQuery.isArray(src) ? src : [];
+
+					} else {
+						clone = src && jQuery.isPlainObject(src) ? src : {};
+					}
+
+					// Never move original objects, clone them
+					target[ name ] = jQuery.extend( deep, clone, copy );
+
+				// Don't bring in undefined values
+				} else if ( copy !== undefined ) {
+					target[ name ] = copy;
+				}
+			}
+		}
+	}
+
+	// Return the modified object
+	return target;
+};
+
+jQuery.extend({
+	// Unique for each copy of jQuery on the page
+	expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
+
+	// Assume jQuery is ready without the ready module
+	isReady: true,
+
+	error: function( msg ) {
+		throw new Error( msg );
+	},
+
+	noop: function() {},
+
+	isFunction: function( obj ) {
+		return jQuery.type(obj) === "function";
+	},
+
+	isArray: Array.isArray,
+
+	isWindow: function( obj ) {
+		return obj != null && obj === obj.window;
+	},
+
+	isNumeric: function( obj ) {
+		// parseFloat NaNs numeric-cast false positives (null|true|false|"")
+		// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+		// subtraction forces infinities to NaN
+		// adding 1 corrects loss of precision from parseFloat (#15100)
+		return !jQuery.isArray( obj ) && (obj - parseFloat( obj ) + 1) >= 0;
+	},
+
+	isPlainObject: function( obj ) {
+		// Not plain objects:
+		// - Any object or value whose internal [[Class]] property is not "[object Object]"
+		// - DOM nodes
+		// - window
+		if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+			return false;
+		}
+
+		if ( obj.constructor &&
+				!hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
+			return false;
+		}
+
+		// If the function hasn't returned already, we're confident that
+		// |obj| is a plain object, created by {} or constructed with new Object
+		return true;
+	},
+
+	isEmptyObject: function( obj ) {
+		var name;
+		for ( name in obj ) {
+			return false;
+		}
+		return true;
+	},
+
+	type: function( obj ) {
+		if ( obj == null ) {
+			return obj + "";
+		}
+		// Support: Android<4.0, iOS<6 (functionish RegExp)
+		return typeof obj === "object" || typeof obj === "function" ?
+			class2type[ toString.call(obj) ] || "object" :
+			typeof obj;
+	},
+
+	// Evaluates a script in a global context
+	globalEval: function( code ) {
+		var script,
+			indirect = eval;
+
+		code = jQuery.trim( code );
+
+		if ( code ) {
+			// If the code includes a valid, prologue position
+			// strict mode pragma, execute code by injecting a
+			// script tag into the document.
+			if ( code.indexOf("use strict") === 1 ) {
+				script = document.createElement("script");
+				script.text = code;
+				document.head.appendChild( script ).parentNode.removeChild( script );
+			} else {
+			// Otherwise, avoid the DOM node creation, insertion
+			// and removal by using an indirect global eval
+				indirect( code );
+			}
+		}
+	},
+
+	// Convert dashed to camelCase; used by the css and data modules
+	// Support: IE9-11+
+	// Microsoft forgot to hump their vendor prefix (#9572)
+	camelCase: function( string ) {
+		return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+	},
+
+	nodeName: function( elem, name ) {
+		return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+	},
+
+	// args is for internal usage only
+	each: function( obj, callback, args ) {
+		var value,
+			i = 0,
+			length = obj.length,
+			isArray = isArraylike( obj );
+
+		if ( args ) {
+			if ( isArray ) {
+				for ( ; i < length; i++ ) {
+					value = callback.apply( obj[ i ], args );
+
+					if ( value === false ) {
+						break;
+					}
+				}
+			} else {
+				for ( i in obj ) {
+					value = callback.apply( obj[ i ], args );
+
+					if ( value === false ) {
+						break;
+					}
+				}
+			}
+
+		// A special, fast, case for the most common use of each
+		} else {
+			if ( isArray ) {
+				for ( ; i < length; i++ ) {
+					value = callback.call( obj[ i ], i, obj[ i ] );
+
+					if ( value === false ) {
+						break;
+					}
+				}
+			} else {
+				for ( i in obj ) {
+					value = callback.call( obj[ i ], i, obj[ i ] );
+
+					if ( value === false ) {
+						break;
+					}
+				}
+			}
+		}
+
+		return obj;
+	},
+
+	// Support: Android<4.1
+	trim: function( text ) {
+		return text == null ?
+			"" :
+			( text + "" ).replace( rtrim, "" );
+	},
+
+	// results is for internal usage only
+	makeArray: function( arr, results ) {
+		var ret = results || [];
+
+		if ( arr != null ) {
+			if ( isArraylike( Object(arr) ) ) {
+				jQuery.merge( ret,
+					typeof arr === "string" ?
+					[ arr ] : arr
+				);
+			} else {
+				push.call( ret, arr );
+			}
+		}
+
+		return ret;
+	},
+
+	inArray: function( elem, arr, i ) {
+		return arr == null ? -1 : indexOf.call( arr, elem, i );
+	},
+
+	merge: function( first, second ) {
+		var len = +second.length,
+			j = 0,
+			i = first.length;
+
+		for ( ; j < len; j++ ) {
+			first[ i++ ] = second[ j ];
+		}
+
+		first.length = i;
+
+		return first;
+	},
+
+	grep: function( elems, callback, invert ) {
+		var callbackInverse,
+			matches = [],
+			i = 0,
+			length = elems.length,
+			callbackExpect = !invert;
+
+		// Go through the array, only saving the items
+		// that pass the validator function
+		for ( ; i < length; i++ ) {
+			callbackInverse = !callback( elems[ i ], i );
+			if ( callbackInverse !== callbackExpect ) {
+				matches.push( elems[ i ] );
+			}
+		}
+
+		return matches;
+	},
+
+	// arg is for internal usage only
+	map: function( elems, callback, arg ) {
+		var value,
+			i = 0,
+			length = elems.length,
+			isArray = isArraylike( elems ),
+			ret = [];
+
+		// Go through the array, translating each of the items to their new values
+		if ( isArray ) {
+			for ( ; i < length; i++ ) {
+				value = callback( elems[ i ], i, arg );
+
+				if ( value != null ) {
+					ret.push( value );
+				}
+			}
+
+		// Go through every key on the object,
+		} else {
+			for ( i in elems ) {
+				value = callback( elems[ i ], i, arg );
+
+				if ( value != null ) {
+					ret.push( value );
+				}
+			}
+		}
+
+		// Flatten any nested arrays
+		return concat.apply( [], ret );
+	},
+
+	// A global GUID counter for objects
+	guid: 1,
+
+	// Bind a function to a context, optionally partially applying any
+	// arguments.
+	proxy: function( fn, context ) {
+		var tmp, args, proxy;
+
+		if ( typeof context === "string" ) {
+			tmp = fn[ context ];
+			context = fn;
+			fn = tmp;
+		}
+
+		// Quick check to determine if target is callable, in the spec
+		// this throws a TypeError, but we will just return undefined.
+		if ( !jQuery.isFunction( fn ) ) {
+			return undefined;
+		}
+
+		// Simulated bind
+		args = slice.call( arguments, 2 );
+		proxy = function() {
+			return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
+		};
+
+		// Set the guid of unique handler to the same of original handler, so it can be removed
+		proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+		return proxy;
+	},
+
+	now: Date.now,
+
+	// jQuery.support is not used in Core but other projects attach their
+	// properties to it so it needs to exist.
+	support: support
+});
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
+	class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+function isArraylike( obj ) {
+
+	// Support: iOS 8.2 (not reproducible in simulator)
+	// `in` check used to prevent JIT error (gh-2145)
+	// hasOwn isn't used here due to false negatives
+	// regarding Nodelist length in IE
+	var length = "length" in obj && obj.length,
+		type = jQuery.type( obj );
+
+	if ( type === "function" || jQuery.isWindow( obj ) ) {
+		return false;
+	}
+
+	if ( obj.nodeType === 1 && length ) {
+		return true;
+	}
+
+	return type === "array" || length === 0 ||
+		typeof length === "number" && length > 0 && ( length - 1 ) in obj;
+}
+var Sizzle =
+/*!
+ * Sizzle CSS Selector Engine v2.2.0-pre
+ * http://sizzlejs.com/
+ *
+ * Copyright 2008, 2014 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2014-12-16
+ */
+(function( window ) {
+
+var i,
+	support,
+	Expr,
+	getText,
+	isXML,
+	tokenize,
+	compile,
+	select,
+	outermostContext,
+	sortInput,
+	hasDuplicate,
+
+	// Local document vars
+	setDocument,
+	document,
+	docElem,
+	documentIsHTML,
+	rbuggyQSA,
+	rbuggyMatches,
+	matches,
+	contains,
+
+	// Instance-specific data
+	expando = "sizzle" + 1 * new Date(),
+	preferredDoc = window.document,
+	dirruns = 0,
+	done = 0,
+	classCache = createCache(),
+	tokenCache = createCache(),
+	compilerCache = createCache(),
+	sortOrder = function( a, b ) {
+		if ( a === b ) {
+			hasDuplicate = true;
+		}
+		return 0;
+	},
+
+	// General-purpose constants
+	MAX_NEGATIVE = 1 << 31,
+
+	// Instance methods
+	hasOwn = ({}).hasOwnProperty,
+	arr = [],
+	pop = arr.pop,
+	push_native = arr.push,
+	push = arr.push,
+	slice = arr.slice,
+	// Use a stripped-down indexOf as it's faster than native
+	// http://jsperf.com/thor-indexof-vs-for/5
+	indexOf = function( list, elem ) {
+		var i = 0,
+			len = list.length;
+		for ( ; i < len; i++ ) {
+			if ( list[i] === elem ) {
+				return i;
+			}
+		}
+		return -1;
+	},
+
+	booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
+
+	// Regular expressions
+
+	// Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+	whitespace = "[\\x20\\t\\r\\n\\f]",
+	// http://www.w3.org/TR/css3-syntax/#characters
+	characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+	// Loosely modeled on CSS identifier characters
+	// An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
+	// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+	identifier = characterEncoding.replace( "w", "w#" ),
+
+	// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
+	attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
+		// Operator (capture 2)
+		"*([*^$|!~]?=)" + whitespace +
+		// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
+		"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
+		"*\\]",
+
+	pseudos = ":(" + characterEncoding + ")(?:\\((" +
+		// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
+		// 1. quoted (capture 3; capture 4 or capture 5)
+		"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
+		// 2. simple (capture 6)
+		"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
+		// 3. anything else (capture 2)
+		".*" +
+		")\\)|)",
+
+	// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+	rwhitespace = new RegExp( whitespace + "+", "g" ),
+	rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+	rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+	rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
+
+	rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
+
+	rpseudo = new RegExp( pseudos ),
+	ridentifier = new RegExp( "^" + identifier + "$" ),
+
+	matchExpr = {
+		"ID": new RegExp( "^#(" + characterEncoding + ")" ),
+		"CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+		"TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+		"ATTR": new RegExp( "^" + attributes ),
+		"PSEUDO": new RegExp( "^" + pseudos ),
+		"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
+			"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+			"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+		"bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+		// For use in libraries implementing .is()
+		// We use this for POS matching in `select`
+		"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
+			whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+	},
+
+	rinputs = /^(?:input|select|textarea|button)$/i,
+	rheader = /^h\d$/i,
+
+	rnative = /^[^{]+\{\s*\[native \w/,
+
+	// Easily-parseable/retrievable ID or TAG or CLASS selectors
+	rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+	rsibling = /[+~]/,
+	rescape = /'|\\/g,
+
+	// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+	runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
+	funescape = function( _, escaped, escapedWhitespace ) {
+		var high = "0x" + escaped - 0x10000;
+		// NaN means non-codepoint
+		// Support: Firefox<24
+		// Workaround erroneous numeric interpretation of +"0x"
+		return high !== high || escapedWhitespace ?
+			escaped :
+			high < 0 ?
+				// BMP codepoint
+				String.fromCharCode( high + 0x10000 ) :
+				// Supplemental Plane codepoint (surrogate pair)
+				String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+	},
+
+	// Used for iframes
+	// See setDocument()
+	// Removing the function wrapper causes a "Permission Denied"
+	// error in IE
+	unloadHandler = function() {
+		setDocument();
+	};
+
+// Optimize for push.apply( _, NodeList )
+try {
+	push.apply(
+		(arr = slice.call( preferredDoc.childNodes )),
+		preferredDoc.childNodes
+	);
+	// Support: Android<4.0
+	// Detect silently failing push.apply
+	arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+	push = { apply: arr.length ?
+
+		// Leverage slice if possible
+		function( target, els ) {
+			push_native.apply( target, slice.call(els) );
+		} :
+
+		// Support: IE<9
+		// Otherwise append directly
+		function( target, els ) {
+			var j = target.length,
+				i = 0;
+			// Can't trust NodeList.length
+			while ( (target[j++] = els[i++]) ) {}
+			target.length = j - 1;
+		}
+	};
+}
+
+function Sizzle( selector, context, results, seed ) {
+	var match, elem, m, nodeType,
+		// QSA vars
+		i, groups, old, nid, newContext, newSelector;
+
+	if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+		setDocument( context );
+	}
+
+	context = context || document;
+	results = results || [];
+	nodeType = context.nodeType;
+
+	if ( typeof selector !== "string" || !selector ||
+		nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
+
+		return results;
+	}
+
+	if ( !seed && documentIsHTML ) {
+
+		// Try to shortcut find operations when possible (e.g., not under DocumentFragment)
+		if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
+			// Speed-up: Sizzle("#ID")
+			if ( (m = match[1]) ) {
+				if ( nodeType === 9 ) {
+					elem = context.getElementById( m );
+					// Check parentNode to catch when Blackberry 4.6 returns
+					// nodes that are no longer in the document (jQuery #6963)
+					if ( elem && elem.parentNode ) {
+						// Handle the case where IE, Opera, and Webkit return items
+						// by name instead of ID
+						if ( elem.id === m ) {
+							results.push( elem );
+							return results;
+						}
+					} else {
+						return results;
+					}
+				} else {
+					// Context is not a document
+					if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+						contains( context, elem ) && elem.id === m ) {
+						results.push( elem );
+						return results;
+					}
+				}
+
+			// Speed-up: Sizzle("TAG")
+			} else if ( match[2] ) {
+				push.apply( results, context.getElementsByTagName( selector ) );
+				return results;
+
+			// Speed-up: Sizzle(".CLASS")
+			} else if ( (m = match[3]) && support.getElementsByClassName ) {
+				push.apply( results, context.getElementsByClassName( m ) );
+				return results;
+			}
+		}
+
+		// QSA path
+		if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
+			nid = old = expando;
+			newContext = context;
+			newSelector = nodeType !== 1 && selector;
+
+			// qSA works strangely on Element-rooted queries
+			// We can work around this by specifying an extra ID on the root
+			// and working up from there (Thanks to Andrew Dupont for the technique)
+			// IE 8 doesn't work on object elements
+			if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+				groups = tokenize( selector );
+
+				if ( (old = context.getAttribute("id")) ) {
+					nid = old.replace( rescape, "\\$&" );
+				} else {
+					context.setAttribute( "id", nid );
+				}
+				nid = "[id='" + nid + "'] ";
+
+				i = groups.length;
+				while ( i-- ) {
+					groups[i] = nid + toSelector( groups[i] );
+				}
+				newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
+				newSelector = groups.join(",");
+			}
+
+			if ( newSelector ) {
+				try {
+					push.apply( results,
+						newContext.querySelectorAll( newSelector )
+					);
+					return results;
+				} catch(qsaError) {
+				} finally {
+					if ( !old ) {
+						context.removeAttribute("id");
+					}
+				}
+			}
+		}
+	}
+
+	// All others
+	return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
+ *	property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ *	deleting the oldest entry
+ */
+function createCache() {
+	var keys = [];
+
+	function cache( key, value ) {
+		// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+		if ( keys.push( key + " " ) > Expr.cacheLength ) {
+			// Only keep the most recent entries
+			delete cache[ keys.shift() ];
+		}
+		return (cache[ key + " " ] = value);
+	}
+	return cache;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+	fn[ expando ] = true;
+	return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created div and expects a boolean result
+ */
+function assert( fn ) {
+	var div = document.createElement("div");
+
+	try {
+		return !!fn( div );
+	} catch (e) {
+		return false;
+	} finally {
+		// Remove from its parent by default
+		if ( div.parentNode ) {
+			div.parentNode.removeChild( div );
+		}
+		// release memory in IE
+		div = null;
+	}
+}
+
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+function addHandle( attrs, handler ) {
+	var arr = attrs.split("|"),
+		i = attrs.length;
+
+	while ( i-- ) {
+		Expr.attrHandle[ arr[i] ] = handler;
+	}
+}
+
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+function siblingCheck( a, b ) {
+	var cur = b && a,
+		diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+			( ~b.sourceIndex || MAX_NEGATIVE ) -
+			( ~a.sourceIndex || MAX_NEGATIVE );
+
+	// Use IE sourceIndex if available on both nodes
+	if ( diff ) {
+		return diff;
+	}
+
+	// Check if b follows a
+	if ( cur ) {
+		while ( (cur = cur.nextSibling) ) {
+			if ( cur === b ) {
+				return -1;
+			}
+		}
+	}
+
+	return a ? 1 : -1;
+}
+
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+	return function( elem ) {
+		var name = elem.nodeName.toLowerCase();
+		return name === "input" && elem.type === type;
+	};
+}
+
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+	return function( elem ) {
+		var name = elem.nodeName.toLowerCase();
+		return (name === "input" || name === "button") && elem.type === type;
+	};
+}
+
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+	return markFunction(function( argument ) {
+		argument = +argument;
+		return markFunction(function( seed, matches ) {
+			var j,
+				matchIndexes = fn( [], seed.length, argument ),
+				i = matchIndexes.length;
+
+			// Match elements found at the specified indexes
+			while ( i-- ) {
+				if ( seed[ (j = matchIndexes[i]) ] ) {
+					seed[j] = !(matches[j] = seed[j]);
+				}
+			}
+		});
+	});
+}
+
+/**
+ * Checks a node for validity as a Sizzle context
+ * @param {Element|Object=} context
+ * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
+ */
+function testContext( context ) {
+	return context && typeof context.getElementsByTagName !== "undefined" && context;
+}
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * Detects XML nodes
+ * @param {Element|Object} elem An element or a document
+ * @returns {Boolean} True iff elem is a non-HTML XML node
+ */
+isXML = Sizzle.isXML = function( elem ) {
+	// documentElement is verified for cases where it doesn't yet exist
+	// (such as loading iframes in IE - #4833)
+	var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+	return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+	var hasCompare, parent,
+		doc = node ? node.ownerDocument || node : preferredDoc;
+
+	// If no document and documentElement is available, return
+	if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+		return document;
+	}
+
+	// Set our document
+	document = doc;
+	docElem = doc.documentElement;
+	parent = doc.defaultView;
+
+	// Support: IE>8
+	// If iframe document is assigned to "document" variable and if iframe has been reloaded,
+	// IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
+	// IE6-8 do not support the defaultView property so parent will be undefined
+	if ( parent && parent !== parent.top ) {
+		// IE11 does not have attachEvent, so all must suffer
+		if ( parent.addEventListener ) {
+			parent.addEventListener( "unload", unloadHandler, false );
+		} else if ( parent.attachEvent ) {
+			parent.attachEvent( "onunload", unloadHandler );
+		}
+	}
+
+	/* Support tests
+	---------------------------------------------------------------------- */
+	documentIsHTML = !isXML( doc );
+
+	/* Attributes
+	---------------------------------------------------------------------- */
+
+	// Support: IE<8
+	// Verify that getAttribute really returns attributes and not properties
+	// (excepting IE8 booleans)
+	support.attributes = assert(function( div ) {
+		div.className = "i";
+		return !div.getAttribute("className");
+	});
+
+	/* getElement(s)By*
+	---------------------------------------------------------------------- */
+
+	// Check if getElementsByTagName("*") returns only elements
+	support.getElementsByTagName = assert(function( div ) {
+		div.appendChild( doc.createComment("") );
+		return !div.getElementsByTagName("*").length;
+	});
+
+	// Support: IE<9
+	support.getElementsByClassName = rnative.test( doc.getElementsByClassName );
+
+	// Support: IE<10
+	// Check if getElementById returns elements by name
+	// The broken getElementById methods don't pick up programatically-set names,
+	// so use a roundabout getElementsByName test
+	support.getById = assert(function( div ) {
+		docElem.appendChild( div ).id = expando;
+		return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
+	});
+
+	// ID find and filter
+	if ( support.getById ) {
+		Expr.find["ID"] = function( id, context ) {
+			if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
+				var m = context.getElementById( id );
+				// Check parentNode to catch when Blackberry 4.6 returns
+				// nodes that are no longer in the document #6963
+				return m && m.parentNode ? [ m ] : [];
+			}
+		};
+		Expr.filter["ID"] = function( id ) {
+			var attrId = id.replace( runescape, funescape );
+			return function( elem ) {
+				return elem.getAttribute("id") === attrId;
+			};
+		};
+	} else {
+		// Support: IE6/7
+		// getElementById is not reliable as a find shortcut
+		delete Expr.find["ID"];
+
+		Expr.filter["ID"] =  function( id ) {
+			var attrId = id.replace( runescape, funescape );
+			return function( elem ) {
+				var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+				return node && node.value === attrId;
+			};
+		};
+	}
+
+	// Tag
+	Expr.find["TAG"] = support.getElementsByTagName ?
+		function( tag, context ) {
+			if ( typeof context.getElementsByTagName !== "undefined" ) {
+				return context.getElementsByTagName( tag );
+
+			// DocumentFragment nodes don't have gEBTN
+			} else if ( support.qsa ) {
+				return context.querySelectorAll( tag );
+			}
+		} :
+
+		function( tag, context ) {
+			var elem,
+				tmp = [],
+				i = 0,
+				// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
+				results = context.getElementsByTagName( tag );
+
+			// Filter out possible comments
+			if ( tag === "*" ) {
+				while ( (elem = results[i++]) ) {
+					if ( elem.nodeType === 1 ) {
+						tmp.push( elem );
+					}
+				}
+
+				return tmp;
+			}
+			return results;
+		};
+
+	// Class
+	Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
+		if ( documentIsHTML ) {
+			return context.getElementsByClassName( className );
+		}
+	};
+
+	/* QSA/matchesSelector
+	---------------------------------------------------------------------- */
+
+	// QSA and matchesSelector support
+
+	// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+	rbuggyMatches = [];
+
+	// qSa(:focus) reports false when true (Chrome 21)
+	// We allow this because of a bug in IE8/9 that throws an error
+	// whenever `document.activeElement` is accessed on an iframe
+	// So, we allow :focus to pass through QSA all the time to avoid the IE error
+	// See http://bugs.jquery.com/ticket/13378
+	rbuggyQSA = [];
+
+	if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
+		// Build QSA regex
+		// Regex strategy adopted from Diego Perini
+		assert(function( div ) {
+			// Select is set to empty string on purpose
+			// This is to test IE's treatment of not explicitly
+			// setting a boolean content attribute,
+			// since its presence should be enough
+			// http://bugs.jquery.com/ticket/12359
+			docElem.appendChild( div ).innerHTML = "<a id='" + expando + "'></a>" +
+				"<select id='" + expando + "-\f]' msallowcapture=''>" +
+				"<option selected=''></option></select>";
+
+			// Support: IE8, Opera 11-12.16
+			// Nothing should be selected when empty strings follow ^= or $= or *=
+			// The test attribute must be unknown in Opera but "safe" for WinRT
+			// http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
+			if ( div.querySelectorAll("[msallowcapture^='']").length ) {
+				rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+			}
+
+			// Support: IE8
+			// Boolean attributes and "value" are not treated correctly
+			if ( !div.querySelectorAll("[selected]").length ) {
+				rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+			}
+
+			// Support: Chrome<29, Android<4.2+, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.7+
+			if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
+				rbuggyQSA.push("~=");
+			}
+
+			// Webkit/Opera - :checked should return selected option elements
+			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+			// IE8 throws error here and will not see later tests
+			if ( !div.querySelectorAll(":checked").length ) {
+				rbuggyQSA.push(":checked");
+			}
+
+			// Support: Safari 8+, iOS 8+
+			// https://bugs.webkit.org/show_bug.cgi?id=136851
+			// In-page `selector#id sibing-combinator selector` fails
+			if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) {
+				rbuggyQSA.push(".#.+[+~]");
+			}
+		});
+
+		assert(function( div ) {
+			// Support: Windows 8 Native Apps
+			// The type and name attributes are restricted during .innerHTML assignment
+			var input = doc.createElement("input");
+			input.setAttribute( "type", "hidden" );
+			div.appendChild( input ).setAttribute( "name", "D" );
+
+			// Support: IE8
+			// Enforce case-sensitivity of name attribute
+			if ( div.querySelectorAll("[name=d]").length ) {
+				rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
+			}
+
+			// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+			// IE8 throws error here and will not see later tests
+			if ( !div.querySelectorAll(":enabled").length ) {
+				rbuggyQSA.push( ":enabled", ":disabled" );
+			}
+
+			// Opera 10-11 does not throw on post-comma invalid pseudos
+			div.querySelectorAll("*,:x");
+			rbuggyQSA.push(",.*:");
+		});
+	}
+
+	if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
+		docElem.webkitMatchesSelector ||
+		docElem.mozMatchesSelector ||
+		docElem.oMatchesSelector ||
+		docElem.msMatchesSelector) )) ) {
+
+		assert(function( div ) {
+			// Check to see if it's possible to do matchesSelector
+			// on a disconnected node (IE 9)
+			support.disconnectedMatch = matches.call( div, "div" );
+
+			// This should fail with an exception
+			// Gecko does not error, returns false instead
+			matches.call( div, "[s!='']:x" );
+			rbuggyMatches.push( "!=", pseudos );
+		});
+	}
+
+	rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
+	rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
+
+	/* Contains
+	---------------------------------------------------------------------- */
+	hasCompare = rnative.test( docElem.compareDocumentPosition );
+
+	// Element contains another
+	// Purposefully does not implement inclusive descendent
+	// As in, an element does not contain itself
+	contains = hasCompare || rnative.test( docElem.contains ) ?
+		function( a, b ) {
+			var adown = a.nodeType === 9 ? a.documentElement : a,
+				bup = b && b.parentNode;
+			return a === bup || !!( bup && bup.nodeType === 1 && (
+				adown.contains ?
+					adown.contains( bup ) :
+					a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+			));
+		} :
+		function( a, b ) {
+			if ( b ) {
+				while ( (b = b.parentNode) ) {
+					if ( b === a ) {
+						return true;
+					}
+				}
+			}
+			return false;
+		};
+
+	/* Sorting
+	---------------------------------------------------------------------- */
+
+	// Document order sorting
+	sortOrder = hasCompare ?
+	function( a, b ) {
+
+		// Flag for duplicate removal
+		if ( a === b ) {
+			hasDuplicate = true;
+			return 0;
+		}
+
+		// Sort on method existence if only one input has compareDocumentPosition
+		var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
+		if ( compare ) {
+			return compare;
+		}
+
+		// Calculate position if both inputs belong to the same document
+		compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
+			a.compareDocumentPosition( b ) :
+
+			// Otherwise we know they are disconnected
+			1;
+
+		// Disconnected nodes
+		if ( compare & 1 ||
+			(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
+
+			// Choose the first element that is related to our preferred document
+			if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
+				return -1;
+			}
+			if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
+				return 1;
+			}
+
+			// Maintain original order
+			return sortInput ?
+				( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+				0;
+		}
+
+		return compare & 4 ? -1 : 1;
+	} :
+	function( a, b ) {
+		// Exit early if the nodes are identical
+		if ( a === b ) {
+			hasDuplicate = true;
+			return 0;
+		}
+
+		var cur,
+			i = 0,
+			aup = a.parentNode,
+			bup = b.parentNode,
+			ap = [ a ],
+			bp = [ b ];
+
+		// Parentless nodes are either documents or disconnected
+		if ( !aup || !bup ) {
+			return a === doc ? -1 :
+				b === doc ? 1 :
+				aup ? -1 :
+				bup ? 1 :
+				sortInput ?
+				( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+				0;
+
+		// If the nodes are siblings, we can do a quick check
+		} else if ( aup === bup ) {
+			return siblingCheck( a, b );
+		}
+
+		// Otherwise we need full lists of their ancestors for comparison
+		cur = a;
+		while ( (cur = cur.parentNode) ) {
+			ap.unshift( cur );
+		}
+		cur = b;
+		while ( (cur = cur.parentNode) ) {
+			bp.unshift( cur );
+		}
+
+		// Walk down the tree looking for a discrepancy
+		while ( ap[i] === bp[i] ) {
+			i++;
+		}
+
+		return i ?
+			// Do a sibling check if the nodes have a common ancestor
+			siblingCheck( ap[i], bp[i] ) :
+
+			// Otherwise nodes in our document sort first
+			ap[i] === preferredDoc ? -1 :
+			bp[i] === preferredDoc ? 1 :
+			0;
+	};
+
+	return doc;
+};
+
+Sizzle.matches = function( expr, elements ) {
+	return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+	// Set document vars if needed
+	if ( ( elem.ownerDocument || elem ) !== document ) {
+		setDocument( elem );
+	}
+
+	// Make sure that attribute selectors are quoted
+	expr = expr.replace( rattributeQuotes, "='$1']" );
+
+	if ( support.matchesSelector && documentIsHTML &&
+		( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+		( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
+
+		try {
+			var ret = matches.call( elem, expr );
+
+			// IE 9's matchesSelector returns false on disconnected nodes
+			if ( ret || support.disconnectedMatch ||
+					// As well, disconnected nodes are said to be in a document
+					// fragment in IE 9
+					elem.document && elem.document.nodeType !== 11 ) {
+				return ret;
+			}
+		} catch (e) {}
+	}
+
+	return Sizzle( expr, document, null, [ elem ] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+	// Set document vars if needed
+	if ( ( context.ownerDocument || context ) !== document ) {
+		setDocument( context );
+	}
+	return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+	// Set document vars if needed
+	if ( ( elem.ownerDocument || elem ) !== document ) {
+		setDocument( elem );
+	}
+
+	var fn = Expr.attrHandle[ name.toLowerCase() ],
+		// Don't get fooled by Object.prototype properties (jQuery #13807)
+		val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+			fn( elem, name, !documentIsHTML ) :
+			undefined;
+
+	return val !== undefined ?
+		val :
+		support.attributes || !documentIsHTML ?
+			elem.getAttribute( name ) :
+			(val = elem.getAttributeNode(name)) && val.specified ?
+				val.value :
+				null;
+};
+
+Sizzle.error = function( msg ) {
+	throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+	var elem,
+		duplicates = [],
+		j = 0,
+		i = 0;
+
+	// Unless we *know* we can detect duplicates, assume their presence
+	hasDuplicate = !support.detectDuplicates;
+	sortInput = !support.sortStable && results.slice( 0 );
+	results.sort( sortOrder );
+
+	if ( hasDuplicate ) {
+		while ( (elem = results[i++]) ) {
+			if ( elem === results[ i ] ) {
+				j = duplicates.push( i );
+			}
+		}
+		while ( j-- ) {
+			results.splice( duplicates[ j ], 1 );
+		}
+	}
+
+	// Clear input after sorting to release objects
+	// See https://github.com/jquery/sizzle/pull/225
+	sortInput = null;
+
+	return results;
+};
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+	var node,
+		ret = "",
+		i = 0,
+		nodeType = elem.nodeType;
+
+	if ( !nodeType ) {
+		// If no nodeType, this is expected to be an array
+		while ( (node = elem[i++]) ) {
+			// Do not traverse comment nodes
+			ret += getText( node );
+		}
+	} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+		// Use textContent for elements
+		// innerText usage removed for consistency of new lines (jQuery #11153)
+		if ( typeof elem.textContent === "string" ) {
+			return elem.textContent;
+		} else {
+			// Traverse its children
+			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+				ret += getText( elem );
+			}
+		}
+	} else if ( nodeType === 3 || nodeType === 4 ) {
+		return elem.nodeValue;
+	}
+	// Do not include comment or processing instruction nodes
+
+	return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+	// Can be adjusted by the user
+	cacheLength: 50,
+
+	createPseudo: markFunction,
+
+	match: matchExpr,
+
+	attrHandle: {},
+
+	find: {},
+
+	relative: {
+		">": { dir: "parentNode", first: true },
+		" ": { dir: "parentNode" },
+		"+": { dir: "previousSibling", first: true },
+		"~": { dir: "previousSibling" }
+	},
+
+	preFilter: {
+		"ATTR": function( match ) {
+			match[1] = match[1].replace( runescape, funescape );
+
+			// Move the given value to match[3] whether quoted or unquoted
+			match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
+
+			if ( match[2] === "~=" ) {
+				match[3] = " " + match[3] + " ";
+			}
+
+			return match.slice( 0, 4 );
+		},
+
+		"CHILD": function( match ) {
+			/* matches from matchExpr["CHILD"]
+				1 type (only|nth|...)
+				2 what (child|of-type)
+				3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+				4 xn-component of xn+y argument ([+-]?\d*n|)
+				5 sign of xn-component
+				6 x of xn-component
+				7 sign of y-component
+				8 y of y-component
+			*/
+			match[1] = match[1].toLowerCase();
+
+			if ( match[1].slice( 0, 3 ) === "nth" ) {
+				// nth-* requires argument
+				if ( !match[3] ) {
+					Sizzle.error( match[0] );
+				}
+
+				// numeric x and y parameters for Expr.filter.CHILD
+				// remember that false/true cast respectively to 0/1
+				match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
+				match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
+
+			// other types prohibit arguments
+			} else if ( match[3] ) {
+				Sizzle.error( match[0] );
+			}
+
+			return match;
+		},
+
+		"PSEUDO": function( match ) {
+			var excess,
+				unquoted = !match[6] && match[2];
+
+			if ( matchExpr["CHILD"].test( match[0] ) ) {
+				return null;
+			}
+
+			// Accept quoted arguments as-is
+			if ( match[3] ) {
+				match[2] = match[4] || match[5] || "";
+
+			// Strip excess characters from unquoted arguments
+			} else if ( unquoted && rpseudo.test( unquoted ) &&
+				// Get excess from tokenize (recursively)
+				(excess = tokenize( unquoted, true )) &&
+				// advance to the next closing parenthesis
+				(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+				// excess is a negative index
+				match[0] = match[0].slice( 0, excess );
+				match[2] = unquoted.slice( 0, excess );
+			}
+
+			// Return only captures needed by the pseudo filter method (type and argument)
+			return match.slice( 0, 3 );
+		}
+	},
+
+	filter: {
+
+		"TAG": function( nodeNameSelector ) {
+			var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+			return nodeNameSelector === "*" ?
+				function() { return true; } :
+				function( elem ) {
+					return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+				};
+		},
+
+		"CLASS": function( className ) {
+			var pattern = classCache[ className + " " ];
+
+			return pattern ||
+				(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+				classCache( className, function( elem ) {
+					return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
+				});
+		},
+
+		"ATTR": function( name, operator, check ) {
+			return function( elem ) {
+				var result = Sizzle.attr( elem, name );
+
+				if ( result == null ) {
+					return operator === "!=";
+				}
+				if ( !operator ) {
+					return true;
+				}
+
+				result += "";
+
+				return operator === "=" ? result === check :
+					operator === "!=" ? result !== check :
+					operator === "^=" ? check && result.indexOf( check ) === 0 :
+					operator === "*=" ? check && result.indexOf( check ) > -1 :
+					operator === "$=" ? check && result.slice( -check.length ) === check :
+					operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
+					operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+					false;
+			};
+		},
+
+		"CHILD": function( type, what, argument, first, last ) {
+			var simple = type.slice( 0, 3 ) !== "nth",
+				forward = type.slice( -4 ) !== "last",
+				ofType = what === "of-type";
+
+			return first === 1 && last === 0 ?
+
+				// Shortcut for :nth-*(n)
+				function( elem ) {
+					return !!elem.parentNode;
+				} :
+
+				function( elem, context, xml ) {
+					var cache, outerCache, node, diff, nodeIndex, start,
+						dir = simple !== forward ? "nextSibling" : "previousSibling",
+						parent = elem.parentNode,
+						name = ofType && elem.nodeName.toLowerCase(),
+						useCache = !xml && !ofType;
+
+					if ( parent ) {
+
+						// :(first|last|only)-(child|of-type)
+						if ( simple ) {
+							while ( dir ) {
+								node = elem;
+								while ( (node = node[ dir ]) ) {
+									if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
+										return false;
+									}
+								}
+								// Reverse direction for :only-* (if we haven't yet done so)
+								start = dir = type === "only" && !start && "nextSibling";
+							}
+							return true;
+						}
+
+						start = [ forward ? parent.firstChild : parent.lastChild ];
+
+						// non-xml :nth-child(...) stores cache data on `parent`
+						if ( forward && useCache ) {
+							// Seek `elem` from a previously-cached index
+							outerCache = parent[ expando ] || (parent[ expando ] = {});
+							cache = outerCache[ type ] || [];
+							nodeIndex = cache[0] === dirruns && cache[1];
+							diff = cache[0] === dirruns && cache[2];
+							node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+							while ( (node = ++nodeIndex && node && node[ dir ] ||
+
+								// Fallback to seeking `elem` from the start
+								(diff = nodeIndex = 0) || start.pop()) ) {
+
+								// When found, cache indexes on `parent` and break
+								if ( node.nodeType === 1 && ++diff && node === elem ) {
+									outerCache[ type ] = [ dirruns, nodeIndex, diff ];
+									break;
+								}
+							}
+
+						// Use previously-cached element index if available
+						} else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
+							diff = cache[1];
+
+						// xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
+						} else {
+							// Use the same loop as above to seek `elem` from the start
+							while ( (node = ++nodeIndex && node && node[ dir ] ||
+								(diff = nodeIndex = 0) || start.pop()) ) {
+
+								if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
+									// Cache the index of each encountered element
+									if ( useCache ) {
+										(node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
+									}
+
+									if ( node === elem ) {
+										break;
+									}
+								}
+							}
+						}
+
+						// Incorporate the offset, then check against cycle size
+						diff -= last;
+						return diff === first || ( diff % first === 0 && diff / first >= 0 );
+					}
+				};
+		},
+
+		"PSEUDO": function( pseudo, argument ) {
+			// pseudo-class names are case-insensitive
+			// http://www.w3.org/TR/selectors/#pseudo-classes
+			// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+			// Remember that setFilters inherits from pseudos
+			var args,
+				fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+					Sizzle.error( "unsupported pseudo: " + pseudo );
+
+			// The user may use createPseudo to indicate that
+			// arguments are needed to create the filter function
+			// just as Sizzle does
+			if ( fn[ expando ] ) {
+				return fn( argument );
+			}
+
+			// But maintain support for old signatures
+			if ( fn.length > 1 ) {
+				args = [ pseudo, pseudo, "", argument ];
+				return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+					markFunction(function( seed, matches ) {
+						var idx,
+							matched = fn( seed, argument ),
+							i = matched.length;
+						while ( i-- ) {
+							idx = indexOf( seed, matched[i] );
+							seed[ idx ] = !( matches[ idx ] = matched[i] );
+						}
+					}) :
+					function( elem ) {
+						return fn( elem, 0, args );
+					};
+			}
+
+			return fn;
+		}
+	},
+
+	pseudos: {
+		// Potentially complex pseudos
+		"not": markFunction(function( selector ) {
+			// Trim the selector passed to compile
+			// to avoid treating leading and trailing
+			// spaces as combinators
+			var input = [],
+				results = [],
+				matcher = compile( selector.replace( rtrim, "$1" ) );
+
+			return matcher[ expando ] ?
+				markFunction(function( seed, matches, context, xml ) {
+					var elem,
+						unmatched = matcher( seed, null, xml, [] ),
+						i = seed.length;
+
+					// Match elements unmatched by `matcher`
+					while ( i-- ) {
+						if ( (elem = unmatched[i]) ) {
+							seed[i] = !(matches[i] = elem);
+						}
+					}
+				}) :
+				function( elem, context, xml ) {
+					input[0] = elem;
+					matcher( input, null, xml, results );
+					// Don't keep the element (issue #299)
+					input[0] = null;
+					return !results.pop();
+				};
+		}),
+
+		"has": markFunction(function( selector ) {
+			return function( elem ) {
+				return Sizzle( selector, elem ).length > 0;
+			};
+		}),
+
+		"contains": markFunction(function( text ) {
+			text = text.replace( runescape, funescape );
+			return function( elem ) {
+				return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+			};
+		}),
+
+		// "Whether an element is represented by a :lang() selector
+		// is based solely on the element's language value
+		// being equal to the identifier C,
+		// or beginning with the identifier C immediately followed by "-".
+		// The matching of C against the element's language value is performed case-insensitively.
+		// The identifier C does not have to be a valid language name."
+		// http://www.w3.org/TR/selectors/#lang-pseudo
+		"lang": markFunction( function( lang ) {
+			// lang value must be a valid identifier
+			if ( !ridentifier.test(lang || "") ) {
+				Sizzle.error( "unsupported lang: " + lang );
+			}
+			lang = lang.replace( runescape, funescape ).toLowerCase();
+			return function( elem ) {
+				var elemLang;
+				do {
+					if ( (elemLang = documentIsHTML ?
+						elem.lang :
+						elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
+
+						elemLang = elemLang.toLowerCase();
+						return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+					}
+				} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
+				return false;
+			};
+		}),
+
+		// Miscellaneous
+		"target": function( elem ) {
+			var hash = window.location && window.location.hash;
+			return hash && hash.slice( 1 ) === elem.id;
+		},
+
+		"root": function( elem ) {
+			return elem === docElem;
+		},
+
+		"focus": function( elem ) {
+			return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+		},
+
+		// Boolean properties
+		"enabled": function( elem ) {
+			return elem.disabled === false;
+		},
+
+		"disabled": function( elem ) {
+			return elem.disabled === true;
+		},
+
+		"checked": function( elem ) {
+			// In CSS3, :checked should return both checked and selected elements
+			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+			var nodeName = elem.nodeName.toLowerCase();
+			return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+		},
+
+		"selected": function( elem ) {
+			// Accessing this property makes selected-by-default
+			// options in Safari work properly
+			if ( elem.parentNode ) {
+				elem.parentNode.selectedIndex;
+			}
+
+			return elem.selected === true;
+		},
+
+		// Contents
+		"empty": function( elem ) {
+			// http://www.w3.org/TR/selectors/#empty-pseudo
+			// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
+			//   but not by others (comment: 8; processing instruction: 7; etc.)
+			// nodeType < 6 works because attributes (2) do not appear as children
+			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+				if ( elem.nodeType < 6 ) {
+					return false;
+				}
+			}
+			return true;
+		},
+
+		"parent": function( elem ) {
+			return !Expr.pseudos["empty"]( elem );
+		},
+
+		// Element/input types
+		"header": function( elem ) {
+			return rheader.test( elem.nodeName );
+		},
+
+		"input": function( elem ) {
+			return rinputs.test( elem.nodeName );
+		},
+
+		"button": function( elem ) {
+			var name = elem.nodeName.toLowerCase();
+			return name === "input" && elem.type === "button" || name === "button";
+		},
+
+		"text": function( elem ) {
+			var attr;
+			return elem.nodeName.toLowerCase() === "input" &&
+				elem.type === "text" &&
+
+				// Support: IE<8
+				// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
+				( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
+		},
+
+		// Position-in-collection
+		"first": createPositionalPseudo(function() {
+			return [ 0 ];
+		}),
+
+		"last": createPositionalPseudo(function( matchIndexes, length ) {
+			return [ length - 1 ];
+		}),
+
+		"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+			return [ argument < 0 ? argument + length : argument ];
+		}),
+
+		"even": createPositionalPseudo(function( matchIndexes, length ) {
+			var i = 0;
+			for ( ; i < length; i += 2 ) {
+				matchIndexes.push( i );
+			}
+			return matchIndexes;
+		}),
+
+		"odd": createPositionalPseudo(function( matchIndexes, length ) {
+			var i = 1;
+			for ( ; i < length; i += 2 ) {
+				matchIndexes.push( i );
+			}
+			return matchIndexes;
+		}),
+
+		"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+			var i = argument < 0 ? argument + length : argument;
+			for ( ; --i >= 0; ) {
+				matchIndexes.push( i );
+			}
+			return matchIndexes;
+		}),
+
+		"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+			var i = argument < 0 ? argument + length : argument;
+			for ( ; ++i < length; ) {
+				matchIndexes.push( i );
+			}
+			return matchIndexes;
+		})
+	}
+};
+
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+	Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+	Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
+	var matched, match, tokens, type,
+		soFar, groups, preFilters,
+		cached = tokenCache[ selector + " " ];
+
+	if ( cached ) {
+		return parseOnly ? 0 : cached.slice( 0 );
+	}
+
+	soFar = selector;
+	groups = [];
+	preFilters = Expr.preFilter;
+
+	while ( soFar ) {
+
+		// Comma and first run
+		if ( !matched || (match = rcomma.exec( soFar )) ) {
+			if ( match ) {
+				// Don't consume trailing commas as valid
+				soFar = soFar.slice( match[0].length ) || soFar;
+			}
+			groups.push( (tokens = []) );
+		}
+
+		matched = false;
+
+		// Combinators
+		if ( (match = rcombinators.exec( soFar )) ) {
+			matched = match.shift();
+			tokens.push({
+				value: matched,
+				// Cast descendant combinators to space
+				type: match[0].replace( rtrim, " " )
+			});
+			soFar = soFar.slice( matched.length );
+		}
+
+		// Filters
+		for ( type in Expr.filter ) {
+			if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+				(match = preFilters[ type ]( match ))) ) {
+				matched = match.shift();
+				tokens.push({
+					value: matched,
+					type: type,
+					matches: match
+				});
+				soFar = soFar.slice( matched.length );
+			}
+		}
+
+		if ( !matched ) {
+			break;
+		}
+	}
+
+	// Return the length of the invalid excess
+	// if we're just parsing
+	// Otherwise, throw an error or return tokens
+	return parseOnly ?
+		soFar.length :
+		soFar ?
+			Sizzle.error( selector ) :
+			// Cache the tokens
+			tokenCache( selector, groups ).slice( 0 );
+};
+
+function toSelector( tokens ) {
+	var i = 0,
+		len = tokens.length,
+		selector = "";
+	for ( ; i < len; i++ ) {
+		selector += tokens[i].value;
+	}
+	return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+	var dir = combinator.dir,
+		checkNonElements = base && dir === "parentNode",
+		doneName = done++;
+
+	return combinator.first ?
+		// Check against closest ancestor/preceding element
+		function( elem, context, xml ) {
+			while ( (elem = elem[ dir ]) ) {
+				if ( elem.nodeType === 1 || checkNonElements ) {
+					return matcher( elem, context, xml );
+				}
+			}
+		} :
+
+		// Check against all ancestor/preceding elements
+		function( elem, context, xml ) {
+			var oldCache, outerCache,
+				newCache = [ dirruns, doneName ];
+
+			// We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+			if ( xml ) {
+				while ( (elem = elem[ dir ]) ) {
+					if ( elem.nodeType === 1 || checkNonElements ) {
+						if ( matcher( elem, context, xml ) ) {
+							return true;
+						}
+					}
+				}
+			} else {
+				while ( (elem = elem[ dir ]) ) {
+					if ( elem.nodeType === 1 || checkNonElements ) {
+						outerCache = elem[ expando ] || (elem[ expando ] = {});
+						if ( (oldCache = outerCache[ dir ]) &&
+							oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
+
+							// Assign to newCache so results back-propagate to previous elements
+							return (newCache[ 2 ] = oldCache[ 2 ]);
+						} else {
+							// Reuse newcache so results back-propagate to previous elements
+							outerCache[ dir ] = newCache;
+
+							// A match means we're done; a fail means we have to keep checking
+							if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
+								return true;
+							}
+						}
+					}
+				}
+			}
+		};
+}
+
+function elementMatcher( matchers ) {
+	return matchers.length > 1 ?
+		function( elem, context, xml ) {
+			var i = matchers.length;
+			while ( i-- ) {
+				if ( !matchers[i]( elem, context, xml ) ) {
+					return false;
+				}
+			}
+			return true;
+		} :
+		matchers[0];
+}
+
+function multipleContexts( selector, contexts, results ) {
+	var i = 0,
+		len = contexts.length;
+	for ( ; i < len; i++ ) {
+		Sizzle( selector, contexts[i], results );
+	}
+	return results;
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+	var elem,
+		newUnmatched = [],
+		i = 0,
+		len = unmatched.length,
+		mapped = map != null;
+
+	for ( ; i < len; i++ ) {
+		if ( (elem = unmatched[i]) ) {
+			if ( !filter || filter( elem, context, xml ) ) {
+				newUnmatched.push( elem );
+				if ( mapped ) {
+					map.push( i );
+				}
+			}
+		}
+	}
+
+	return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+	if ( postFilter && !postFilter[ expando ] ) {
+		postFilter = setMatcher( postFilter );
+	}
+	if ( postFinder && !postFinder[ expando ] ) {
+		postFinder = setMatcher( postFinder, postSelector );
+	}
+	return markFunction(function( seed, results, context, xml ) {
+		var temp, i, elem,
+			preMap = [],
+			postMap = [],
+			preexisting = results.length,
+
+			// Get initial elements from seed or context
+			elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+			// Prefilter to get matcher input, preserving a map for seed-results synchronization
+			matcherIn = preFilter && ( seed || !selector ) ?
+				condense( elems, preMap, preFilter, context, xml ) :
+				elems,
+
+			matcherOut = matcher ?
+				// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+				postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+					// ...intermediate processing is necessary
+					[] :
+
+					// ...otherwise use results directly
+					results :
+				matcherIn;
+
+		// Find primary matches
+		if ( matcher ) {
+			matcher( matcherIn, matcherOut, context, xml );
+		}
+
+		// Apply postFilter
+		if ( postFilter ) {
+			temp = condense( matcherOut, postMap );
+			postFilter( temp, [], context, xml );
+
+			// Un-match failing elements by moving them back to matcherIn
+			i = temp.length;
+			while ( i-- ) {
+				if ( (elem = temp[i]) ) {
+					matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+				}
+			}
+		}
+
+		if ( seed ) {
+			if ( postFinder || preFilter ) {
+				if ( postFinder ) {
+					// Get the final matcherOut by condensing this intermediate into postFinder contexts
+					temp = [];
+					i = matcherOut.length;
+					while ( i-- ) {
+						if ( (elem = matcherOut[i]) ) {
+							// Restore matcherIn since elem is not yet a final match
+							temp.push( (matcherIn[i] = elem) );
+						}
+					}
+					postFinder( null, (matcherOut = []), temp, xml );
+				}
+
+				// Move matched elements from seed to results to keep them synchronized
+				i = matcherOut.length;
+				while ( i-- ) {
+					if ( (elem = matcherOut[i]) &&
+						(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
+
+						seed[temp] = !(results[temp] = elem);
+					}
+				}
+			}
+
+		// Add elements to results, through postFinder if defined
+		} else {
+			matcherOut = condense(
+				matcherOut === results ?
+					matcherOut.splice( preexisting, matcherOut.length ) :
+					matcherOut
+			);
+			if ( postFinder ) {
+				postFinder( null, results, matcherOut, xml );
+			} else {
+				push.apply( results, matcherOut );
+			}
+		}
+	});
+}
+
+function matcherFromTokens( tokens ) {
+	var checkContext, matcher, j,
+		len = tokens.length,
+		leadingRelative = Expr.relative[ tokens[0].type ],
+		implicitRelative = leadingRelative || Expr.relative[" "],
+		i = leadingRelative ? 1 : 0,
+
+		// The foundational matcher ensures that elements are reachable from top-level context(s)
+		matchContext = addCombinator( function( elem ) {
+			return elem === checkContext;
+		}, implicitRelative, true ),
+		matchAnyContext = addCombinator( function( elem ) {
+			return indexOf( checkContext, elem ) > -1;
+		}, implicitRelative, true ),
+		matchers = [ function( elem, context, xml ) {
+			var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+				(checkContext = context).nodeType ?
+					matchContext( elem, context, xml ) :
+					matchAnyContext( elem, context, xml ) );
+			// Avoid hanging onto element (issue #299)
+			checkContext = null;
+			return ret;
+		} ];
+
+	for ( ; i < len; i++ ) {
+		if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+			matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
+		} else {
+			matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+			// Return special upon seeing a positional matcher
+			if ( matcher[ expando ] ) {
+				// Find the next relative operator (if any) for proper handling
+				j = ++i;
+				for ( ; j < len; j++ ) {
+					if ( Expr.relative[ tokens[j].type ] ) {
+						break;
+					}
+				}
+				return setMatcher(
+					i > 1 && elementMatcher( matchers ),
+					i > 1 && toSelector(
+						// If the preceding token was a descendant combinator, insert an implicit any-element `*`
+						tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
+					).replace( rtrim, "$1" ),
+					matcher,
+					i < j && matcherFromTokens( tokens.slice( i, j ) ),
+					j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+					j < len && toSelector( tokens )
+				);
+			}
+			matchers.push( matcher );
+		}
+	}
+
+	return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+	var bySet = setMatchers.length > 0,
+		byElement = elementMatchers.length > 0,
+		superMatcher = function( seed, context, xml, results, outermost ) {
+			var elem, j, matcher,
+				matchedCount = 0,
+				i = "0",
+				unmatched = seed && [],
+				setMatched = [],
+				contextBackup = outermostContext,
+				// We must always have either seed elements or outermost context
+				elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
+				// Use integer dirruns iff this is the outermost matcher
+				dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
+				len = elems.length;
+
+			if ( outermost ) {
+				outermostContext = context !== document && context;
+			}
+
+			// Add elements passing elementMatchers directly to results
+			// Keep `i` a string if there are no elements so `matchedCount` will be "00" below
+			// Support: IE<9, Safari
+			// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
+			for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
+				if ( byElement && elem ) {
+					j = 0;
+					while ( (matcher = elementMatchers[j++]) ) {
+						if ( matcher( elem, context, xml ) ) {
+							results.push( elem );
+							break;
+						}
+					}
+					if ( outermost ) {
+						dirruns = dirrunsUnique;
+					}
+				}
+
+				// Track unmatched elements for set filters
+				if ( bySet ) {
+					// They will have gone through all possible matchers
+					if ( (elem = !matcher && elem) ) {
+						matchedCount--;
+					}
+
+					// Lengthen the array for every element, matched or not
+					if ( seed ) {
+						unmatched.push( elem );
+					}
+				}
+			}
+
+			// Apply set filters to unmatched elements
+			matchedCount += i;
+			if ( bySet && i !== matchedCount ) {
+				j = 0;
+				while ( (matcher = setMatchers[j++]) ) {
+					matcher( unmatched, setMatched, context, xml );
+				}
+
+				if ( seed ) {
+					// Reintegrate element matches to eliminate the need for sorting
+					if ( matchedCount > 0 ) {
+						while ( i-- ) {
+							if ( !(unmatched[i] || setMatched[i]) ) {
+								setMatched[i] = pop.call( results );
+							}
+						}
+					}
+
+					// Discard index placeholder values to get only actual matches
+					setMatched = condense( setMatched );
+				}
+
+				// Add matches to results
+				push.apply( results, setMatched );
+
+				// Seedless set matches succeeding multiple successful matchers stipulate sorting
+				if ( outermost && !seed && setMatched.length > 0 &&
+					( matchedCount + setMatchers.length ) > 1 ) {
+
+					Sizzle.uniqueSort( results );
+				}
+			}
+
+			// Override manipulation of globals by nested matchers
+			if ( outermost ) {
+				dirruns = dirrunsUnique;
+				outermostContext = contextBackup;
+			}
+
+			return unmatched;
+		};
+
+	return bySet ?
+		markFunction( superMatcher ) :
+		superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
+	var i,
+		setMatchers = [],
+		elementMatchers = [],
+		cached = compilerCache[ selector + " " ];
+
+	if ( !cached ) {
+		// Generate a function of recursive functions that can be used to check each element
+		if ( !match ) {
+			match = tokenize( selector );
+		}
+		i = match.length;
+		while ( i-- ) {
+			cached = matcherFromTokens( match[i] );
+			if ( cached[ expando ] ) {
+				setMatchers.push( cached );
+			} else {
+				elementMatchers.push( cached );
+			}
+		}
+
+		// Cache the compiled function
+		cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+
+		// Save selector and tokenization
+		cached.selector = selector;
+	}
+	return cached;
+};
+
+/**
+ * A low-level selection function that works with Sizzle's compiled
+ *  selector functions
+ * @param {String|Function} selector A selector or a pre-compiled
+ *  selector function built with Sizzle.compile
+ * @param {Element} context
+ * @param {Array} [results]
+ * @param {Array} [seed] A set of elements to match against
+ */
+select = Sizzle.select = function( selector, context, results, seed ) {
+	var i, tokens, token, type, find,
+		compiled = typeof selector === "function" && selector,
+		match = !seed && tokenize( (selector = compiled.selector || selector) );
+
+	results = results || [];
+
+	// Try to minimize operations if there is no seed and only one group
+	if ( match.length === 1 ) {
+
+		// Take a shortcut and set the context if the root selector is an ID
+		tokens = match[0] = match[0].slice( 0 );
+		if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+				support.getById && context.nodeType === 9 && documentIsHTML &&
+				Expr.relative[ tokens[1].type ] ) {
+
+			context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
+			if ( !context ) {
+				return results;
+
+			// Precompiled matchers will still verify ancestry, so step up a level
+			} else if ( compiled ) {
+				context = context.parentNode;
+			}
+
+			selector = selector.slice( tokens.shift().value.length );
+		}
+
+		// Fetch a seed set for right-to-left matching
+		i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
+		while ( i-- ) {
+			token = tokens[i];
+
+			// Abort if we hit a combinator
+			if ( Expr.relative[ (type = token.type) ] ) {
+				break;
+			}
+			if ( (find = Expr.find[ type ]) ) {
+				// Search, expanding context for leading sibling combinators
+				if ( (seed = find(
+					token.matches[0].replace( runescape, funescape ),
+					rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
+				)) ) {
+
+					// If seed is empty or no tokens remain, we can return early
+					tokens.splice( i, 1 );
+					selector = seed.length && toSelector( tokens );
+					if ( !selector ) {
+						push.apply( results, seed );
+						return results;
+					}
+
+					break;
+				}
+			}
+		}
+	}
+
+	// Compile and execute a filtering function if one is not provided
+	// Provide `match` to avoid retokenization if we modified the selector above
+	( compiled || compile( selector, match ) )(
+		seed,
+		context,
+		!documentIsHTML,
+		results,
+		rsibling.test( selector ) && testContext( context.parentNode ) || context
+	);
+	return results;
+};
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
+
+// Support: Chrome 14-35+
+// Always assume duplicates if they aren't passed to the comparison function
+support.detectDuplicates = !!hasDuplicate;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Detached nodes confoundingly follow *each other*
+support.sortDetached = assert(function( div1 ) {
+	// Should return 1, but returns 4 (following)
+	return div1.compareDocumentPosition( document.createElement("div") ) & 1;
+});
+
+// Support: IE<8
+// Prevent attribute/property "interpolation"
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert(function( div ) {
+	div.innerHTML = "<a href='#'></a>";
+	return div.firstChild.getAttribute("href") === "#" ;
+}) ) {
+	addHandle( "type|href|height|width", function( elem, name, isXML ) {
+		if ( !isXML ) {
+			return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+		}
+	});
+}
+
+// Support: IE<9
+// Use defaultValue in place of getAttribute("value")
+if ( !support.attributes || !assert(function( div ) {
+	div.innerHTML = "<input/>";
+	div.firstChild.setAttribute( "value", "" );
+	return div.firstChild.getAttribute( "value" ) === "";
+}) ) {
+	addHandle( "value", function( elem, name, isXML ) {
+		if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+			return elem.defaultValue;
+		}
+	});
+}
+
+// Support: IE<9
+// Use getAttributeNode to fetch booleans when getAttribute lies
+if ( !assert(function( div ) {
+	return div.getAttribute("disabled") == null;
+}) ) {
+	addHandle( booleans, function( elem, name, isXML ) {
+		var val;
+		if ( !isXML ) {
+			return elem[ name ] === true ? name.toLowerCase() :
+					(val = elem.getAttributeNode( name )) && val.specified ?
+					val.value :
+				null;
+		}
+	});
+}
+
+return Sizzle;
+
+})( window );
+
+
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+
+var rneedsContext = jQuery.expr.match.needsContext;
+
+var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
+
+
+
+var risSimple = /^.[^:#\[\.,]*$/;
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, not ) {
+	if ( jQuery.isFunction( qualifier ) ) {
+		return jQuery.grep( elements, function( elem, i ) {
+			/* jshint -W018 */
+			return !!qualifier.call( elem, i, elem ) !== not;
+		});
+
+	}
+
+	if ( qualifier.nodeType ) {
+		return jQuery.grep( elements, function( elem ) {
+			return ( elem === qualifier ) !== not;
+		});
+
+	}
+
+	if ( typeof qualifier === "string" ) {
+		if ( risSimple.test( qualifier ) ) {
+			return jQuery.filter( qualifier, elements, not );
+		}
+
+		qualifier = jQuery.filter( qualifier, elements );
+	}
+
+	return jQuery.grep( elements, function( elem ) {
+		return ( indexOf.call( qualifier, elem ) >= 0 ) !== not;
+	});
+}
+
+jQuery.filter = function( expr, elems, not ) {
+	var elem = elems[ 0 ];
+
+	if ( not ) {
+		expr = ":not(" + expr + ")";
+	}
+
+	return elems.length === 1 && elem.nodeType === 1 ?
+		jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
+		jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+			return elem.nodeType === 1;
+		}));
+};
+
+jQuery.fn.extend({
+	find: function( selector ) {
+		var i,
+			len = this.length,
+			ret = [],
+			self = this;
+
+		if ( typeof selector !== "string" ) {
+			return this.pushStack( jQuery( selector ).filter(function() {
+				for ( i = 0; i < len; i++ ) {
+					if ( jQuery.contains( self[ i ], this ) ) {
+						return true;
+					}
+				}
+			}) );
+		}
+
+		for ( i = 0; i < len; i++ ) {
+			jQuery.find( selector, self[ i ], ret );
+		}
+
+		// Needed because $( selector, context ) becomes $( context ).find( selector )
+		ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
+		ret.selector = this.selector ? this.selector + " " + selector : selector;
+		return ret;
+	},
+	filter: function( selector ) {
+		return this.pushStack( winnow(this, selector || [], false) );
+	},
+	not: function( selector ) {
+		return this.pushStack( winnow(this, selector || [], true) );
+	},
+	is: function( selector ) {
+		return !!winnow(
+			this,
+
+			// If this is a positional/relative selector, check membership in the returned set
+			// so $("p:first").is("p:last") won't return true for a doc with two "p".
+			typeof selector === "string" && rneedsContext.test( selector ) ?
+				jQuery( selector ) :
+				selector || [],
+			false
+		).length;
+	}
+});
+
+
+// Initialize a jQuery object
+
+
+// A central reference to the root jQuery(document)
+var rootjQuery,
+
+	// A simple way to check for HTML strings
+	// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+	// Strict HTML recognition (#11290: must start with <)
+	rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+
+	init = jQuery.fn.init = function( selector, context ) {
+		var match, elem;
+
+		// HANDLE: $(""), $(null), $(undefined), $(false)
+		if ( !selector ) {
+			return this;
+		}
+
+		// Handle HTML strings
+		if ( typeof selector === "string" ) {
+			if ( selector[0] === "<" && selector[ selector.length - 1 ] === ">" && selector.length >= 3 ) {
+				// Assume that strings that start and end with <> are HTML and skip the regex check
+				match = [ null, selector, null ];
+
+			} else {
+				match = rquickExpr.exec( selector );
+			}
+
+			// Match html or make sure no context is specified for #id
+			if ( match && (match[1] || !context) ) {
+
+				// HANDLE: $(html) -> $(array)
+				if ( match[1] ) {
+					context = context instanceof jQuery ? context[0] : context;
+
+					// Option to run scripts is true for back-compat
+					// Intentionally let the error be thrown if parseHTML is not present
+					jQuery.merge( this, jQuery.parseHTML(
+						match[1],
+						context && context.nodeType ? context.ownerDocument || context : document,
+						true
+					) );
+
+					// HANDLE: $(html, props)
+					if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+						for ( match in context ) {
+							// Properties of context are called as methods if possible
+							if ( jQuery.isFunction( this[ match ] ) ) {
+								this[ match ]( context[ match ] );
+
+							// ...and otherwise set as attributes
+							} else {
+								this.attr( match, context[ match ] );
+							}
+						}
+					}
+
+					return this;
+
+				// HANDLE: $(#id)
+				} else {
+					elem = document.getElementById( match[2] );
+
+					// Support: Blackberry 4.6
+					// gEBID returns nodes no longer in the document (#6963)
+					if ( elem && elem.parentNode ) {
+						// Inject the element directly into the jQuery object
+						this.length = 1;
+						this[0] = elem;
+					}
+
+					this.context = document;
+					this.selector = selector;
+					return this;
+				}
+
+			// HANDLE: $(expr, $(...))
+			} else if ( !context || context.jquery ) {
+				return ( context || rootjQuery ).find( selector );
+
+			// HANDLE: $(expr, context)
+			// (which is just equivalent to: $(context).find(expr)
+			} else {
+				return this.constructor( context ).find( selector );
+			}
+
+		// HANDLE: $(DOMElement)
+		} else if ( selector.nodeType ) {
+			this.context = this[0] = selector;
+			this.length = 1;
+			return this;
+
+		// HANDLE: $(function)
+		// Shortcut for document ready
+		} else if ( jQuery.isFunction( selector ) ) {
+			return typeof rootjQuery.ready !== "undefined" ?
+				rootjQuery.ready( selector ) :
+				// Execute immediately if ready is not present
+				selector( jQuery );
+		}
+
+		if ( selector.selector !== undefined ) {
+			this.selector = selector.selector;
+			this.context = selector.context;
+		}
+
+		return jQuery.makeArray( selector, this );
+	};
+
+// Give the init function the jQuery prototype for later instantiation
+init.prototype = jQuery.fn;
+
+// Initialize central reference
+rootjQuery = jQuery( document );
+
+
+var rparentsprev = /^(?:parents|prev(?:Until|All))/,
+	// Methods guaranteed to produce a unique set when starting from a unique set
+	guaranteedUnique = {
+		children: true,
+		contents: true,
+		next: true,
+		prev: true
+	};
+
+jQuery.extend({
+	dir: function( elem, dir, until ) {
+		var matched = [],
+			truncate = until !== undefined;
+
+		while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {
+			if ( elem.nodeType === 1 ) {
+				if ( truncate && jQuery( elem ).is( until ) ) {
+					break;
+				}
+				matched.push( elem );
+			}
+		}
+		return matched;
+	},
+
+	sibling: function( n, elem ) {
+		var matched = [];
+
+		for ( ; n; n = n.nextSibling ) {
+			if ( n.nodeType === 1 && n !== elem ) {
+				matched.push( n );
+			}
+		}
+
+		return matched;
+	}
+});
+
+jQuery.fn.extend({
+	has: function( target ) {
+		var targets = jQuery( target, this ),
+			l = targets.length;
+
+		return this.filter(function() {
+			var i = 0;
+			for ( ; i < l; i++ ) {
+				if ( jQuery.contains( this, targets[i] ) ) {
+					return true;
+				}
+			}
+		});
+	},
+
+	closest: function( selectors, context ) {
+		var cur,
+			i = 0,
+			l = this.length,
+			matched = [],
+			pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
+				jQuery( selectors, context || this.context ) :
+				0;
+
+		for ( ; i < l; i++ ) {
+			for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
+				// Always skip document fragments
+				if ( cur.nodeType < 11 && (pos ?
+					pos.index(cur) > -1 :
+
+					// Don't pass non-elements to Sizzle
+					cur.nodeType === 1 &&
+						jQuery.find.matchesSelector(cur, selectors)) ) {
+
+					matched.push( cur );
+					break;
+				}
+			}
+		}
+
+		return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
+	},
+
+	// Determine the position of an element within the set
+	index: function( elem ) {
+
+		// No argument, return index in parent
+		if ( !elem ) {
+			return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
+		}
+
+		// Index in selector
+		if ( typeof elem === "string" ) {
+			return indexOf.call( jQuery( elem ), this[ 0 ] );
+		}
+
+		// Locate the position of the desired element
+		return indexOf.call( this,
+
+			// If it receives a jQuery object, the first element is used
+			elem.jquery ? elem[ 0 ] : elem
+		);
+	},
+
+	add: function( selector, context ) {
+		return this.pushStack(
+			jQuery.unique(
+				jQuery.merge( this.get(), jQuery( selector, context ) )
+			)
+		);
+	},
+
+	addBack: function( selector ) {
+		return this.add( selector == null ?
+			this.prevObject : this.prevObject.filter(selector)
+		);
+	}
+});
+
+function sibling( cur, dir ) {
+	while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}
+	return cur;
+}
+
+jQuery.each({
+	parent: function( elem ) {
+		var parent = elem.parentNode;
+		return parent && parent.nodeType !== 11 ? parent : null;
+	},
+	parents: function( elem ) {
+		return jQuery.dir( elem, "parentNode" );
+	},
+	parentsUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "parentNode", until );
+	},
+	next: function( elem ) {
+		return sibling( elem, "nextSibling" );
+	},
+	prev: function( elem ) {
+		return sibling( elem, "previousSibling" );
+	},
+	nextAll: function( elem ) {
+		return jQuery.dir( elem, "nextSibling" );
+	},
+	prevAll: function( elem ) {
+		return jQuery.dir( elem, "previousSibling" );
+	},
+	nextUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "nextSibling", until );
+	},
+	prevUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "previousSibling", until );
+	},
+	siblings: function( elem ) {
+		return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+	},
+	children: function( elem ) {
+		return jQuery.sibling( elem.firstChild );
+	},
+	contents: function( elem ) {
+		return elem.contentDocument || jQuery.merge( [], elem.childNodes );
+	}
+}, function( name, fn ) {
+	jQuery.fn[ name ] = function( until, selector ) {
+		var matched = jQuery.map( this, fn, until );
+
+		if ( name.slice( -5 ) !== "Until" ) {
+			selector = until;
+		}
+
+		if ( selector && typeof selector === "string" ) {
+			matched = jQuery.filter( selector, matched );
+		}
+
+		if ( this.length > 1 ) {
+			// Remove duplicates
+			if ( !guaranteedUnique[ name ] ) {
+				jQuery.unique( matched );
+			}
+
+			// Reverse order for parents* and prev-derivatives
+			if ( rparentsprev.test( name ) ) {
+				matched.reverse();
+			}
+		}
+
+		return this.pushStack( matched );
+	};
+});
+var rnotwhite = (/\S+/g);
+
+
+
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+	var object = optionsCache[ options ] = {};
+	jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
+		object[ flag ] = true;
+	});
+	return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ *	options: an optional list of space-separated options that will change how
+ *			the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ *	once:			will ensure the callback list can only be fired once (like a Deferred)
+ *
+ *	memory:			will keep track of previous values and will call any callback added
+ *					after the list has been fired right away with the latest "memorized"
+ *					values (like a Deferred)
+ *
+ *	unique:			will ensure a callback can only be added once (no duplicate in the list)
+ *
+ *	stopOnFalse:	interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+	// Convert options from String-formatted to Object-formatted if needed
+	// (we check in cache first)
+	options = typeof options === "string" ?
+		( optionsCache[ options ] || createOptions( options ) ) :
+		jQuery.extend( {}, options );
+
+	var // Last fire value (for non-forgettable lists)
+		memory,
+		// Flag to know if list was already fired
+		fired,
+		// Flag to know if list is currently firing
+		firing,
+		// First callback to fire (used internally by add and fireWith)
+		firingStart,
+		// End of the loop when firing
+		firingLength,
+		// Index of currently firing callback (modified by remove if needed)
+		firingIndex,
+		// Actual callback list
+		list = [],
+		// Stack of fire calls for repeatable lists
+		stack = !options.once && [],
+		// Fire callbacks
+		fire = function( data ) {
+			memory = options.memory && data;
+			fired = true;
+			firingIndex = firingStart || 0;
+			firingStart = 0;
+			firingLength = list.length;
+			firing = true;
+			for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+				if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+					memory = false; // To prevent further calls using add
+					break;
+				}
+			}
+			firing = false;
+			if ( list ) {
+				if ( stack ) {
+					if ( stack.length ) {
+						fire( stack.shift() );
+					}
+				} else if ( memory ) {
+					list = [];
+				} else {
+					self.disable();
+				}
+			}
+		},
+		// Actual Callbacks object
+		self = {
+			// Add a callback or a collection of callbacks to the list
+			add: function() {
+				if ( list ) {
+					// First, we save the current length
+					var start = list.length;
+					(function add( args ) {
+						jQuery.each( args, function( _, arg ) {
+							var type = jQuery.type( arg );
+							if ( type === "function" ) {
+								if ( !options.unique || !self.has( arg ) ) {
+									list.push( arg );
+								}
+							} else if ( arg && arg.length && type !== "string" ) {
+								// Inspect recursively
+								add( arg );
+							}
+						});
+					})( arguments );
+					// Do we need to add the callbacks to the
+					// current firing batch?
+					if ( firing ) {
+						firingLength = list.length;
+					// With memory, if we're not firing then
+					// we should call right away
+					} else if ( memory ) {
+						firingStart = start;
+						fire( memory );
+					}
+				}
+				return this;
+			},
+			// Remove a callback from the list
+			remove: function() {
+				if ( list ) {
+					jQuery.each( arguments, function( _, arg ) {
+						var index;
+						while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+							list.splice( index, 1 );
+							// Handle firing indexes
+							if ( firing ) {
+								if ( index <= firingLength ) {
+									firingLength--;
+								}
+								if ( index <= firingIndex ) {
+									firingIndex--;
+								}
+							}
+						}
+					});
+				}
+				return this;
+			},
+			// Check if a given callback is in the list.
+			// If no argument is given, return whether or not list has callbacks attached.
+			has: function( fn ) {
+				return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
+			},
+			// Remove all callbacks from the list
+			empty: function() {
+				list = [];
+				firingLength = 0;
+				return this;
+			},
+			// Have the list do nothing anymore
+			disable: function() {
+				list = stack = memory = undefined;
+				return this;
+			},
+			// Is it disabled?
+			disabled: function() {
+				return !list;
+			},
+			// Lock the list in its current state
+			lock: function() {
+				stack = undefined;
+				if ( !memory ) {
+					self.disable();
+				}
+				return this;
+			},
+			// Is it locked?
+			locked: function() {
+				return !stack;
+			},
+			// Call all callbacks with the given context and arguments
+			fireWith: function( context, args ) {
+				if ( list && ( !fired || stack ) ) {
+					args = args || [];
+					args = [ context, args.slice ? args.slice() : args ];
+					if ( firing ) {
+						stack.push( args );
+					} else {
+						fire( args );
+					}
+				}
+				return this;
+			},
+			// Call all the callbacks with the given arguments
+			fire: function() {
+				self.fireWith( this, arguments );
+				return this;
+			},
+			// To know if the callbacks have already been called at least once
+			fired: function() {
+				return !!fired;
+			}
+		};
+
+	return self;
+};
+
+
+jQuery.extend({
+
+	Deferred: function( func ) {
+		var tuples = [
+				// action, add listener, listener list, final state
+				[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+				[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+				[ "notify", "progress", jQuery.Callbacks("memory") ]
+			],
+			state = "pending",
+			promise = {
+				state: function() {
+					return state;
+				},
+				always: function() {
+					deferred.done( arguments ).fail( arguments );
+					return this;
+				},
+				then: function( /* fnDone, fnFail, fnProgress */ ) {
+					var fns = arguments;
+					return jQuery.Deferred(function( newDefer ) {
+						jQuery.each( tuples, function( i, tuple ) {
+							var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+							// deferred[ done | fail | progress ] for forwarding actions to newDefer
+							deferred[ tuple[1] ](function() {
+								var returned = fn && fn.apply( this, arguments );
+								if ( returned && jQuery.isFunction( returned.promise ) ) {
+									returned.promise()
+										.done( newDefer.resolve )
+										.fail( newDefer.reject )
+										.progress( newDefer.notify );
+								} else {
+									newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
+								}
+							});
+						});
+						fns = null;
+					}).promise();
+				},
+				// Get a promise for this deferred
+				// If obj is provided, the promise aspect is added to the object
+				promise: function( obj ) {
+					return obj != null ? jQuery.extend( obj, promise ) : promise;
+				}
+			},
+			deferred = {};
+
+		// Keep pipe for back-compat
+		promise.pipe = promise.then;
+
+		// Add list-specific methods
+		jQuery.each( tuples, function( i, tuple ) {
+			var list = tuple[ 2 ],
+				stateString = tuple[ 3 ];
+
+			// promise[ done | fail | progress ] = list.add
+			promise[ tuple[1] ] = list.add;
+
+			// Handle state
+			if ( stateString ) {
+				list.add(function() {
+					// state = [ resolved | rejected ]
+					state = stateString;
+
+				// [ reject_list | resolve_list ].disable; progress_list.lock
+				}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+			}
+
+			// deferred[ resolve | reject | notify ]
+			deferred[ tuple[0] ] = function() {
+				deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
+				return this;
+			};
+			deferred[ tuple[0] + "With" ] = list.fireWith;
+		});
+
+		// Make the deferred a promise
+		promise.promise( deferred );
+
+		// Call given func if any
+		if ( func ) {
+			func.call( deferred, deferred );
+		}
+
+		// All done!
+		return deferred;
+	},
+
+	// Deferred helper
+	when: function( subordinate /* , ..., subordinateN */ ) {
+		var i = 0,
+			resolveValues = slice.call( arguments ),
+			length = resolveValues.length,
+
+			// the count of uncompleted subordinates
+			remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+			// the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+			deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+			// Update function for both resolve and progress values
+			updateFunc = function( i, contexts, values ) {
+				return function( value ) {
+					contexts[ i ] = this;
+					values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
+					if ( values === progressValues ) {
+						deferred.notifyWith( contexts, values );
+					} else if ( !( --remaining ) ) {
+						deferred.resolveWith( contexts, values );
+					}
+				};
+			},
+
+			progressValues, progressContexts, resolveContexts;
+
+		// Add listeners to Deferred subordinates; treat others as resolved
+		if ( length > 1 ) {
+			progressValues = new Array( length );
+			progressContexts = new Array( length );
+			resolveContexts = new Array( length );
+			for ( ; i < length; i++ ) {
+				if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+					resolveValues[ i ].promise()
+						.done( updateFunc( i, resolveContexts, resolveValues ) )
+						.fail( deferred.reject )
+						.progress( updateFunc( i, progressContexts, progressValues ) );
+				} else {
+					--remaining;
+				}
+			}
+		}
+
+		// If we're not waiting on anything, resolve the master
+		if ( !remaining ) {
+			deferred.resolveWith( resolveContexts, resolveValues );
+		}
+
+		return deferred.promise();
+	}
+});
+
+
+// The deferred used on DOM ready
+var readyList;
+
+jQuery.fn.ready = function( fn ) {
+	// Add the callback
+	jQuery.ready.promise().done( fn );
+
+	return this;
+};
+
+jQuery.extend({
+	// Is the DOM ready to be used? Set to true once it occurs.
+	isReady: false,
+
+	// A counter to track how many items to wait for before
+	// the ready event fires. See #6781
+	readyWait: 1,
+
+	// Hold (or release) the ready event
+	holdReady: function( hold ) {
+		if ( hold ) {
+			jQuery.readyWait++;
+		} else {
+			jQuery.ready( true );
+		}
+	},
+
+	// Handle when the DOM is ready
+	ready: function( wait ) {
+
+		// Abort if there are pending holds or we're already ready
+		if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+			return;
+		}
+
+		// Remember that the DOM is ready
+		jQuery.isReady = true;
+
+		// If a normal DOM Ready event fired, decrement, and wait if need be
+		if ( wait !== true && --jQuery.readyWait > 0 ) {
+			return;
+		}
+
+		// If there are functions bound, to execute
+		readyList.resolveWith( document, [ jQuery ] );
+
+		// Trigger any bound ready events
+		if ( jQuery.fn.triggerHandler ) {
+			jQuery( document ).triggerHandler( "ready" );
+			jQuery( document ).off( "ready" );
+		}
+	}
+});
+
+/**
+ * The ready event handler and self cleanup method
+ */
+function completed() {
+	document.removeEventListener( "DOMContentLoaded", completed, false );
+	window.removeEventListener( "load", completed, false );
+	jQuery.ready();
+}
+
+jQuery.ready.promise = function( obj ) {
+	if ( !readyList ) {
+
+		readyList = jQuery.Deferred();
+
+		// Catch cases where $(document).ready() is called after the browser event has already occurred.
+		// We once tried to use readyState "interactive" here, but it caused issues like the one
+		// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+		if ( document.readyState === "complete" ) {
+			// Handle it asynchronously to allow scripts the opportunity to delay ready
+			setTimeout( jQuery.ready );
+
+		} else {
+
+			// Use the handy event callback
+			document.addEventListener( "DOMContentLoaded", completed, false );
+
+			// A fallback to window.onload, that will always work
+			window.addEventListener( "load", completed, false );
+		}
+	}
+	return readyList.promise( obj );
+};
+
+// Kick off the DOM ready check even if the user does not
+jQuery.ready.promise();
+
+
+
+
+// Multifunctional method to get and set values of a collection
+// The value/s can optionally be executed if it's a function
+var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
+	var i = 0,
+		len = elems.length,
+		bulk = key == null;
+
+	// Sets many values
+	if ( jQuery.type( key ) === "object" ) {
+		chainable = true;
+		for ( i in key ) {
+			jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
+		}
+
+	// Sets one value
+	} else if ( value !== undefined ) {
+		chainable = true;
+
+		if ( !jQuery.isFunction( value ) ) {
+			raw = true;
+		}
+
+		if ( bulk ) {
+			// Bulk operations run against the entire set
+			if ( raw ) {
+				fn.call( elems, value );
+				fn = null;
+
+			// ...except when executing function values
+			} else {
+				bulk = fn;
+				fn = function( elem, key, value ) {
+					return bulk.call( jQuery( elem ), value );
+				};
+			}
+		}
+
+		if ( fn ) {
+			for ( ; i < len; i++ ) {
+				fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
+			}
+		}
+	}
+
+	return chainable ?
+		elems :
+
+		// Gets
+		bulk ?
+			fn.call( elems ) :
+			len ? fn( elems[0], key ) : emptyGet;
+};
+
+
+/**
+ * Determines whether an object can have data
+ */
+jQuery.acceptData = function( owner ) {
+	// Accepts only:
+	//  - Node
+	//    - Node.ELEMENT_NODE
+	//    - Node.DOCUMENT_NODE
+	//  - Object
+	//    - Any
+	/* jshint -W018 */
+	return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
+};
+
+
+function Data() {
+	// Support: Android<4,
+	// Old WebKit does not have Object.preventExtensions/freeze method,
+	// return new empty object instead with no [[set]] accessor
+	Object.defineProperty( this.cache = {}, 0, {
+		get: function() {
+			return {};
+		}
+	});
+
+	this.expando = jQuery.expando + Data.uid++;
+}
+
+Data.uid = 1;
+Data.accepts = jQuery.acceptData;
+
+Data.prototype = {
+	key: function( owner ) {
+		// We can accept data for non-element nodes in modern browsers,
+		// but we should not, see #8335.
+		// Always return the key for a frozen object.
+		if ( !Data.accepts( owner ) ) {
+			return 0;
+		}
+
+		var descriptor = {},
+			// Check if the owner object already has a cache key
+			unlock = owner[ this.expando ];
+
+		// If not, create one
+		if ( !unlock ) {
+			unlock = Data.uid++;
+
+			// Secure it in a non-enumerable, non-writable property
+			try {
+				descriptor[ this.expando ] = { value: unlock };
+				Object.defineProperties( owner, descriptor );
+
+			// Support: Android<4
+			// Fallback to a less secure definition
+			} catch ( e ) {
+				descriptor[ this.expando ] = unlock;
+				jQuery.extend( owner, descriptor );
+			}
+		}
+
+		// Ensure the cache object
+		if ( !this.cache[ unlock ] ) {
+			this.cache[ unlock ] = {};
+		}
+
+		return unlock;
+	},
+	set: function( owner, data, value ) {
+		var prop,
+			// There may be an unlock assigned to this node,
+			// if there is no entry for this "owner", create one inline
+			// and set the unlock as though an owner entry had always existed
+			unlock = this.key( owner ),
+			cache = this.cache[ unlock ];
+
+		// Handle: [ owner, key, value ] args
+		if ( typeof data === "string" ) {
+			cache[ data ] = value;
+
+		// Handle: [ owner, { properties } ] args
+		} else {
+			// Fresh assignments by object are shallow copied
+			if ( jQuery.isEmptyObject( cache ) ) {
+				jQuery.extend( this.cache[ unlock ], data );
+			// Otherwise, copy the properties one-by-one to the cache object
+			} else {
+				for ( prop in data ) {
+					cache[ prop ] = data[ prop ];
+				}
+			}
+		}
+		return cache;
+	},
+	get: function( owner, key ) {
+		// Either a valid cache is found, or will be created.
+		// New caches will be created and the unlock returned,
+		// allowing direct access to the newly created
+		// empty data object. A valid owner object must be provided.
+		var cache = this.cache[ this.key( owner ) ];
+
+		return key === undefined ?
+			cache : cache[ key ];
+	},
+	access: function( owner, key, value ) {
+		var stored;
+		// In cases where either:
+		//
+		//   1. No key was specified
+		//   2. A string key was specified, but no value provided
+		//
+		// Take the "read" path and allow the get method to determine
+		// which value to return, respectively either:
+		//
+		//   1. The entire cache object
+		//   2. The data stored at the key
+		//
+		if ( key === undefined ||
+				((key && typeof key === "string") && value === undefined) ) {
+
+			stored = this.get( owner, key );
+
+			return stored !== undefined ?
+				stored : this.get( owner, jQuery.camelCase(key) );
+		}
+
+		// [*]When the key is not a string, or both a key and value
+		// are specified, set or extend (existing objects) with either:
+		//
+		//   1. An object of properties
+		//   2. A key and value
+		//
+		this.set( owner, key, value );
+
+		// Since the "set" path can have two possible entry points
+		// return the expected data based on which path was taken[*]
+		return value !== undefined ? value : key;
+	},
+	remove: function( owner, key ) {
+		var i, name, camel,
+			unlock = this.key( owner ),
+			cache = this.cache[ unlock ];
+
+		if ( key === undefined ) {
+			this.cache[ unlock ] = {};
+
+		} else {
+			// Support array or space separated string of keys
+			if ( jQuery.isArray( key ) ) {
+				// If "name" is an array of keys...
+				// When data is initially created, via ("key", "val") signature,
+				// keys will be converted to camelCase.
+				// Since there is no way to tell _how_ a key was added, remove
+				// both plain key and camelCase key. #12786
+				// This will only penalize the array argument path.
+				name = key.concat( key.map( jQuery.camelCase ) );
+			} else {
+				camel = jQuery.camelCase( key );
+				// Try the string as a key before any manipulation
+				if ( key in cache ) {
+					name = [ key, camel ];
+				} else {
+					// If a key with the spaces exists, use it.
+					// Otherwise, create an array by matching non-whitespace
+					name = camel;
+					name = name in cache ?
+						[ name ] : ( name.match( rnotwhite ) || [] );
+				}
+			}
+
+			i = name.length;
+			while ( i-- ) {
+				delete cache[ name[ i ] ];
+			}
+		}
+	},
+	hasData: function( owner ) {
+		return !jQuery.isEmptyObject(
+			this.cache[ owner[ this.expando ] ] || {}
+		);
+	},
+	discard: function( owner ) {
+		if ( owner[ this.expando ] ) {
+			delete this.cache[ owner[ this.expando ] ];
+		}
+	}
+};
+var data_priv = new Data();
+
+var data_user = new Data();
+
+
+
+//	Implementation Summary
+//
+//	1. Enforce API surface and semantic compatibility with 1.9.x branch
+//	2. Improve the module's maintainability by reducing the storage
+//		paths to a single mechanism.
+//	3. Use the same single mechanism to support "private" and "user" data.
+//	4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
+//	5. Avoid exposing implementation details on user objects (eg. expando properties)
+//	6. Provide a clear path for implementation upgrade to WeakMap in 2014
+
+var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
+	rmultiDash = /([A-Z])/g;
+
+function dataAttr( elem, key, data ) {
+	var name;
+
+	// If nothing was found internally, try to fetch any
+	// data from the HTML5 data-* attribute
+	if ( data === undefined && elem.nodeType === 1 ) {
+		name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+		data = elem.getAttribute( name );
+
+		if ( typeof data === "string" ) {
+			try {
+				data = data === "true" ? true :
+					data === "false" ? false :
+					data === "null" ? null :
+					// Only convert to a number if it doesn't change the string
+					+data + "" === data ? +data :
+					rbrace.test( data ) ? jQuery.parseJSON( data ) :
+					data;
+			} catch( e ) {}
+
+			// Make sure we set the data so it isn't changed later
+			data_user.set( elem, key, data );
+		} else {
+			data = undefined;
+		}
+	}
+	return data;
+}
+
+jQuery.extend({
+	hasData: function( elem ) {
+		return data_user.hasData( elem ) || data_priv.hasData( elem );
+	},
+
+	data: function( elem, name, data ) {
+		return data_user.access( elem, name, data );
+	},
+
+	removeData: function( elem, name ) {
+		data_user.remove( elem, name );
+	},
+
+	// TODO: Now that all calls to _data and _removeData have been replaced
+	// with direct calls to data_priv methods, these can be deprecated.
+	_data: function( elem, name, data ) {
+		return data_priv.access( elem, name, data );
+	},
+
+	_removeData: function( elem, name ) {
+		data_priv.remove( elem, name );
+	}
+});
+
+jQuery.fn.extend({
+	data: function( key, value ) {
+		var i, name, data,
+			elem = this[ 0 ],
+			attrs = elem && elem.attributes;
+
+		// Gets all values
+		if ( key === undefined ) {
+			if ( this.length ) {
+				data = data_user.get( elem );
+
+				if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) {
+					i = attrs.length;
+					while ( i-- ) {
+
+						// Support: IE11+
+						// The attrs elements can be null (#14894)
+						if ( attrs[ i ] ) {
+							name = attrs[ i ].name;
+							if ( name.indexOf( "data-" ) === 0 ) {
+								name = jQuery.camelCase( name.slice(5) );
+								dataAttr( elem, name, data[ name ] );
+							}
+						}
+					}
+					data_priv.set( elem, "hasDataAttrs", true );
+				}
+			}
+
+			return data;
+		}
+
+		// Sets multiple values
+		if ( typeof key === "object" ) {
+			return this.each(function() {
+				data_user.set( this, key );
+			});
+		}
+
+		return access( this, function( value ) {
+			var data,
+				camelKey = jQuery.camelCase( key );
+
+			// The calling jQuery object (element matches) is not empty
+			// (and therefore has an element appears at this[ 0 ]) and the
+			// `value` parameter was not undefined. An empty jQuery object
+			// will result in `undefined` for elem = this[ 0 ] which will
+			// throw an exception if an attempt to read a data cache is made.
+			if ( elem && value === undefined ) {
+				// Attempt to get data from the cache
+				// with the key as-is
+				data = data_user.get( elem, key );
+				if ( data !== undefined ) {
+					return data;
+				}
+
+				// Attempt to get data from the cache
+				// with the key camelized
+				data = data_user.get( elem, camelKey );
+				if ( data !== undefined ) {
+					return data;
+				}
+
+				// Attempt to "discover" the data in
+				// HTML5 custom data-* attrs
+				data = dataAttr( elem, camelKey, undefined );
+				if ( data !== undefined ) {
+					return data;
+				}
+
+				// We tried really hard, but the data doesn't exist.
+				return;
+			}
+
+			// Set the data...
+			this.each(function() {
+				// First, attempt to store a copy or reference of any
+				// data that might've been store with a camelCased key.
+				var data = data_user.get( this, camelKey );
+
+				// For HTML5 data-* attribute interop, we have to
+				// store property names with dashes in a camelCase form.
+				// This might not apply to all properties...*
+				data_user.set( this, camelKey, value );
+
+				// *... In the case of properties that might _actually_
+				// have dashes, we need to also store a copy of that
+				// unchanged property.
+				if ( key.indexOf("-") !== -1 && data !== undefined ) {
+					data_user.set( this, key, value );
+				}
+			});
+		}, null, value, arguments.length > 1, null, true );
+	},
+
+	removeData: function( key ) {
+		return this.each(function() {
+			data_user.remove( this, key );
+		});
+	}
+});
+
+
+jQuery.extend({
+	queue: function( elem, type, data ) {
+		var queue;
+
+		if ( elem ) {
+			type = ( type || "fx" ) + "queue";
+			queue = data_priv.get( elem, type );
+
+			// Speed up dequeue by getting out quickly if this is just a lookup
+			if ( data ) {
+				if ( !queue || jQuery.isArray( data ) ) {
+					queue = data_priv.access( elem, type, jQuery.makeArray(data) );
+				} else {
+					queue.push( data );
+				}
+			}
+			return queue || [];
+		}
+	},
+
+	dequeue: function( elem, type ) {
+		type = type || "fx";
+
+		var queue = jQuery.queue( elem, type ),
+			startLength = queue.length,
+			fn = queue.shift(),
+			hooks = jQuery._queueHooks( elem, type ),
+			next = function() {
+				jQuery.dequeue( elem, type );
+			};
+
+		// If the fx queue is dequeued, always remove the progress sentinel
+		if ( fn === "inprogress" ) {
+			fn = queue.shift();
+			startLength--;
+		}
+
+		if ( fn ) {
+
+			// Add a progress sentinel to prevent the fx queue from being
+			// automatically dequeued
+			if ( type === "fx" ) {
+				queue.unshift( "inprogress" );
+			}
+
+			// Clear up the last queue stop function
+			delete hooks.stop;
+			fn.call( elem, next, hooks );
+		}
+
+		if ( !startLength && hooks ) {
+			hooks.empty.fire();
+		}
+	},
+
+	// Not public - generate a queueHooks object, or return the current one
+	_queueHooks: function( elem, type ) {
+		var key = type + "queueHooks";
+		return data_priv.get( elem, key ) || data_priv.access( elem, key, {
+			empty: jQuery.Callbacks("once memory").add(function() {
+				data_priv.remove( elem, [ type + "queue", key ] );
+			})
+		});
+	}
+});
+
+jQuery.fn.extend({
+	queue: function( type, data ) {
+		var setter = 2;
+
+		if ( typeof type !== "string" ) {
+			data = type;
+			type = "fx";
+			setter--;
+		}
+
+		if ( arguments.length < setter ) {
+			return jQuery.queue( this[0], type );
+		}
+
+		return data === undefined ?
+			this :
+			this.each(function() {
+				var queue = jQuery.queue( this, type, data );
+
+				// Ensure a hooks for this queue
+				jQuery._queueHooks( this, type );
+
+				if ( type === "fx" && queue[0] !== "inprogress" ) {
+					jQuery.dequeue( this, type );
+				}
+			});
+	},
+	dequeue: function( type ) {
+		return this.each(function() {
+			jQuery.dequeue( this, type );
+		});
+	},
+	clearQueue: function( type ) {
+		return this.queue( type || "fx", [] );
+	},
+	// Get a promise resolved when queues of a certain type
+	// are emptied (fx is the type by default)
+	promise: function( type, obj ) {
+		var tmp,
+			count = 1,
+			defer = jQuery.Deferred(),
+			elements = this,
+			i = this.length,
+			resolve = function() {
+				if ( !( --count ) ) {
+					defer.resolveWith( elements, [ elements ] );
+				}
+			};
+
+		if ( typeof type !== "string" ) {
+			obj = type;
+			type = undefined;
+		}
+		type = type || "fx";
+
+		while ( i-- ) {
+			tmp = data_priv.get( elements[ i ], type + "queueHooks" );
+			if ( tmp && tmp.empty ) {
+				count++;
+				tmp.empty.add( resolve );
+			}
+		}
+		resolve();
+		return defer.promise( obj );
+	}
+});
+var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
+
+var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
+
+var isHidden = function( elem, el ) {
+		// isHidden might be called from jQuery#filter function;
+		// in that case, element will be second argument
+		elem = el || elem;
+		return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+	};
+
+var rcheckableType = (/^(?:checkbox|radio)$/i);
+
+
+
+(function() {
+	var fragment = document.createDocumentFragment(),
+		div = fragment.appendChild( document.createElement( "div" ) ),
+		input = document.createElement( "input" );
+
+	// Support: Safari<=5.1
+	// Check state lost if the name is set (#11217)
+	// Support: Windows Web Apps (WWA)
+	// `name` and `type` must use .setAttribute for WWA (#14901)
+	input.setAttribute( "type", "radio" );
+	input.setAttribute( "checked", "checked" );
+	input.setAttribute( "name", "t" );
+
+	div.appendChild( input );
+
+	// Support: Safari<=5.1, Android<4.2
+	// Older WebKit doesn't clone checked state correctly in fragments
+	support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+	// Support: IE<=11+
+	// Make sure textarea (and checkbox) defaultValue is properly cloned
+	div.innerHTML = "<textarea>x</textarea>";
+	support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
+})();
+var strundefined = typeof undefined;
+
+
+
+support.focusinBubbles = "onfocusin" in window;
+
+
+var
+	rkeyEvent = /^key/,
+	rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
+	rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+	rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+
+function returnTrue() {
+	return true;
+}
+
+function returnFalse() {
+	return false;
+}
+
+function safeActiveElement() {
+	try {
+		return document.activeElement;
+	} catch ( err ) { }
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+	global: {},
+
+	add: function( elem, types, handler, data, selector ) {
+
+		var handleObjIn, eventHandle, tmp,
+			events, t, handleObj,
+			special, handlers, type, namespaces, origType,
+			elemData = data_priv.get( elem );
+
+		// Don't attach events to noData or text/comment nodes (but allow plain objects)
+		if ( !elemData ) {
+			return;
+		}
+
+		// Caller can pass in an object of custom data in lieu of the handler
+		if ( handler.handler ) {
+			handleObjIn = handler;
+			handler = handleObjIn.handler;
+			selector = handleObjIn.selector;
+		}
+
+		// Make sure that the handler has a unique ID, used to find/remove it later
+		if ( !handler.guid ) {
+			handler.guid = jQuery.guid++;
+		}
+
+		// Init the element's event structure and main handler, if this is the first
+		if ( !(events = elemData.events) ) {
+			events = elemData.events = {};
+		}
+		if ( !(eventHandle = elemData.handle) ) {
+			eventHandle = elemData.handle = function( e ) {
+				// Discard the second event of a jQuery.event.trigger() and
+				// when an event is called after a page has unloaded
+				return typeof jQuery !== strundefined && jQuery.event.triggered !== e.type ?
+					jQuery.event.dispatch.apply( elem, arguments ) : undefined;
+			};
+		}
+
+		// Handle multiple events separated by a space
+		types = ( types || "" ).match( rnotwhite ) || [ "" ];
+		t = types.length;
+		while ( t-- ) {
+			tmp = rtypenamespace.exec( types[t] ) || [];
+			type = origType = tmp[1];
+			namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+			// There *must* be a type, no attaching namespace-only handlers
+			if ( !type ) {
+				continue;
+			}
+
+			// If event changes its type, use the special event handlers for the changed type
+			special = jQuery.event.special[ type ] || {};
+
+			// If selector defined, determine special event api type, otherwise given type
+			type = ( selector ? special.delegateType : special.bindType ) || type;
+
+			// Update special based on newly reset type
+			special = jQuery.event.special[ type ] || {};
+
+			// handleObj is passed to all event handlers
+			handleObj = jQuery.extend({
+				type: type,
+				origType: origType,
+				data: data,
+				handler: handler,
+				guid: handler.guid,
+				selector: selector,
+				needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+				namespace: namespaces.join(".")
+			}, handleObjIn );
+
+			// Init the event handler queue if we're the first
+			if ( !(handlers = events[ type ]) ) {
+				handlers = events[ type ] = [];
+				handlers.delegateCount = 0;
+
+				// Only use addEventListener if the special events handler returns false
+				if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+					if ( elem.addEventListener ) {
+						elem.addEventListener( type, eventHandle, false );
+					}
+				}
+			}
+
+			if ( special.add ) {
+				special.add.call( elem, handleObj );
+
+				if ( !handleObj.handler.guid ) {
+					handleObj.handler.guid = handler.guid;
+				}
+			}
+
+			// Add to the element's handler list, delegates in front
+			if ( selector ) {
+				handlers.splice( handlers.delegateCount++, 0, handleObj );
+			} else {
+				handlers.push( handleObj );
+			}
+
+			// Keep track of which events have ever been used, for event optimization
+			jQuery.event.global[ type ] = true;
+		}
+
+	},
+
+	// Detach an event or set of events from an element
+	remove: function( elem, types, handler, selector, mappedTypes ) {
+
+		var j, origCount, tmp,
+			events, t, handleObj,
+			special, handlers, type, namespaces, origType,
+			elemData = data_priv.hasData( elem ) && data_priv.get( elem );
+
+		if ( !elemData || !(events = elemData.events) ) {
+			return;
+		}
+
+		// Once for each type.namespace in types; type may be omitted
+		types = ( types || "" ).match( rnotwhite ) || [ "" ];
+		t = types.length;
+		while ( t-- ) {
+			tmp = rtypenamespace.exec( types[t] ) || [];
+			type = origType = tmp[1];
+			namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+			// Unbind all events (on this namespace, if provided) for the element
+			if ( !type ) {
+				for ( type in events ) {
+					jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+				}
+				continue;
+			}
+
+			special = jQuery.event.special[ type ] || {};
+			type = ( selector ? special.delegateType : special.bindType ) || type;
+			handlers = events[ type ] || [];
+			tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+
+			// Remove matching events
+			origCount = j = handlers.length;
+			while ( j-- ) {
+				handleObj = handlers[ j ];
+
+				if ( ( mappedTypes || origType === handleObj.origType ) &&
+					( !handler || handler.guid === handleObj.guid ) &&
+					( !tmp || tmp.test( handleObj.namespace ) ) &&
+					( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+					handlers.splice( j, 1 );
+
+					if ( handleObj.selector ) {
+						handlers.delegateCount--;
+					}
+					if ( special.remove ) {
+						special.remove.call( elem, handleObj );
+					}
+				}
+			}
+
+			// Remove generic event handler if we removed something and no more handlers exist
+			// (avoids potential for endless recursion during removal of special event handlers)
+			if ( origCount && !handlers.length ) {
+				if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+					jQuery.removeEvent( elem, type, elemData.handle );
+				}
+
+				delete events[ type ];
+			}
+		}
+
+		// Remove the expando if it's no longer used
+		if ( jQuery.isEmptyObject( events ) ) {
+			delete elemData.handle;
+			data_priv.remove( elem, "events" );
+		}
+	},
+
+	trigger: function( event, data, elem, onlyHandlers ) {
+
+		var i, cur, tmp, bubbleType, ontype, handle, special,
+			eventPath = [ elem || document ],
+			type = hasOwn.call( event, "type" ) ? event.type : event,
+			namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
+
+		cur = tmp = elem = elem || document;
+
+		// Don't do events on text and comment nodes
+		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+			return;
+		}
+
+		// focus/blur morphs to focusin/out; ensure we're not firing them right now
+		if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+			return;
+		}
+
+		if ( type.indexOf(".") >= 0 ) {
+			// Namespaced trigger; create a regexp to match event type in handle()
+			namespaces = type.split(".");
+			type = namespaces.shift();
+			namespaces.sort();
+		}
+		ontype = type.indexOf(":") < 0 && "on" + type;
+
+		// Caller can pass in a jQuery.Event object, Object, or just an event type string
+		event = event[ jQuery.expando ] ?
+			event :
+			new jQuery.Event( type, typeof event === "object" && event );
+
+		// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+		event.isTrigger = onlyHandlers ? 2 : 3;
+		event.namespace = namespaces.join(".");
+		event.namespace_re = event.namespace ?
+			new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
+			null;
+
+		// Clean up the event in case it is being reused
+		event.result = undefined;
+		if ( !event.target ) {
+			event.target = elem;
+		}
+
+		// Clone any incoming data and prepend the event, creating the handler arg list
+		data = data == null ?
+			[ event ] :
+			jQuery.makeArray( data, [ event ] );
+
+		// Allow special events to draw outside the lines
+		special = jQuery.event.special[ type ] || {};
+		if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+			return;
+		}
+
+		// Determine event propagation path in advance, per W3C events spec (#9951)
+		// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+		if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+			bubbleType = special.delegateType || type;
+			if ( !rfocusMorph.test( bubbleType + type ) ) {
+				cur = cur.parentNode;
+			}
+			for ( ; cur; cur = cur.parentNode ) {
+				eventPath.push( cur );
+				tmp = cur;
+			}
+
+			// Only add window if we got to document (e.g., not plain obj or detached DOM)
+			if ( tmp === (elem.ownerDocument || document) ) {
+				eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+			}
+		}
+
+		// Fire handlers on the event path
+		i = 0;
+		while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
+
+			event.type = i > 1 ?
+				bubbleType :
+				special.bindType || type;
+
+			// jQuery handler
+			handle = ( data_priv.get( cur, "events" ) || {} )[ event.type ] && data_priv.get( cur, "handle" );
+			if ( handle ) {
+				handle.apply( cur, data );
+			}
+
+			// Native handler
+			handle = ontype && cur[ ontype ];
+			if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
+				event.result = handle.apply( cur, data );
+				if ( event.result === false ) {
+					event.preventDefault();
+				}
+			}
+		}
+		event.type = type;
+
+		// If nobody prevented the default action, do it now
+		if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+			if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
+				jQuery.acceptData( elem ) ) {
+
+				// Call a native DOM method on the target with the same name name as the event.
+				// Don't do default actions on window, that's where global variables be (#6170)
+				if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
+
+					// Don't re-trigger an onFOO event when we call its FOO() method
+					tmp = elem[ ontype ];
+
+					if ( tmp ) {
+						elem[ ontype ] = null;
+					}
+
+					// Prevent re-triggering of the same event, since we already bubbled it above
+					jQuery.event.triggered = type;
+					elem[ type ]();
+					jQuery.event.triggered = undefined;
+
+					if ( tmp ) {
+						elem[ ontype ] = tmp;
+					}
+				}
+			}
+		}
+
+		return event.result;
+	},
+
+	dispatch: function( event ) {
+
+		// Make a writable jQuery.Event from the native event object
+		event = jQuery.event.fix( event );
+
+		var i, j, ret, matched, handleObj,
+			handlerQueue = [],
+			args = slice.call( arguments ),
+			handlers = ( data_priv.get( this, "events" ) || {} )[ event.type ] || [],
+			special = jQuery.event.special[ event.type ] || {};
+
+		// Use the fix-ed jQuery.Event rather than the (read-only) native event
+		args[0] = event;
+		event.delegateTarget = this;
+
+		// Call the preDispatch hook for the mapped type, and let it bail if desired
+		if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+			return;
+		}
+
+		// Determine handlers
+		handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+		// Run delegates first; they may want to stop propagation beneath us
+		i = 0;
+		while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
+			event.currentTarget = matched.elem;
+
+			j = 0;
+			while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
+
+				// Triggered event must either 1) have no namespace, or 2) have namespace(s)
+				// a subset or equal to those in the bound event (both can have no namespace).
+				if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
+
+					event.handleObj = handleObj;
+					event.data = handleObj.data;
+
+					ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+							.apply( matched.elem, args );
+
+					if ( ret !== undefined ) {
+						if ( (event.result = ret) === false ) {
+							event.preventDefault();
+							event.stopPropagation();
+						}
+					}
+				}
+			}
+		}
+
+		// Call the postDispatch hook for the mapped type
+		if ( special.postDispatch ) {
+			special.postDispatch.call( this, event );
+		}
+
+		return event.result;
+	},
+
+	handlers: function( event, handlers ) {
+		var i, matches, sel, handleObj,
+			handlerQueue = [],
+			delegateCount = handlers.delegateCount,
+			cur = event.target;
+
+		// Find delegate handlers
+		// Black-hole SVG <use> instance trees (#13180)
+		// Avoid non-left-click bubbling in Firefox (#3861)
+		if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
+
+			for ( ; cur !== this; cur = cur.parentNode || this ) {
+
+				// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+				if ( cur.disabled !== true || event.type !== "click" ) {
+					matches = [];
+					for ( i = 0; i < delegateCount; i++ ) {
+						handleObj = handlers[ i ];
+
+						// Don't conflict with Object.prototype properties (#13203)
+						sel = handleObj.selector + " ";
+
+						if ( matches[ sel ] === undefined ) {
+							matches[ sel ] = handleObj.needsContext ?
+								jQuery( sel, this ).index( cur ) >= 0 :
+								jQuery.find( sel, this, null, [ cur ] ).length;
+						}
+						if ( matches[ sel ] ) {
+							matches.push( handleObj );
+						}
+					}
+					if ( matches.length ) {
+						handlerQueue.push({ elem: cur, handlers: matches });
+					}
+				}
+			}
+		}
+
+		// Add the remaining (directly-bound) handlers
+		if ( delegateCount < handlers.length ) {
+			handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
+		}
+
+		return handlerQueue;
+	},
+
+	// Includes some event props shared by KeyEvent and MouseEvent
+	props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+	fixHooks: {},
+
+	keyHooks: {
+		props: "char charCode key keyCode".split(" "),
+		filter: function( event, original ) {
+
+			// Add which for key events
+			if ( event.which == null ) {
+				event.which = original.charCode != null ? original.charCode : original.keyCode;
+			}
+
+			return event;
+		}
+	},
+
+	mouseHooks: {
+		props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+		filter: function( event, original ) {
+			var eventDoc, doc, body,
+				button = original.button;
+
+			// Calculate pageX/Y if missing and clientX/Y available
+			if ( event.pageX == null && original.clientX != null ) {
+				eventDoc = event.target.ownerDocument || document;
+				doc = eventDoc.documentElement;
+				body = eventDoc.body;
+
+				event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+				event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
+			}
+
+			// Add which for click: 1 === left; 2 === middle; 3 === right
+			// Note: button is not normalized, so don't use it
+			if ( !event.which && button !== undefined ) {
+				event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+			}
+
+			return event;
+		}
+	},
+
+	fix: function( event ) {
+		if ( event[ jQuery.expando ] ) {
+			return event;
+		}
+
+		// Create a writable copy of the event object and normalize some properties
+		var i, prop, copy,
+			type = event.type,
+			originalEvent = event,
+			fixHook = this.fixHooks[ type ];
+
+		if ( !fixHook ) {
+			this.fixHooks[ type ] = fixHook =
+				rmouseEvent.test( type ) ? this.mouseHooks :
+				rkeyEvent.test( type ) ? this.keyHooks :
+				{};
+		}
+		copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+		event = new jQuery.Event( originalEvent );
+
+		i = copy.length;
+		while ( i-- ) {
+			prop = copy[ i ];
+			event[ prop ] = originalEvent[ prop ];
+		}
+
+		// Support: Cordova 2.5 (WebKit) (#13255)
+		// All events should have a target; Cordova deviceready doesn't
+		if ( !event.target ) {
+			event.target = document;
+		}
+
+		// Support: Safari 6.0+, Chrome<28
+		// Target should not be a text node (#504, #13143)
+		if ( event.target.nodeType === 3 ) {
+			event.target = event.target.parentNode;
+		}
+
+		return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
+	},
+
+	special: {
+		load: {
+			// Prevent triggered image.load events from bubbling to window.load
+			noBubble: true
+		},
+		focus: {
+			// Fire native event if possible so blur/focus sequence is correct
+			trigger: function() {
+				if ( this !== safeActiveElement() && this.focus ) {
+					this.focus();
+					return false;
+				}
+			},
+			delegateType: "focusin"
+		},
+		blur: {
+			trigger: function() {
+				if ( this === safeActiveElement() && this.blur ) {
+					this.blur();
+					return false;
+				}
+			},
+			delegateType: "focusout"
+		},
+		click: {
+			// For checkbox, fire native event so checked state will be right
+			trigger: function() {
+				if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) {
+					this.click();
+					return false;
+				}
+			},
+
+			// For cross-browser consistency, don't fire native .click() on links
+			_default: function( event ) {
+				return jQuery.nodeName( event.target, "a" );
+			}
+		},
+
+		beforeunload: {
+			postDispatch: function( event ) {
+
+				// Support: Firefox 20+
+				// Firefox doesn't alert if the returnValue field is not set.
+				if ( event.result !== undefined && event.originalEvent ) {
+					event.originalEvent.returnValue = event.result;
+				}
+			}
+		}
+	},
+
+	simulate: function( type, elem, event, bubble ) {
+		// Piggyback on a donor event to simulate a different one.
+		// Fake originalEvent to avoid donor's stopPropagation, but if the
+		// simulated event prevents default then we do the same on the donor.
+		var e = jQuery.extend(
+			new jQuery.Event(),
+			event,
+			{
+				type: type,
+				isSimulated: true,
+				originalEvent: {}
+			}
+		);
+		if ( bubble ) {
+			jQuery.event.trigger( e, null, elem );
+		} else {
+			jQuery.event.dispatch.call( elem, e );
+		}
+		if ( e.isDefaultPrevented() ) {
+			event.preventDefault();
+		}
+	}
+};
+
+jQuery.removeEvent = function( elem, type, handle ) {
+	if ( elem.removeEventListener ) {
+		elem.removeEventListener( type, handle, false );
+	}
+};
+
+jQuery.Event = function( src, props ) {
+	// Allow instantiation without the 'new' keyword
+	if ( !(this instanceof jQuery.Event) ) {
+		return new jQuery.Event( src, props );
+	}
+
+	// Event object
+	if ( src && src.type ) {
+		this.originalEvent = src;
+		this.type = src.type;
+
+		// Events bubbling up the document may have been marked as prevented
+		// by a handler lower down the tree; reflect the correct value.
+		this.isDefaultPrevented = src.defaultPrevented ||
+				src.defaultPrevented === undefined &&
+				// Support: Android<4.0
+				src.returnValue === false ?
+			returnTrue :
+			returnFalse;
+
+	// Event type
+	} else {
+		this.type = src;
+	}
+
+	// Put explicitly provided properties onto the event object
+	if ( props ) {
+		jQuery.extend( this, props );
+	}
+
+	// Create a timestamp if incoming event doesn't have one
+	this.timeStamp = src && src.timeStamp || jQuery.now();
+
+	// Mark it as fixed
+	this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+	isDefaultPrevented: returnFalse,
+	isPropagationStopped: returnFalse,
+	isImmediatePropagationStopped: returnFalse,
+
+	preventDefault: function() {
+		var e = this.originalEvent;
+
+		this.isDefaultPrevented = returnTrue;
+
+		if ( e && e.preventDefault ) {
+			e.preventDefault();
+		}
+	},
+	stopPropagation: function() {
+		var e = this.originalEvent;
+
+		this.isPropagationStopped = returnTrue;
+
+		if ( e && e.stopPropagation ) {
+			e.stopPropagation();
+		}
+	},
+	stopImmediatePropagation: function() {
+		var e = this.originalEvent;
+
+		this.isImmediatePropagationStopped = returnTrue;
+
+		if ( e && e.stopImmediatePropagation ) {
+			e.stopImmediatePropagation();
+		}
+
+		this.stopPropagation();
+	}
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+// Support: Chrome 15+
+jQuery.each({
+	mouseenter: "mouseover",
+	mouseleave: "mouseout",
+	pointerenter: "pointerover",
+	pointerleave: "pointerout"
+}, function( orig, fix ) {
+	jQuery.event.special[ orig ] = {
+		delegateType: fix,
+		bindType: fix,
+
+		handle: function( event ) {
+			var ret,
+				target = this,
+				related = event.relatedTarget,
+				handleObj = event.handleObj;
+
+			// For mousenter/leave call the handler if related is outside the target.
+			// NB: No relatedTarget if the mouse left/entered the browser window
+			if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+				event.type = handleObj.origType;
+				ret = handleObj.handler.apply( this, arguments );
+				event.type = fix;
+			}
+			return ret;
+		}
+	};
+});
+
+// Support: Firefox, Chrome, Safari
+// Create "bubbling" focus and blur events
+if ( !support.focusinBubbles ) {
+	jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+		// Attach a single capturing handler on the document while someone wants focusin/focusout
+		var handler = function( event ) {
+				jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+			};
+
+		jQuery.event.special[ fix ] = {
+			setup: function() {
+				var doc = this.ownerDocument || this,
+					attaches = data_priv.access( doc, fix );
+
+				if ( !attaches ) {
+					doc.addEventListener( orig, handler, true );
+				}
+				data_priv.access( doc, fix, ( attaches || 0 ) + 1 );
+			},
+			teardown: function() {
+				var doc = this.ownerDocument || this,
+					attaches = data_priv.access( doc, fix ) - 1;
+
+				if ( !attaches ) {
+					doc.removeEventListener( orig, handler, true );
+					data_priv.remove( doc, fix );
+
+				} else {
+					data_priv.access( doc, fix, attaches );
+				}
+			}
+		};
+	});
+}
+
+jQuery.fn.extend({
+
+	on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+		var origFn, type;
+
+		// Types can be a map of types/handlers
+		if ( typeof types === "object" ) {
+			// ( types-Object, selector, data )
+			if ( typeof selector !== "string" ) {
+				// ( types-Object, data )
+				data = data || selector;
+				selector = undefined;
+			}
+			for ( type in types ) {
+				this.on( type, selector, data, types[ type ], one );
+			}
+			return this;
+		}
+
+		if ( data == null && fn == null ) {
+			// ( types, fn )
+			fn = selector;
+			data = selector = undefined;
+		} else if ( fn == null ) {
+			if ( typeof selector === "string" ) {
+				// ( types, selector, fn )
+				fn = data;
+				data = undefined;
+			} else {
+				// ( types, data, fn )
+				fn = data;
+				data = selector;
+				selector = undefined;
+			}
+		}
+		if ( fn === false ) {
+			fn = returnFalse;
+		} else if ( !fn ) {
+			return this;
+		}
+
+		if ( one === 1 ) {
+			origFn = fn;
+			fn = function( event ) {
+				// Can use an empty set, since event contains the info
+				jQuery().off( event );
+				return origFn.apply( this, arguments );
+			};
+			// Use same guid so caller can remove using origFn
+			fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+		}
+		return this.each( function() {
+			jQuery.event.add( this, types, fn, data, selector );
+		});
+	},
+	one: function( types, selector, data, fn ) {
+		return this.on( types, selector, data, fn, 1 );
+	},
+	off: function( types, selector, fn ) {
+		var handleObj, type;
+		if ( types && types.preventDefault && types.handleObj ) {
+			// ( event )  dispatched jQuery.Event
+			handleObj = types.handleObj;
+			jQuery( types.delegateTarget ).off(
+				handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+				handleObj.selector,
+				handleObj.handler
+			);
+			return this;
+		}
+		if ( typeof types === "object" ) {
+			// ( types-object [, selector] )
+			for ( type in types ) {
+				this.off( type, selector, types[ type ] );
+			}
+			return this;
+		}
+		if ( selector === false || typeof selector === "function" ) {
+			// ( types [, fn] )
+			fn = selector;
+			selector = undefined;
+		}
+		if ( fn === false ) {
+			fn = returnFalse;
+		}
+		return this.each(function() {
+			jQuery.event.remove( this, types, fn, selector );
+		});
+	},
+
+	trigger: function( type, data ) {
+		return this.each(function() {
+			jQuery.event.trigger( type, data, this );
+		});
+	},
+	triggerHandler: function( type, data ) {
+		var elem = this[0];
+		if ( elem ) {
+			return jQuery.event.trigger( type, data, elem, true );
+		}
+	}
+});
+
+
+var
+	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+	rtagName = /<([\w:]+)/,
+	rhtml = /<|&#?\w+;/,
+	rnoInnerhtml = /<(?:script|style|link)/i,
+	// checked="checked" or checked
+	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+	rscriptType = /^$|\/(?:java|ecma)script/i,
+	rscriptTypeMasked = /^true\/(.*)/,
+	rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
+
+	// We have to close these tags to support XHTML (#13200)
+	wrapMap = {
+
+		// Support: IE9
+		option: [ 1, "<select multiple='multiple'>", "</select>" ],
+
+		thead: [ 1, "<table>", "</table>" ],
+		col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
+		tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+		td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+
+		_default: [ 0, "", "" ]
+	};
+
+// Support: IE9
+wrapMap.optgroup = wrapMap.option;
+
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// Support: 1.x compatibility
+// Manipulating tables requires a tbody
+function manipulationTarget( elem, content ) {
+	return jQuery.nodeName( elem, "table" ) &&
+		jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
+
+		elem.getElementsByTagName("tbody")[0] ||
+			elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
+		elem;
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+	elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
+	return elem;
+}
+function restoreScript( elem ) {
+	var match = rscriptTypeMasked.exec( elem.type );
+
+	if ( match ) {
+		elem.type = match[ 1 ];
+	} else {
+		elem.removeAttribute("type");
+	}
+
+	return elem;
+}
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+	var i = 0,
+		l = elems.length;
+
+	for ( ; i < l; i++ ) {
+		data_priv.set(
+			elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" )
+		);
+	}
+}
+
+function cloneCopyEvent( src, dest ) {
+	var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
+
+	if ( dest.nodeType !== 1 ) {
+		return;
+	}
+
+	// 1. Copy private data: events, handlers, etc.
+	if ( data_priv.hasData( src ) ) {
+		pdataOld = data_priv.access( src );
+		pdataCur = data_priv.set( dest, pdataOld );
+		events = pdataOld.events;
+
+		if ( events ) {
+			delete pdataCur.handle;
+			pdataCur.events = {};
+
+			for ( type in events ) {
+				for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+					jQuery.event.add( dest, type, events[ type ][ i ] );
+				}
+			}
+		}
+	}
+
+	// 2. Copy user data
+	if ( data_user.hasData( src ) ) {
+		udataOld = data_user.access( src );
+		udataCur = jQuery.extend( {}, udataOld );
+
+		data_user.set( dest, udataCur );
+	}
+}
+
+function getAll( context, tag ) {
+	var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) :
+			context.querySelectorAll ? context.querySelectorAll( tag || "*" ) :
+			[];
+
+	return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+		jQuery.merge( [ context ], ret ) :
+		ret;
+}
+
+// Fix IE bugs, see support tests
+function fixInput( src, dest ) {
+	var nodeName = dest.nodeName.toLowerCase();
+
+	// Fails to persist the checked state of a cloned checkbox or radio button.
+	if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
+		dest.checked = src.checked;
+
+	// Fails to return the selected option to the default selected state when cloning options
+	} else if ( nodeName === "input" || nodeName === "textarea" ) {
+		dest.defaultValue = src.defaultValue;
+	}
+}
+
+jQuery.extend({
+	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+		var i, l, srcElements, destElements,
+			clone = elem.cloneNode( true ),
+			inPage = jQuery.contains( elem.ownerDocument, elem );
+
+		// Fix IE cloning issues
+		if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
+				!jQuery.isXMLDoc( elem ) ) {
+
+			// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
+			destElements = getAll( clone );
+			srcElements = getAll( elem );
+
+			for ( i = 0, l = srcElements.length; i < l; i++ ) {
+				fixInput( srcElements[ i ], destElements[ i ] );
+			}
+		}
+
+		// Copy the events from the original to the clone
+		if ( dataAndEvents ) {
+			if ( deepDataAndEvents ) {
+				srcElements = srcElements || getAll( elem );
+				destElements = destElements || getAll( clone );
+
+				for ( i = 0, l = srcElements.length; i < l; i++ ) {
+					cloneCopyEvent( srcElements[ i ], destElements[ i ] );
+				}
+			} else {
+				cloneCopyEvent( elem, clone );
+			}
+		}
+
+		// Preserve script evaluation history
+		destElements = getAll( clone, "script" );
+		if ( destElements.length > 0 ) {
+			setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+		}
+
+		// Return the cloned set
+		return clone;
+	},
+
+	buildFragment: function( elems, context, scripts, selection ) {
+		var elem, tmp, tag, wrap, contains, j,
+			fragment = context.createDocumentFragment(),
+			nodes = [],
+			i = 0,
+			l = elems.length;
+
+		for ( ; i < l; i++ ) {
+			elem = elems[ i ];
+
+			if ( elem || elem === 0 ) {
+
+				// Add nodes directly
+				if ( jQuery.type( elem ) === "object" ) {
+					// Support: QtWebKit, PhantomJS
+					// push.apply(_, arraylike) throws on ancient WebKit
+					jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+				// Convert non-html into a text node
+				} else if ( !rhtml.test( elem ) ) {
+					nodes.push( context.createTextNode( elem ) );
+
+				// Convert html into DOM nodes
+				} else {
+					tmp = tmp || fragment.appendChild( context.createElement("div") );
+
+					// Deserialize a standard representation
+					tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
+					wrap = wrapMap[ tag ] || wrapMap._default;
+					tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[ 2 ];
+
+					// Descend through wrappers to the right content
+					j = wrap[ 0 ];
+					while ( j-- ) {
+						tmp = tmp.lastChild;
+					}
+
+					// Support: QtWebKit, PhantomJS
+					// push.apply(_, arraylike) throws on ancient WebKit
+					jQuery.merge( nodes, tmp.childNodes );
+
+					// Remember the top-level container
+					tmp = fragment.firstChild;
+
+					// Ensure the created nodes are orphaned (#12392)
+					tmp.textContent = "";
+				}
+			}
+		}
+
+		// Remove wrapper from fragment
+		fragment.textContent = "";
+
+		i = 0;
+		while ( (elem = nodes[ i++ ]) ) {
+
+			// #4087 - If origin and destination elements are the same, and this is
+			// that element, do not do anything
+			if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
+				continue;
+			}
+
+			contains = jQuery.contains( elem.ownerDocument, elem );
+
+			// Append to fragment
+			tmp = getAll( fragment.appendChild( elem ), "script" );
+
+			// Preserve script evaluation history
+			if ( contains ) {
+				setGlobalEval( tmp );
+			}
+
+			// Capture executables
+			if ( scripts ) {
+				j = 0;
+				while ( (elem = tmp[ j++ ]) ) {
+					if ( rscriptType.test( elem.type || "" ) ) {
+						scripts.push( elem );
+					}
+				}
+			}
+		}
+
+		return fragment;
+	},
+
+	cleanData: function( elems ) {
+		var data, elem, type, key,
+			special = jQuery.event.special,
+			i = 0;
+
+		for ( ; (elem = elems[ i ]) !== undefined; i++ ) {
+			if ( jQuery.acceptData( elem ) ) {
+				key = elem[ data_priv.expando ];
+
+				if ( key && (data = data_priv.cache[ key ]) ) {
+					if ( data.events ) {
+						for ( type in data.events ) {
+							if ( special[ type ] ) {
+								jQuery.event.remove( elem, type );
+
+							// This is a shortcut to avoid jQuery.event.remove's overhead
+							} else {
+								jQuery.removeEvent( elem, type, data.handle );
+							}
+						}
+					}
+					if ( data_priv.cache[ key ] ) {
+						// Discard any remaining `private` data
+						delete data_priv.cache[ key ];
+					}
+				}
+			}
+			// Discard any remaining `user` data
+			delete data_user.cache[ elem[ data_user.expando ] ];
+		}
+	}
+});
+
+jQuery.fn.extend({
+	text: function( value ) {
+		return access( this, function( value ) {
+			return value === undefined ?
+				jQuery.text( this ) :
+				this.empty().each(function() {
+					if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+						this.textContent = value;
+					}
+				});
+		}, null, value, arguments.length );
+	},
+
+	append: function() {
+		return this.domManip( arguments, function( elem ) {
+			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+				var target = manipulationTarget( this, elem );
+				target.appendChild( elem );
+			}
+		});
+	},
+
+	prepend: function() {
+		return this.domManip( arguments, function( elem ) {
+			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+				var target = manipulationTarget( this, elem );
+				target.insertBefore( elem, target.firstChild );
+			}
+		});
+	},
+
+	before: function() {
+		return this.domManip( arguments, function( elem ) {
+			if ( this.parentNode ) {
+				this.parentNode.insertBefore( elem, this );
+			}
+		});
+	},
+
+	after: function() {
+		return this.domManip( arguments, function( elem ) {
+			if ( this.parentNode ) {
+				this.parentNode.insertBefore( elem, this.nextSibling );
+			}
+		});
+	},
+
+	remove: function( selector, keepData /* Internal Use Only */ ) {
+		var elem,
+			elems = selector ? jQuery.filter( selector, this ) : this,
+			i = 0;
+
+		for ( ; (elem = elems[i]) != null; i++ ) {
+			if ( !keepData && elem.nodeType === 1 ) {
+				jQuery.cleanData( getAll( elem ) );
+			}
+
+			if ( elem.parentNode ) {
+				if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
+					setGlobalEval( getAll( elem, "script" ) );
+				}
+				elem.parentNode.removeChild( elem );
+			}
+		}
+
+		return this;
+	},
+
+	empty: function() {
+		var elem,
+			i = 0;
+
+		for ( ; (elem = this[i]) != null; i++ ) {
+			if ( elem.nodeType === 1 ) {
+
+				// Prevent memory leaks
+				jQuery.cleanData( getAll( elem, false ) );
+
+				// Remove any remaining nodes
+				elem.textContent = "";
+			}
+		}
+
+		return this;
+	},
+
+	clone: function( dataAndEvents, deepDataAndEvents ) {
+		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+		return this.map(function() {
+			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+		});
+	},
+
+	html: function( value ) {
+		return access( this, function( value ) {
+			var elem = this[ 0 ] || {},
+				i = 0,
+				l = this.length;
+
+			if ( value === undefined && elem.nodeType === 1 ) {
+				return elem.innerHTML;
+			}
+
+			// See if we can take a shortcut and just use innerHTML
+			if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+				!wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
+
+				value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+				try {
+					for ( ; i < l; i++ ) {
+						elem = this[ i ] || {};
+
+						// Remove element nodes and prevent memory leaks
+						if ( elem.nodeType === 1 ) {
+							jQuery.cleanData( getAll( elem, false ) );
+							elem.innerHTML = value;
+						}
+					}
+
+					elem = 0;
+
+				// If using innerHTML throws an exception, use the fallback method
+				} catch( e ) {}
+			}
+
+			if ( elem ) {
+				this.empty().append( value );
+			}
+		}, null, value, arguments.length );
+	},
+
+	replaceWith: function() {
+		var arg = arguments[ 0 ];
+
+		// Make the changes, replacing each context element with the new content
+		this.domManip( arguments, function( elem ) {
+			arg = this.parentNode;
+
+			jQuery.cleanData( getAll( this ) );
+
+			if ( arg ) {
+				arg.replaceChild( elem, this );
+			}
+		});
+
+		// Force removal if there was no new content (e.g., from empty arguments)
+		return arg && (arg.length || arg.nodeType) ? this : this.remove();
+	},
+
+	detach: function( selector ) {
+		return this.remove( selector, true );
+	},
+
+	domManip: function( args, callback ) {
+
+		// Flatten any nested arrays
+		args = concat.apply( [], args );
+
+		var fragment, first, scripts, hasScripts, node, doc,
+			i = 0,
+			l = this.length,
+			set = this,
+			iNoClone = l - 1,
+			value = args[ 0 ],
+			isFunction = jQuery.isFunction( value );
+
+		// We can't cloneNode fragments that contain checked, in WebKit
+		if ( isFunction ||
+				( l > 1 && typeof value === "string" &&
+					!support.checkClone && rchecked.test( value ) ) ) {
+			return this.each(function( index ) {
+				var self = set.eq( index );
+				if ( isFunction ) {
+					args[ 0 ] = value.call( this, index, self.html() );
+				}
+				self.domManip( args, callback );
+			});
+		}
+
+		if ( l ) {
+			fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
+			first = fragment.firstChild;
+
+			if ( fragment.childNodes.length === 1 ) {
+				fragment = first;
+			}
+
+			if ( first ) {
+				scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+				hasScripts = scripts.length;
+
+				// Use the original fragment for the last item instead of the first because it can end up
+				// being emptied incorrectly in certain situations (#8070).
+				for ( ; i < l; i++ ) {
+					node = fragment;
+
+					if ( i !== iNoClone ) {
+						node = jQuery.clone( node, true, true );
+
+						// Keep references to cloned scripts for later restoration
+						if ( hasScripts ) {
+							// Support: QtWebKit
+							// jQuery.merge because push.apply(_, arraylike) throws
+							jQuery.merge( scripts, getAll( node, "script" ) );
+						}
+					}
+
+					callback.call( this[ i ], node, i );
+				}
+
+				if ( hasScripts ) {
+					doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+					// Reenable scripts
+					jQuery.map( scripts, restoreScript );
+
+					// Evaluate executable scripts on first document insertion
+					for ( i = 0; i < hasScripts; i++ ) {
+						node = scripts[ i ];
+						if ( rscriptType.test( node.type || "" ) &&
+							!data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
+
+							if ( node.src ) {
+								// Optional AJAX dependency, but won't run scripts if not present
+								if ( jQuery._evalUrl ) {
+									jQuery._evalUrl( node.src );
+								}
+							} else {
+								jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
+							}
+						}
+					}
+				}
+			}
+		}
+
+		return this;
+	}
+});
+
+jQuery.each({
+	appendTo: "append",
+	prependTo: "prepend",
+	insertBefore: "before",
+	insertAfter: "after",
+	replaceAll: "replaceWith"
+}, function( name, original ) {
+	jQuery.fn[ name ] = function( selector ) {
+		var elems,
+			ret = [],
+			insert = jQuery( selector ),
+			last = insert.length - 1,
+			i = 0;
+
+		for ( ; i <= last; i++ ) {
+			elems = i === last ? this : this.clone( true );
+			jQuery( insert[ i ] )[ original ]( elems );
+
+			// Support: QtWebKit
+			// .get() because push.apply(_, arraylike) throws
+			push.apply( ret, elems.get() );
+		}
+
+		return this.pushStack( ret );
+	};
+});
+
+
+var iframe,
+	elemdisplay = {};
+
+/**
+ * Retrieve the actual display of a element
+ * @param {String} name nodeName of the element
+ * @param {Object} doc Document object
+ */
+// Called only from within defaultDisplay
+function actualDisplay( name, doc ) {
+	var style,
+		elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
+
+		// getDefaultComputedStyle might be reliably used only on attached element
+		display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?
+
+			// Use of this method is a temporary fix (more like optimization) until something better comes along,
+			// since it was removed from specification and supported only in FF
+			style.display : jQuery.css( elem[ 0 ], "display" );
+
+	// We don't have any data stored on the element,
+	// so use "detach" method as fast way to get rid of the element
+	elem.detach();
+
+	return display;
+}
+
+/**
+ * Try to determine the default display value of an element
+ * @param {String} nodeName
+ */
+function defaultDisplay( nodeName ) {
+	var doc = document,
+		display = elemdisplay[ nodeName ];
+
+	if ( !display ) {
+		display = actualDisplay( nodeName, doc );
+
+		// If the simple way fails, read from inside an iframe
+		if ( display === "none" || !display ) {
+
+			// Use the already-created iframe if possible
+			iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" )).appendTo( doc.documentElement );
+
+			// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
+			doc = iframe[ 0 ].contentDocument;
+
+			// Support: IE
+			doc.write();
+			doc.close();
+
+			display = actualDisplay( nodeName, doc );
+			iframe.detach();
+		}
+
+		// Store the correct default display
+		elemdisplay[ nodeName ] = display;
+	}
+
+	return display;
+}
+var rmargin = (/^margin/);
+
+var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
+
+var getStyles = function( elem ) {
+		// Support: IE<=11+, Firefox<=30+ (#15098, #14150)
+		// IE throws on elements created in popups
+		// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
+		if ( elem.ownerDocument.defaultView.opener ) {
+			return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
+		}
+
+		return window.getComputedStyle( elem, null );
+	};
+
+
+
+function curCSS( elem, name, computed ) {
+	var width, minWidth, maxWidth, ret,
+		style = elem.style;
+
+	computed = computed || getStyles( elem );
+
+	// Support: IE9
+	// getPropertyValue is only needed for .css('filter') (#12537)
+	if ( computed ) {
+		ret = computed.getPropertyValue( name ) || computed[ name ];
+	}
+
+	if ( computed ) {
+
+		if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+			ret = jQuery.style( elem, name );
+		}
+
+		// Support: iOS < 6
+		// A tribute to the "awesome hack by Dean Edwards"
+		// iOS < 6 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+		// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+		if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+
+			// Remember the original values
+			width = style.width;
+			minWidth = style.minWidth;
+			maxWidth = style.maxWidth;
+
+			// Put in the new values to get a computed value out
+			style.minWidth = style.maxWidth = style.width = ret;
+			ret = computed.width;
+
+			// Revert the changed values
+			style.width = width;
+			style.minWidth = minWidth;
+			style.maxWidth = maxWidth;
+		}
+	}
+
+	return ret !== undefined ?
+		// Support: IE
+		// IE returns zIndex value as an integer.
+		ret + "" :
+		ret;
+}
+
+
+function addGetHookIf( conditionFn, hookFn ) {
+	// Define the hook, we'll check on the first run if it's really needed.
+	return {
+		get: function() {
+			if ( conditionFn() ) {
+				// Hook not needed (or it's not possible to use it due
+				// to missing dependency), remove it.
+				delete this.get;
+				return;
+			}
+
+			// Hook needed; redefine it so that the support test is not executed again.
+			return (this.get = hookFn).apply( this, arguments );
+		}
+	};
+}
+
+
+(function() {
+	var pixelPositionVal, boxSizingReliableVal,
+		docElem = document.documentElement,
+		container = document.createElement( "div" ),
+		div = document.createElement( "div" );
+
+	if ( !div.style ) {
+		return;
+	}
+
+	// Support: IE9-11+
+	// Style of cloned element affects source element cloned (#8908)
+	div.style.backgroundClip = "content-box";
+	div.cloneNode( true ).style.backgroundClip = "";
+	support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+	container.style.cssText = "border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;" +
+		"position:absolute";
+	container.appendChild( div );
+
+	// Executing both pixelPosition & boxSizingReliable tests require only one layout
+	// so they're executed at the same time to save the second computation.
+	function computePixelPositionAndBoxSizingReliable() {
+		div.style.cssText =
+			// Support: Firefox<29, Android 2.3
+			// Vendor-prefix box-sizing
+			"-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
+			"box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
+			"border:1px;padding:1px;width:4px;position:absolute";
+		div.innerHTML = "";
+		docElem.appendChild( container );
+
+		var divStyle = window.getComputedStyle( div, null );
+		pixelPositionVal = divStyle.top !== "1%";
+		boxSizingReliableVal = divStyle.width === "4px";
+
+		docElem.removeChild( container );
+	}
+
+	// Support: node.js jsdom
+	// Don't assume that getComputedStyle is a property of the global object
+	if ( window.getComputedStyle ) {
+		jQuery.extend( support, {
+			pixelPosition: function() {
+
+				// This test is executed only once but we still do memoizing
+				// since we can use the boxSizingReliable pre-computing.
+				// No need to check if the test was already performed, though.
+				computePixelPositionAndBoxSizingReliable();
+				return pixelPositionVal;
+			},
+			boxSizingReliable: function() {
+				if ( boxSizingReliableVal == null ) {
+					computePixelPositionAndBoxSizingReliable();
+				}
+				return boxSizingReliableVal;
+			},
+			reliableMarginRight: function() {
+
+				// Support: Android 2.3
+				// Check if div with explicit width and no margin-right incorrectly
+				// gets computed margin-right based on width of container. (#3333)
+				// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+				// This support function is only executed once so no memoizing is needed.
+				var ret,
+					marginDiv = div.appendChild( document.createElement( "div" ) );
+
+				// Reset CSS: box-sizing; display; margin; border; padding
+				marginDiv.style.cssText = div.style.cssText =
+					// Support: Firefox<29, Android 2.3
+					// Vendor-prefix box-sizing
+					"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
+					"box-sizing:content-box;display:block;margin:0;border:0;padding:0";
+				marginDiv.style.marginRight = marginDiv.style.width = "0";
+				div.style.width = "1px";
+				docElem.appendChild( container );
+
+				ret = !parseFloat( window.getComputedStyle( marginDiv, null ).marginRight );
+
+				docElem.removeChild( container );
+				div.removeChild( marginDiv );
+
+				return ret;
+			}
+		});
+	}
+})();
+
+
+// A method for quickly swapping in/out CSS properties to get correct calculations.
+jQuery.swap = function( elem, options, callback, args ) {
+	var ret, name,
+		old = {};
+
+	// Remember the old values, and insert the new ones
+	for ( name in options ) {
+		old[ name ] = elem.style[ name ];
+		elem.style[ name ] = options[ name ];
+	}
+
+	ret = callback.apply( elem, args || [] );
+
+	// Revert the old values
+	for ( name in options ) {
+		elem.style[ name ] = old[ name ];
+	}
+
+	return ret;
+};
+
+
+var
+	// Swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+	// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+	rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+	rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
+	rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
+
+	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+	cssNormalTransform = {
+		letterSpacing: "0",
+		fontWeight: "400"
+	},
+
+	cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
+
+// Return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+	// Shortcut for names that are not vendor prefixed
+	if ( name in style ) {
+		return name;
+	}
+
+	// Check for vendor prefixed names
+	var capName = name[0].toUpperCase() + name.slice(1),
+		origName = name,
+		i = cssPrefixes.length;
+
+	while ( i-- ) {
+		name = cssPrefixes[ i ] + capName;
+		if ( name in style ) {
+			return name;
+		}
+	}
+
+	return origName;
+}
+
+function setPositiveNumber( elem, value, subtract ) {
+	var matches = rnumsplit.exec( value );
+	return matches ?
+		// Guard against undefined "subtract", e.g., when used as in cssHooks
+		Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+		value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
+	var i = extra === ( isBorderBox ? "border" : "content" ) ?
+		// If we already have the right measurement, avoid augmentation
+		4 :
+		// Otherwise initialize for horizontal or vertical properties
+		name === "width" ? 1 : 0,
+
+		val = 0;
+
+	for ( ; i < 4; i += 2 ) {
+		// Both box models exclude margin, so add it if we want it
+		if ( extra === "margin" ) {
+			val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
+		}
+
+		if ( isBorderBox ) {
+			// border-box includes padding, so remove it if we want content
+			if ( extra === "content" ) {
+				val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+			}
+
+			// At this point, extra isn't border nor margin, so remove border
+			if ( extra !== "margin" ) {
+				val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+			}
+		} else {
+			// At this point, extra isn't content, so add padding
+			val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+			// At this point, extra isn't content nor padding, so add border
+			if ( extra !== "padding" ) {
+				val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+			}
+		}
+	}
+
+	return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+	// Start with offset property, which is equivalent to the border-box value
+	var valueIsBorderBox = true,
+		val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+		styles = getStyles( elem ),
+		isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+	// Some non-html elements return undefined for offsetWidth, so check for null/undefined
+	// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+	// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+	if ( val <= 0 || val == null ) {
+		// Fall back to computed then uncomputed css if necessary
+		val = curCSS( elem, name, styles );
+		if ( val < 0 || val == null ) {
+			val = elem.style[ name ];
+		}
+
+		// Computed unit is not pixels. Stop here and return.
+		if ( rnumnonpx.test(val) ) {
+			return val;
+		}
+
+		// Check for style in case a browser which returns unreliable values
+		// for getComputedStyle silently falls back to the reliable elem.style
+		valueIsBorderBox = isBorderBox &&
+			( support.boxSizingReliable() || val === elem.style[ name ] );
+
+		// Normalize "", auto, and prepare for extra
+		val = parseFloat( val ) || 0;
+	}
+
+	// Use the active box-sizing model to add/subtract irrelevant styles
+	return ( val +
+		augmentWidthOrHeight(
+			elem,
+			name,
+			extra || ( isBorderBox ? "border" : "content" ),
+			valueIsBorderBox,
+			styles
+		)
+	) + "px";
+}
+
+function showHide( elements, show ) {
+	var display, elem, hidden,
+		values = [],
+		index = 0,
+		length = elements.length;
+
+	for ( ; index < length; index++ ) {
+		elem = elements[ index ];
+		if ( !elem.style ) {
+			continue;
+		}
+
+		values[ index ] = data_priv.get( elem, "olddisplay" );
+		display = elem.style.display;
+		if ( show ) {
+			// Reset the inline display of this element to learn if it is
+			// being hidden by cascaded rules or not
+			if ( !values[ index ] && display === "none" ) {
+				elem.style.display = "";
+			}
+
+			// Set elements which have been overridden with display: none
+			// in a stylesheet to whatever the default browser style is
+			// for such an element
+			if ( elem.style.display === "" && isHidden( elem ) ) {
+				values[ index ] = data_priv.access( elem, "olddisplay", defaultDisplay(elem.nodeName) );
+			}
+		} else {
+			hidden = isHidden( elem );
+
+			if ( display !== "none" || !hidden ) {
+				data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
+			}
+		}
+	}
+
+	// Set the display of most of the elements in a second loop
+	// to avoid the constant reflow
+	for ( index = 0; index < length; index++ ) {
+		elem = elements[ index ];
+		if ( !elem.style ) {
+			continue;
+		}
+		if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+			elem.style.display = show ? values[ index ] || "" : "none";
+		}
+	}
+
+	return elements;
+}
+
+jQuery.extend({
+
+	// Add in style property hooks for overriding the default
+	// behavior of getting and setting a style property
+	cssHooks: {
+		opacity: {
+			get: function( elem, computed ) {
+				if ( computed ) {
+
+					// We should always get a number back from opacity
+					var ret = curCSS( elem, "opacity" );
+					return ret === "" ? "1" : ret;
+				}
+			}
+		}
+	},
+
+	// Don't automatically add "px" to these possibly-unitless properties
+	cssNumber: {
+		"columnCount": true,
+		"fillOpacity": true,
+		"flexGrow": true,
+		"flexShrink": true,
+		"fontWeight": true,
+		"lineHeight": true,
+		"opacity": true,
+		"order": true,
+		"orphans": true,
+		"widows": true,
+		"zIndex": true,
+		"zoom": true
+	},
+
+	// Add in properties whose names you wish to fix before
+	// setting or getting the value
+	cssProps: {
+		"float": "cssFloat"
+	},
+
+	// Get and set the style property on a DOM Node
+	style: function( elem, name, value, extra ) {
+
+		// Don't set styles on text and comment nodes
+		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+			return;
+		}
+
+		// Make sure that we're working with the right name
+		var ret, type, hooks,
+			origName = jQuery.camelCase( name ),
+			style = elem.style;
+
+		name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+		// Gets hook for the prefixed version, then unprefixed version
+		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+		// Check if we're setting a value
+		if ( value !== undefined ) {
+			type = typeof value;
+
+			// Convert "+=" or "-=" to relative numbers (#7345)
+			if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+				value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+				// Fixes bug #9237
+				type = "number";
+			}
+
+			// Make sure that null and NaN values aren't set (#7116)
+			if ( value == null || value !== value ) {
+				return;
+			}
+
+			// If a number, add 'px' to the (except for certain CSS properties)
+			if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+				value += "px";
+			}
+
+			// Support: IE9-11+
+			// background-* props affect original clone's values
+			if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
+				style[ name ] = "inherit";
+			}
+
+			// If a hook was provided, use that value, otherwise just set the specified value
+			if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+				style[ name ] = value;
+			}
+
+		} else {
+			// If a hook was provided get the non-computed value from there
+			if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+				return ret;
+			}
+
+			// Otherwise just get the value from the style object
+			return style[ name ];
+		}
+	},
+
+	css: function( elem, name, extra, styles ) {
+		var val, num, hooks,
+			origName = jQuery.camelCase( name );
+
+		// Make sure that we're working with the right name
+		name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+		// Try prefixed name followed by the unprefixed name
+		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+		// If a hook was provided get the computed value from there
+		if ( hooks && "get" in hooks ) {
+			val = hooks.get( elem, true, extra );
+		}
+
+		// Otherwise, if a way to get the computed value exists, use that
+		if ( val === undefined ) {
+			val = curCSS( elem, name, styles );
+		}
+
+		// Convert "normal" to computed value
+		if ( val === "normal" && name in cssNormalTransform ) {
+			val = cssNormalTransform[ name ];
+		}
+
+		// Make numeric if forced or a qualifier was provided and val looks numeric
+		if ( extra === "" || extra ) {
+			num = parseFloat( val );
+			return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
+		}
+		return val;
+	}
+});
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+	jQuery.cssHooks[ name ] = {
+		get: function( elem, computed, extra ) {
+			if ( computed ) {
+
+				// Certain elements can have dimension info if we invisibly show them
+				// but it must have a current display style that would benefit
+				return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ?
+					jQuery.swap( elem, cssShow, function() {
+						return getWidthOrHeight( elem, name, extra );
+					}) :
+					getWidthOrHeight( elem, name, extra );
+			}
+		},
+
+		set: function( elem, value, extra ) {
+			var styles = extra && getStyles( elem );
+			return setPositiveNumber( elem, value, extra ?
+				augmentWidthOrHeight(
+					elem,
+					name,
+					extra,
+					jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+					styles
+				) : 0
+			);
+		}
+	};
+});
+
+// Support: Android 2.3
+jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
+	function( elem, computed ) {
+		if ( computed ) {
+			return jQuery.swap( elem, { "display": "inline-block" },
+				curCSS, [ elem, "marginRight" ] );
+		}
+	}
+);
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+	margin: "",
+	padding: "",
+	border: "Width"
+}, function( prefix, suffix ) {
+	jQuery.cssHooks[ prefix + suffix ] = {
+		expand: function( value ) {
+			var i = 0,
+				expanded = {},
+
+				// Assumes a single number if not a string
+				parts = typeof value === "string" ? value.split(" ") : [ value ];
+
+			for ( ; i < 4; i++ ) {
+				expanded[ prefix + cssExpand[ i ] + suffix ] =
+					parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+			}
+
+			return expanded;
+		}
+	};
+
+	if ( !rmargin.test( prefix ) ) {
+		jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+	}
+});
+
+jQuery.fn.extend({
+	css: function( name, value ) {
+		return access( this, function( elem, name, value ) {
+			var styles, len,
+				map = {},
+				i = 0;
+
+			if ( jQuery.isArray( name ) ) {
+				styles = getStyles( elem );
+				len = name.length;
+
+				for ( ; i < len; i++ ) {
+					map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+				}
+
+				return map;
+			}
+
+			return value !== undefined ?
+				jQuery.style( elem, name, value ) :
+				jQuery.css( elem, name );
+		}, name, value, arguments.length > 1 );
+	},
+	show: function() {
+		return showHide( this, true );
+	},
+	hide: function() {
+		return showHide( this );
+	},
+	toggle: function( state ) {
+		if ( typeof state === "boolean" ) {
+			return state ? this.show() : this.hide();
+		}
+
+		return this.each(function() {
+			if ( isHidden( this ) ) {
+				jQuery( this ).show();
+			} else {
+				jQuery( this ).hide();
+			}
+		});
+	}
+});
+
+
+function Tween( elem, options, prop, end, easing ) {
+	return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+	constructor: Tween,
+	init: function( elem, options, prop, end, easing, unit ) {
+		this.elem = elem;
+		this.prop = prop;
+		this.easing = easing || "swing";
+		this.options = options;
+		this.start = this.now = this.cur();
+		this.end = end;
+		this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+	},
+	cur: function() {
+		var hooks = Tween.propHooks[ this.prop ];
+
+		return hooks && hooks.get ?
+			hooks.get( this ) :
+			Tween.propHooks._default.get( this );
+	},
+	run: function( percent ) {
+		var eased,
+			hooks = Tween.propHooks[ this.prop ];
+
+		if ( this.options.duration ) {
+			this.pos = eased = jQuery.easing[ this.easing ](
+				percent, this.options.duration * percent, 0, 1, this.options.duration
+			);
+		} else {
+			this.pos = eased = percent;
+		}
+		this.now = ( this.end - this.start ) * eased + this.start;
+
+		if ( this.options.step ) {
+			this.options.step.call( this.elem, this.now, this );
+		}
+
+		if ( hooks && hooks.set ) {
+			hooks.set( this );
+		} else {
+			Tween.propHooks._default.set( this );
+		}
+		return this;
+	}
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+	_default: {
+		get: function( tween ) {
+			var result;
+
+			if ( tween.elem[ tween.prop ] != null &&
+				(!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+				return tween.elem[ tween.prop ];
+			}
+
+			// Passing an empty string as a 3rd parameter to .css will automatically
+			// attempt a parseFloat and fallback to a string if the parse fails.
+			// Simple values such as "10px" are parsed to Float;
+			// complex values such as "rotate(1rad)" are returned as-is.
+			result = jQuery.css( tween.elem, tween.prop, "" );
+			// Empty strings, null, undefined and "auto" are converted to 0.
+			return !result || result === "auto" ? 0 : result;
+		},
+		set: function( tween ) {
+			// Use step hook for back compat.
+			// Use cssHook if its there.
+			// Use .style if available and use plain properties where available.
+			if ( jQuery.fx.step[ tween.prop ] ) {
+				jQuery.fx.step[ tween.prop ]( tween );
+			} else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+				jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+			} else {
+				tween.elem[ tween.prop ] = tween.now;
+			}
+		}
+	}
+};
+
+// Support: IE9
+// Panic based approach to setting things on disconnected nodes
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+	set: function( tween ) {
+		if ( tween.elem.nodeType && tween.elem.parentNode ) {
+			tween.elem[ tween.prop ] = tween.now;
+		}
+	}
+};
+
+jQuery.easing = {
+	linear: function( p ) {
+		return p;
+	},
+	swing: function( p ) {
+		return 0.5 - Math.cos( p * Math.PI ) / 2;
+	}
+};
+
+jQuery.fx = Tween.prototype.init;
+
+// Back Compat <1.8 extension point
+jQuery.fx.step = {};
+
+
+
+
+var
+	fxNow, timerId,
+	rfxtypes = /^(?:toggle|show|hide)$/,
+	rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
+	rrun = /queueHooks$/,
+	animationPrefilters = [ defaultPrefilter ],
+	tweeners = {
+		"*": [ function( prop, value ) {
+			var tween = this.createTween( prop, value ),
+				target = tween.cur(),
+				parts = rfxnum.exec( value ),
+				unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+				// Starting value computation is required for potential unit mismatches
+				start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
+					rfxnum.exec( jQuery.css( tween.elem, prop ) ),
+				scale = 1,
+				maxIterations = 20;
+
+			if ( start && start[ 3 ] !== unit ) {
+				// Trust units reported by jQuery.css
+				unit = unit || start[ 3 ];
+
+				// Make sure we update the tween properties later on
+				parts = parts || [];
+
+				// Iteratively approximate from a nonzero starting point
+				start = +target || 1;
+
+				do {
+					// If previous iteration zeroed out, double until we get *something*.
+					// Use string for doubling so we don't accidentally see scale as unchanged below
+					scale = scale || ".5";
+
+					// Adjust and apply
+					start = start / scale;
+					jQuery.style( tween.elem, prop, start + unit );
+
+				// Update scale, tolerating zero or NaN from tween.cur(),
+				// break the loop if scale is unchanged or perfect, or if we've just had enough
+				} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
+			}
+
+			// Update tween properties
+			if ( parts ) {
+				start = tween.start = +start || +target || 0;
+				tween.unit = unit;
+				// If a +=/-= token was provided, we're doing a relative animation
+				tween.end = parts[ 1 ] ?
+					start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
+					+parts[ 2 ];
+			}
+
+			return tween;
+		} ]
+	};
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+	setTimeout(function() {
+		fxNow = undefined;
+	});
+	return ( fxNow = jQuery.now() );
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+	var which,
+		i = 0,
+		attrs = { height: type };
+
+	// If we include width, step value is 1 to do all cssExpand values,
+	// otherwise step value is 2 to skip over Left and Right
+	includeWidth = includeWidth ? 1 : 0;
+	for ( ; i < 4 ; i += 2 - includeWidth ) {
+		which = cssExpand[ i ];
+		attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+	}
+
+	if ( includeWidth ) {
+		attrs.opacity = attrs.width = type;
+	}
+
+	return attrs;
+}
+
+function createTween( value, prop, animation ) {
+	var tween,
+		collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+		index = 0,
+		length = collection.length;
+	for ( ; index < length; index++ ) {
+		if ( (tween = collection[ index ].call( animation, prop, value )) ) {
+
+			// We're done with this property
+			return tween;
+		}
+	}
+}
+
+function defaultPrefilter( elem, props, opts ) {
+	/* jshint validthis: true */
+	var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
+		anim = this,
+		orig = {},
+		style = elem.style,
+		hidden = elem.nodeType && isHidden( elem ),
+		dataShow = data_priv.get( elem, "fxshow" );
+
+	// Handle queue: false promises
+	if ( !opts.queue ) {
+		hooks = jQuery._queueHooks( elem, "fx" );
+		if ( hooks.unqueued == null ) {
+			hooks.unqueued = 0;
+			oldfire = hooks.empty.fire;
+			hooks.empty.fire = function() {
+				if ( !hooks.unqueued ) {
+					oldfire();
+				}
+			};
+		}
+		hooks.unqueued++;
+
+		anim.always(function() {
+			// Ensure the complete handler is called before this completes
+			anim.always(function() {
+				hooks.unqueued--;
+				if ( !jQuery.queue( elem, "fx" ).length ) {
+					hooks.empty.fire();
+				}
+			});
+		});
+	}
+
+	// Height/width overflow pass
+	if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
+		// Make sure that nothing sneaks out
+		// Record all 3 overflow attributes because IE9-10 do not
+		// change the overflow attribute when overflowX and
+		// overflowY are set to the same value
+		opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+		// Set display property to inline-block for height/width
+		// animations on inline elements that are having width/height animated
+		display = jQuery.css( elem, "display" );
+
+		// Test default display if display is currently "none"
+		checkDisplay = display === "none" ?
+			data_priv.get( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
+
+		if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
+			style.display = "inline-block";
+		}
+	}
+
+	if ( opts.overflow ) {
+		style.overflow = "hidden";
+		anim.always(function() {
+			style.overflow = opts.overflow[ 0 ];
+			style.overflowX = opts.overflow[ 1 ];
+			style.overflowY = opts.overflow[ 2 ];
+		});
+	}
+
+	// show/hide pass
+	for ( prop in props ) {
+		value = props[ prop ];
+		if ( rfxtypes.exec( value ) ) {
+			delete props[ prop ];
+			toggle = toggle || value === "toggle";
+			if ( value === ( hidden ? "hide" : "show" ) ) {
+
+				// If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
+				if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
+					hidden = true;
+				} else {
+					continue;
+				}
+			}
+			orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+
+		// Any non-fx value stops us from restoring the original display value
+		} else {
+			display = undefined;
+		}
+	}
+
+	if ( !jQuery.isEmptyObject( orig ) ) {
+		if ( dataShow ) {
+			if ( "hidden" in dataShow ) {
+				hidden = dataShow.hidden;
+			}
+		} else {
+			dataShow = data_priv.access( elem, "fxshow", {} );
+		}
+
+		// Store state if its toggle - enables .stop().toggle() to "reverse"
+		if ( toggle ) {
+			dataShow.hidden = !hidden;
+		}
+		if ( hidden ) {
+			jQuery( elem ).show();
+		} else {
+			anim.done(function() {
+				jQuery( elem ).hide();
+			});
+		}
+		anim.done(function() {
+			var prop;
+
+			data_priv.remove( elem, "fxshow" );
+			for ( prop in orig ) {
+				jQuery.style( elem, prop, orig[ prop ] );
+			}
+		});
+		for ( prop in orig ) {
+			tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+
+			if ( !( prop in dataShow ) ) {
+				dataShow[ prop ] = tween.start;
+				if ( hidden ) {
+					tween.end = tween.start;
+					tween.start = prop === "width" || prop === "height" ? 1 : 0;
+				}
+			}
+		}
+
+	// If this is a noop like .hide().hide(), restore an overwritten display value
+	} else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
+		style.display = display;
+	}
+}
+
+function propFilter( props, specialEasing ) {
+	var index, name, easing, value, hooks;
+
+	// camelCase, specialEasing and expand cssHook pass
+	for ( index in props ) {
+		name = jQuery.camelCase( index );
+		easing = specialEasing[ name ];
+		value = props[ index ];
+		if ( jQuery.isArray( value ) ) {
+			easing = value[ 1 ];
+			value = props[ index ] = value[ 0 ];
+		}
+
+		if ( index !== name ) {
+			props[ name ] = value;
+			delete props[ index ];
+		}
+
+		hooks = jQuery.cssHooks[ name ];
+		if ( hooks && "expand" in hooks ) {
+			value = hooks.expand( value );
+			delete props[ name ];
+
+			// Not quite $.extend, this won't overwrite existing keys.
+			// Reusing 'index' because we have the correct "name"
+			for ( index in value ) {
+				if ( !( index in props ) ) {
+					props[ index ] = value[ index ];
+					specialEasing[ index ] = easing;
+				}
+			}
+		} else {
+			specialEasing[ name ] = easing;
+		}
+	}
+}
+
+function Animation( elem, properties, options ) {
+	var result,
+		stopped,
+		index = 0,
+		length = animationPrefilters.length,
+		deferred = jQuery.Deferred().always( function() {
+			// Don't match elem in the :animated selector
+			delete tick.elem;
+		}),
+		tick = function() {
+			if ( stopped ) {
+				return false;
+			}
+			var currentTime = fxNow || createFxNow(),
+				remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+				// Support: Android 2.3
+				// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
+				temp = remaining / animation.duration || 0,
+				percent = 1 - temp,
+				index = 0,
+				length = animation.tweens.length;
+
+			for ( ; index < length ; index++ ) {
+				animation.tweens[ index ].run( percent );
+			}
+
+			deferred.notifyWith( elem, [ animation, percent, remaining ]);
+
+			if ( percent < 1 && length ) {
+				return remaining;
+			} else {
+				deferred.resolveWith( elem, [ animation ] );
+				return false;
+			}
+		},
+		animation = deferred.promise({
+			elem: elem,
+			props: jQuery.extend( {}, properties ),
+			opts: jQuery.extend( true, { specialEasing: {} }, options ),
+			originalProperties: properties,
+			originalOptions: options,
+			startTime: fxNow || createFxNow(),
+			duration: options.duration,
+			tweens: [],
+			createTween: function( prop, end ) {
+				var tween = jQuery.Tween( elem, animation.opts, prop, end,
+						animation.opts.specialEasing[ prop ] || animation.opts.easing );
+				animation.tweens.push( tween );
+				return tween;
+			},
+			stop: function( gotoEnd ) {
+				var index = 0,
+					// If we are going to the end, we want to run all the tweens
+					// otherwise we skip this part
+					length = gotoEnd ? animation.tweens.length : 0;
+				if ( stopped ) {
+					return this;
+				}
+				stopped = true;
+				for ( ; index < length ; index++ ) {
+					animation.tweens[ index ].run( 1 );
+				}
+
+				// Resolve when we played the last frame; otherwise, reject
+				if ( gotoEnd ) {
+					deferred.resolveWith( elem, [ animation, gotoEnd ] );
+				} else {
+					deferred.rejectWith( elem, [ animation, gotoEnd ] );
+				}
+				return this;
+			}
+		}),
+		props = animation.props;
+
+	propFilter( props, animation.opts.specialEasing );
+
+	for ( ; index < length ; index++ ) {
+		result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+		if ( result ) {
+			return result;
+		}
+	}
+
+	jQuery.map( props, createTween, animation );
+
+	if ( jQuery.isFunction( animation.opts.start ) ) {
+		animation.opts.start.call( elem, animation );
+	}
+
+	jQuery.fx.timer(
+		jQuery.extend( tick, {
+			elem: elem,
+			anim: animation,
+			queue: animation.opts.queue
+		})
+	);
+
+	// attach callbacks from options
+	return animation.progress( animation.opts.progress )
+		.done( animation.opts.done, animation.opts.complete )
+		.fail( animation.opts.fail )
+		.always( animation.opts.always );
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+
+	tweener: function( props, callback ) {
+		if ( jQuery.isFunction( props ) ) {
+			callback = props;
+			props = [ "*" ];
+		} else {
+			props = props.split(" ");
+		}
+
+		var prop,
+			index = 0,
+			length = props.length;
+
+		for ( ; index < length ; index++ ) {
+			prop = props[ index ];
+			tweeners[ prop ] = tweeners[ prop ] || [];
+			tweeners[ prop ].unshift( callback );
+		}
+	},
+
+	prefilter: function( callback, prepend ) {
+		if ( prepend ) {
+			animationPrefilters.unshift( callback );
+		} else {
+			animationPrefilters.push( callback );
+		}
+	}
+});
+
+jQuery.speed = function( speed, easing, fn ) {
+	var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+		complete: fn || !fn && easing ||
+			jQuery.isFunction( speed ) && speed,
+		duration: speed,
+		easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+	};
+
+	opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+		opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+	// Normalize opt.queue - true/undefined/null -> "fx"
+	if ( opt.queue == null || opt.queue === true ) {
+		opt.queue = "fx";
+	}
+
+	// Queueing
+	opt.old = opt.complete;
+
+	opt.complete = function() {
+		if ( jQuery.isFunction( opt.old ) ) {
+			opt.old.call( this );
+		}
+
+		if ( opt.queue ) {
+			jQuery.dequeue( this, opt.queue );
+		}
+	};
+
+	return opt;
+};
+
+jQuery.fn.extend({
+	fadeTo: function( speed, to, easing, callback ) {
+
+		// Show any hidden elements after setting opacity to 0
+		return this.filter( isHidden ).css( "opacity", 0 ).show()
+
+			// Animate to the value specified
+			.end().animate({ opacity: to }, speed, easing, callback );
+	},
+	animate: function( prop, speed, easing, callback ) {
+		var empty = jQuery.isEmptyObject( prop ),
+			optall = jQuery.speed( speed, easing, callback ),
+			doAnimation = function() {
+				// Operate on a copy of prop so per-property easing won't be lost
+				var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+
+				// Empty animations, or finishing resolves immediately
+				if ( empty || data_priv.get( this, "finish" ) ) {
+					anim.stop( true );
+				}
+			};
+			doAnimation.finish = doAnimation;
+
+		return empty || optall.queue === false ?
+			this.each( doAnimation ) :
+			this.queue( optall.queue, doAnimation );
+	},
+	stop: function( type, clearQueue, gotoEnd ) {
+		var stopQueue = function( hooks ) {
+			var stop = hooks.stop;
+			delete hooks.stop;
+			stop( gotoEnd );
+		};
+
+		if ( typeof type !== "string" ) {
+			gotoEnd = clearQueue;
+			clearQueue = type;
+			type = undefined;
+		}
+		if ( clearQueue && type !== false ) {
+			this.queue( type || "fx", [] );
+		}
+
+		return this.each(function() {
+			var dequeue = true,
+				index = type != null && type + "queueHooks",
+				timers = jQuery.timers,
+				data = data_priv.get( this );
+
+			if ( index ) {
+				if ( data[ index ] && data[ index ].stop ) {
+					stopQueue( data[ index ] );
+				}
+			} else {
+				for ( index in data ) {
+					if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+						stopQueue( data[ index ] );
+					}
+				}
+			}
+
+			for ( index = timers.length; index--; ) {
+				if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+					timers[ index ].anim.stop( gotoEnd );
+					dequeue = false;
+					timers.splice( index, 1 );
+				}
+			}
+
+			// Start the next in the queue if the last step wasn't forced.
+			// Timers currently will call their complete callbacks, which
+			// will dequeue but only if they were gotoEnd.
+			if ( dequeue || !gotoEnd ) {
+				jQuery.dequeue( this, type );
+			}
+		});
+	},
+	finish: function( type ) {
+		if ( type !== false ) {
+			type = type || "fx";
+		}
+		return this.each(function() {
+			var index,
+				data = data_priv.get( this ),
+				queue = data[ type + "queue" ],
+				hooks = data[ type + "queueHooks" ],
+				timers = jQuery.timers,
+				length = queue ? queue.length : 0;
+
+			// Enable finishing flag on private data
+			data.finish = true;
+
+			// Empty the queue first
+			jQuery.queue( this, type, [] );
+
+			if ( hooks && hooks.stop ) {
+				hooks.stop.call( this, true );
+			}
+
+			// Look for any active animations, and finish them
+			for ( index = timers.length; index--; ) {
+				if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+					timers[ index ].anim.stop( true );
+					timers.splice( index, 1 );
+				}
+			}
+
+			// Look for any animations in the old queue and finish them
+			for ( index = 0; index < length; index++ ) {
+				if ( queue[ index ] && queue[ index ].finish ) {
+					queue[ index ].finish.call( this );
+				}
+			}
+
+			// Turn off finishing flag
+			delete data.finish;
+		});
+	}
+});
+
+jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+	var cssFn = jQuery.fn[ name ];
+	jQuery.fn[ name ] = function( speed, easing, callback ) {
+		return speed == null || typeof speed === "boolean" ?
+			cssFn.apply( this, arguments ) :
+			this.animate( genFx( name, true ), speed, easing, callback );
+	};
+});
+
+// Generate shortcuts for custom animations
+jQuery.each({
+	slideDown: genFx("show"),
+	slideUp: genFx("hide"),
+	slideToggle: genFx("toggle"),
+	fadeIn: { opacity: "show" },
+	fadeOut: { opacity: "hide" },
+	fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+	jQuery.fn[ name ] = function( speed, easing, callback ) {
+		return this.animate( props, speed, easing, callback );
+	};
+});
+
+jQuery.timers = [];
+jQuery.fx.tick = function() {
+	var timer,
+		i = 0,
+		timers = jQuery.timers;
+
+	fxNow = jQuery.now();
+
+	for ( ; i < timers.length; i++ ) {
+		timer = timers[ i ];
+		// Checks the timer has not already been removed
+		if ( !timer() && timers[ i ] === timer ) {
+			timers.splice( i--, 1 );
+		}
+	}
+
+	if ( !timers.length ) {
+		jQuery.fx.stop();
+	}
+	fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+	jQuery.timers.push( timer );
+	if ( timer() ) {
+		jQuery.fx.start();
+	} else {
+		jQuery.timers.pop();
+	}
+};
+
+jQuery.fx.interval = 13;
+
+jQuery.fx.start = function() {
+	if ( !timerId ) {
+		timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+	}
+};
+
+jQuery.fx.stop = function() {
+	clearInterval( timerId );
+	timerId = null;
+};
+
+jQuery.fx.speeds = {
+	slow: 600,
+	fast: 200,
+	// Default speed
+	_default: 400
+};
+
+
+// Based off of the plugin by Clint Helfers, with permission.
+// http://blindsignals.com/index.php/2009/07/jquery-delay/
+jQuery.fn.delay = function( time, type ) {
+	time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+	type = type || "fx";
+
+	return this.queue( type, function( next, hooks ) {
+		var timeout = setTimeout( next, time );
+		hooks.stop = function() {
+			clearTimeout( timeout );
+		};
+	});
+};
+
+
+(function() {
+	var input = document.createElement( "input" ),
+		select = document.createElement( "select" ),
+		opt = select.appendChild( document.createElement( "option" ) );
+
+	input.type = "checkbox";
+
+	// Support: iOS<=5.1, Android<=4.2+
+	// Default value for a checkbox should be "on"
+	support.checkOn = input.value !== "";
+
+	// Support: IE<=11+
+	// Must access selectedIndex to make default options select
+	support.optSelected = opt.selected;
+
+	// Support: Android<=2.3
+	// Options inside disabled selects are incorrectly marked as disabled
+	select.disabled = true;
+	support.optDisabled = !opt.disabled;
+
+	// Support: IE<=11+
+	// An input loses its value after becoming a radio
+	input = document.createElement( "input" );
+	input.value = "t";
+	input.type = "radio";
+	support.radioValue = input.value === "t";
+})();
+
+
+var nodeHook, boolHook,
+	attrHandle = jQuery.expr.attrHandle;
+
+jQuery.fn.extend({
+	attr: function( name, value ) {
+		return access( this, jQuery.attr, name, value, arguments.length > 1 );
+	},
+
+	removeAttr: function( name ) {
+		return this.each(function() {
+			jQuery.removeAttr( this, name );
+		});
+	}
+});
+
+jQuery.extend({
+	attr: function( elem, name, value ) {
+		var hooks, ret,
+			nType = elem.nodeType;
+
+		// don't get/set attributes on text, comment and attribute nodes
+		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+			return;
+		}
+
+		// Fallback to prop when attributes are not supported
+		if ( typeof elem.getAttribute === strundefined ) {
+			return jQuery.prop( elem, name, value );
+		}
+
+		// All attributes are lowercase
+		// Grab necessary hook if one is defined
+		if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+			name = name.toLowerCase();
+			hooks = jQuery.attrHooks[ name ] ||
+				( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
+		}
+
+		if ( value !== undefined ) {
+
+			if ( value === null ) {
+				jQuery.removeAttr( elem, name );
+
+			} else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+				return ret;
+
+			} else {
+				elem.setAttribute( name, value + "" );
+				return value;
+			}
+
+		} else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+			return ret;
+
+		} else {
+			ret = jQuery.find.attr( elem, name );
+
+			// Non-existent attributes return null, we normalize to undefined
+			return ret == null ?
+				undefined :
+				ret;
+		}
+	},
+
+	removeAttr: function( elem, value ) {
+		var name, propName,
+			i = 0,
+			attrNames = value && value.match( rnotwhite );
+
+		if ( attrNames && elem.nodeType === 1 ) {
+			while ( (name = attrNames[i++]) ) {
+				propName = jQuery.propFix[ name ] || name;
+
+				// Boolean attributes get special treatment (#10870)
+				if ( jQuery.expr.match.bool.test( name ) ) {
+					// Set corresponding property to false
+					elem[ propName ] = false;
+				}
+
+				elem.removeAttribute( name );
+			}
+		}
+	},
+
+	attrHooks: {
+		type: {
+			set: function( elem, value ) {
+				if ( !support.radioValue && value === "radio" &&
+					jQuery.nodeName( elem, "input" ) ) {
+					var val = elem.value;
+					elem.setAttribute( "type", value );
+					if ( val ) {
+						elem.value = val;
+					}
+					return value;
+				}
+			}
+		}
+	}
+});
+
+// Hooks for boolean attributes
+boolHook = {
+	set: function( elem, value, name ) {
+		if ( value === false ) {
+			// Remove boolean attributes when set to false
+			jQuery.removeAttr( elem, name );
+		} else {
+			elem.setAttribute( name, name );
+		}
+		return name;
+	}
+};
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
+	var getter = attrHandle[ name ] || jQuery.find.attr;
+
+	attrHandle[ name ] = function( elem, name, isXML ) {
+		var ret, handle;
+		if ( !isXML ) {
+			// Avoid an infinite loop by temporarily removing this function from the getter
+			handle = attrHandle[ name ];
+			attrHandle[ name ] = ret;
+			ret = getter( elem, name, isXML ) != null ?
+				name.toLowerCase() :
+				null;
+			attrHandle[ name ] = handle;
+		}
+		return ret;
+	};
+});
+
+
+
+
+var rfocusable = /^(?:input|select|textarea|button)$/i;
+
+jQuery.fn.extend({
+	prop: function( name, value ) {
+		return access( this, jQuery.prop, name, value, arguments.length > 1 );
+	},
+
+	removeProp: function( name ) {
+		return this.each(function() {
+			delete this[ jQuery.propFix[ name ] || name ];
+		});
+	}
+});
+
+jQuery.extend({
+	propFix: {
+		"for": "htmlFor",
+		"class": "className"
+	},
+
+	prop: function( elem, name, value ) {
+		var ret, hooks, notxml,
+			nType = elem.nodeType;
+
+		// Don't get/set properties on text, comment and attribute nodes
+		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+			return;
+		}
+
+		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+		if ( notxml ) {
+			// Fix name and attach hooks
+			name = jQuery.propFix[ name ] || name;
+			hooks = jQuery.propHooks[ name ];
+		}
+
+		if ( value !== undefined ) {
+			return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
+				ret :
+				( elem[ name ] = value );
+
+		} else {
+			return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
+				ret :
+				elem[ name ];
+		}
+	},
+
+	propHooks: {
+		tabIndex: {
+			get: function( elem ) {
+				return elem.hasAttribute( "tabindex" ) || rfocusable.test( elem.nodeName ) || elem.href ?
+					elem.tabIndex :
+					-1;
+			}
+		}
+	}
+});
+
+if ( !support.optSelected ) {
+	jQuery.propHooks.selected = {
+		get: function( elem ) {
+			var parent = elem.parentNode;
+			if ( parent && parent.parentNode ) {
+				parent.parentNode.selectedIndex;
+			}
+			return null;
+		}
+	};
+}
+
+jQuery.each([
+	"tabIndex",
+	"readOnly",
+	"maxLength",
+	"cellSpacing",
+	"cellPadding",
+	"rowSpan",
+	"colSpan",
+	"useMap",
+	"frameBorder",
+	"contentEditable"
+], function() {
+	jQuery.propFix[ this.toLowerCase() ] = this;
+});
+
+
+
+
+var rclass = /[\t\r\n\f]/g;
+
+jQuery.fn.extend({
+	addClass: function( value ) {
+		var classes, elem, cur, clazz, j, finalValue,
+			proceed = typeof value === "string" && value,
+			i = 0,
+			len = this.length;
+
+		if ( jQuery.isFunction( value ) ) {
+			return this.each(function( j ) {
+				jQuery( this ).addClass( value.call( this, j, this.className ) );
+			});
+		}
+
+		if ( proceed ) {
+			// The disjunction here is for better compressibility (see removeClass)
+			classes = ( value || "" ).match( rnotwhite ) || [];
+
+			for ( ; i < len; i++ ) {
+				elem = this[ i ];
+				cur = elem.nodeType === 1 && ( elem.className ?
+					( " " + elem.className + " " ).replace( rclass, " " ) :
+					" "
+				);
+
+				if ( cur ) {
+					j = 0;
+					while ( (clazz = classes[j++]) ) {
+						if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+							cur += clazz + " ";
+						}
+					}
+
+					// only assign if different to avoid unneeded rendering.
+					finalValue = jQuery.trim( cur );
+					if ( elem.className !== finalValue ) {
+						elem.className = finalValue;
+					}
+				}
+			}
+		}
+
+		return this;
+	},
+
+	removeClass: function( value ) {
+		var classes, elem, cur, clazz, j, finalValue,
+			proceed = arguments.length === 0 || typeof value === "string" && value,
+			i = 0,
+			len = this.length;
+
+		if ( jQuery.isFunction( value ) ) {
+			return this.each(function( j ) {
+				jQuery( this ).removeClass( value.call( this, j, this.className ) );
+			});
+		}
+		if ( proceed ) {
+			classes = ( value || "" ).match( rnotwhite ) || [];
+
+			for ( ; i < len; i++ ) {
+				elem = this[ i ];
+				// This expression is here for better compressibility (see addClass)
+				cur = elem.nodeType === 1 && ( elem.className ?
+					( " " + elem.className + " " ).replace( rclass, " " ) :
+					""
+				);
+
+				if ( cur ) {
+					j = 0;
+					while ( (clazz = classes[j++]) ) {
+						// Remove *all* instances
+						while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
+							cur = cur.replace( " " + clazz + " ", " " );
+						}
+					}
+
+					// Only assign if different to avoid unneeded rendering.
+					finalValue = value ? jQuery.trim( cur ) : "";
+					if ( elem.className !== finalValue ) {
+						elem.className = finalValue;
+					}
+				}
+			}
+		}
+
+		return this;
+	},
+
+	toggleClass: function( value, stateVal ) {
+		var type = typeof value;
+
+		if ( typeof stateVal === "boolean" && type === "string" ) {
+			return stateVal ? this.addClass( value ) : this.removeClass( value );
+		}
+
+		if ( jQuery.isFunction( value ) ) {
+			return this.each(function( i ) {
+				jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+			});
+		}
+
+		return this.each(function() {
+			if ( type === "string" ) {
+				// Toggle individual class names
+				var className,
+					i = 0,
+					self = jQuery( this ),
+					classNames = value.match( rnotwhite ) || [];
+
+				while ( (className = classNames[ i++ ]) ) {
+					// Check each className given, space separated list
+					if ( self.hasClass( className ) ) {
+						self.removeClass( className );
+					} else {
+						self.addClass( className );
+					}
+				}
+
+			// Toggle whole class name
+			} else if ( type === strundefined || type === "boolean" ) {
+				if ( this.className ) {
+					// store className if set
+					data_priv.set( this, "__className__", this.className );
+				}
+
+				// If the element has a class name or if we're passed `false`,
+				// then remove the whole classname (if there was one, the above saved it).
+				// Otherwise bring back whatever was previously saved (if anything),
+				// falling back to the empty string if nothing was stored.
+				this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";
+			}
+		});
+	},
+
+	hasClass: function( selector ) {
+		var className = " " + selector + " ",
+			i = 0,
+			l = this.length;
+		for ( ; i < l; i++ ) {
+			if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+});
+
+
+
+
+var rreturn = /\r/g;
+
+jQuery.fn.extend({
+	val: function( value ) {
+		var hooks, ret, isFunction,
+			elem = this[0];
+
+		if ( !arguments.length ) {
+			if ( elem ) {
+				hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+				if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+					return ret;
+				}
+
+				ret = elem.value;
+
+				return typeof ret === "string" ?
+					// Handle most common string cases
+					ret.replace(rreturn, "") :
+					// Handle cases where value is null/undef or number
+					ret == null ? "" : ret;
+			}
+
+			return;
+		}
+
+		isFunction = jQuery.isFunction( value );
+
+		return this.each(function( i ) {
+			var val;
+
+			if ( this.nodeType !== 1 ) {
+				return;
+			}
+
+			if ( isFunction ) {
+				val = value.call( this, i, jQuery( this ).val() );
+			} else {
+				val = value;
+			}
+
+			// Treat null/undefined as ""; convert numbers to string
+			if ( val == null ) {
+				val = "";
+
+			} else if ( typeof val === "number" ) {
+				val += "";
+
+			} else if ( jQuery.isArray( val ) ) {
+				val = jQuery.map( val, function( value ) {
+					return value == null ? "" : value + "";
+				});
+			}
+
+			hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+			// If set returns undefined, fall back to normal setting
+			if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+				this.value = val;
+			}
+		});
+	}
+});
+
+jQuery.extend({
+	valHooks: {
+		option: {
+			get: function( elem ) {
+				var val = jQuery.find.attr( elem, "value" );
+				return val != null ?
+					val :
+					// Support: IE10-11+
+					// option.text throws exceptions (#14686, #14858)
+					jQuery.trim( jQuery.text( elem ) );
+			}
+		},
+		select: {
+			get: function( elem ) {
+				var value, option,
+					options = elem.options,
+					index = elem.selectedIndex,
+					one = elem.type === "select-one" || index < 0,
+					values = one ? null : [],
+					max = one ? index + 1 : options.length,
+					i = index < 0 ?
+						max :
+						one ? index : 0;
+
+				// Loop through all the selected options
+				for ( ; i < max; i++ ) {
+					option = options[ i ];
+
+					// IE6-9 doesn't update selected after form reset (#2551)
+					if ( ( option.selected || i === index ) &&
+							// Don't return options that are disabled or in a disabled optgroup
+							( support.optDisabled ? !option.disabled : option.getAttribute( "disabled" ) === null ) &&
+							( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+						// Get the specific value for the option
+						value = jQuery( option ).val();
+
+						// We don't need an array for one selects
+						if ( one ) {
+							return value;
+						}
+
+						// Multi-Selects return an array
+						values.push( value );
+					}
+				}
+
+				return values;
+			},
+
+			set: function( elem, value ) {
+				var optionSet, option,
+					options = elem.options,
+					values = jQuery.makeArray( value ),
+					i = options.length;
+
+				while ( i-- ) {
+					option = options[ i ];
+					if ( (option.selected = jQuery.inArray( option.value, values ) >= 0) ) {
+						optionSet = true;
+					}
+				}
+
+				// Force browsers to behave consistently when non-matching value is set
+				if ( !optionSet ) {
+					elem.selectedIndex = -1;
+				}
+				return values;
+			}
+		}
+	}
+});
+
+// Radios and checkboxes getter/setter
+jQuery.each([ "radio", "checkbox" ], function() {
+	jQuery.valHooks[ this ] = {
+		set: function( elem, value ) {
+			if ( jQuery.isArray( value ) ) {
+				return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+			}
+		}
+	};
+	if ( !support.checkOn ) {
+		jQuery.valHooks[ this ].get = function( elem ) {
+			return elem.getAttribute("value") === null ? "on" : elem.value;
+		};
+	}
+});
+
+
+
+
+// Return jQuery for attributes-only inclusion
+
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+	"change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+	// Handle event binding
+	jQuery.fn[ name ] = function( data, fn ) {
+		return arguments.length > 0 ?
+			this.on( name, null, data, fn ) :
+			this.trigger( name );
+	};
+});
+
+jQuery.fn.extend({
+	hover: function( fnOver, fnOut ) {
+		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+	},
+
+	bind: function( types, data, fn ) {
+		return this.on( types, null, data, fn );
+	},
+	unbind: function( types, fn ) {
+		return this.off( types, null, fn );
+	},
+
+	delegate: function( selector, types, data, fn ) {
+		return this.on( types, selector, data, fn );
+	},
+	undelegate: function( selector, types, fn ) {
+		// ( namespace ) or ( selector, types [, fn] )
+		return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+	}
+});
+
+
+var nonce = jQuery.now();
+
+var rquery = (/\?/);
+
+
+
+// Support: Android 2.3
+// Workaround failure to string-cast null input
+jQuery.parseJSON = function( data ) {
+	return JSON.parse( data + "" );
+};
+
+
+// Cross-browser xml parsing
+jQuery.parseXML = function( data ) {
+	var xml, tmp;
+	if ( !data || typeof data !== "string" ) {
+		return null;
+	}
+
+	// Support: IE9
+	try {
+		tmp = new DOMParser();
+		xml = tmp.parseFromString( data, "text/xml" );
+	} catch ( e ) {
+		xml = undefined;
+	}
+
+	if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
+		jQuery.error( "Invalid XML: " + data );
+	}
+	return xml;
+};
+
+
+var
+	rhash = /#.*$/,
+	rts = /([?&])_=[^&]*/,
+	rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
+	// #7653, #8125, #8152: local protocol detection
+	rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+	rnoContent = /^(?:GET|HEAD)$/,
+	rprotocol = /^\/\//,
+	rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
+
+	/* Prefilters
+	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+	 * 2) These are called:
+	 *    - BEFORE asking for a transport
+	 *    - AFTER param serialization (s.data is a string if s.processData is true)
+	 * 3) key is the dataType
+	 * 4) the catchall symbol "*" can be used
+	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+	 */
+	prefilters = {},
+
+	/* Transports bindings
+	 * 1) key is the dataType
+	 * 2) the catchall symbol "*" can be used
+	 * 3) selection will start with transport dataType and THEN go to "*" if needed
+	 */
+	transports = {},
+
+	// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+	allTypes = "*/".concat( "*" ),
+
+	// Document location
+	ajaxLocation = window.location.href,
+
+	// Segment location into parts
+	ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+	// dataTypeExpression is optional and defaults to "*"
+	return function( dataTypeExpression, func ) {
+
+		if ( typeof dataTypeExpression !== "string" ) {
+			func = dataTypeExpression;
+			dataTypeExpression = "*";
+		}
+
+		var dataType,
+			i = 0,
+			dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
+
+		if ( jQuery.isFunction( func ) ) {
+			// For each dataType in the dataTypeExpression
+			while ( (dataType = dataTypes[i++]) ) {
+				// Prepend if requested
+				if ( dataType[0] === "+" ) {
+					dataType = dataType.slice( 1 ) || "*";
+					(structure[ dataType ] = structure[ dataType ] || []).unshift( func );
+
+				// Otherwise append
+				} else {
+					(structure[ dataType ] = structure[ dataType ] || []).push( func );
+				}
+			}
+		}
+	};
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+	var inspected = {},
+		seekingTransport = ( structure === transports );
+
+	function inspect( dataType ) {
+		var selected;
+		inspected[ dataType ] = true;
+		jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+			var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+			if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+				options.dataTypes.unshift( dataTypeOrTransport );
+				inspect( dataTypeOrTransport );
+				return false;
+			} else if ( seekingTransport ) {
+				return !( selected = dataTypeOrTransport );
+			}
+		});
+		return selected;
+	}
+
+	return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+	var key, deep,
+		flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+	for ( key in src ) {
+		if ( src[ key ] !== undefined ) {
+			( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
+		}
+	}
+	if ( deep ) {
+		jQuery.extend( true, target, deep );
+	}
+
+	return target;
+}
+
+/* Handles responses to an ajax request:
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+	var ct, type, finalDataType, firstDataType,
+		contents = s.contents,
+		dataTypes = s.dataTypes;
+
+	// Remove auto dataType and get content-type in the process
+	while ( dataTypes[ 0 ] === "*" ) {
+		dataTypes.shift();
+		if ( ct === undefined ) {
+			ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
+		}
+	}
+
+	// Check if we're dealing with a known content-type
+	if ( ct ) {
+		for ( type in contents ) {
+			if ( contents[ type ] && contents[ type ].test( ct ) ) {
+				dataTypes.unshift( type );
+				break;
+			}
+		}
+	}
+
+	// Check to see if we have a response for the expected dataType
+	if ( dataTypes[ 0 ] in responses ) {
+		finalDataType = dataTypes[ 0 ];
+	} else {
+		// Try convertible dataTypes
+		for ( type in responses ) {
+			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+				finalDataType = type;
+				break;
+			}
+			if ( !firstDataType ) {
+				firstDataType = type;
+			}
+		}
+		// Or just use first one
+		finalDataType = finalDataType || firstDataType;
+	}
+
+	// If we found a dataType
+	// We add the dataType to the list if needed
+	// and return the corresponding response
+	if ( finalDataType ) {
+		if ( finalDataType !== dataTypes[ 0 ] ) {
+			dataTypes.unshift( finalDataType );
+		}
+		return responses[ finalDataType ];
+	}
+}
+
+/* Chain conversions given the request and the original response
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+	var conv2, current, conv, tmp, prev,
+		converters = {},
+		// Work with a copy of dataTypes in case we need to modify it for conversion
+		dataTypes = s.dataTypes.slice();
+
+	// Create converters map with lowercased keys
+	if ( dataTypes[ 1 ] ) {
+		for ( conv in s.converters ) {
+			converters[ conv.toLowerCase() ] = s.converters[ conv ];
+		}
+	}
+
+	current = dataTypes.shift();
+
+	// Convert to each sequential dataType
+	while ( current ) {
+
+		if ( s.responseFields[ current ] ) {
+			jqXHR[ s.responseFields[ current ] ] = response;
+		}
+
+		// Apply the dataFilter if provided
+		if ( !prev && isSuccess && s.dataFilter ) {
+			response = s.dataFilter( response, s.dataType );
+		}
+
+		prev = current;
+		current = dataTypes.shift();
+
+		if ( current ) {
+
+		// There's only work to do if current dataType is non-auto
+			if ( current === "*" ) {
+
+				current = prev;
+
+			// Convert response if prev dataType is non-auto and differs from current
+			} else if ( prev !== "*" && prev !== current ) {
+
+				// Seek a direct converter
+				conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+				// If none found, seek a pair
+				if ( !conv ) {
+					for ( conv2 in converters ) {
+
+						// If conv2 outputs current
+						tmp = conv2.split( " " );
+						if ( tmp[ 1 ] === current ) {
+
+							// If prev can be converted to accepted input
+							conv = converters[ prev + " " + tmp[ 0 ] ] ||
+								converters[ "* " + tmp[ 0 ] ];
+							if ( conv ) {
+								// Condense equivalence converters
+								if ( conv === true ) {
+									conv = converters[ conv2 ];
+
+								// Otherwise, insert the intermediate dataType
+								} else if ( converters[ conv2 ] !== true ) {
+									current = tmp[ 0 ];
+									dataTypes.unshift( tmp[ 1 ] );
+								}
+								break;
+							}
+						}
+					}
+				}
+
+				// Apply converter (if not an equivalence)
+				if ( conv !== true ) {
+
+					// Unless errors are allowed to bubble, catch and return them
+					if ( conv && s[ "throws" ] ) {
+						response = conv( response );
+					} else {
+						try {
+							response = conv( response );
+						} catch ( e ) {
+							return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
+						}
+					}
+				}
+			}
+		}
+	}
+
+	return { state: "success", data: response };
+}
+
+jQuery.extend({
+
+	// Counter for holding the number of active queries
+	active: 0,
+
+	// Last-Modified header cache for next request
+	lastModified: {},
+	etag: {},
+
+	ajaxSettings: {
+		url: ajaxLocation,
+		type: "GET",
+		isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+		global: true,
+		processData: true,
+		async: true,
+		contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+		/*
+		timeout: 0,
+		data: null,
+		dataType: null,
+		username: null,
+		password: null,
+		cache: null,
+		throws: false,
+		traditional: false,
+		headers: {},
+		*/
+
+		accepts: {
+			"*": allTypes,
+			text: "text/plain",
+			html: "text/html",
+			xml: "application/xml, text/xml",
+			json: "application/json, text/javascript"
+		},
+
+		contents: {
+			xml: /xml/,
+			html: /html/,
+			json: /json/
+		},
+
+		responseFields: {
+			xml: "responseXML",
+			text: "responseText",
+			json: "responseJSON"
+		},
+
+		// Data converters
+		// Keys separate source (or catchall "*") and destination types with a single space
+		converters: {
+
+			// Convert anything to text
+			"* text": String,
+
+			// Text to html (true = no transformation)
+			"text html": true,
+
+			// Evaluate text as a json expression
+			"text json": jQuery.parseJSON,
+
+			// Parse text as xml
+			"text xml": jQuery.parseXML
+		},
+
+		// For options that shouldn't be deep extended:
+		// you can add your own custom options here if
+		// and when you create one that shouldn't be
+		// deep extended (see ajaxExtend)
+		flatOptions: {
+			url: true,
+			context: true
+		}
+	},
+
+	// Creates a full fledged settings object into target
+	// with both ajaxSettings and settings fields.
+	// If target is omitted, writes into ajaxSettings.
+	ajaxSetup: function( target, settings ) {
+		return settings ?
+
+			// Building a settings object
+			ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+			// Extending ajaxSettings
+			ajaxExtend( jQuery.ajaxSettings, target );
+	},
+
+	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+	ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+	// Main method
+	ajax: function( url, options ) {
+
+		// If url is an object, simulate pre-1.5 signature
+		if ( typeof url === "object" ) {
+			options = url;
+			url = undefined;
+		}
+
+		// Force options to be an object
+		options = options || {};
+
+		var transport,
+			// URL without anti-cache param
+			cacheURL,
+			// Response headers
+			responseHeadersString,
+			responseHeaders,
+			// timeout handle
+			timeoutTimer,
+			// Cross-domain detection vars
+			parts,
+			// To know if global events are to be dispatched
+			fireGlobals,
+			// Loop variable
+			i,
+			// Create the final options object
+			s = jQuery.ajaxSetup( {}, options ),
+			// Callbacks context
+			callbackContext = s.context || s,
+			// Context for global events is callbackContext if it is a DOM node or jQuery collection
+			globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
+				jQuery( callbackContext ) :
+				jQuery.event,
+			// Deferreds
+			deferred = jQuery.Deferred(),
+			completeDeferred = jQuery.Callbacks("once memory"),
+			// Status-dependent callbacks
+			statusCode = s.statusCode || {},
+			// Headers (they are sent all at once)
+			requestHeaders = {},
+			requestHeadersNames = {},
+			// The jqXHR state
+			state = 0,
+			// Default abort message
+			strAbort = "canceled",
+			// Fake xhr
+			jqXHR = {
+				readyState: 0,
+
+				// Builds headers hashtable if needed
+				getResponseHeader: function( key ) {
+					var match;
+					if ( state === 2 ) {
+						if ( !responseHeaders ) {
+							responseHeaders = {};
+							while ( (match = rheaders.exec( responseHeadersString )) ) {
+								responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+							}
+						}
+						match = responseHeaders[ key.toLowerCase() ];
+					}
+					return match == null ? null : match;
+				},
+
+				// Raw string
+				getAllResponseHeaders: function() {
+					return state === 2 ? responseHeadersString : null;
+				},
+
+				// Caches the header
+				setRequestHeader: function( name, value ) {
+					var lname = name.toLowerCase();
+					if ( !state ) {
+						name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+						requestHeaders[ name ] = value;
+					}
+					return this;
+				},
+
+				// Overrides response content-type header
+				overrideMimeType: function( type ) {
+					if ( !state ) {
+						s.mimeType = type;
+					}
+					return this;
+				},
+
+				// Status-dependent callbacks
+				statusCode: function( map ) {
+					var code;
+					if ( map ) {
+						if ( state < 2 ) {
+							for ( code in map ) {
+								// Lazy-add the new callback in a way that preserves old ones
+								statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+							}
+						} else {
+							// Execute the appropriate callbacks
+							jqXHR.always( map[ jqXHR.status ] );
+						}
+					}
+					return this;
+				},
+
+				// Cancel the request
+				abort: function( statusText ) {
+					var finalText = statusText || strAbort;
+					if ( transport ) {
+						transport.abort( finalText );
+					}
+					done( 0, finalText );
+					return this;
+				}
+			};
+
+		// Attach deferreds
+		deferred.promise( jqXHR ).complete = completeDeferred.add;
+		jqXHR.success = jqXHR.done;
+		jqXHR.error = jqXHR.fail;
+
+		// Remove hash character (#7531: and string promotion)
+		// Add protocol if not provided (prefilters might expect it)
+		// Handle falsy url in the settings object (#10093: consistency with old signature)
+		// We also use the url parameter if available
+		s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" )
+			.replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+		// Alias method option to type as per ticket #12004
+		s.type = options.method || options.type || s.method || s.type;
+
+		// Extract dataTypes list
+		s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
+
+		// A cross-domain request is in order when we have a protocol:host:port mismatch
+		if ( s.crossDomain == null ) {
+			parts = rurl.exec( s.url.toLowerCase() );
+			s.crossDomain = !!( parts &&
+				( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
+					( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
+						( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
+			);
+		}
+
+		// Convert data if not already a string
+		if ( s.data && s.processData && typeof s.data !== "string" ) {
+			s.data = jQuery.param( s.data, s.traditional );
+		}
+
+		// Apply prefilters
+		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+		// If request was aborted inside a prefilter, stop there
+		if ( state === 2 ) {
+			return jqXHR;
+		}
+
+		// We can fire global events as of now if asked to
+		// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
+		fireGlobals = jQuery.event && s.global;
+
+		// Watch for a new set of requests
+		if ( fireGlobals && jQuery.active++ === 0 ) {
+			jQuery.event.trigger("ajaxStart");
+		}
+
+		// Uppercase the type
+		s.type = s.type.toUpperCase();
+
+		// Determine if request has content
+		s.hasContent = !rnoContent.test( s.type );
+
+		// Save the URL in case we're toying with the If-Modified-Since
+		// and/or If-None-Match header later on
+		cacheURL = s.url;
+
+		// More options handling for requests with no content
+		if ( !s.hasContent ) {
+
+			// If data is available, append data to url
+			if ( s.data ) {
+				cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
+				// #9682: remove data so that it's not used in an eventual retry
+				delete s.data;
+			}
+
+			// Add anti-cache in url if needed
+			if ( s.cache === false ) {
+				s.url = rts.test( cacheURL ) ?
+
+					// If there is already a '_' parameter, set its value
+					cacheURL.replace( rts, "$1_=" + nonce++ ) :
+
+					// Otherwise add one to the end
+					cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
+			}
+		}
+
+		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+		if ( s.ifModified ) {
+			if ( jQuery.lastModified[ cacheURL ] ) {
+				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+			}
+			if ( jQuery.etag[ cacheURL ] ) {
+				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+			}
+		}
+
+		// Set the correct header, if data is being sent
+		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+			jqXHR.setRequestHeader( "Content-Type", s.contentType );
+		}
+
+		// Set the Accepts header for the server, depending on the dataType
+		jqXHR.setRequestHeader(
+			"Accept",
+			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+				s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+				s.accepts[ "*" ]
+		);
+
+		// Check for headers option
+		for ( i in s.headers ) {
+			jqXHR.setRequestHeader( i, s.headers[ i ] );
+		}
+
+		// Allow custom headers/mimetypes and early abort
+		if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+			// Abort if not done already and return
+			return jqXHR.abort();
+		}
+
+		// Aborting is no longer a cancellation
+		strAbort = "abort";
+
+		// Install callbacks on deferreds
+		for ( i in { success: 1, error: 1, complete: 1 } ) {
+			jqXHR[ i ]( s[ i ] );
+		}
+
+		// Get transport
+		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+		// If no transport, we auto-abort
+		if ( !transport ) {
+			done( -1, "No Transport" );
+		} else {
+			jqXHR.readyState = 1;
+
+			// Send global event
+			if ( fireGlobals ) {
+				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+			}
+			// Timeout
+			if ( s.async && s.timeout > 0 ) {
+				timeoutTimer = setTimeout(function() {
+					jqXHR.abort("timeout");
+				}, s.timeout );
+			}
+
+			try {
+				state = 1;
+				transport.send( requestHeaders, done );
+			} catch ( e ) {
+				// Propagate exception as error if not done
+				if ( state < 2 ) {
+					done( -1, e );
+				// Simply rethrow otherwise
+				} else {
+					throw e;
+				}
+			}
+		}
+
+		// Callback for when everything is done
+		function done( status, nativeStatusText, responses, headers ) {
+			var isSuccess, success, error, response, modified,
+				statusText = nativeStatusText;
+
+			// Called once
+			if ( state === 2 ) {
+				return;
+			}
+
+			// State is "done" now
+			state = 2;
+
+			// Clear timeout if it exists
+			if ( timeoutTimer ) {
+				clearTimeout( timeoutTimer );
+			}
+
+			// Dereference transport for early garbage collection
+			// (no matter how long the jqXHR object will be used)
+			transport = undefined;
+
+			// Cache response headers
+			responseHeadersString = headers || "";
+
+			// Set readyState
+			jqXHR.readyState = status > 0 ? 4 : 0;
+
+			// Determine if successful
+			isSuccess = status >= 200 && status < 300 || status === 304;
+
+			// Get response data
+			if ( responses ) {
+				response = ajaxHandleResponses( s, jqXHR, responses );
+			}
+
+			// Convert no matter what (that way responseXXX fields are always set)
+			response = ajaxConvert( s, response, jqXHR, isSuccess );
+
+			// If successful, handle type chaining
+			if ( isSuccess ) {
+
+				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+				if ( s.ifModified ) {
+					modified = jqXHR.getResponseHeader("Last-Modified");
+					if ( modified ) {
+						jQuery.lastModified[ cacheURL ] = modified;
+					}
+					modified = jqXHR.getResponseHeader("etag");
+					if ( modified ) {
+						jQuery.etag[ cacheURL ] = modified;
+					}
+				}
+
+				// if no content
+				if ( status === 204 || s.type === "HEAD" ) {
+					statusText = "nocontent";
+
+				// if not modified
+				} else if ( status === 304 ) {
+					statusText = "notmodified";
+
+				// If we have data, let's convert it
+				} else {
+					statusText = response.state;
+					success = response.data;
+					error = response.error;
+					isSuccess = !error;
+				}
+			} else {
+				// Extract error from statusText and normalize for non-aborts
+				error = statusText;
+				if ( status || !statusText ) {
+					statusText = "error";
+					if ( status < 0 ) {
+						status = 0;
+					}
+				}
+			}
+
+			// Set data for the fake xhr object
+			jqXHR.status = status;
+			jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+			// Success/Error
+			if ( isSuccess ) {
+				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+			} else {
+				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+			}
+
+			// Status-dependent callbacks
+			jqXHR.statusCode( statusCode );
+			statusCode = undefined;
+
+			if ( fireGlobals ) {
+				globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+					[ jqXHR, s, isSuccess ? success : error ] );
+			}
+
+			// Complete
+			completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+			if ( fireGlobals ) {
+				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+				// Handle the global AJAX counter
+				if ( !( --jQuery.active ) ) {
+					jQuery.event.trigger("ajaxStop");
+				}
+			}
+		}
+
+		return jqXHR;
+	},
+
+	getJSON: function( url, data, callback ) {
+		return jQuery.get( url, data, callback, "json" );
+	},
+
+	getScript: function( url, callback ) {
+		return jQuery.get( url, undefined, callback, "script" );
+	}
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+	jQuery[ method ] = function( url, data, callback, type ) {
+		// Shift arguments if data argument was omitted
+		if ( jQuery.isFunction( data ) ) {
+			type = type || callback;
+			callback = data;
+			data = undefined;
+		}
+
+		return jQuery.ajax({
+			url: url,
+			type: method,
+			dataType: type,
+			data: data,
+			success: callback
+		});
+	};
+});
+
+
+jQuery._evalUrl = function( url ) {
+	return jQuery.ajax({
+		url: url,
+		type: "GET",
+		dataType: "script",
+		async: false,
+		global: false,
+		"throws": true
+	});
+};
+
+
+jQuery.fn.extend({
+	wrapAll: function( html ) {
+		var wrap;
+
+		if ( jQuery.isFunction( html ) ) {
+			return this.each(function( i ) {
+				jQuery( this ).wrapAll( html.call(this, i) );
+			});
+		}
+
+		if ( this[ 0 ] ) {
+
+			// The elements to wrap the target around
+			wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
+
+			if ( this[ 0 ].parentNode ) {
+				wrap.insertBefore( this[ 0 ] );
+			}
+
+			wrap.map(function() {
+				var elem = this;
+
+				while ( elem.firstElementChild ) {
+					elem = elem.firstElementChild;
+				}
+
+				return elem;
+			}).append( this );
+		}
+
+		return this;
+	},
+
+	wrapInner: function( html ) {
+		if ( jQuery.isFunction( html ) ) {
+			return this.each(function( i ) {
+				jQuery( this ).wrapInner( html.call(this, i) );
+			});
+		}
+
+		return this.each(function() {
+			var self = jQuery( this ),
+				contents = self.contents();
+
+			if ( contents.length ) {
+				contents.wrapAll( html );
+
+			} else {
+				self.append( html );
+			}
+		});
+	},
+
+	wrap: function( html ) {
+		var isFunction = jQuery.isFunction( html );
+
+		return this.each(function( i ) {
+			jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+		});
+	},
+
+	unwrap: function() {
+		return this.parent().each(function() {
+			if ( !jQuery.nodeName( this, "body" ) ) {
+				jQuery( this ).replaceWith( this.childNodes );
+			}
+		}).end();
+	}
+});
+
+
+jQuery.expr.filters.hidden = function( elem ) {
+	// Support: Opera <= 12.12
+	// Opera reports offsetWidths and offsetHeights less than zero on some elements
+	return elem.offsetWidth <= 0 && elem.offsetHeight <= 0;
+};
+jQuery.expr.filters.visible = function( elem ) {
+	return !jQuery.expr.filters.hidden( elem );
+};
+
+
+
+
+var r20 = /%20/g,
+	rbracket = /\[\]$/,
+	rCRLF = /\r?\n/g,
+	rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+	rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+function buildParams( prefix, obj, traditional, add ) {
+	var name;
+
+	if ( jQuery.isArray( obj ) ) {
+		// Serialize array item.
+		jQuery.each( obj, function( i, v ) {
+			if ( traditional || rbracket.test( prefix ) ) {
+				// Treat each array item as a scalar.
+				add( prefix, v );
+
+			} else {
+				// Item is non-scalar (array or object), encode its numeric index.
+				buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+			}
+		});
+
+	} else if ( !traditional && jQuery.type( obj ) === "object" ) {
+		// Serialize object item.
+		for ( name in obj ) {
+			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+		}
+
+	} else {
+		// Serialize scalar item.
+		add( prefix, obj );
+	}
+}
+
+// Serialize an array of form elements or a set of
+// key/values into a query string
+jQuery.param = function( a, traditional ) {
+	var prefix,
+		s = [],
+		add = function( key, value ) {
+			// If value is a function, invoke it and return its value
+			value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+			s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+		};
+
+	// Set traditional to true for jQuery <= 1.3.2 behavior.
+	if ( traditional === undefined ) {
+		traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+	}
+
+	// If an array was passed in, assume that it is an array of form elements.
+	if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+		// Serialize the form elements
+		jQuery.each( a, function() {
+			add( this.name, this.value );
+		});
+
+	} else {
+		// If traditional, encode the "old" way (the way 1.3.2 or older
+		// did it), otherwise encode params recursively.
+		for ( prefix in a ) {
+			buildParams( prefix, a[ prefix ], traditional, add );
+		}
+	}
+
+	// Return the resulting serialization
+	return s.join( "&" ).replace( r20, "+" );
+};
+
+jQuery.fn.extend({
+	serialize: function() {
+		return jQuery.param( this.serializeArray() );
+	},
+	serializeArray: function() {
+		return this.map(function() {
+			// Can add propHook for "elements" to filter or add form elements
+			var elements = jQuery.prop( this, "elements" );
+			return elements ? jQuery.makeArray( elements ) : this;
+		})
+		.filter(function() {
+			var type = this.type;
+
+			// Use .is( ":disabled" ) so that fieldset[disabled] works
+			return this.name && !jQuery( this ).is( ":disabled" ) &&
+				rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+				( this.checked || !rcheckableType.test( type ) );
+		})
+		.map(function( i, elem ) {
+			var val = jQuery( this ).val();
+
+			return val == null ?
+				null :
+				jQuery.isArray( val ) ?
+					jQuery.map( val, function( val ) {
+						return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+					}) :
+					{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+		}).get();
+	}
+});
+
+
+jQuery.ajaxSettings.xhr = function() {
+	try {
+		return new XMLHttpRequest();
+	} catch( e ) {}
+};
+
+var xhrId = 0,
+	xhrCallbacks = {},
+	xhrSuccessStatus = {
+		// file protocol always yields status code 0, assume 200
+		0: 200,
+		// Support: IE9
+		// #1450: sometimes IE returns 1223 when it should be 204
+		1223: 204
+	},
+	xhrSupported = jQuery.ajaxSettings.xhr();
+
+// Support: IE9
+// Open requests must be manually aborted on unload (#5280)
+// See https://support.microsoft.com/kb/2856746 for more info
+if ( window.attachEvent ) {
+	window.attachEvent( "onunload", function() {
+		for ( var key in xhrCallbacks ) {
+			xhrCallbacks[ key ]();
+		}
+	});
+}
+
+support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+support.ajax = xhrSupported = !!xhrSupported;
+
+jQuery.ajaxTransport(function( options ) {
+	var callback;
+
+	// Cross domain only allowed if supported through XMLHttpRequest
+	if ( support.cors || xhrSupported && !options.crossDomain ) {
+		return {
+			send: function( headers, complete ) {
+				var i,
+					xhr = options.xhr(),
+					id = ++xhrId;
+
+				xhr.open( options.type, options.url, options.async, options.username, options.password );
+
+				// Apply custom fields if provided
+				if ( options.xhrFields ) {
+					for ( i in options.xhrFields ) {
+						xhr[ i ] = options.xhrFields[ i ];
+					}
+				}
+
+				// Override mime type if needed
+				if ( options.mimeType && xhr.overrideMimeType ) {
+					xhr.overrideMimeType( options.mimeType );
+				}
+
+				// X-Requested-With header
+				// For cross-domain requests, seeing as conditions for a preflight are
+				// akin to a jigsaw puzzle, we simply never set it to be sure.
+				// (it can always be set on a per-request basis or even using ajaxSetup)
+				// For same-domain requests, won't change header if already provided.
+				if ( !options.crossDomain && !headers["X-Requested-With"] ) {
+					headers["X-Requested-With"] = "XMLHttpRequest";
+				}
+
+				// Set headers
+				for ( i in headers ) {
+					xhr.setRequestHeader( i, headers[ i ] );
+				}
+
+				// Callback
+				callback = function( type ) {
+					return function() {
+						if ( callback ) {
+							delete xhrCallbacks[ id ];
+							callback = xhr.onload = xhr.onerror = null;
+
+							if ( type === "abort" ) {
+								xhr.abort();
+							} else if ( type === "error" ) {
+								complete(
+									// file: protocol always yields status 0; see #8605, #14207
+									xhr.status,
+									xhr.statusText
+								);
+							} else {
+								complete(
+									xhrSuccessStatus[ xhr.status ] || xhr.status,
+									xhr.statusText,
+									// Support: IE9
+									// Accessing binary-data responseText throws an exception
+									// (#11426)
+									typeof xhr.responseText === "string" ? {
+										text: xhr.responseText
+									} : undefined,
+									xhr.getAllResponseHeaders()
+								);
+							}
+						}
+					};
+				};
+
+				// Listen to events
+				xhr.onload = callback();
+				xhr.onerror = callback("error");
+
+				// Create the abort callback
+				callback = xhrCallbacks[ id ] = callback("abort");
+
+				try {
+					// Do send the request (this may raise an exception)
+					xhr.send( options.hasContent && options.data || null );
+				} catch ( e ) {
+					// #14683: Only rethrow if this hasn't been notified as an error yet
+					if ( callback ) {
+						throw e;
+					}
+				}
+			},
+
+			abort: function() {
+				if ( callback ) {
+					callback();
+				}
+			}
+		};
+	}
+});
+
+
+
+
+// Install script dataType
+jQuery.ajaxSetup({
+	accepts: {
+		script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+	},
+	contents: {
+		script: /(?:java|ecma)script/
+	},
+	converters: {
+		"text script": function( text ) {
+			jQuery.globalEval( text );
+			return text;
+		}
+	}
+});
+
+// Handle cache's special case and crossDomain
+jQuery.ajaxPrefilter( "script", function( s ) {
+	if ( s.cache === undefined ) {
+		s.cache = false;
+	}
+	if ( s.crossDomain ) {
+		s.type = "GET";
+	}
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function( s ) {
+	// This transport only deals with cross domain requests
+	if ( s.crossDomain ) {
+		var script, callback;
+		return {
+			send: function( _, complete ) {
+				script = jQuery("<script>").prop({
+					async: true,
+					charset: s.scriptCharset,
+					src: s.url
+				}).on(
+					"load error",
+					callback = function( evt ) {
+						script.remove();
+						callback = null;
+						if ( evt ) {
+							complete( evt.type === "error" ? 404 : 200, evt.type );
+						}
+					}
+				);
+				document.head.appendChild( script[ 0 ] );
+			},
+			abort: function() {
+				if ( callback ) {
+					callback();
+				}
+			}
+		};
+	}
+});
+
+
+
+
+var oldCallbacks = [],
+	rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+	jsonp: "callback",
+	jsonpCallback: function() {
+		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
+		this[ callback ] = true;
+		return callback;
+	}
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+	var callbackName, overwritten, responseContainer,
+		jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+			"url" :
+			typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
+		);
+
+	// Handle iff the expected data type is "jsonp" or we have a parameter to set
+	if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+		// Get callback name, remembering preexisting value associated with it
+		callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
+			s.jsonpCallback() :
+			s.jsonpCallback;
+
+		// Insert callback into url or form data
+		if ( jsonProp ) {
+			s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+		} else if ( s.jsonp !== false ) {
+			s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+		}
+
+		// Use data converter to retrieve json after script execution
+		s.converters["script json"] = function() {
+			if ( !responseContainer ) {
+				jQuery.error( callbackName + " was not called" );
+			}
+			return responseContainer[ 0 ];
+		};
+
+		// force json dataType
+		s.dataTypes[ 0 ] = "json";
+
+		// Install callback
+		overwritten = window[ callbackName ];
+		window[ callbackName ] = function() {
+			responseContainer = arguments;
+		};
+
+		// Clean-up function (fires after converters)
+		jqXHR.always(function() {
+			// Restore preexisting value
+			window[ callbackName ] = overwritten;
+
+			// Save back as free
+			if ( s[ callbackName ] ) {
+				// make sure that re-using the options doesn't screw things around
+				s.jsonpCallback = originalSettings.jsonpCallback;
+
+				// save the callback name for future use
+				oldCallbacks.push( callbackName );
+			}
+
+			// Call if it was a function and we have a response
+			if ( responseContainer && jQuery.isFunction( overwritten ) ) {
+				overwritten( responseContainer[ 0 ] );
+			}
+
+			responseContainer = overwritten = undefined;
+		});
+
+		// Delegate to script
+		return "script";
+	}
+});
+
+
+
+
+// data: string of html
+// context (optional): If specified, the fragment will be created in this context, defaults to document
+// keepScripts (optional): If true, will include scripts passed in the html string
+jQuery.parseHTML = function( data, context, keepScripts ) {
+	if ( !data || typeof data !== "string" ) {
+		return null;
+	}
+	if ( typeof context === "boolean" ) {
+		keepScripts = context;
+		context = false;
+	}
+	context = context || document;
+
+	var parsed = rsingleTag.exec( data ),
+		scripts = !keepScripts && [];
+
+	// Single tag
+	if ( parsed ) {
+		return [ context.createElement( parsed[1] ) ];
+	}
+
+	parsed = jQuery.buildFragment( [ data ], context, scripts );
+
+	if ( scripts && scripts.length ) {
+		jQuery( scripts ).remove();
+	}
+
+	return jQuery.merge( [], parsed.childNodes );
+};
+
+
+// Keep a copy of the old load method
+var _load = jQuery.fn.load;
+
+/**
+ * Load a url into a page
+ */
+jQuery.fn.load = function( url, params, callback ) {
+	if ( typeof url !== "string" && _load ) {
+		return _load.apply( this, arguments );
+	}
+
+	var selector, type, response,
+		self = this,
+		off = url.indexOf(" ");
+
+	if ( off >= 0 ) {
+		selector = jQuery.trim( url.slice( off ) );
+		url = url.slice( 0, off );
+	}
+
+	// If it's a function
+	if ( jQuery.isFunction( params ) ) {
+
+		// We assume that it's the callback
+		callback = params;
+		params = undefined;
+
+	// Otherwise, build a param string
+	} else if ( params && typeof params === "object" ) {
+		type = "POST";
+	}
+
+	// If we have elements to modify, make the request
+	if ( self.length > 0 ) {
+		jQuery.ajax({
+			url: url,
+
+			// if "type" variable is undefined, then "GET" method will be used
+			type: type,
+			dataType: "html",
+			data: params
+		}).done(function( responseText ) {
+
+			// Save response for use in complete callback
+			response = arguments;
+
+			self.html( selector ?
+
+				// If a selector was specified, locate the right elements in a dummy div
+				// Exclude scripts to avoid IE 'Permission Denied' errors
+				jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+				// Otherwise use the full result
+				responseText );
+
+		}).complete( callback && function( jqXHR, status ) {
+			self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
+		});
+	}
+
+	return this;
+};
+
+
+
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
+	jQuery.fn[ type ] = function( fn ) {
+		return this.on( type, fn );
+	};
+});
+
+
+
+
+jQuery.expr.filters.animated = function( elem ) {
+	return jQuery.grep(jQuery.timers, function( fn ) {
+		return elem === fn.elem;
+	}).length;
+};
+
+
+
+
+var docElem = window.document.documentElement;
+
+/**
+ * Gets a window from an element
+ */
+function getWindow( elem ) {
+	return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
+}
+
+jQuery.offset = {
+	setOffset: function( elem, options, i ) {
+		var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
+			position = jQuery.css( elem, "position" ),
+			curElem = jQuery( elem ),
+			props = {};
+
+		// Set position first, in-case top/left are set even on static elem
+		if ( position === "static" ) {
+			elem.style.position = "relative";
+		}
+
+		curOffset = curElem.offset();
+		curCSSTop = jQuery.css( elem, "top" );
+		curCSSLeft = jQuery.css( elem, "left" );
+		calculatePosition = ( position === "absolute" || position === "fixed" ) &&
+			( curCSSTop + curCSSLeft ).indexOf("auto") > -1;
+
+		// Need to be able to calculate position if either
+		// top or left is auto and position is either absolute or fixed
+		if ( calculatePosition ) {
+			curPosition = curElem.position();
+			curTop = curPosition.top;
+			curLeft = curPosition.left;
+
+		} else {
+			curTop = parseFloat( curCSSTop ) || 0;
+			curLeft = parseFloat( curCSSLeft ) || 0;
+		}
+
+		if ( jQuery.isFunction( options ) ) {
+			options = options.call( elem, i, curOffset );
+		}
+
+		if ( options.top != null ) {
+			props.top = ( options.top - curOffset.top ) + curTop;
+		}
+		if ( options.left != null ) {
+			props.left = ( options.left - curOffset.left ) + curLeft;
+		}
+
+		if ( "using" in options ) {
+			options.using.call( elem, props );
+
+		} else {
+			curElem.css( props );
+		}
+	}
+};
+
+jQuery.fn.extend({
+	offset: function( options ) {
+		if ( arguments.length ) {
+			return options === undefined ?
+				this :
+				this.each(function( i ) {
+					jQuery.offset.setOffset( this, options, i );
+				});
+		}
+
+		var docElem, win,
+			elem = this[ 0 ],
+			box = { top: 0, left: 0 },
+			doc = elem && elem.ownerDocument;
+
+		if ( !doc ) {
+			return;
+		}
+
+		docElem = doc.documentElement;
+
+		// Make sure it's not a disconnected DOM node
+		if ( !jQuery.contains( docElem, elem ) ) {
+			return box;
+		}
+
+		// Support: BlackBerry 5, iOS 3 (original iPhone)
+		// If we don't have gBCR, just use 0,0 rather than error
+		if ( typeof elem.getBoundingClientRect !== strundefined ) {
+			box = elem.getBoundingClientRect();
+		}
+		win = getWindow( doc );
+		return {
+			top: box.top + win.pageYOffset - docElem.clientTop,
+			left: box.left + win.pageXOffset - docElem.clientLeft
+		};
+	},
+
+	position: function() {
+		if ( !this[ 0 ] ) {
+			return;
+		}
+
+		var offsetParent, offset,
+			elem = this[ 0 ],
+			parentOffset = { top: 0, left: 0 };
+
+		// Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
+		if ( jQuery.css( elem, "position" ) === "fixed" ) {
+			// Assume getBoundingClientRect is there when computed position is fixed
+			offset = elem.getBoundingClientRect();
+
+		} else {
+			// Get *real* offsetParent
+			offsetParent = this.offsetParent();
+
+			// Get correct offsets
+			offset = this.offset();
+			if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
+				parentOffset = offsetParent.offset();
+			}
+
+			// Add offsetParent borders
+			parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
+			parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
+		}
+
+		// Subtract parent offsets and element margins
+		return {
+			top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+			left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
+		};
+	},
+
+	offsetParent: function() {
+		return this.map(function() {
+			var offsetParent = this.offsetParent || docElem;
+
+			while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
+				offsetParent = offsetParent.offsetParent;
+			}
+
+			return offsetParent || docElem;
+		});
+	}
+});
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
+	var top = "pageYOffset" === prop;
+
+	jQuery.fn[ method ] = function( val ) {
+		return access( this, function( elem, method, val ) {
+			var win = getWindow( elem );
+
+			if ( val === undefined ) {
+				return win ? win[ prop ] : elem[ method ];
+			}
+
+			if ( win ) {
+				win.scrollTo(
+					!top ? val : window.pageXOffset,
+					top ? val : window.pageYOffset
+				);
+
+			} else {
+				elem[ method ] = val;
+			}
+		}, method, val, arguments.length, null );
+	};
+});
+
+// Support: Safari<7+, Chrome<37+
+// Add the top/left cssHooks using jQuery.fn.position
+// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+// Blink bug: https://code.google.com/p/chromium/issues/detail?id=229280
+// getComputedStyle returns percent when specified for top/left/bottom/right;
+// rather than make the css module depend on the offset module, just check for it here
+jQuery.each( [ "top", "left" ], function( i, prop ) {
+	jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
+		function( elem, computed ) {
+			if ( computed ) {
+				computed = curCSS( elem, prop );
+				// If curCSS returns percentage, fallback to offset
+				return rnumnonpx.test( computed ) ?
+					jQuery( elem ).position()[ prop ] + "px" :
+					computed;
+			}
+		}
+	);
+});
+
+
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+	jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
+		// Margin is only for outerHeight, outerWidth
+		jQuery.fn[ funcName ] = function( margin, value ) {
+			var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+				extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+			return access( this, function( elem, type, value ) {
+				var doc;
+
+				if ( jQuery.isWindow( elem ) ) {
+					// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
+					// isn't a whole lot we can do. See pull request at this URL for discussion:
+					// https://github.com/jquery/jquery/pull/764
+					return elem.document.documentElement[ "client" + name ];
+				}
+
+				// Get document width or height
+				if ( elem.nodeType === 9 ) {
+					doc = elem.documentElement;
+
+					// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
+					// whichever is greatest
+					return Math.max(
+						elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+						elem.body[ "offset" + name ], doc[ "offset" + name ],
+						doc[ "client" + name ]
+					);
+				}
+
+				return value === undefined ?
+					// Get width or height on the element, requesting but not forcing parseFloat
+					jQuery.css( elem, type, extra ) :
+
+					// Set width or height on the element
+					jQuery.style( elem, type, value, extra );
+			}, type, chainable ? margin : undefined, chainable, null );
+		};
+	});
+});
+
+
+// The number of elements contained in the matched element set
+jQuery.fn.size = function() {
+	return this.length;
+};
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+
+
+
+// Register as a named AMD module, since jQuery can be concatenated with other
+// files that may use define, but not via a proper concatenation script that
+// understands anonymous AMD modules. A named AMD is safest and most robust
+// way to register. Lowercase jquery is used because AMD module names are
+// derived from file names, and jQuery is normally delivered in a lowercase
+// file name. Do this after creating the global so that if an AMD module wants
+// to call noConflict to hide this version of jQuery, it will work.
+
+// Note that for maximum portability, libraries that are not jQuery should
+// declare themselves as anonymous modules, and avoid setting a global if an
+// AMD loader is present. jQuery is a special case. For more information, see
+// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
+
+if ( typeof define === "function" && define.amd ) {
+	define( "jquery", [], function() {
+		return jQuery;
+	});
+}
+
+
+
+
+var
+	// Map over jQuery in case of overwrite
+	_jQuery = window.jQuery,
+
+	// Map over the $ in case of overwrite
+	_$ = window.$;
+
+jQuery.noConflict = function( deep ) {
+	if ( window.$ === jQuery ) {
+		window.$ = _$;
+	}
+
+	if ( deep && window.jQuery === jQuery ) {
+		window.jQuery = _jQuery;
+	}
+
+	return jQuery;
+};
+
+// Expose jQuery and $ identifiers, even in AMD
+// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
+// and CommonJS for browser emulators (#13566)
+if ( typeof noGlobal === strundefined ) {
+	window.jQuery = window.$ = jQuery;
+}
+
+
+
+
+return jQuery;
+
+}));
diff --git a/platforms/android/app/src/main/assets/www/js/lib/jquery-weui.js b/platforms/android/app/src/main/assets/www/js/lib/jquery-weui.js
new file mode 100755
index 0000000..c4c1d98
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/jquery-weui.js
@@ -0,0 +1,6450 @@
+/** 
+* jQuery WeUI V1.2.1 
+* By 言川
+* http://lihongxun945.github.io/jquery-weui/
+ */
+/* global $:true */
+/* global WebKitCSSMatrix:true */
+
+(function($) {
+  "use strict";
+
+  $.fn.transitionEnd = function(callback) {
+    var events = ['webkitTransitionEnd', 'transitionend', 'oTransitionEnd', 'MSTransitionEnd', 'msTransitionEnd'],
+      i, dom = this;
+
+    function fireCallBack(e) {
+      /*jshint validthis:true */
+      if (e.target !== this) return;
+      callback.call(this, e);
+      for (i = 0; i < events.length; i++) {
+        dom.off(events[i], fireCallBack);
+      }
+    }
+    if (callback) {
+      for (i = 0; i < events.length; i++) {
+        dom.on(events[i], fireCallBack);
+      }
+    }
+    return this;
+  };
+
+  $.support = (function() {
+    var support = {
+      touch: !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch)
+    };
+    return support;
+  })();
+
+  $.touchEvents = {
+    start: $.support.touch ? 'touchstart' : 'mousedown',
+    move: $.support.touch ? 'touchmove' : 'mousemove',
+    end: $.support.touch ? 'touchend' : 'mouseup'
+  };
+
+  $.getTouchPosition = function(e) {
+    e = e.originalEvent || e; //jquery wrap the originevent
+    if(e.type === 'touchstart' || e.type === 'touchmove' || e.type === 'touchend') {
+      return {
+        x: e.targetTouches[0].pageX,
+        y: e.targetTouches[0].pageY
+      };
+    } else {
+      return {
+        x: e.pageX,
+        y: e.pageY
+      };
+    }
+  };
+
+  $.fn.scrollHeight = function() {
+    return this[0].scrollHeight;
+  };
+
+  $.fn.transform = function(transform) {
+    for (var i = 0; i < this.length; i++) {
+      var elStyle = this[i].style;
+      elStyle.webkitTransform = elStyle.MsTransform = elStyle.msTransform = elStyle.MozTransform = elStyle.OTransform = elStyle.transform = transform;
+    }
+    return this;
+  };
+  $.fn.transition = function(duration) {
+    if (typeof duration !== 'string') {
+      duration = duration + 'ms';
+    }
+    for (var i = 0; i < this.length; i++) {
+      var elStyle = this[i].style;
+      elStyle.webkitTransitionDuration = elStyle.MsTransitionDuration = elStyle.msTransitionDuration = elStyle.MozTransitionDuration = elStyle.OTransitionDuration = elStyle.transitionDuration = duration;
+    }
+    return this;
+  };
+
+  $.getTranslate = function (el, axis) {
+    var matrix, curTransform, curStyle, transformMatrix;
+
+    // automatic axis detection
+    if (typeof axis === 'undefined') {
+      axis = 'x';
+    }
+
+    curStyle = window.getComputedStyle(el, null);
+    if (window.WebKitCSSMatrix) {
+      // Some old versions of Webkit choke when 'none' is passed; pass
+      // empty string instead in this case
+      transformMatrix = new WebKitCSSMatrix(curStyle.webkitTransform === 'none' ? '' : curStyle.webkitTransform);
+    }
+    else {
+      transformMatrix = curStyle.MozTransform || curStyle.OTransform || curStyle.MsTransform || curStyle.msTransform  || curStyle.transform || curStyle.getPropertyValue('transform').replace('translate(', 'matrix(1, 0, 0, 1,');
+      matrix = transformMatrix.toString().split(',');
+    }
+
+    if (axis === 'x') {
+      //Latest Chrome and webkits Fix
+      if (window.WebKitCSSMatrix)
+        curTransform = transformMatrix.m41;
+      //Crazy IE10 Matrix
+      else if (matrix.length === 16)
+        curTransform = parseFloat(matrix[12]);
+      //Normal Browsers
+      else
+        curTransform = parseFloat(matrix[4]);
+    }
+    if (axis === 'y') {
+      //Latest Chrome and webkits Fix
+      if (window.WebKitCSSMatrix)
+        curTransform = transformMatrix.m42;
+      //Crazy IE10 Matrix
+      else if (matrix.length === 16)
+        curTransform = parseFloat(matrix[13]);
+      //Normal Browsers
+      else
+        curTransform = parseFloat(matrix[5]);
+    }
+
+    return curTransform || 0;
+  };
+  $.requestAnimationFrame = function (callback) {
+    if (window.requestAnimationFrame) return window.requestAnimationFrame(callback);
+    else if (window.webkitRequestAnimationFrame) return window.webkitRequestAnimationFrame(callback);
+    else if (window.mozRequestAnimationFrame) return window.mozRequestAnimationFrame(callback);
+    else {
+      return window.setTimeout(callback, 1000 / 60);
+    }
+  };
+
+  $.cancelAnimationFrame = function (id) {
+    if (window.cancelAnimationFrame) return window.cancelAnimationFrame(id);
+    else if (window.webkitCancelAnimationFrame) return window.webkitCancelAnimationFrame(id);
+    else if (window.mozCancelAnimationFrame) return window.mozCancelAnimationFrame(id);
+    else {
+      return window.clearTimeout(id);
+    }  
+  };
+
+  $.fn.join = function(arg) {
+    return this.toArray().join(arg);
+  }
+})($);
+
+/*===========================
+  Template7 Template engine
+  ===========================*/
+/* global $:true */
+/* jshint unused:false */
+/* jshint forin:false */
++function ($) {
+  "use strict";
+  $.Template7 = $.t7 = (function () {
+    function isArray(arr) {
+      return Object.prototype.toString.apply(arr) === '[object Array]';
+    }
+    function isObject(obj) {
+      return obj instanceof Object;
+    }
+    function isFunction(func) {
+      return typeof func === 'function';
+    }
+    var cache = {};
+    function helperToSlices(string) {
+      var helperParts = string.replace(/[{}#}]/g, '').split(' ');
+      var slices = [];
+      var shiftIndex, i, j;
+      for (i = 0; i < helperParts.length; i++) {
+        var part = helperParts[i];
+        if (i === 0) slices.push(part);
+        else {
+          if (part.indexOf('"') === 0) {
+            // Plain String
+            if (part.match(/"/g).length === 2) {
+              // One word string
+              slices.push(part);
+            }
+            else {
+              // Find closed Index
+              shiftIndex = 0;
+              for (j = i + 1; j < helperParts.length; j++) {
+                part += ' ' + helperParts[j];
+                if (helperParts[j].indexOf('"') >= 0) {
+                  shiftIndex = j;
+                  slices.push(part);
+                  break;
+                }
+              }
+              if (shiftIndex) i = shiftIndex;
+            }
+          }
+          else {
+            if (part.indexOf('=') > 0) {
+              // Hash
+              var hashParts = part.split('=');
+              var hashName = hashParts[0];
+              var hashContent = hashParts[1];
+              if (hashContent.match(/"/g).length !== 2) {
+                shiftIndex = 0;
+                for (j = i + 1; j < helperParts.length; j++) {
+                  hashContent += ' ' + helperParts[j];
+                  if (helperParts[j].indexOf('"') >= 0) {
+                    shiftIndex = j;
+                    break;
+                  }
+                }
+                if (shiftIndex) i = shiftIndex;
+              }
+              var hash = [hashName, hashContent.replace(/"/g,'')];
+              slices.push(hash);
+            }
+            else {
+              // Plain variable
+              slices.push(part);
+            }
+          }
+        }
+      }
+      return slices;
+    }
+    function stringToBlocks(string) {
+      var blocks = [], i, j, k;
+      if (!string) return [];
+      var _blocks = string.split(/({{[^{^}]*}})/);
+      for (i = 0; i < _blocks.length; i++) {
+        var block = _blocks[i];
+        if (block === '') continue;
+        if (block.indexOf('{{') < 0) {
+          blocks.push({
+            type: 'plain',
+            content: block
+          });
+        }
+        else {
+          if (block.indexOf('{/') >= 0) {
+            continue;
+          }
+          if (block.indexOf('{#') < 0 && block.indexOf(' ') < 0 && block.indexOf('else') < 0) {
+            // Simple variable
+            blocks.push({
+              type: 'variable',
+              contextName: block.replace(/[{}]/g, '')
+            });
+            continue;
+          }
+          // Helpers
+          var helperSlices = helperToSlices(block);
+          var helperName = helperSlices[0];
+          var helperContext = [];
+          var helperHash = {};
+          for (j = 1; j < helperSlices.length; j++) {
+            var slice = helperSlices[j];
+            if (isArray(slice)) {
+              // Hash
+              helperHash[slice[0]] = slice[1] === 'false' ? false : slice[1];
+            }
+            else {
+              helperContext.push(slice);
+            }
+          }
+
+          if (block.indexOf('{#') >= 0) {
+            // Condition/Helper
+            var helperStartIndex = i;
+            var helperContent = '';
+            var elseContent = '';
+            var toSkip = 0;
+            var shiftIndex;
+            var foundClosed = false, foundElse = false, foundClosedElse = false, depth = 0;
+            for (j = i + 1; j < _blocks.length; j++) {
+              if (_blocks[j].indexOf('{{#') >= 0) {
+                depth ++;
+              }
+              if (_blocks[j].indexOf('{{/') >= 0) {
+                depth --;
+              }
+              if (_blocks[j].indexOf('{{#' + helperName) >= 0) {
+                helperContent += _blocks[j];
+                if (foundElse) elseContent += _blocks[j];
+                toSkip ++;
+              }
+              else if (_blocks[j].indexOf('{{/' + helperName) >= 0) {
+                if (toSkip > 0) {
+                  toSkip--;
+                  helperContent += _blocks[j];
+                  if (foundElse) elseContent += _blocks[j];
+                }
+                else {
+                  shiftIndex = j;
+                  foundClosed = true;
+                  break;
+                }
+              }
+              else if (_blocks[j].indexOf('else') >= 0 && depth === 0) {
+                foundElse = true;
+              }
+              else {
+                if (!foundElse) helperContent += _blocks[j];
+                if (foundElse) elseContent += _blocks[j];
+              }
+
+            }
+            if (foundClosed) {
+              if (shiftIndex) i = shiftIndex;
+              blocks.push({
+                type: 'helper',
+                helperName: helperName,
+                contextName: helperContext,
+                content: helperContent,
+                inverseContent: elseContent,
+                hash: helperHash
+              });
+            }
+          }
+          else if (block.indexOf(' ') > 0) {
+            blocks.push({
+              type: 'helper',
+              helperName: helperName,
+              contextName: helperContext,
+              hash: helperHash
+            });
+          }
+        }
+      }
+      return blocks;
+    }
+    var Template7 = function (template) {
+      var t = this;
+      t.template = template;
+
+      function getCompileFn(block, depth) {
+        if (block.content) return compile(block.content, depth);
+        else return function () {return ''; };
+      }
+      function getCompileInverse(block, depth) {
+        if (block.inverseContent) return compile(block.inverseContent, depth);
+        else return function () {return ''; };
+      }
+      function getCompileVar(name, ctx) {
+        var variable, parts, levelsUp = 0, initialCtx = ctx;
+        if (name.indexOf('../') === 0) {
+          levelsUp = name.split('../').length - 1;
+          var newDepth = ctx.split('_')[1] - levelsUp;
+          ctx = 'ctx_' + (newDepth >= 1 ? newDepth : 1);
+          parts = name.split('../')[levelsUp].split('.');
+        }
+        else if (name.indexOf('@global') === 0) {
+          ctx = '$.Template7.global';
+          parts = name.split('@global.')[1].split('.');
+        }
+        else if (name.indexOf('@root') === 0) {
+          ctx = 'ctx_1';
+          parts = name.split('@root.')[1].split('.');
+        }
+        else {
+          parts = name.split('.');
+        }
+        variable = ctx;
+        for (var i = 0; i < parts.length; i++) {
+          var part = parts[i];
+          if (part.indexOf('@') === 0) {
+            if (i > 0) {
+              variable += '[(data && data.' + part.replace('@', '') + ')]';
+            }
+            else {
+              variable = '(data && data.' + name.replace('@', '') + ')';
+            }
+          }
+          else {
+            if (isFinite(part)) {
+              variable += '[' + part + ']';
+            }
+            else {
+              if (part.indexOf('this') === 0) {
+                variable = part.replace('this', ctx);
+              }
+              else {
+                variable += '.' + part;       
+              }
+            }
+          }
+        }
+
+        return variable;
+      }
+      function getCompiledArguments(contextArray, ctx) {
+        var arr = [];
+        for (var i = 0; i < contextArray.length; i++) {
+          if (contextArray[i].indexOf('"') === 0) arr.push(contextArray[i]);
+          else {
+            arr.push(getCompileVar(contextArray[i], ctx));
+          }
+        }
+        return arr.join(', ');
+      }
+      function compile(template, depth) {
+        depth = depth || 1;
+        template = template || t.template;
+        if (typeof template !== 'string') {
+          throw new Error('Template7: Template must be a string');
+        }
+        var blocks = stringToBlocks(template);
+        if (blocks.length === 0) {
+          return function () { return ''; };
+        }
+        var ctx = 'ctx_' + depth;
+        var resultString = '(function (' + ctx + ', data) {\n';
+        if (depth === 1) {
+          resultString += 'function isArray(arr){return Object.prototype.toString.apply(arr) === \'[object Array]\';}\n';
+          resultString += 'function isFunction(func){return (typeof func === \'function\');}\n';
+          resultString += 'function c(val, ctx) {if (typeof val !== "undefined") {if (isFunction(val)) {return val.call(ctx);} else return val;} else return "";}\n';
+        }
+        resultString += 'var r = \'\';\n';
+        var i, j, context;
+        for (i = 0; i < blocks.length; i++) {
+          var block = blocks[i];
+          // Plain block
+          if (block.type === 'plain') {
+            resultString += 'r +=\'' + (block.content).replace(/\r/g, '\\r').replace(/\n/g, '\\n').replace(/'/g, '\\' + '\'') + '\';';
+            continue;
+          }
+          var variable, compiledArguments;
+          // Variable block
+          if (block.type === 'variable') {
+            variable = getCompileVar(block.contextName, ctx);
+            resultString += 'r += c(' + variable + ', ' + ctx + ');';
+          }
+          // Helpers block
+          if (block.type === 'helper') {
+            if (block.helperName in t.helpers) {
+              compiledArguments = getCompiledArguments(block.contextName, ctx);
+              resultString += 'r += ($.Template7.helpers.' + block.helperName + ').call(' + ctx + ', ' + (compiledArguments && (compiledArguments + ', ')) +'{hash:' + JSON.stringify(block.hash) + ', data: data || {}, fn: ' + getCompileFn(block, depth+1) + ', inverse: ' + getCompileInverse(block, depth+1) + ', root: ctx_1});';
+            }
+            else {
+              if (block.contextName.length > 0) {
+                throw new Error('Template7: Missing helper: "' + block.helperName + '"');
+              }
+              else {
+                variable = getCompileVar(block.helperName, ctx);
+                resultString += 'if (' + variable + ') {';
+                resultString += 'if (isArray(' + variable + ')) {';
+                resultString += 'r += ($.Template7.helpers.each).call(' + ctx + ', ' + variable + ', {hash:' + JSON.stringify(block.hash) + ', data: data || {}, fn: ' + getCompileFn(block, depth+1) + ', inverse: ' + getCompileInverse(block, depth+1) + ', root: ctx_1});';
+                resultString += '}else {';
+                resultString += 'r += ($.Template7.helpers.with).call(' + ctx + ', ' + variable + ', {hash:' + JSON.stringify(block.hash) + ', data: data || {}, fn: ' + getCompileFn(block, depth+1) + ', inverse: ' + getCompileInverse(block, depth+1) + ', root: ctx_1});';
+                resultString += '}}';
+              }
+            }
+          }
+        }
+        resultString += '\nreturn r;})';
+        return eval.call(window, resultString);
+      }
+      t.compile = function (template) {
+        if (!t.compiled) {
+          t.compiled = compile(template);
+        }
+        return t.compiled;
+      };
+    };
+    Template7.prototype = {
+      options: {},
+      helpers: {
+        'if': function (context, options) {
+          if (isFunction(context)) { context = context.call(this); }
+          if (context) {
+            return options.fn(this, options.data);
+          }
+          else {
+            return options.inverse(this, options.data);
+          }
+        },
+        'unless': function (context, options) {
+          if (isFunction(context)) { context = context.call(this); }
+          if (!context) {
+            return options.fn(this, options.data);
+          }
+          else {
+            return options.inverse(this, options.data);
+          }
+        },
+        'each': function (context, options) {
+          var ret = '', i = 0;
+          if (isFunction(context)) { context = context.call(this); }
+          if (isArray(context)) {
+            if (options.hash.reverse) {
+              context = context.reverse();
+            }
+            for (i = 0; i < context.length; i++) {
+              ret += options.fn(context[i], {first: i === 0, last: i === context.length - 1, index: i});
+            }
+            if (options.hash.reverse) {
+              context = context.reverse();
+            }
+          }
+          else {
+            for (var key in context) {
+              i++;
+              ret += options.fn(context[key], {key: key});
+            }
+          }
+          if (i > 0) return ret;
+          else return options.inverse(this);
+        },
+        'with': function (context, options) {
+          if (isFunction(context)) { context = context.call(this); }
+          return options.fn(context);
+        },
+        'join': function (context, options) {
+          if (isFunction(context)) { context = context.call(this); }
+          return context.join(options.hash.delimiter || options.hash.delimeter);
+        },
+        'js': function (expression, options) {
+          var func;
+          if (expression.indexOf('return')>=0) {
+            func = '(function(){'+expression+'})';
+          }
+          else {
+            func = '(function(){return ('+expression+')})';
+          }
+          return eval.call(this, func).call(this);
+        },
+        'js_compare': function (expression, options) {
+          var func;
+          if (expression.indexOf('return')>=0) {
+            func = '(function(){'+expression+'})';
+          }
+          else {
+            func = '(function(){return ('+expression+')})';
+          }
+          var condition = eval.call(this, func).call(this);
+          if (condition) {
+            return options.fn(this, options.data);
+          }
+          else {
+            return options.inverse(this, options.data);   
+          }
+        }
+      }
+    };
+    var t7 = function (template, data) {
+      if (arguments.length === 2) {
+        var instance = new Template7(template);
+        var rendered = instance.compile()(data);
+        instance = null;
+        return (rendered);
+      }
+      else return new Template7(template);
+    };
+    t7.registerHelper = function (name, fn) {
+      Template7.prototype.helpers[name] = fn;
+    };
+    t7.unregisterHelper = function (name) {
+      Template7.prototype.helpers[name] = undefined;  
+      delete Template7.prototype.helpers[name];
+    };
+
+    t7.compile = function (template, options) {
+      var instance = new Template7(template, options);
+      return instance.compile();
+    };
+
+    t7.options = Template7.prototype.options;
+    t7.helpers = Template7.prototype.helpers;
+    return t7;
+  })();
+}($);
+
+/*! Hammer.JS - v2.0.8 - 2016-04-23
+ * http://hammerjs.github.io/
+ *
+ * Copyright (c) 2016 Jorik Tangelder;
+ * Licensed under the MIT license */
+(function(window, document, exportName, undefined) {
+  'use strict';
+
+var VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o'];
+var TEST_ELEMENT = document.createElement('div');
+
+var TYPE_FUNCTION = 'function';
+
+var round = Math.round;
+var abs = Math.abs;
+var now = Date.now;
+
+/**
+ * set a timeout with a given scope
+ * @param {Function} fn
+ * @param {Number} timeout
+ * @param {Object} context
+ * @returns {number}
+ */
+function setTimeoutContext(fn, timeout, context) {
+    return setTimeout(bindFn(fn, context), timeout);
+}
+
+/**
+ * if the argument is an array, we want to execute the fn on each entry
+ * if it aint an array we don't want to do a thing.
+ * this is used by all the methods that accept a single and array argument.
+ * @param {*|Array} arg
+ * @param {String} fn
+ * @param {Object} [context]
+ * @returns {Boolean}
+ */
+function invokeArrayArg(arg, fn, context) {
+    if (Array.isArray(arg)) {
+        each(arg, context[fn], context);
+        return true;
+    }
+    return false;
+}
+
+/**
+ * walk objects and arrays
+ * @param {Object} obj
+ * @param {Function} iterator
+ * @param {Object} context
+ */
+function each(obj, iterator, context) {
+    var i;
+
+    if (!obj) {
+        return;
+    }
+
+    if (obj.forEach) {
+        obj.forEach(iterator, context);
+    } else if (obj.length !== undefined) {
+        i = 0;
+        while (i < obj.length) {
+            iterator.call(context, obj[i], i, obj);
+            i++;
+        }
+    } else {
+        for (i in obj) {
+            obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);
+        }
+    }
+}
+
+/**
+ * wrap a method with a deprecation warning and stack trace
+ * @param {Function} method
+ * @param {String} name
+ * @param {String} message
+ * @returns {Function} A new function wrapping the supplied method.
+ */
+function deprecate(method, name, message) {
+    var deprecationMessage = 'DEPRECATED METHOD: ' + name + '\n' + message + ' AT \n';
+    return function() {
+        var e = new Error('get-stack-trace');
+        var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, '')
+            .replace(/^\s+at\s+/gm, '')
+            .replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@') : 'Unknown Stack Trace';
+
+        var log = window.console && (window.console.warn || window.console.log);
+        if (log) {
+            log.call(window.console, deprecationMessage, stack);
+        }
+        return method.apply(this, arguments);
+    };
+}
+
+/**
+ * extend object.
+ * means that properties in dest will be overwritten by the ones in src.
+ * @param {Object} target
+ * @param {...Object} objects_to_assign
+ * @returns {Object} target
+ */
+var assign;
+if (typeof Object.assign !== 'function') {
+    assign = function assign(target) {
+        if (target === undefined || target === null) {
+            throw new TypeError('Cannot convert undefined or null to object');
+        }
+
+        var output = Object(target);
+        for (var index = 1; index < arguments.length; index++) {
+            var source = arguments[index];
+            if (source !== undefined && source !== null) {
+                for (var nextKey in source) {
+                    if (source.hasOwnProperty(nextKey)) {
+                        output[nextKey] = source[nextKey];
+                    }
+                }
+            }
+        }
+        return output;
+    };
+} else {
+    assign = Object.assign;
+}
+
+/**
+ * extend object.
+ * means that properties in dest will be overwritten by the ones in src.
+ * @param {Object} dest
+ * @param {Object} src
+ * @param {Boolean} [merge=false]
+ * @returns {Object} dest
+ */
+var extend = deprecate(function extend(dest, src, merge) {
+    var keys = Object.keys(src);
+    var i = 0;
+    while (i < keys.length) {
+        if (!merge || (merge && dest[keys[i]] === undefined)) {
+            dest[keys[i]] = src[keys[i]];
+        }
+        i++;
+    }
+    return dest;
+}, 'extend', 'Use `assign`.');
+
+/**
+ * merge the values from src in the dest.
+ * means that properties that exist in dest will not be overwritten by src
+ * @param {Object} dest
+ * @param {Object} src
+ * @returns {Object} dest
+ */
+var merge = deprecate(function merge(dest, src) {
+    return extend(dest, src, true);
+}, 'merge', 'Use `assign`.');
+
+/**
+ * simple class inheritance
+ * @param {Function} child
+ * @param {Function} base
+ * @param {Object} [properties]
+ */
+function inherit(child, base, properties) {
+    var baseP = base.prototype,
+        childP;
+
+    childP = child.prototype = Object.create(baseP);
+    childP.constructor = child;
+    childP._super = baseP;
+
+    if (properties) {
+        assign(childP, properties);
+    }
+}
+
+/**
+ * simple function bind
+ * @param {Function} fn
+ * @param {Object} context
+ * @returns {Function}
+ */
+function bindFn(fn, context) {
+    return function boundFn() {
+        return fn.apply(context, arguments);
+    };
+}
+
+/**
+ * let a boolean value also be a function that must return a boolean
+ * this first item in args will be used as the context
+ * @param {Boolean|Function} val
+ * @param {Array} [args]
+ * @returns {Boolean}
+ */
+function boolOrFn(val, args) {
+    if (typeof val == TYPE_FUNCTION) {
+        return val.apply(args ? args[0] || undefined : undefined, args);
+    }
+    return val;
+}
+
+/**
+ * use the val2 when val1 is undefined
+ * @param {*} val1
+ * @param {*} val2
+ * @returns {*}
+ */
+function ifUndefined(val1, val2) {
+    return (val1 === undefined) ? val2 : val1;
+}
+
+/**
+ * addEventListener with multiple events at once
+ * @param {EventTarget} target
+ * @param {String} types
+ * @param {Function} handler
+ */
+function addEventListeners(target, types, handler) {
+    each(splitStr(types), function(type) {
+        target.addEventListener(type, handler, false);
+    });
+}
+
+/**
+ * removeEventListener with multiple events at once
+ * @param {EventTarget} target
+ * @param {String} types
+ * @param {Function} handler
+ */
+function removeEventListeners(target, types, handler) {
+    each(splitStr(types), function(type) {
+        target.removeEventListener(type, handler, false);
+    });
+}
+
+/**
+ * find if a node is in the given parent
+ * @method hasParent
+ * @param {HTMLElement} node
+ * @param {HTMLElement} parent
+ * @return {Boolean} found
+ */
+function hasParent(node, parent) {
+    while (node) {
+        if (node == parent) {
+            return true;
+        }
+        node = node.parentNode;
+    }
+    return false;
+}
+
+/**
+ * small indexOf wrapper
+ * @param {String} str
+ * @param {String} find
+ * @returns {Boolean} found
+ */
+function inStr(str, find) {
+    return str.indexOf(find) > -1;
+}
+
+/**
+ * split string on whitespace
+ * @param {String} str
+ * @returns {Array} words
+ */
+function splitStr(str) {
+    return str.trim().split(/\s+/g);
+}
+
+/**
+ * find if a array contains the object using indexOf or a simple polyFill
+ * @param {Array} src
+ * @param {String} find
+ * @param {String} [findByKey]
+ * @return {Boolean|Number} false when not found, or the index
+ */
+function inArray(src, find, findByKey) {
+    if (src.indexOf && !findByKey) {
+        return src.indexOf(find);
+    } else {
+        var i = 0;
+        while (i < src.length) {
+            if ((findByKey && src[i][findByKey] == find) || (!findByKey && src[i] === find)) {
+                return i;
+            }
+            i++;
+        }
+        return -1;
+    }
+}
+
+/**
+ * convert array-like objects to real arrays
+ * @param {Object} obj
+ * @returns {Array}
+ */
+function toArray(obj) {
+    return Array.prototype.slice.call(obj, 0);
+}
+
+/**
+ * unique array with objects based on a key (like 'id') or just by the array's value
+ * @param {Array} src [{id:1},{id:2},{id:1}]
+ * @param {String} [key]
+ * @param {Boolean} [sort=False]
+ * @returns {Array} [{id:1},{id:2}]
+ */
+function uniqueArray(src, key, sort) {
+    var results = [];
+    var values = [];
+    var i = 0;
+
+    while (i < src.length) {
+        var val = key ? src[i][key] : src[i];
+        if (inArray(values, val) < 0) {
+            results.push(src[i]);
+        }
+        values[i] = val;
+        i++;
+    }
+
+    if (sort) {
+        if (!key) {
+            results = results.sort();
+        } else {
+            results = results.sort(function sortUniqueArray(a, b) {
+                return a[key] > b[key];
+            });
+        }
+    }
+
+    return results;
+}
+
+/**
+ * get the prefixed property
+ * @param {Object} obj
+ * @param {String} property
+ * @returns {String|Undefined} prefixed
+ */
+function prefixed(obj, property) {
+    var prefix, prop;
+    var camelProp = property[0].toUpperCase() + property.slice(1);
+
+    var i = 0;
+    while (i < VENDOR_PREFIXES.length) {
+        prefix = VENDOR_PREFIXES[i];
+        prop = (prefix) ? prefix + camelProp : property;
+
+        if (prop in obj) {
+            return prop;
+        }
+        i++;
+    }
+    return undefined;
+}
+
+/**
+ * get a unique id
+ * @returns {number} uniqueId
+ */
+var _uniqueId = 1;
+function uniqueId() {
+    return _uniqueId++;
+}
+
+/**
+ * get the window object of an element
+ * @param {HTMLElement} element
+ * @returns {DocumentView|Window}
+ */
+function getWindowForElement(element) {
+    var doc = element.ownerDocument || element;
+    return (doc.defaultView || doc.parentWindow || window);
+}
+
+var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
+
+var SUPPORT_TOUCH = ('ontouchstart' in window);
+var SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined;
+var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
+
+var INPUT_TYPE_TOUCH = 'touch';
+var INPUT_TYPE_PEN = 'pen';
+var INPUT_TYPE_MOUSE = 'mouse';
+var INPUT_TYPE_KINECT = 'kinect';
+
+var COMPUTE_INTERVAL = 25;
+
+var INPUT_START = 1;
+var INPUT_MOVE = 2;
+var INPUT_END = 4;
+var INPUT_CANCEL = 8;
+
+var DIRECTION_NONE = 1;
+var DIRECTION_LEFT = 2;
+var DIRECTION_RIGHT = 4;
+var DIRECTION_UP = 8;
+var DIRECTION_DOWN = 16;
+
+var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
+var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
+var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
+
+var PROPS_XY = ['x', 'y'];
+var PROPS_CLIENT_XY = ['clientX', 'clientY'];
+
+/**
+ * create new input type manager
+ * @param {Manager} manager
+ * @param {Function} callback
+ * @returns {Input}
+ * @constructor
+ */
+function Input(manager, callback) {
+    var self = this;
+    this.manager = manager;
+    this.callback = callback;
+    this.element = manager.element;
+    this.target = manager.options.inputTarget;
+
+    // smaller wrapper around the handler, for the scope and the enabled state of the manager,
+    // so when disabled the input events are completely bypassed.
+    this.domHandler = function(ev) {
+        if (boolOrFn(manager.options.enable, [manager])) {
+            self.handler(ev);
+        }
+    };
+
+    this.init();
+
+}
+
+Input.prototype = {
+    /**
+     * should handle the inputEvent data and trigger the callback
+     * @virtual
+     */
+    handler: function() { },
+
+    /**
+     * bind the events
+     */
+    init: function() {
+        this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
+        this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
+        this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
+    },
+
+    /**
+     * unbind the events
+     */
+    destroy: function() {
+        this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
+        this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
+        this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
+    }
+};
+
+/**
+ * create new input type manager
+ * called by the Manager constructor
+ * @param {Hammer} manager
+ * @returns {Input}
+ */
+function createInputInstance(manager) {
+    var Type;
+    var inputClass = manager.options.inputClass;
+
+    if (inputClass) {
+        Type = inputClass;
+    } else if (SUPPORT_POINTER_EVENTS) {
+        Type = PointerEventInput;
+    } else if (SUPPORT_ONLY_TOUCH) {
+        Type = TouchInput;
+    } else if (!SUPPORT_TOUCH) {
+        Type = MouseInput;
+    } else {
+        Type = TouchMouseInput;
+    }
+    return new (Type)(manager, inputHandler);
+}
+
+/**
+ * handle input events
+ * @param {Manager} manager
+ * @param {String} eventType
+ * @param {Object} input
+ */
+function inputHandler(manager, eventType, input) {
+    var pointersLen = input.pointers.length;
+    var changedPointersLen = input.changedPointers.length;
+    var isFirst = (eventType & INPUT_START && (pointersLen - changedPointersLen === 0));
+    var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (pointersLen - changedPointersLen === 0));
+
+    input.isFirst = !!isFirst;
+    input.isFinal = !!isFinal;
+
+    if (isFirst) {
+        manager.session = {};
+    }
+
+    // source event is the normalized value of the domEvents
+    // like 'touchstart, mouseup, pointerdown'
+    input.eventType = eventType;
+
+    // compute scale, rotation etc
+    computeInputData(manager, input);
+
+    // emit secret event
+    manager.emit('hammer.input', input);
+
+    manager.recognize(input);
+    manager.session.prevInput = input;
+}
+
+/**
+ * extend the data with some usable properties like scale, rotate, velocity etc
+ * @param {Object} manager
+ * @param {Object} input
+ */
+function computeInputData(manager, input) {
+    var session = manager.session;
+    var pointers = input.pointers;
+    var pointersLength = pointers.length;
+
+    // store the first input to calculate the distance and direction
+    if (!session.firstInput) {
+        session.firstInput = simpleCloneInputData(input);
+    }
+
+    // to compute scale and rotation we need to store the multiple touches
+    if (pointersLength > 1 && !session.firstMultiple) {
+        session.firstMultiple = simpleCloneInputData(input);
+    } else if (pointersLength === 1) {
+        session.firstMultiple = false;
+    }
+
+    var firstInput = session.firstInput;
+    var firstMultiple = session.firstMultiple;
+    var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;
+
+    var center = input.center = getCenter(pointers);
+    input.timeStamp = now();
+    input.deltaTime = input.timeStamp - firstInput.timeStamp;
+
+    input.angle = getAngle(offsetCenter, center);
+    input.distance = getDistance(offsetCenter, center);
+
+    computeDeltaXY(session, input);
+    input.offsetDirection = getDirection(input.deltaX, input.deltaY);
+
+    var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY);
+    input.overallVelocityX = overallVelocity.x;
+    input.overallVelocityY = overallVelocity.y;
+    input.overallVelocity = (abs(overallVelocity.x) > abs(overallVelocity.y)) ? overallVelocity.x : overallVelocity.y;
+
+    input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
+    input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;
+
+    input.maxPointers = !session.prevInput ? input.pointers.length : ((input.pointers.length >
+        session.prevInput.maxPointers) ? input.pointers.length : session.prevInput.maxPointers);
+
+    computeIntervalInputData(session, input);
+
+    // find the correct target
+    var target = manager.element;
+    if (hasParent(input.srcEvent.target, target)) {
+        target = input.srcEvent.target;
+    }
+    input.target = target;
+}
+
+function computeDeltaXY(session, input) {
+    var center = input.center;
+    var offset = session.offsetDelta || {};
+    var prevDelta = session.prevDelta || {};
+    var prevInput = session.prevInput || {};
+
+    if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
+        prevDelta = session.prevDelta = {
+            x: prevInput.deltaX || 0,
+            y: prevInput.deltaY || 0
+        };
+
+        offset = session.offsetDelta = {
+            x: center.x,
+            y: center.y
+        };
+    }
+
+    input.deltaX = prevDelta.x + (center.x - offset.x);
+    input.deltaY = prevDelta.y + (center.y - offset.y);
+}
+
+/**
+ * velocity is calculated every x ms
+ * @param {Object} session
+ * @param {Object} input
+ */
+function computeIntervalInputData(session, input) {
+    var last = session.lastInterval || input,
+        deltaTime = input.timeStamp - last.timeStamp,
+        velocity, velocityX, velocityY, direction;
+
+    if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {
+        var deltaX = input.deltaX - last.deltaX;
+        var deltaY = input.deltaY - last.deltaY;
+
+        var v = getVelocity(deltaTime, deltaX, deltaY);
+        velocityX = v.x;
+        velocityY = v.y;
+        velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y;
+        direction = getDirection(deltaX, deltaY);
+
+        session.lastInterval = input;
+    } else {
+        // use latest velocity info if it doesn't overtake a minimum period
+        velocity = last.velocity;
+        velocityX = last.velocityX;
+        velocityY = last.velocityY;
+        direction = last.direction;
+    }
+
+    input.velocity = velocity;
+    input.velocityX = velocityX;
+    input.velocityY = velocityY;
+    input.direction = direction;
+}
+
+/**
+ * create a simple clone from the input used for storage of firstInput and firstMultiple
+ * @param {Object} input
+ * @returns {Object} clonedInputData
+ */
+function simpleCloneInputData(input) {
+    // make a simple copy of the pointers because we will get a reference if we don't
+    // we only need clientXY for the calculations
+    var pointers = [];
+    var i = 0;
+    while (i < input.pointers.length) {
+        pointers[i] = {
+            clientX: round(input.pointers[i].clientX),
+            clientY: round(input.pointers[i].clientY)
+        };
+        i++;
+    }
+
+    return {
+        timeStamp: now(),
+        pointers: pointers,
+        center: getCenter(pointers),
+        deltaX: input.deltaX,
+        deltaY: input.deltaY
+    };
+}
+
+/**
+ * get the center of all the pointers
+ * @param {Array} pointers
+ * @return {Object} center contains `x` and `y` properties
+ */
+function getCenter(pointers) {
+    var pointersLength = pointers.length;
+
+    // no need to loop when only one touch
+    if (pointersLength === 1) {
+        return {
+            x: round(pointers[0].clientX),
+            y: round(pointers[0].clientY)
+        };
+    }
+
+    var x = 0, y = 0, i = 0;
+    while (i < pointersLength) {
+        x += pointers[i].clientX;
+        y += pointers[i].clientY;
+        i++;
+    }
+
+    return {
+        x: round(x / pointersLength),
+        y: round(y / pointersLength)
+    };
+}
+
+/**
+ * calculate the velocity between two points. unit is in px per ms.
+ * @param {Number} deltaTime
+ * @param {Number} x
+ * @param {Number} y
+ * @return {Object} velocity `x` and `y`
+ */
+function getVelocity(deltaTime, x, y) {
+    return {
+        x: x / deltaTime || 0,
+        y: y / deltaTime || 0
+    };
+}
+
+/**
+ * get the direction between two points
+ * @param {Number} x
+ * @param {Number} y
+ * @return {Number} direction
+ */
+function getDirection(x, y) {
+    if (x === y) {
+        return DIRECTION_NONE;
+    }
+
+    if (abs(x) >= abs(y)) {
+        return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
+    }
+    return y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
+}
+
+/**
+ * calculate the absolute distance between two points
+ * @param {Object} p1 {x, y}
+ * @param {Object} p2 {x, y}
+ * @param {Array} [props] containing x and y keys
+ * @return {Number} distance
+ */
+function getDistance(p1, p2, props) {
+    if (!props) {
+        props = PROPS_XY;
+    }
+    var x = p2[props[0]] - p1[props[0]],
+        y = p2[props[1]] - p1[props[1]];
+
+    return Math.sqrt((x * x) + (y * y));
+}
+
+/**
+ * calculate the angle between two coordinates
+ * @param {Object} p1
+ * @param {Object} p2
+ * @param {Array} [props] containing x and y keys
+ * @return {Number} angle
+ */
+function getAngle(p1, p2, props) {
+    if (!props) {
+        props = PROPS_XY;
+    }
+    var x = p2[props[0]] - p1[props[0]],
+        y = p2[props[1]] - p1[props[1]];
+    return Math.atan2(y, x) * 180 / Math.PI;
+}
+
+/**
+ * calculate the rotation degrees between two pointersets
+ * @param {Array} start array of pointers
+ * @param {Array} end array of pointers
+ * @return {Number} rotation
+ */
+function getRotation(start, end) {
+    return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY);
+}
+
+/**
+ * calculate the scale factor between two pointersets
+ * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
+ * @param {Array} start array of pointers
+ * @param {Array} end array of pointers
+ * @return {Number} scale
+ */
+function getScale(start, end) {
+    return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
+}
+
+var MOUSE_INPUT_MAP = {
+    mousedown: INPUT_START,
+    mousemove: INPUT_MOVE,
+    mouseup: INPUT_END
+};
+
+var MOUSE_ELEMENT_EVENTS = 'mousedown';
+var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';
+
+/**
+ * Mouse events input
+ * @constructor
+ * @extends Input
+ */
+function MouseInput() {
+    this.evEl = MOUSE_ELEMENT_EVENTS;
+    this.evWin = MOUSE_WINDOW_EVENTS;
+
+    this.pressed = false; // mousedown state
+
+    Input.apply(this, arguments);
+}
+
+inherit(MouseInput, Input, {
+    /**
+     * handle mouse events
+     * @param {Object} ev
+     */
+    handler: function MEhandler(ev) {
+        var eventType = MOUSE_INPUT_MAP[ev.type];
+
+        // on start we want to have the left mouse button down
+        if (eventType & INPUT_START && ev.button === 0) {
+            this.pressed = true;
+        }
+
+        if (eventType & INPUT_MOVE && ev.which !== 1) {
+            eventType = INPUT_END;
+        }
+
+        // mouse must be down
+        if (!this.pressed) {
+            return;
+        }
+
+        if (eventType & INPUT_END) {
+            this.pressed = false;
+        }
+
+        this.callback(this.manager, eventType, {
+            pointers: [ev],
+            changedPointers: [ev],
+            pointerType: INPUT_TYPE_MOUSE,
+            srcEvent: ev
+        });
+    }
+});
+
+var POINTER_INPUT_MAP = {
+    pointerdown: INPUT_START,
+    pointermove: INPUT_MOVE,
+    pointerup: INPUT_END,
+    pointercancel: INPUT_CANCEL,
+    pointerout: INPUT_CANCEL
+};
+
+// in IE10 the pointer types is defined as an enum
+var IE10_POINTER_TYPE_ENUM = {
+    2: INPUT_TYPE_TOUCH,
+    3: INPUT_TYPE_PEN,
+    4: INPUT_TYPE_MOUSE,
+    5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
+};
+
+var POINTER_ELEMENT_EVENTS = 'pointerdown';
+var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel';
+
+// IE10 has prefixed support, and case-sensitive
+if (window.MSPointerEvent && !window.PointerEvent) {
+    POINTER_ELEMENT_EVENTS = 'MSPointerDown';
+    POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
+}
+
+/**
+ * Pointer events input
+ * @constructor
+ * @extends Input
+ */
+function PointerEventInput() {
+    this.evEl = POINTER_ELEMENT_EVENTS;
+    this.evWin = POINTER_WINDOW_EVENTS;
+
+    Input.apply(this, arguments);
+
+    this.store = (this.manager.session.pointerEvents = []);
+}
+
+inherit(PointerEventInput, Input, {
+    /**
+     * handle mouse events
+     * @param {Object} ev
+     */
+    handler: function PEhandler(ev) {
+        var store = this.store;
+        var removePointer = false;
+
+        var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
+        var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
+        var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
+
+        var isTouch = (pointerType == INPUT_TYPE_TOUCH);
+
+        // get index of the event in the store
+        var storeIndex = inArray(store, ev.pointerId, 'pointerId');
+
+        // start and mouse must be down
+        if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
+            if (storeIndex < 0) {
+                store.push(ev);
+                storeIndex = store.length - 1;
+            }
+        } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
+            removePointer = true;
+        }
+
+        // it not found, so the pointer hasn't been down (so it's probably a hover)
+        if (storeIndex < 0) {
+            return;
+        }
+
+        // update the event in the store
+        store[storeIndex] = ev;
+
+        this.callback(this.manager, eventType, {
+            pointers: store,
+            changedPointers: [ev],
+            pointerType: pointerType,
+            srcEvent: ev
+        });
+
+        if (removePointer) {
+            // remove from the store
+            store.splice(storeIndex, 1);
+        }
+    }
+});
+
+var SINGLE_TOUCH_INPUT_MAP = {
+    touchstart: INPUT_START,
+    touchmove: INPUT_MOVE,
+    touchend: INPUT_END,
+    touchcancel: INPUT_CANCEL
+};
+
+var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
+var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';
+
+/**
+ * Touch events input
+ * @constructor
+ * @extends Input
+ */
+function SingleTouchInput() {
+    this.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
+    this.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
+    this.started = false;
+
+    Input.apply(this, arguments);
+}
+
+inherit(SingleTouchInput, Input, {
+    handler: function TEhandler(ev) {
+        var type = SINGLE_TOUCH_INPUT_MAP[ev.type];
+
+        // should we handle the touch events?
+        if (type === INPUT_START) {
+            this.started = true;
+        }
+
+        if (!this.started) {
+            return;
+        }
+
+        var touches = normalizeSingleTouches.call(this, ev, type);
+
+        // when done, reset the started state
+        if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
+            this.started = false;
+        }
+
+        this.callback(this.manager, type, {
+            pointers: touches[0],
+            changedPointers: touches[1],
+            pointerType: INPUT_TYPE_TOUCH,
+            srcEvent: ev
+        });
+    }
+});
+
+/**
+ * @this {TouchInput}
+ * @param {Object} ev
+ * @param {Number} type flag
+ * @returns {undefined|Array} [all, changed]
+ */
+function normalizeSingleTouches(ev, type) {
+    var all = toArray(ev.touches);
+    var changed = toArray(ev.changedTouches);
+
+    if (type & (INPUT_END | INPUT_CANCEL)) {
+        all = uniqueArray(all.concat(changed), 'identifier', true);
+    }
+
+    return [all, changed];
+}
+
+var TOUCH_INPUT_MAP = {
+    touchstart: INPUT_START,
+    touchmove: INPUT_MOVE,
+    touchend: INPUT_END,
+    touchcancel: INPUT_CANCEL
+};
+
+var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';
+
+/**
+ * Multi-user touch events input
+ * @constructor
+ * @extends Input
+ */
+function TouchInput() {
+    this.evTarget = TOUCH_TARGET_EVENTS;
+    this.targetIds = {};
+
+    Input.apply(this, arguments);
+}
+
+inherit(TouchInput, Input, {
+    handler: function MTEhandler(ev) {
+        var type = TOUCH_INPUT_MAP[ev.type];
+        var touches = getTouches.call(this, ev, type);
+        if (!touches) {
+            return;
+        }
+
+        this.callback(this.manager, type, {
+            pointers: touches[0],
+            changedPointers: touches[1],
+            pointerType: INPUT_TYPE_TOUCH,
+            srcEvent: ev
+        });
+    }
+});
+
+/**
+ * @this {TouchInput}
+ * @param {Object} ev
+ * @param {Number} type flag
+ * @returns {undefined|Array} [all, changed]
+ */
+function getTouches(ev, type) {
+    var allTouches = toArray(ev.touches);
+    var targetIds = this.targetIds;
+
+    // when there is only one touch, the process can be simplified
+    if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
+        targetIds[allTouches[0].identifier] = true;
+        return [allTouches, allTouches];
+    }
+
+    var i,
+        targetTouches,
+        changedTouches = toArray(ev.changedTouches),
+        changedTargetTouches = [],
+        target = this.target;
+
+    // get target touches from touches
+    targetTouches = allTouches.filter(function(touch) {
+        return hasParent(touch.target, target);
+    });
+
+    // collect touches
+    if (type === INPUT_START) {
+        i = 0;
+        while (i < targetTouches.length) {
+            targetIds[targetTouches[i].identifier] = true;
+            i++;
+        }
+    }
+
+    // filter changed touches to only contain touches that exist in the collected target ids
+    i = 0;
+    while (i < changedTouches.length) {
+        if (targetIds[changedTouches[i].identifier]) {
+            changedTargetTouches.push(changedTouches[i]);
+        }
+
+        // cleanup removed touches
+        if (type & (INPUT_END | INPUT_CANCEL)) {
+            delete targetIds[changedTouches[i].identifier];
+        }
+        i++;
+    }
+
+    if (!changedTargetTouches.length) {
+        return;
+    }
+
+    return [
+        // merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
+        uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true),
+        changedTargetTouches
+    ];
+}
+
+/**
+ * Combined touch and mouse input
+ *
+ * Touch has a higher priority then mouse, and while touching no mouse events are allowed.
+ * This because touch devices also emit mouse events while doing a touch.
+ *
+ * @constructor
+ * @extends Input
+ */
+
+var DEDUP_TIMEOUT = 2500;
+var DEDUP_DISTANCE = 25;
+
+function TouchMouseInput() {
+    Input.apply(this, arguments);
+
+    var handler = bindFn(this.handler, this);
+    this.touch = new TouchInput(this.manager, handler);
+    this.mouse = new MouseInput(this.manager, handler);
+
+    this.primaryTouch = null;
+    this.lastTouches = [];
+}
+
+inherit(TouchMouseInput, Input, {
+    /**
+     * handle mouse and touch events
+     * @param {Hammer} manager
+     * @param {String} inputEvent
+     * @param {Object} inputData
+     */
+    handler: function TMEhandler(manager, inputEvent, inputData) {
+        var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH),
+            isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE);
+
+        if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) {
+            return;
+        }
+
+        // when we're in a touch event, record touches to  de-dupe synthetic mouse event
+        if (isTouch) {
+            recordTouches.call(this, inputEvent, inputData);
+        } else if (isMouse && isSyntheticEvent.call(this, inputData)) {
+            return;
+        }
+
+        this.callback(manager, inputEvent, inputData);
+    },
+
+    /**
+     * remove the event listeners
+     */
+    destroy: function destroy() {
+        this.touch.destroy();
+        this.mouse.destroy();
+    }
+});
+
+function recordTouches(eventType, eventData) {
+    if (eventType & INPUT_START) {
+        this.primaryTouch = eventData.changedPointers[0].identifier;
+        setLastTouch.call(this, eventData);
+    } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
+        setLastTouch.call(this, eventData);
+    }
+}
+
+function setLastTouch(eventData) {
+    var touch = eventData.changedPointers[0];
+
+    if (touch.identifier === this.primaryTouch) {
+        var lastTouch = {x: touch.clientX, y: touch.clientY};
+        this.lastTouches.push(lastTouch);
+        var lts = this.lastTouches;
+        var removeLastTouch = function() {
+            var i = lts.indexOf(lastTouch);
+            if (i > -1) {
+                lts.splice(i, 1);
+            }
+        };
+        setTimeout(removeLastTouch, DEDUP_TIMEOUT);
+    }
+}
+
+function isSyntheticEvent(eventData) {
+    var x = eventData.srcEvent.clientX, y = eventData.srcEvent.clientY;
+    for (var i = 0; i < this.lastTouches.length; i++) {
+        var t = this.lastTouches[i];
+        var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y);
+        if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) {
+            return true;
+        }
+    }
+    return false;
+}
+
+var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');
+var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined;
+
+// magical touchAction value
+var TOUCH_ACTION_COMPUTE = 'compute';
+var TOUCH_ACTION_AUTO = 'auto';
+var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
+var TOUCH_ACTION_NONE = 'none';
+var TOUCH_ACTION_PAN_X = 'pan-x';
+var TOUCH_ACTION_PAN_Y = 'pan-y';
+var TOUCH_ACTION_MAP = getTouchActionProps();
+
+/**
+ * Touch Action
+ * sets the touchAction property or uses the js alternative
+ * @param {Manager} manager
+ * @param {String} value
+ * @constructor
+ */
+function TouchAction(manager, value) {
+    this.manager = manager;
+    this.set(value);
+}
+
+TouchAction.prototype = {
+    /**
+     * set the touchAction value on the element or enable the polyfill
+     * @param {String} value
+     */
+    set: function(value) {
+        // find out the touch-action by the event handlers
+        if (value == TOUCH_ACTION_COMPUTE) {
+            value = this.compute();
+        }
+
+        if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) {
+            this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
+        }
+        this.actions = value.toLowerCase().trim();
+    },
+
+    /**
+     * just re-set the touchAction value
+     */
+    update: function() {
+        this.set(this.manager.options.touchAction);
+    },
+
+    /**
+     * compute the value for the touchAction property based on the recognizer's settings
+     * @returns {String} value
+     */
+    compute: function() {
+        var actions = [];
+        each(this.manager.recognizers, function(recognizer) {
+            if (boolOrFn(recognizer.options.enable, [recognizer])) {
+                actions = actions.concat(recognizer.getTouchAction());
+            }
+        });
+        return cleanTouchActions(actions.join(' '));
+    },
+
+    /**
+     * this method is called on each input cycle and provides the preventing of the browser behavior
+     * @param {Object} input
+     */
+    preventDefaults: function(input) {
+        var srcEvent = input.srcEvent;
+        var direction = input.offsetDirection;
+
+        // if the touch action did prevented once this session
+        if (this.manager.session.prevented) {
+            srcEvent.preventDefault();
+            return;
+        }
+
+        var actions = this.actions;
+        var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE];
+        var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y];
+        var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X];
+
+        if (hasNone) {
+            //do not prevent defaults if this is a tap gesture
+
+            var isTapPointer = input.pointers.length === 1;
+            var isTapMovement = input.distance < 2;
+            var isTapTouchTime = input.deltaTime < 250;
+
+            if (isTapPointer && isTapMovement && isTapTouchTime) {
+                return;
+            }
+        }
+
+        if (hasPanX && hasPanY) {
+            // `pan-x pan-y` means browser handles all scrolling/panning, do not prevent
+            return;
+        }
+
+        if (hasNone ||
+            (hasPanY && direction & DIRECTION_HORIZONTAL) ||
+            (hasPanX && direction & DIRECTION_VERTICAL)) {
+            return this.preventSrc(srcEvent);
+        }
+    },
+
+    /**
+     * call preventDefault to prevent the browser's default behavior (scrolling in most cases)
+     * @param {Object} srcEvent
+     */
+    preventSrc: function(srcEvent) {
+        this.manager.session.prevented = true;
+        srcEvent.preventDefault();
+    }
+};
+
+/**
+ * when the touchActions are collected they are not a valid value, so we need to clean things up. *
+ * @param {String} actions
+ * @returns {*}
+ */
+function cleanTouchActions(actions) {
+    // none
+    if (inStr(actions, TOUCH_ACTION_NONE)) {
+        return TOUCH_ACTION_NONE;
+    }
+
+    var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
+    var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);
+
+    // if both pan-x and pan-y are set (different recognizers
+    // for different directions, e.g. horizontal pan but vertical swipe?)
+    // we need none (as otherwise with pan-x pan-y combined none of these
+    // recognizers will work, since the browser would handle all panning
+    if (hasPanX && hasPanY) {
+        return TOUCH_ACTION_NONE;
+    }
+
+    // pan-x OR pan-y
+    if (hasPanX || hasPanY) {
+        return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
+    }
+
+    // manipulation
+    if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
+        return TOUCH_ACTION_MANIPULATION;
+    }
+
+    return TOUCH_ACTION_AUTO;
+}
+
+function getTouchActionProps() {
+    if (!NATIVE_TOUCH_ACTION) {
+        return false;
+    }
+    var touchMap = {};
+    var cssSupports = window.CSS && window.CSS.supports;
+    ['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function(val) {
+
+        // If css.supports is not supported but there is native touch-action assume it supports
+        // all values. This is the case for IE 10 and 11.
+        touchMap[val] = cssSupports ? window.CSS.supports('touch-action', val) : true;
+    });
+    return touchMap;
+}
+
+/**
+ * Recognizer flow explained; *
+ * All recognizers have the initial state of POSSIBLE when a input session starts.
+ * The definition of a input session is from the first input until the last input, with all it's movement in it. *
+ * Example session for mouse-input: mousedown -> mousemove -> mouseup
+ *
+ * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
+ * which determines with state it should be.
+ *
+ * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
+ * POSSIBLE to give it another change on the next cycle.
+ *
+ *               Possible
+ *                  |
+ *            +-----+---------------+
+ *            |                     |
+ *      +-----+-----+               |
+ *      |           |               |
+ *   Failed      Cancelled          |
+ *                          +-------+------+
+ *                          |              |
+ *                      Recognized       Began
+ *                                         |
+ *                                      Changed
+ *                                         |
+ *                                  Ended/Recognized
+ */
+var STATE_POSSIBLE = 1;
+var STATE_BEGAN = 2;
+var STATE_CHANGED = 4;
+var STATE_ENDED = 8;
+var STATE_RECOGNIZED = STATE_ENDED;
+var STATE_CANCELLED = 16;
+var STATE_FAILED = 32;
+
+/**
+ * Recognizer
+ * Every recognizer needs to extend from this class.
+ * @constructor
+ * @param {Object} options
+ */
+function Recognizer(options) {
+    this.options = assign({}, this.defaults, options || {});
+
+    this.id = uniqueId();
+
+    this.manager = null;
+
+    // default is enable true
+    this.options.enable = ifUndefined(this.options.enable, true);
+
+    this.state = STATE_POSSIBLE;
+
+    this.simultaneous = {};
+    this.requireFail = [];
+}
+
+Recognizer.prototype = {
+    /**
+     * @virtual
+     * @type {Object}
+     */
+    defaults: {},
+
+    /**
+     * set options
+     * @param {Object} options
+     * @return {Recognizer}
+     */
+    set: function(options) {
+        assign(this.options, options);
+
+        // also update the touchAction, in case something changed about the directions/enabled state
+        this.manager && this.manager.touchAction.update();
+        return this;
+    },
+
+    /**
+     * recognize simultaneous with an other recognizer.
+     * @param {Recognizer} otherRecognizer
+     * @returns {Recognizer} this
+     */
+    recognizeWith: function(otherRecognizer) {
+        if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
+            return this;
+        }
+
+        var simultaneous = this.simultaneous;
+        otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
+        if (!simultaneous[otherRecognizer.id]) {
+            simultaneous[otherRecognizer.id] = otherRecognizer;
+            otherRecognizer.recognizeWith(this);
+        }
+        return this;
+    },
+
+    /**
+     * drop the simultaneous link. it doesnt remove the link on the other recognizer.
+     * @param {Recognizer} otherRecognizer
+     * @returns {Recognizer} this
+     */
+    dropRecognizeWith: function(otherRecognizer) {
+        if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
+            return this;
+        }
+
+        otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
+        delete this.simultaneous[otherRecognizer.id];
+        return this;
+    },
+
+    /**
+     * recognizer can only run when an other is failing
+     * @param {Recognizer} otherRecognizer
+     * @returns {Recognizer} this
+     */
+    requireFailure: function(otherRecognizer) {
+        if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
+            return this;
+        }
+
+        var requireFail = this.requireFail;
+        otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
+        if (inArray(requireFail, otherRecognizer) === -1) {
+            requireFail.push(otherRecognizer);
+            otherRecognizer.requireFailure(this);
+        }
+        return this;
+    },
+
+    /**
+     * drop the requireFailure link. it does not remove the link on the other recognizer.
+     * @param {Recognizer} otherRecognizer
+     * @returns {Recognizer} this
+     */
+    dropRequireFailure: function(otherRecognizer) {
+        if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
+            return this;
+        }
+
+        otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
+        var index = inArray(this.requireFail, otherRecognizer);
+        if (index > -1) {
+            this.requireFail.splice(index, 1);
+        }
+        return this;
+    },
+
+    /**
+     * has require failures boolean
+     * @returns {boolean}
+     */
+    hasRequireFailures: function() {
+        return this.requireFail.length > 0;
+    },
+
+    /**
+     * if the recognizer can recognize simultaneous with an other recognizer
+     * @param {Recognizer} otherRecognizer
+     * @returns {Boolean}
+     */
+    canRecognizeWith: function(otherRecognizer) {
+        return !!this.simultaneous[otherRecognizer.id];
+    },
+
+    /**
+     * You should use `tryEmit` instead of `emit` directly to check
+     * that all the needed recognizers has failed before emitting.
+     * @param {Object} input
+     */
+    emit: function(input) {
+        var self = this;
+        var state = this.state;
+
+        function emit(event) {
+            self.manager.emit(event, input);
+        }
+
+        // 'panstart' and 'panmove'
+        if (state < STATE_ENDED) {
+            emit(self.options.event + stateStr(state));
+        }
+
+        emit(self.options.event); // simple 'eventName' events
+
+        if (input.additionalEvent) { // additional event(panleft, panright, pinchin, pinchout...)
+            emit(input.additionalEvent);
+        }
+
+        // panend and pancancel
+        if (state >= STATE_ENDED) {
+            emit(self.options.event + stateStr(state));
+        }
+    },
+
+    /**
+     * Check that all the require failure recognizers has failed,
+     * if true, it emits a gesture event,
+     * otherwise, setup the state to FAILED.
+     * @param {Object} input
+     */
+    tryEmit: function(input) {
+        if (this.canEmit()) {
+            return this.emit(input);
+        }
+        // it's failing anyway
+        this.state = STATE_FAILED;
+    },
+
+    /**
+     * can we emit?
+     * @returns {boolean}
+     */
+    canEmit: function() {
+        var i = 0;
+        while (i < this.requireFail.length) {
+            if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {
+                return false;
+            }
+            i++;
+        }
+        return true;
+    },
+
+    /**
+     * update the recognizer
+     * @param {Object} inputData
+     */
+    recognize: function(inputData) {
+        // make a new copy of the inputData
+        // so we can change the inputData without messing up the other recognizers
+        var inputDataClone = assign({}, inputData);
+
+        // is is enabled and allow recognizing?
+        if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
+            this.reset();
+            this.state = STATE_FAILED;
+            return;
+        }
+
+        // reset when we've reached the end
+        if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {
+            this.state = STATE_POSSIBLE;
+        }
+
+        this.state = this.process(inputDataClone);
+
+        // the recognizer has recognized a gesture
+        // so trigger an event
+        if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {
+            this.tryEmit(inputDataClone);
+        }
+    },
+
+    /**
+     * return the state of the recognizer
+     * the actual recognizing happens in this method
+     * @virtual
+     * @param {Object} inputData
+     * @returns {Const} STATE
+     */
+    process: function(inputData) { }, // jshint ignore:line
+
+    /**
+     * return the preferred touch-action
+     * @virtual
+     * @returns {Array}
+     */
+    getTouchAction: function() { },
+
+    /**
+     * called when the gesture isn't allowed to recognize
+     * like when another is being recognized or it is disabled
+     * @virtual
+     */
+    reset: function() { }
+};
+
+/**
+ * get a usable string, used as event postfix
+ * @param {Const} state
+ * @returns {String} state
+ */
+function stateStr(state) {
+    if (state & STATE_CANCELLED) {
+        return 'cancel';
+    } else if (state & STATE_ENDED) {
+        return 'end';
+    } else if (state & STATE_CHANGED) {
+        return 'move';
+    } else if (state & STATE_BEGAN) {
+        return 'start';
+    }
+    return '';
+}
+
+/**
+ * direction cons to string
+ * @param {Const} direction
+ * @returns {String}
+ */
+function directionStr(direction) {
+    if (direction == DIRECTION_DOWN) {
+        return 'down';
+    } else if (direction == DIRECTION_UP) {
+        return 'up';
+    } else if (direction == DIRECTION_LEFT) {
+        return 'left';
+    } else if (direction == DIRECTION_RIGHT) {
+        return 'right';
+    }
+    return '';
+}
+
+/**
+ * get a recognizer by name if it is bound to a manager
+ * @param {Recognizer|String} otherRecognizer
+ * @param {Recognizer} recognizer
+ * @returns {Recognizer}
+ */
+function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
+    var manager = recognizer.manager;
+    if (manager) {
+        return manager.get(otherRecognizer);
+    }
+    return otherRecognizer;
+}
+
+/**
+ * This recognizer is just used as a base for the simple attribute recognizers.
+ * @constructor
+ * @extends Recognizer
+ */
+function AttrRecognizer() {
+    Recognizer.apply(this, arguments);
+}
+
+inherit(AttrRecognizer, Recognizer, {
+    /**
+     * @namespace
+     * @memberof AttrRecognizer
+     */
+    defaults: {
+        /**
+         * @type {Number}
+         * @default 1
+         */
+        pointers: 1
+    },
+
+    /**
+     * Used to check if it the recognizer receives valid input, like input.distance > 10.
+     * @memberof AttrRecognizer
+     * @param {Object} input
+     * @returns {Boolean} recognized
+     */
+    attrTest: function(input) {
+        var optionPointers = this.options.pointers;
+        return optionPointers === 0 || input.pointers.length === optionPointers;
+    },
+
+    /**
+     * Process the input and return the state for the recognizer
+     * @memberof AttrRecognizer
+     * @param {Object} input
+     * @returns {*} State
+     */
+    process: function(input) {
+        var state = this.state;
+        var eventType = input.eventType;
+
+        var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
+        var isValid = this.attrTest(input);
+
+        // on cancel input and we've recognized before, return STATE_CANCELLED
+        if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
+            return state | STATE_CANCELLED;
+        } else if (isRecognized || isValid) {
+            if (eventType & INPUT_END) {
+                return state | STATE_ENDED;
+            } else if (!(state & STATE_BEGAN)) {
+                return STATE_BEGAN;
+            }
+            return state | STATE_CHANGED;
+        }
+        return STATE_FAILED;
+    }
+});
+
+/**
+ * Pan
+ * Recognized when the pointer is down and moved in the allowed direction.
+ * @constructor
+ * @extends AttrRecognizer
+ */
+function PanRecognizer() {
+    AttrRecognizer.apply(this, arguments);
+
+    this.pX = null;
+    this.pY = null;
+}
+
+inherit(PanRecognizer, AttrRecognizer, {
+    /**
+     * @namespace
+     * @memberof PanRecognizer
+     */
+    defaults: {
+        event: 'pan',
+        threshold: 10,
+        pointers: 1,
+        direction: DIRECTION_ALL
+    },
+
+    getTouchAction: function() {
+        var direction = this.options.direction;
+        var actions = [];
+        if (direction & DIRECTION_HORIZONTAL) {
+            actions.push(TOUCH_ACTION_PAN_Y);
+        }
+        if (direction & DIRECTION_VERTICAL) {
+            actions.push(TOUCH_ACTION_PAN_X);
+        }
+        return actions;
+    },
+
+    directionTest: function(input) {
+        var options = this.options;
+        var hasMoved = true;
+        var distance = input.distance;
+        var direction = input.direction;
+        var x = input.deltaX;
+        var y = input.deltaY;
+
+        // lock to axis?
+        if (!(direction & options.direction)) {
+            if (options.direction & DIRECTION_HORIZONTAL) {
+                direction = (x === 0) ? DIRECTION_NONE : (x < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT;
+                hasMoved = x != this.pX;
+                distance = Math.abs(input.deltaX);
+            } else {
+                direction = (y === 0) ? DIRECTION_NONE : (y < 0) ? DIRECTION_UP : DIRECTION_DOWN;
+                hasMoved = y != this.pY;
+                distance = Math.abs(input.deltaY);
+            }
+        }
+        input.direction = direction;
+        return hasMoved && distance > options.threshold && direction & options.direction;
+    },
+
+    attrTest: function(input) {
+        return AttrRecognizer.prototype.attrTest.call(this, input) &&
+            (this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) && this.directionTest(input)));
+    },
+
+    emit: function(input) {
+
+        this.pX = input.deltaX;
+        this.pY = input.deltaY;
+
+        var direction = directionStr(input.direction);
+
+        if (direction) {
+            input.additionalEvent = this.options.event + direction;
+        }
+        this._super.emit.call(this, input);
+    }
+});
+
+/**
+ * Pinch
+ * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
+ * @constructor
+ * @extends AttrRecognizer
+ */
+function PinchRecognizer() {
+    AttrRecognizer.apply(this, arguments);
+}
+
+inherit(PinchRecognizer, AttrRecognizer, {
+    /**
+     * @namespace
+     * @memberof PinchRecognizer
+     */
+    defaults: {
+        event: 'pinch',
+        threshold: 0,
+        pointers: 2
+    },
+
+    getTouchAction: function() {
+        return [TOUCH_ACTION_NONE];
+    },
+
+    attrTest: function(input) {
+        return this._super.attrTest.call(this, input) &&
+            (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
+    },
+
+    emit: function(input) {
+        if (input.scale !== 1) {
+            var inOut = input.scale < 1 ? 'in' : 'out';
+            input.additionalEvent = this.options.event + inOut;
+        }
+        this._super.emit.call(this, input);
+    }
+});
+
+/**
+ * Press
+ * Recognized when the pointer is down for x ms without any movement.
+ * @constructor
+ * @extends Recognizer
+ */
+function PressRecognizer() {
+    Recognizer.apply(this, arguments);
+
+    this._timer = null;
+    this._input = null;
+}
+
+inherit(PressRecognizer, Recognizer, {
+    /**
+     * @namespace
+     * @memberof PressRecognizer
+     */
+    defaults: {
+        event: 'press',
+        pointers: 1,
+        time: 251, // minimal time of the pointer to be pressed
+        threshold: 9 // a minimal movement is ok, but keep it low
+    },
+
+    getTouchAction: function() {
+        return [TOUCH_ACTION_AUTO];
+    },
+
+    process: function(input) {
+        var options = this.options;
+        var validPointers = input.pointers.length === options.pointers;
+        var validMovement = input.distance < options.threshold;
+        var validTime = input.deltaTime > options.time;
+
+        this._input = input;
+
+        // we only allow little movement
+        // and we've reached an end event, so a tap is possible
+        if (!validMovement || !validPointers || (input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime)) {
+            this.reset();
+        } else if (input.eventType & INPUT_START) {
+            this.reset();
+            this._timer = setTimeoutContext(function() {
+                this.state = STATE_RECOGNIZED;
+                this.tryEmit();
+            }, options.time, this);
+        } else if (input.eventType & INPUT_END) {
+            return STATE_RECOGNIZED;
+        }
+        return STATE_FAILED;
+    },
+
+    reset: function() {
+        clearTimeout(this._timer);
+    },
+
+    emit: function(input) {
+        if (this.state !== STATE_RECOGNIZED) {
+            return;
+        }
+
+        if (input && (input.eventType & INPUT_END)) {
+            this.manager.emit(this.options.event + 'up', input);
+        } else {
+            this._input.timeStamp = now();
+            this.manager.emit(this.options.event, this._input);
+        }
+    }
+});
+
+/**
+ * Rotate
+ * Recognized when two or more pointer are moving in a circular motion.
+ * @constructor
+ * @extends AttrRecognizer
+ */
+function RotateRecognizer() {
+    AttrRecognizer.apply(this, arguments);
+}
+
+inherit(RotateRecognizer, AttrRecognizer, {
+    /**
+     * @namespace
+     * @memberof RotateRecognizer
+     */
+    defaults: {
+        event: 'rotate',
+        threshold: 0,
+        pointers: 2
+    },
+
+    getTouchAction: function() {
+        return [TOUCH_ACTION_NONE];
+    },
+
+    attrTest: function(input) {
+        return this._super.attrTest.call(this, input) &&
+            (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
+    }
+});
+
+/**
+ * Swipe
+ * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
+ * @constructor
+ * @extends AttrRecognizer
+ */
+function SwipeRecognizer() {
+    AttrRecognizer.apply(this, arguments);
+}
+
+inherit(SwipeRecognizer, AttrRecognizer, {
+    /**
+     * @namespace
+     * @memberof SwipeRecognizer
+     */
+    defaults: {
+        event: 'swipe',
+        threshold: 10,
+        velocity: 0.3,
+        direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
+        pointers: 1
+    },
+
+    getTouchAction: function() {
+        return PanRecognizer.prototype.getTouchAction.call(this);
+    },
+
+    attrTest: function(input) {
+        var direction = this.options.direction;
+        var velocity;
+
+        if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
+            velocity = input.overallVelocity;
+        } else if (direction & DIRECTION_HORIZONTAL) {
+            velocity = input.overallVelocityX;
+        } else if (direction & DIRECTION_VERTICAL) {
+            velocity = input.overallVelocityY;
+        }
+
+        return this._super.attrTest.call(this, input) &&
+            direction & input.offsetDirection &&
+            input.distance > this.options.threshold &&
+            input.maxPointers == this.options.pointers &&
+            abs(velocity) > this.options.velocity && input.eventType & INPUT_END;
+    },
+
+    emit: function(input) {
+        var direction = directionStr(input.offsetDirection);
+        if (direction) {
+            this.manager.emit(this.options.event + direction, input);
+        }
+
+        this.manager.emit(this.options.event, input);
+    }
+});
+
+/**
+ * A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
+ * between the given interval and position. The delay option can be used to recognize multi-taps without firing
+ * a single tap.
+ *
+ * The eventData from the emitted event contains the property `tapCount`, which contains the amount of
+ * multi-taps being recognized.
+ * @constructor
+ * @extends Recognizer
+ */
+function TapRecognizer() {
+    Recognizer.apply(this, arguments);
+
+    // previous time and center,
+    // used for tap counting
+    this.pTime = false;
+    this.pCenter = false;
+
+    this._timer = null;
+    this._input = null;
+    this.count = 0;
+}
+
+inherit(TapRecognizer, Recognizer, {
+    /**
+     * @namespace
+     * @memberof PinchRecognizer
+     */
+    defaults: {
+        event: 'tap',
+        pointers: 1,
+        taps: 1,
+        interval: 300, // max time between the multi-tap taps
+        time: 250, // max time of the pointer to be down (like finger on the screen)
+        threshold: 9, // a minimal movement is ok, but keep it low
+        posThreshold: 10 // a multi-tap can be a bit off the initial position
+    },
+
+    getTouchAction: function() {
+        return [TOUCH_ACTION_MANIPULATION];
+    },
+
+    process: function(input) {
+        var options = this.options;
+
+        var validPointers = input.pointers.length === options.pointers;
+        var validMovement = input.distance < options.threshold;
+        var validTouchTime = input.deltaTime < options.time;
+
+        this.reset();
+
+        if ((input.eventType & INPUT_START) && (this.count === 0)) {
+            return this.failTimeout();
+        }
+
+        // we only allow little movement
+        // and we've reached an end event, so a tap is possible
+        if (validMovement && validTouchTime && validPointers) {
+            if (input.eventType != INPUT_END) {
+                return this.failTimeout();
+            }
+
+            var validInterval = this.pTime ? (input.timeStamp - this.pTime < options.interval) : true;
+            var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;
+
+            this.pTime = input.timeStamp;
+            this.pCenter = input.center;
+
+            if (!validMultiTap || !validInterval) {
+                this.count = 1;
+            } else {
+                this.count += 1;
+            }
+
+            this._input = input;
+
+            // if tap count matches we have recognized it,
+            // else it has began recognizing...
+            var tapCount = this.count % options.taps;
+            if (tapCount === 0) {
+                // no failing requirements, immediately trigger the tap event
+                // or wait as long as the multitap interval to trigger
+                if (!this.hasRequireFailures()) {
+                    return STATE_RECOGNIZED;
+                } else {
+                    this._timer = setTimeoutContext(function() {
+                        this.state = STATE_RECOGNIZED;
+                        this.tryEmit();
+                    }, options.interval, this);
+                    return STATE_BEGAN;
+                }
+            }
+        }
+        return STATE_FAILED;
+    },
+
+    failTimeout: function() {
+        this._timer = setTimeoutContext(function() {
+            this.state = STATE_FAILED;
+        }, this.options.interval, this);
+        return STATE_FAILED;
+    },
+
+    reset: function() {
+        clearTimeout(this._timer);
+    },
+
+    emit: function() {
+        if (this.state == STATE_RECOGNIZED) {
+            this._input.tapCount = this.count;
+            this.manager.emit(this.options.event, this._input);
+        }
+    }
+});
+
+/**
+ * Simple way to create a manager with a default set of recognizers.
+ * @param {HTMLElement} element
+ * @param {Object} [options]
+ * @constructor
+ */
+function Hammer(element, options) {
+    options = options || {};
+    options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset);
+    return new Manager(element, options);
+}
+
+/**
+ * @const {string}
+ */
+Hammer.VERSION = '2.0.8';
+
+/**
+ * default settings
+ * @namespace
+ */
+Hammer.defaults = {
+    /**
+     * set if DOM events are being triggered.
+     * But this is slower and unused by simple implementations, so disabled by default.
+     * @type {Boolean}
+     * @default false
+     */
+    domEvents: false,
+
+    /**
+     * The value for the touchAction property/fallback.
+     * When set to `compute` it will magically set the correct value based on the added recognizers.
+     * @type {String}
+     * @default compute
+     */
+    touchAction: TOUCH_ACTION_COMPUTE,
+
+    /**
+     * @type {Boolean}
+     * @default true
+     */
+    enable: true,
+
+    /**
+     * EXPERIMENTAL FEATURE -- can be removed/changed
+     * Change the parent input target element.
+     * If Null, then it is being set the to main element.
+     * @type {Null|EventTarget}
+     * @default null
+     */
+    inputTarget: null,
+
+    /**
+     * force an input class
+     * @type {Null|Function}
+     * @default null
+     */
+    inputClass: null,
+
+    /**
+     * Default recognizer setup when calling `Hammer()`
+     * When creating a new Manager these will be skipped.
+     * @type {Array}
+     */
+    preset: [
+        // RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...]
+        [RotateRecognizer, {enable: false}],
+        [PinchRecognizer, {enable: false}, ['rotate']],
+        [SwipeRecognizer, {direction: DIRECTION_HORIZONTAL}],
+        [PanRecognizer, {direction: DIRECTION_HORIZONTAL}, ['swipe']],
+        [TapRecognizer],
+        [TapRecognizer, {event: 'doubletap', taps: 2}, ['tap']],
+        [PressRecognizer]
+    ],
+
+    /**
+     * Some CSS properties can be used to improve the working of Hammer.
+     * Add them to this method and they will be set when creating a new Manager.
+     * @namespace
+     */
+    cssProps: {
+        /**
+         * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
+         * @type {String}
+         * @default 'none'
+         */
+        userSelect: 'none',
+
+        /**
+         * Disable the Windows Phone grippers when pressing an element.
+         * @type {String}
+         * @default 'none'
+         */
+        touchSelect: 'none',
+
+        /**
+         * Disables the default callout shown when you touch and hold a touch target.
+         * On iOS, when you touch and hold a touch target such as a link, Safari displays
+         * a callout containing information about the link. This property allows you to disable that callout.
+         * @type {String}
+         * @default 'none'
+         */
+        touchCallout: 'none',
+
+        /**
+         * Specifies whether zooming is enabled. Used by IE10>
+         * @type {String}
+         * @default 'none'
+         */
+        contentZooming: 'none',
+
+        /**
+         * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
+         * @type {String}
+         * @default 'none'
+         */
+        userDrag: 'none',
+
+        /**
+         * Overrides the highlight color shown when the user taps a link or a JavaScript
+         * clickable element in iOS. This property obeys the alpha value, if specified.
+         * @type {String}
+         * @default 'rgba(0,0,0,0)'
+         */
+        tapHighlightColor: 'rgba(0,0,0,0)'
+    }
+};
+
+var STOP = 1;
+var FORCED_STOP = 2;
+
+/**
+ * Manager
+ * @param {HTMLElement} element
+ * @param {Object} [options]
+ * @constructor
+ */
+function Manager(element, options) {
+    this.options = assign({}, Hammer.defaults, options || {});
+
+    this.options.inputTarget = this.options.inputTarget || element;
+
+    this.handlers = {};
+    this.session = {};
+    this.recognizers = [];
+    this.oldCssProps = {};
+
+    this.element = element;
+    this.input = createInputInstance(this);
+    this.touchAction = new TouchAction(this, this.options.touchAction);
+
+    toggleCssProps(this, true);
+
+    each(this.options.recognizers, function(item) {
+        var recognizer = this.add(new (item[0])(item[1]));
+        item[2] && recognizer.recognizeWith(item[2]);
+        item[3] && recognizer.requireFailure(item[3]);
+    }, this);
+}
+
+Manager.prototype = {
+    /**
+     * set options
+     * @param {Object} options
+     * @returns {Manager}
+     */
+    set: function(options) {
+        assign(this.options, options);
+
+        // Options that need a little more setup
+        if (options.touchAction) {
+            this.touchAction.update();
+        }
+        if (options.inputTarget) {
+            // Clean up existing event listeners and reinitialize
+            this.input.destroy();
+            this.input.target = options.inputTarget;
+            this.input.init();
+        }
+        return this;
+    },
+
+    /**
+     * stop recognizing for this session.
+     * This session will be discarded, when a new [input]start event is fired.
+     * When forced, the recognizer cycle is stopped immediately.
+     * @param {Boolean} [force]
+     */
+    stop: function(force) {
+        this.session.stopped = force ? FORCED_STOP : STOP;
+    },
+
+    /**
+     * run the recognizers!
+     * called by the inputHandler function on every movement of the pointers (touches)
+     * it walks through all the recognizers and tries to detect the gesture that is being made
+     * @param {Object} inputData
+     */
+    recognize: function(inputData) {
+        var session = this.session;
+        if (session.stopped) {
+            return;
+        }
+
+        // run the touch-action polyfill
+        this.touchAction.preventDefaults(inputData);
+
+        var recognizer;
+        var recognizers = this.recognizers;
+
+        // this holds the recognizer that is being recognized.
+        // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
+        // if no recognizer is detecting a thing, it is set to `null`
+        var curRecognizer = session.curRecognizer;
+
+        // reset when the last recognizer is recognized
+        // or when we're in a new session
+        if (!curRecognizer || (curRecognizer && curRecognizer.state & STATE_RECOGNIZED)) {
+            curRecognizer = session.curRecognizer = null;
+        }
+
+        var i = 0;
+        while (i < recognizers.length) {
+            recognizer = recognizers[i];
+
+            // find out if we are allowed try to recognize the input for this one.
+            // 1.   allow if the session is NOT forced stopped (see the .stop() method)
+            // 2.   allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
+            //      that is being recognized.
+            // 3.   allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
+            //      this can be setup with the `recognizeWith()` method on the recognizer.
+            if (session.stopped !== FORCED_STOP && ( // 1
+                    !curRecognizer || recognizer == curRecognizer || // 2
+                    recognizer.canRecognizeWith(curRecognizer))) { // 3
+                recognizer.recognize(inputData);
+            } else {
+                recognizer.reset();
+            }
+
+            // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
+            // current active recognizer. but only if we don't already have an active recognizer
+            if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {
+                curRecognizer = session.curRecognizer = recognizer;
+            }
+            i++;
+        }
+    },
+
+    /**
+     * get a recognizer by its event name.
+     * @param {Recognizer|String} recognizer
+     * @returns {Recognizer|Null}
+     */
+    get: function(recognizer) {
+        if (recognizer instanceof Recognizer) {
+            return recognizer;
+        }
+
+        var recognizers = this.recognizers;
+        for (var i = 0; i < recognizers.length; i++) {
+            if (recognizers[i].options.event == recognizer) {
+                return recognizers[i];
+            }
+        }
+        return null;
+    },
+
+    /**
+     * add a recognizer to the manager
+     * existing recognizers with the same event name will be removed
+     * @param {Recognizer} recognizer
+     * @returns {Recognizer|Manager}
+     */
+    add: function(recognizer) {
+        if (invokeArrayArg(recognizer, 'add', this)) {
+            return this;
+        }
+
+        // remove existing
+        var existing = this.get(recognizer.options.event);
+        if (existing) {
+            this.remove(existing);
+        }
+
+        this.recognizers.push(recognizer);
+        recognizer.manager = this;
+
+        this.touchAction.update();
+        return recognizer;
+    },
+
+    /**
+     * remove a recognizer by name or instance
+     * @param {Recognizer|String} recognizer
+     * @returns {Manager}
+     */
+    remove: function(recognizer) {
+        if (invokeArrayArg(recognizer, 'remove', this)) {
+            return this;
+        }
+
+        recognizer = this.get(recognizer);
+
+        // let's make sure this recognizer exists
+        if (recognizer) {
+            var recognizers = this.recognizers;
+            var index = inArray(recognizers, recognizer);
+
+            if (index !== -1) {
+                recognizers.splice(index, 1);
+                this.touchAction.update();
+            }
+        }
+
+        return this;
+    },
+
+    /**
+     * bind event
+     * @param {String} events
+     * @param {Function} handler
+     * @returns {EventEmitter} this
+     */
+    on: function(events, handler) {
+        if (events === undefined) {
+            return;
+        }
+        if (handler === undefined) {
+            return;
+        }
+
+        var handlers = this.handlers;
+        each(splitStr(events), function(event) {
+            handlers[event] = handlers[event] || [];
+            handlers[event].push(handler);
+        });
+        return this;
+    },
+
+    /**
+     * unbind event, leave emit blank to remove all handlers
+     * @param {String} events
+     * @param {Function} [handler]
+     * @returns {EventEmitter} this
+     */
+    off: function(events, handler) {
+        if (events === undefined) {
+            return;
+        }
+
+        var handlers = this.handlers;
+        each(splitStr(events), function(event) {
+            if (!handler) {
+                delete handlers[event];
+            } else {
+                handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1);
+            }
+        });
+        return this;
+    },
+
+    /**
+     * emit event to the listeners
+     * @param {String} event
+     * @param {Object} data
+     */
+    emit: function(event, data) {
+        // we also want to trigger dom events
+        if (this.options.domEvents) {
+            triggerDomEvent(event, data);
+        }
+
+        // no handlers, so skip it all
+        var handlers = this.handlers[event] && this.handlers[event].slice();
+        if (!handlers || !handlers.length) {
+            return;
+        }
+
+        data.type = event;
+        data.preventDefault = function() {
+            data.srcEvent.preventDefault();
+        };
+
+        var i = 0;
+        while (i < handlers.length) {
+            handlers[i](data);
+            i++;
+        }
+    },
+
+    /**
+     * destroy the manager and unbinds all events
+     * it doesn't unbind dom events, that is the user own responsibility
+     */
+    destroy: function() {
+        this.element && toggleCssProps(this, false);
+
+        this.handlers = {};
+        this.session = {};
+        this.input.destroy();
+        this.element = null;
+    }
+};
+
+/**
+ * add/remove the css properties as defined in manager.options.cssProps
+ * @param {Manager} manager
+ * @param {Boolean} add
+ */
+function toggleCssProps(manager, add) {
+    var element = manager.element;
+    if (!element.style) {
+        return;
+    }
+    var prop;
+    each(manager.options.cssProps, function(value, name) {
+        prop = prefixed(element.style, name);
+        if (add) {
+            manager.oldCssProps[prop] = element.style[prop];
+            element.style[prop] = value;
+        } else {
+            element.style[prop] = manager.oldCssProps[prop] || '';
+        }
+    });
+    if (!add) {
+        manager.oldCssProps = {};
+    }
+}
+
+/**
+ * trigger dom event
+ * @param {String} event
+ * @param {Object} data
+ */
+function triggerDomEvent(event, data) {
+    var gestureEvent = document.createEvent('Event');
+    gestureEvent.initEvent(event, true, true);
+    gestureEvent.gesture = data;
+    data.target.dispatchEvent(gestureEvent);
+}
+
+assign(Hammer, {
+    INPUT_START: INPUT_START,
+    INPUT_MOVE: INPUT_MOVE,
+    INPUT_END: INPUT_END,
+    INPUT_CANCEL: INPUT_CANCEL,
+
+    STATE_POSSIBLE: STATE_POSSIBLE,
+    STATE_BEGAN: STATE_BEGAN,
+    STATE_CHANGED: STATE_CHANGED,
+    STATE_ENDED: STATE_ENDED,
+    STATE_RECOGNIZED: STATE_RECOGNIZED,
+    STATE_CANCELLED: STATE_CANCELLED,
+    STATE_FAILED: STATE_FAILED,
+
+    DIRECTION_NONE: DIRECTION_NONE,
+    DIRECTION_LEFT: DIRECTION_LEFT,
+    DIRECTION_RIGHT: DIRECTION_RIGHT,
+    DIRECTION_UP: DIRECTION_UP,
+    DIRECTION_DOWN: DIRECTION_DOWN,
+    DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL,
+    DIRECTION_VERTICAL: DIRECTION_VERTICAL,
+    DIRECTION_ALL: DIRECTION_ALL,
+
+    Manager: Manager,
+    Input: Input,
+    TouchAction: TouchAction,
+
+    TouchInput: TouchInput,
+    MouseInput: MouseInput,
+    PointerEventInput: PointerEventInput,
+    TouchMouseInput: TouchMouseInput,
+    SingleTouchInput: SingleTouchInput,
+
+    Recognizer: Recognizer,
+    AttrRecognizer: AttrRecognizer,
+    Tap: TapRecognizer,
+    Pan: PanRecognizer,
+    Swipe: SwipeRecognizer,
+    Pinch: PinchRecognizer,
+    Rotate: RotateRecognizer,
+    Press: PressRecognizer,
+
+    on: addEventListeners,
+    off: removeEventListeners,
+    each: each,
+    merge: merge,
+    extend: extend,
+    assign: assign,
+    inherit: inherit,
+    bindFn: bindFn,
+    prefixed: prefixed
+});
+
+// this prevents errors when Hammer is loaded in the presence of an AMD
+//  style loader but by script tag, not by the loader.
+var freeGlobal = (typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : {})); // jshint ignore:line
+freeGlobal.Hammer = Hammer;
+
+if (typeof define === 'function' && define.amd) {
+    define(function() {
+        return Hammer;
+    });
+} else if (typeof module != 'undefined' && module.exports) {
+    module.exports = Hammer;
+} else {
+    window[exportName] = Hammer;
+}
+
+})(window, document, 'Hammer');
+
++ function($) {
+  "use strict";
+
+  var defaults;
+  
+  $.modal = function(params, onOpen) {
+    params = $.extend({}, defaults, params);
+
+
+    var buttons = params.buttons;
+
+    var buttonsHtml = buttons.map(function(d, i) {
+      return '<a href="javascript:;" class="weui-dialog__btn ' + (d.className || "") + '">' + d.text + '</a>';
+    }).join("");
+
+    var tpl = '<div class="weui-dialog">' +
+                '<div class="weui-dialog__hd"><strong class="weui-dialog__title">' + params.title + '</strong></div>' +
+                ( params.text ? '<div class="weui-dialog__bd">'+params.text+'</div>' : '')+
+                '<div class="weui-dialog__ft">' + buttonsHtml + '</div>' +
+              '</div>';
+    
+    var dialog = $.openModal(tpl, onOpen);
+
+    dialog.find(".weui-dialog__btn").each(function(i, e) {
+      var el = $(e);
+      el.click(function() {
+        //先关闭对话框,再调用回调函数
+        if(params.autoClose) $.closeModal();
+
+        if(buttons[i].onClick) {
+          buttons[i].onClick.call(dialog);
+        }
+      });
+    });
+
+    return dialog;
+  };
+
+  $.openModal = function(tpl, onOpen) {
+    var mask = $("<div class='weui-mask'></div>").appendTo(document.body);
+    mask.show();
+
+    var dialog = $(tpl).appendTo(document.body);
+ 
+    if (onOpen) {
+      dialog.transitionEnd(function () {
+        onOpen.call(dialog);
+      });
+    }   
+
+    dialog.show();
+    mask.addClass("weui-mask--visible");
+    dialog.addClass("weui-dialog--visible");
+
+
+    return dialog;
+  }
+
+  $.closeModal = function() {
+    $(".weui-mask--visible").removeClass("weui-mask--visible").transitionEnd(function() {
+      $(this).remove();
+    });
+    $(".weui-dialog--visible").removeClass("weui-dialog--visible").transitionEnd(function() {
+      $(this).remove();
+    });
+  };
+
+  $.alert = function(text, title, onOK) {
+    var config;
+    if (typeof text === 'object') {
+      config = text;
+    } else {
+      if (typeof title === 'function') {
+        onOK = arguments[1];
+        title = undefined;
+      }
+
+      config = {
+        text: text,
+        title: title,
+        onOK: onOK
+      }
+    }
+    return $.modal({
+      text: config.text,
+      title: config.title,
+      buttons: [{
+        text: defaults.buttonOK,
+        className: "primary",
+        onClick: config.onOK
+      }]
+    });
+  }
+
+  $.confirm = function(text, title, onOK, onCancel) {
+    var config;
+    if (typeof text === 'object') {
+      config = text
+    } else {
+      if (typeof title === 'function') {
+        onCancel = arguments[2];
+        onOK = arguments[1];
+        title = undefined;
+      }
+
+      config = {
+        text: text,
+        title: title,
+        onOK: onOK,
+        onCancel: onCancel
+      }
+    }
+    return $.modal({
+      text: config.text,
+      title: config.title,
+      buttons: [
+      {
+        text: defaults.buttonCancel,
+        className: "default",
+        onClick: config.onCancel
+      },
+      {
+        text: defaults.buttonOK,
+        className: "primary",
+        onClick: config.onOK
+      }]
+    });
+  };
+
+  //如果参数过多,建议通过 config 对象进行配置,而不是传入多个参数。
+  $.prompt = function(text, title, onOK, onCancel, input) {
+    var config;
+    if (typeof text === 'object') {
+      config = text;
+    } else {
+      if (typeof title === 'function') {
+        input = arguments[3];
+        onCancel = arguments[2];
+        onOK = arguments[1];
+        title = undefined;
+      }
+      config = {
+        text: text,
+        title: title,
+        input: input,
+        onOK: onOK,
+        onCancel: onCancel,
+        empty: false  //allow empty
+      }
+    }
+
+    var modal = $.modal({
+      text: '<p class="weui-prompt-text">'+(config.text || '')+'</p><input type="text" class="weui-input weui-prompt-input" id="weui-prompt-input" value="' + (config.input || '') + '" />',
+      title: config.title,
+      autoClose: false,
+      buttons: [
+      {
+        text: defaults.buttonCancel,
+        className: "default",
+        onClick: function () {
+          $.closeModal();
+          config.onCancel && config.onCancel.call(modal);
+        }
+      },
+      {
+        text: defaults.buttonOK,
+        className: "primary",
+        onClick: function() {
+          var input = $("#weui-prompt-input").val();
+          if (!config.empty && (input === "" || input === null)) {
+            modal.find('.weui-prompt-input').focus()[0].select();
+            return false;
+          }
+          $.closeModal();
+          config.onOK && config.onOK.call(modal, input);
+        }
+      }]
+    }, function () {
+      this.find('.weui-prompt-input').focus()[0].select();
+    });
+
+    return modal;
+  };
+
+  //如果参数过多,建议通过 config 对象进行配置,而不是传入多个参数。
+  $.login = function(text, title, onOK, onCancel, username, password) {
+    var config;
+    if (typeof text === 'object') {
+      config = text;
+    } else {
+      if (typeof title === 'function') {
+        password = arguments[4];
+        username = arguments[3];
+        onCancel = arguments[2];
+        onOK = arguments[1];
+        title = undefined;
+      }
+      config = {
+        text: text,
+        title: title,
+        username: username,
+        password: password,
+        onOK: onOK,
+        onCancel: onCancel
+      }
+    }
+
+    var modal = $.modal({
+      text: '<p class="weui-prompt-text">'+(config.text || '')+'</p>' +
+            '<input type="text" class="weui-input weui-prompt-input" id="weui-prompt-username" value="' + (config.username || '') + '" placeholder="输入用户名" />' +
+            '<input type="password" class="weui-input weui-prompt-input" id="weui-prompt-password" value="' + (config.password || '') + '" placeholder="输入密码" />',
+      title: config.title,
+      autoClose: false,
+      buttons: [
+      {
+        text: defaults.buttonCancel,
+        className: "default",
+        onClick: function () {
+          $.closeModal();
+          config.onCancel && config.onCancel.call(modal);
+        }
+      }, {
+        text: defaults.buttonOK,
+        className: "primary",
+        onClick: function() {
+          var username = $("#weui-prompt-username").val();
+          var password = $("#weui-prompt-password").val();
+          if (!config.empty && (username === "" || username === null)) {
+            modal.find('#weui-prompt-username').focus()[0].select();
+            return false;
+          }
+          if (!config.empty && (password === "" || password === null)) {
+            modal.find('#weui-prompt-password').focus()[0].select();
+            return false;
+          }
+          $.closeModal();
+          config.onOK && config.onOK.call(modal, username, password);
+        }
+      }]
+    }, function () {
+      this.find('#weui-prompt-username').focus()[0].select();
+    });
+
+    return modal;
+  };
+
+  defaults = $.modal.prototype.defaults = {
+    title: "提示",
+    text: undefined,
+    buttonOK: "确定",
+    buttonCancel: "取消",
+    buttons: [{
+      text: "确定",
+      className: "primary"
+    }],
+    autoClose: true //点击按钮自动关闭对话框,如果你不希望点击按钮就关闭对话框,可以把这个设置为false
+  };
+
+}($);
+
++ function($) {
+  "use strict";
+
+  var defaults;
+  
+  var show = function(html, className) {
+    className = className || "";
+    var mask = $("<div class='weui-mask_transparent'></div>").appendTo(document.body);
+
+    var tpl = '<div class="weui-toast ' + className + '">' + html + '</div>';
+    var dialog = $(tpl).appendTo(document.body);
+
+    dialog.addClass("weui-toast--visible");
+    dialog.show();
+  };
+
+  var hide = function(callback) {
+    $(".weui-mask_transparent").remove();
+    var done = false;
+    var $el = $(".weui-toast--visible").removeClass("weui-toast--visible").transitionEnd(function() {
+      var $this = $(this);
+      $this.remove();
+      callback && callback();
+      done = true
+    });
+
+    setTimeout(function () {
+      if (!done) {
+        $el.remove()
+        callback && callback();
+      }
+    }, 1000)
+  }
+
+  $.toast = function(text, style, callback) {
+    if(typeof style === "function") {
+      callback = style;
+    }
+    var className, iconClassName = 'weui-icon-success-no-circle';
+    var duration = toastDefaults.duration;
+    if(style == "cancel") {
+      className = "weui-toast_cancel";
+      iconClassName = 'weui-icon-cancel'
+    } else if(style == "forbidden") {
+      className = "weui-toast--forbidden";
+      iconClassName = 'weui-icon-warn'
+    } else if(style == "text") {
+      className = "weui-toast--text";
+    } else if(typeof style === typeof 1) {
+      duration = style
+    }
+    show('<i class="' + iconClassName + ' weui-icon_toast"></i><p class="weui-toast_content">' + (text || "已经完成") + '</p>', className);
+
+    setTimeout(function() {
+      hide(callback);
+    }, duration);
+  }
+
+  $.showLoading = function(text) {
+    var html = '<div class="weui_loading">';
+    html += '<i class="weui-loading weui-icon_toast"></i>';
+    html += '</div>';
+    html += '<p class="weui-toast_content">' + (text || "数据加载中") + '</p>';
+    show(html, 'weui_loading_toast');
+  }
+
+  $.hideLoading = function() {
+    hide();
+  }
+
+  var toastDefaults = $.toast.prototype.defaults = {
+    duration: 2500
+  }
+
+}($);
+
++ function($) {
+  "use strict";
+
+  var defaults;
+  
+  var show = function(params) {
+
+    var mask = $("<div class='weui-mask weui-actions_mask'></div>").appendTo(document.body);
+
+    var actions = params.actions || [];
+
+    var actionsHtml = actions.map(function(d, i) {
+      return '<div class="weui-actionsheet__cell ' + (d.className || "") + '">' + d.text + '</div>';
+    }).join("");
+
+    var titleHtml = "";
+    
+    if (params.title) {
+      titleHtml = '<div class="weui-actionsheet__title"><p class="weui-actionsheet__title-text">' + params.title + '</p></div>';
+    }
+
+    var tpl = '<div class="weui-actionsheet " id="weui-actionsheet">'+
+                titleHtml +
+                '<div class="weui-actionsheet__menu">'+
+                actionsHtml +
+                '</div>'+
+                '<div class="weui-actionsheet__action">'+
+                  '<div class="weui-actionsheet__cell weui-actionsheet_cancel">取消</div>'+
+                  '</div>'+
+                '</div>';
+    var dialog = $(tpl).appendTo(document.body);
+
+    dialog.find(".weui-actionsheet__menu .weui-actionsheet__cell, .weui-actionsheet__action .weui-actionsheet__cell").each(function(i, e) {
+      $(e).click(function() {
+        $.closeActions();
+        params.onClose && params.onClose();
+        if(actions[i] && actions[i].onClick) {
+          actions[i].onClick();
+        }
+      })
+    });
+
+    mask.show();
+    dialog.show();
+    mask.addClass("weui-mask--visible");
+    dialog.addClass("weui-actionsheet_toggle");
+  };
+
+  var hide = function() {
+    $(".weui-mask").removeClass("weui-mask--visible").transitionEnd(function() {
+      $(this).remove();
+    });
+    $(".weui-actionsheet").removeClass("weui-actionsheet_toggle").transitionEnd(function() {
+      $(this).remove();
+    });
+  }
+
+  $.actions = function(params) {
+    params = $.extend({}, defaults, params);
+    show(params);
+  }
+
+  $.closeActions = function() {
+    hide();
+  }
+
+  $(document).on("click", ".weui-actions_mask", function() {
+    $.closeActions();
+  });
+
+  var defaults = $.actions.prototype.defaults = {
+    title: undefined,
+    onClose: undefined,
+    /*actions: [{
+      text: "菜单",
+      className: "color-danger",
+      onClick: function() {
+        console.log(1);
+      }
+    },{
+      text: "菜单2",
+      className: "color-success",
+      onClick: function() {
+        console.log(2);
+      }
+    }]*/
+  }
+
+}($);
+
+/* ===============================================================================
+************   Pull to refreh ************
+=============================================================================== */
+/* global $:true */
+
++function ($) {
+  "use strict";
+
+  var PTR = function(el, opt) {
+    if (typeof opt === typeof function () {}) {
+      opt = {
+        onRefresh: opt
+      }
+    }
+    if (typeof opt === typeof 'a') {
+      opt = undefined
+    }
+    this.opt = $.extend(PTR.defaults, opt || {});
+    this.container = $(el);
+    this.attachEvents();
+  }
+
+  PTR.defaults = {
+    distance: 50,
+    onRefresh: undefined,
+    onPull: undefined
+  }
+
+  PTR.prototype.touchStart = function(e) {
+    if(this.container.hasClass("refreshing")) return;
+    var p = $.getTouchPosition(e);
+    this.start = p;
+    this.diffX = this.diffY = 0;
+  };
+
+  PTR.prototype.touchMove= function(e) {
+    if(this.container.hasClass("refreshing")) return;
+    if(!this.start) return false;
+    if(this.container.scrollTop() > 0) return;
+    var p = $.getTouchPosition(e);
+    this.diffX = p.x - this.start.x;
+    this.diffY = p.y - this.start.y;
+    if (Math.abs(this.diffX) > Math.abs(this.diffY)) return true; // 说明是左右方向的拖动
+    if(this.diffY < 0) return;
+    this.container.addClass("touching");
+    e.preventDefault();
+    e.stopPropagation();
+    this.diffY = Math.pow(this.diffY, 0.75);
+    this.container.css("transform", "translate3d(0, "+this.diffY+"px, 0)");
+    this.triggerPull(this.diffY)
+  };
+  PTR.prototype.touchEnd = function() {
+    this.start = false;
+    if(this.diffY <= 0 || this.container.hasClass("refreshing")) return;
+    this.container.removeClass("touching");
+    this.container.removeClass("pull-down pull-up");
+    this.container.css("transform", "");
+    if(Math.abs(this.diffY) <= this.opt.distance) {
+    } else {
+      this.triggerPullToRefresh();
+    }
+  };
+
+  PTR.prototype.triggerPullToRefresh = function() {
+    this.triggerPull(this.opt.distance)
+    this.container.removeClass('pull-up').addClass("refreshing");
+    if (this.opt.onRefresh) {
+      this.opt.onRefresh.call(this)
+    }
+    this.container.trigger("pull-to-refresh");
+  }
+
+  PTR.prototype.triggerPull = function(diffY) {
+
+    if(diffY < this.opt.distance) {
+      this.container.removeClass("pull-up").addClass("pull-down");
+    } else {
+      this.container.removeClass("pull-down").addClass("pull-up");
+    }
+
+    if (this.opt.onPull) {
+      this.opt.onPull.call(this, Math.floor(diffY / this.opt.distance * 100))
+    }
+    this.container.trigger("pull");
+  }
+
+  PTR.prototype.pullToRefreshDone = function() {
+    this.container.removeClass("refreshing");
+  }
+
+  PTR.prototype.attachEvents = function() {
+    var el = this.container;
+    el.addClass("weui-pull-to-refresh");
+    el.on($.touchEvents.start, $.proxy(this.touchStart, this));
+    el.on($.touchEvents.move, $.proxy(this.touchMove, this));
+    el.on($.touchEvents.end, $.proxy(this.touchEnd, this));
+  };
+
+  var pullToRefreshDone = function(el) {
+    $(el).removeClass("refreshing");
+  }
+
+  $.fn.pullToRefresh = function(opt) {
+    return this.each(function() {
+      var $this = $(this)
+      var ptr = $this.data('ptr')
+      if (!ptr) $this.data('ptr', ptr = new PTR(this, opt))
+      if (typeof opt === typeof 'a') {
+        ptr[opt].call(ptr)
+      }
+    });
+  }
+
+  $.fn.pullToRefreshDone = function() {
+    return this.each(function() {
+      pullToRefreshDone(this);
+    });
+  }
+
+}($);
+
+/* ===============================================================================
+************   Infinite ************
+=============================================================================== */
+/* global $:true */
++function ($) {
+  "use strict";
+
+  // fix https://github.com/lihongxun945/jquery-weui/issues/442
+  // chrome will always return 0, when use document.body.scrollTop
+  // https://stackoverflow.com/questions/43717316/google-chrome-document-body-scrolltop-always-returns-0
+  var getOffset = function (container) {
+    var tagName = container[0].tagName.toUpperCase()
+    var scrollTop 
+    if (tagName === 'BODY' || tagName === 'HTML') {
+      scrollTop = container.scrollTop() || $(window).scrollTop()
+    } else {
+      scrollTop = container.scrollTop()
+    }
+    var offset = container.scrollHeight() - ($(window).height() + scrollTop)
+    console.log(offset)
+    return offset
+  }
+
+  var Infinite = function(el, distance) {
+    this.container = $(el);
+    this.container.data("infinite", this);
+    this.distance = distance || 50;
+    this.attachEvents();
+  }
+
+  Infinite.prototype.scroll = function() {
+    var container = this.container;
+    this._check();
+  }
+
+  Infinite.prototype.attachEvents = function(off) {
+    var el = this.container;
+    var scrollContainer = (el[0].tagName.toUpperCase() === "BODY" ? $(document) : el);
+    scrollContainer[off ? "off" : "on"]("scroll", $.proxy(this.scroll, this));
+  };
+  Infinite.prototype.detachEvents = function(off) {
+    this.attachEvents(true);
+  }
+  Infinite.prototype._check = function() {
+    var offset = getOffset(this.container);
+    if(Math.abs(offset) <= this.distance) {
+      this.container.trigger("infinite");
+    }
+  }
+
+  var infinite = function(el) {
+    attachEvents(el);
+  }
+
+  $.fn.infinite = function(distance) {
+    return this.each(function() {
+      new Infinite(this, distance);
+    });
+  }
+  $.fn.destroyInfinite = function() {
+    return this.each(function() {
+      var infinite = $(this).data("infinite");
+      if(infinite && infinite.detachEvents) infinite.detachEvents();
+    });
+  }
+
+}($);
+
+/* global $:true */
++function ($) {
+  "use strict";
+
+  var ITEM_ON = "weui-bar__item--on";
+
+  var showTab = function(a) {
+    var $a = $(a);
+    if($a.hasClass(ITEM_ON)) return;
+    var href = $a.attr("href");
+
+    if(!/^#/.test(href)) return ;
+
+    $a.parent().find("."+ITEM_ON).removeClass(ITEM_ON);
+    $a.addClass(ITEM_ON);
+
+    var bd = $a.parents(".weui-tab").find(".weui-tab__bd");
+
+    bd.find(".weui-tab__bd-item--active").removeClass("weui-tab__bd-item--active");
+
+    $(href).addClass("weui-tab__bd-item--active");
+  }
+
+  $.showTab = showTab;
+
+  $(document).on("click", ".weui-navbar__item, .weui-tabbar__item", function(e) {
+    var $a = $(e.currentTarget);
+    var href = $a.attr("href");
+    if($a.hasClass(ITEM_ON)) return;
+    if(!/^#/.test(href)) return;
+
+    e.preventDefault();
+
+    showTab($a);
+  });
+
+}($);
+
+/* global $:true */
++ function($) {
+  "use strict";
+
+  $(document).on("click touchstart", ".weui-search-bar__label", function(e) {
+    $(e.target).parents(".weui-search-bar").addClass("weui-search-bar_focusing").find('input').focus();
+  }) 
+  /*
+  .on("blur", ".weui-search-bar__input", function(e) {
+    var $input = $(e.target);
+    if(!$input.val()) $input.parents(".weui-search-bar").removeClass("weui-search-bar_focusing");
+  })
+  */
+  .on("click", ".weui-search-bar__cancel-btn", function(e) {
+    var $input = $(e.target).parents(".weui-search-bar").removeClass("weui-search-bar_focusing").find(".weui-search-bar__input").val("").blur();
+  })
+  .on("click", ".weui-icon-clear", function(e) {
+    var $input = $(e.target).parents(".weui-search-bar").find(".weui-search-bar__input").val("").focus();
+  });
+
+}($);
+
+/*===========================
+Device/OS Detection
+===========================*/
+/* global $:true */
+;(function ($) {
+    "use strict";
+    var device = {};
+    var ua = navigator.userAgent;
+
+    var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/);
+    var ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
+    var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/);
+    var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/);
+
+    device.ios = device.android = device.iphone = device.ipad = device.androidChrome = false;
+    
+    // Android
+    if (android) {
+        device.os = 'android';
+        device.osVersion = android[2];
+        device.android = true;
+        device.androidChrome = ua.toLowerCase().indexOf('chrome') >= 0;
+    }
+    if (ipad || iphone || ipod) {
+        device.os = 'ios';
+        device.ios = true;
+    }
+    // iOS
+    if (iphone && !ipod) {
+        device.osVersion = iphone[2].replace(/_/g, '.');
+        device.iphone = true;
+    }
+    if (ipad) {
+        device.osVersion = ipad[2].replace(/_/g, '.');
+        device.ipad = true;
+    }
+    if (ipod) {
+        device.osVersion = ipod[3] ? ipod[3].replace(/_/g, '.') : null;
+        device.iphone = true;
+    }
+    // iOS 8+ changed UA
+    if (device.ios && device.osVersion && ua.indexOf('Version/') >= 0) {
+        if (device.osVersion.split('.')[0] === '10') {
+            device.osVersion = ua.toLowerCase().split('version/')[1].split(' ')[0];
+        }
+    }
+
+    // Webview
+    device.webView = (iphone || ipad || ipod) && ua.match(/.*AppleWebKit(?!.*Safari)/i);
+        
+    // Minimal UI
+    if (device.os && device.os === 'ios') {
+        var osVersionArr = device.osVersion.split('.');
+        device.minimalUi = !device.webView &&
+                            (ipod || iphone) &&
+                            (osVersionArr[0] * 1 === 7 ? osVersionArr[1] * 1 >= 1 : osVersionArr[0] * 1 > 7) &&
+                            $('meta[name="viewport"]').length > 0 && $('meta[name="viewport"]').attr('content').indexOf('minimal-ui') >= 0;
+    }
+
+    // Check for status bar and fullscreen app mode
+    var windowWidth = $(window).width();
+    var windowHeight = $(window).height();
+    device.statusBar = false;
+    if (device.webView && (windowWidth * windowHeight === screen.width * screen.height)) {
+        device.statusBar = true;
+    }
+    else {
+        device.statusBar = false;
+    }
+
+    // Classes
+    var classNames = [];
+
+    // Pixel Ratio
+    device.pixelRatio = window.devicePixelRatio || 1;
+    classNames.push('pixel-ratio-' + Math.floor(device.pixelRatio));
+    if (device.pixelRatio >= 2) {
+        classNames.push('retina');
+    }
+
+    // OS classes
+    if (device.os) {
+        classNames.push(device.os, device.os + '-' + device.osVersion.split('.')[0], device.os + '-' + device.osVersion.replace(/\./g, '-'));
+        if (device.os === 'ios') {
+            var major = parseInt(device.osVersion.split('.')[0], 10);
+            for (var i = major - 1; i >= 6; i--) {
+                classNames.push('ios-gt-' + i);
+            }
+        }
+        
+    }
+    // Status bar classes
+    if (device.statusBar) {
+        classNames.push('with-statusbar-overlay');
+    }
+    else {
+        $('html').removeClass('with-statusbar-overlay');
+    }
+
+    // Add html classes
+    if (classNames.length > 0) $('html').addClass(classNames.join(' '));
+
+    $.device = device;
+})($);
+
+/*======================================================
+************   Picker   ************
+======================================================*/
+/* global $:true */
+/* jshint unused:false */
+/* jshint multistr:true */
++ function($) {
+  "use strict";
+  var Picker = function (params) {
+      var p = this;
+      var defaults = {
+          updateValuesOnMomentum: false,
+          updateValuesOnTouchmove: true,
+          rotateEffect: false,
+          momentumRatio: 7,
+          freeMode: false,
+          // Common settings
+          scrollToInput: true,
+          inputReadOnly: true,
+          toolbar: true,
+          toolbarCloseText: '完成',
+          title: '请选择',
+          toolbarTemplate: '<div class="toolbar">\
+          <div class="toolbar-inner">\
+          <a href="javascript:;" class="picker-button close-picker">{{closeText}}</a>\
+          <h1 class="title">{{title}}</h1>\
+          </div>\
+          </div>',
+      };
+      params = params || {};
+      for (var def in defaults) {
+          if (typeof params[def] === 'undefined') {
+              params[def] = defaults[def];
+          }
+      }
+      p.params = params;
+      p.cols = [];
+      p.initialized = false;
+      
+      // Inline flag
+      p.inline = p.params.container ? true : false;
+
+      // 3D Transforms origin bug, only on safari
+      var originBug = $.device.ios || (navigator.userAgent.toLowerCase().indexOf('safari') >= 0 && navigator.userAgent.toLowerCase().indexOf('chrome') < 0) && !$.device.android;
+
+      // Should be converted to popover
+      function isPopover() {
+          var toPopover = false;
+          if (!p.params.convertToPopover && !p.params.onlyInPopover) return toPopover;
+          if (!p.inline && p.params.input) {
+              if (p.params.onlyInPopover) toPopover = true;
+              else {
+                  if ($.device.ios) {
+                      toPopover = $.device.ipad ? true : false;
+                  }
+                  else {
+                      if ($(window).width() >= 768) toPopover = true;
+                  }
+              }
+          } 
+          return toPopover; 
+      }
+      function inPopover() {
+          if (p.opened && p.container && p.container.length > 0 && p.container.parents('.popover').length > 0) return true;
+          else return false;
+      }
+
+      // Value
+      p.setValue = function (arrValues, transition) {
+          var valueIndex = 0;
+          for (var i = 0; i < p.cols.length; i++) {
+              if (p.cols[i] && !p.cols[i].divider) {
+                  p.cols[i].setValue(arrValues[valueIndex], transition);
+                  valueIndex++;
+              }
+          }
+      };
+      p.updateValue = function () {
+          var newValue = [];
+          var newDisplayValue = [];
+          for (var i = 0; i < p.cols.length; i++) {
+              if (!p.cols[i].divider) {
+                  newValue.push(p.cols[i].value);
+                  newDisplayValue.push(p.cols[i].displayValue);
+              }
+          }
+          if (newValue.indexOf(undefined) >= 0) {
+              return;
+          }
+          p.value = newValue;
+          p.displayValue = newDisplayValue;
+          if (p.params.onChange) {
+              p.params.onChange(p, p.value, p.displayValue);
+          }
+          if (p.input && p.input.length > 0) {
+              $(p.input).val(p.params.formatValue ? p.params.formatValue(p, p.value, p.displayValue) : p.value.join(' '));
+              $(p.input).trigger('change');
+          }
+      };
+
+      // Columns Handlers
+      p.initPickerCol = function (colElement, updateItems) {
+          var colContainer = $(colElement);
+          var colIndex = colContainer.index();
+          var col = p.cols[colIndex];
+          if (col.divider) return;
+          col.container = colContainer;
+          col.wrapper = col.container.find('.picker-items-col-wrapper');
+          col.items = col.wrapper.find('.picker-item');
+          
+          var i, j;
+          var wrapperHeight, itemHeight, itemsHeight, minTranslate, maxTranslate;
+          col.replaceValues = function (values, displayValues) {
+              col.destroyEvents();
+              col.values = values;
+              col.displayValues = displayValues;
+              var newItemsHTML = p.columnHTML(col, true);
+              col.wrapper.html(newItemsHTML);
+              col.items = col.wrapper.find('.picker-item');
+              col.calcSize();
+              col.setValue(col.values[0] || '', 0, true);
+              col.initEvents();
+          };
+          col.calcSize = function () {
+              if (!col.values.length) return;
+              if (p.params.rotateEffect) {
+                  col.container.removeClass('picker-items-col-absolute');
+                  if (!col.width) col.container.css({width:''});
+              }
+              var colWidth, colHeight;
+              colWidth = 0;
+              colHeight = col.container[0].offsetHeight;
+              wrapperHeight = col.wrapper[0].offsetHeight;
+              itemHeight = col.items[0].offsetHeight;
+              itemsHeight = itemHeight * col.items.length;
+              minTranslate = colHeight / 2 - itemsHeight + itemHeight / 2;
+              maxTranslate = colHeight / 2 - itemHeight / 2;    
+              if (col.width) {
+                  colWidth = col.width;
+                  if (parseInt(colWidth, 10) === colWidth) colWidth = colWidth + 'px';
+                  col.container.css({width: colWidth});
+              }
+              if (p.params.rotateEffect) {
+                  if (!col.width) {
+                      col.items.each(function () {
+                          var item = $(this);
+                          item.css({width:'auto'});
+                          colWidth = Math.max(colWidth, item[0].offsetWidth);
+                          item.css({width:''});
+                      });
+                      col.container.css({width: (colWidth + 2) + 'px'});
+                  }
+                  col.container.addClass('picker-items-col-absolute');
+              }
+          };
+          col.calcSize();
+          
+          col.wrapper.transform('translate3d(0,' + maxTranslate + 'px,0)').transition(0);
+
+
+          var activeIndex = 0;
+          var animationFrameId;
+
+          // Set Value Function
+          col.setValue = function (newValue, transition, valueCallbacks) {
+              if (typeof transition === 'undefined') transition = '';
+              var newActiveIndex = col.wrapper.find('.picker-item[data-picker-value="' + newValue + '"]').index();
+              if(typeof newActiveIndex === 'undefined' || newActiveIndex === -1) {
+                  col.value = col.displayValue = newValue;
+                  return;
+              }
+              var newTranslate = -newActiveIndex * itemHeight + maxTranslate;
+              // Update wrapper
+              col.wrapper.transition(transition);
+              col.wrapper.transform('translate3d(0,' + (newTranslate) + 'px,0)');
+                  
+              // Watch items
+              if (p.params.updateValuesOnMomentum && col.activeIndex && col.activeIndex !== newActiveIndex ) {
+                  $.cancelAnimationFrame(animationFrameId);
+                  col.wrapper.transitionEnd(function(){
+                      $.cancelAnimationFrame(animationFrameId);
+                  });
+                  updateDuringScroll();
+              }
+
+              // Update items
+              col.updateItems(newActiveIndex, newTranslate, transition, valueCallbacks);
+          };
+
+          col.updateItems = function (activeIndex, translate, transition, valueCallbacks) {
+              if (typeof translate === 'undefined') {
+                  translate = $.getTranslate(col.wrapper[0], 'y');
+              }
+              if(typeof activeIndex === 'undefined') activeIndex = -Math.round((translate - maxTranslate)/itemHeight);
+              if (activeIndex < 0) activeIndex = 0;
+              if (activeIndex >= col.items.length) activeIndex = col.items.length - 1;
+              var previousActiveIndex = col.activeIndex;
+              col.activeIndex = activeIndex;
+              /*
+              col.wrapper.find('.picker-selected, .picker-after-selected, .picker-before-selected').removeClass('picker-selected picker-after-selected picker-before-selected');
+
+              col.items.transition(transition);
+              var selectedItem = col.items.eq(activeIndex).addClass('picker-selected').transform('');
+              var prevItems = selectedItem.prevAll().addClass('picker-before-selected');
+              var nextItems = selectedItem.nextAll().addClass('picker-after-selected');
+              */
+              //去掉 .picker-after-selected, .picker-before-selected 以提高性能
+              col.wrapper.find('.picker-selected').removeClass('picker-selected');
+              if (p.params.rotateEffect) {
+                col.items.transition(transition);
+              }
+              var selectedItem = col.items.eq(activeIndex).addClass('picker-selected').transform('');
+
+              if (valueCallbacks || typeof valueCallbacks === 'undefined') {
+                  // Update values
+                  col.value = selectedItem.attr('data-picker-value');
+                  col.displayValue = col.displayValues ? col.displayValues[activeIndex] : col.value;
+                  // On change callback
+                  if (previousActiveIndex !== activeIndex) {
+                      if (col.onChange) {
+                          col.onChange(p, col.value, col.displayValue);
+                      }
+                      p.updateValue();
+                  }
+              }
+                  
+              // Set 3D rotate effect
+              if (!p.params.rotateEffect) {
+                  return;
+              }
+              var percentage = (translate - (Math.floor((translate - maxTranslate)/itemHeight) * itemHeight + maxTranslate)) / itemHeight;
+              
+              col.items.each(function () {
+                  var item = $(this);
+                  var itemOffsetTop = item.index() * itemHeight;
+                  var translateOffset = maxTranslate - translate;
+                  var itemOffset = itemOffsetTop - translateOffset;
+                  var percentage = itemOffset / itemHeight;
+
+                  var itemsFit = Math.ceil(col.height / itemHeight / 2) + 1;
+                  
+                  var angle = (-18*percentage);
+                  if (angle > 180) angle = 180;
+                  if (angle < -180) angle = -180;
+                  // Far class
+                  if (Math.abs(percentage) > itemsFit) item.addClass('picker-item-far');
+                  else item.removeClass('picker-item-far');
+                  // Set transform
+                  item.transform('translate3d(0, ' + (-translate + maxTranslate) + 'px, ' + (originBug ? -110 : 0) + 'px) rotateX(' + angle + 'deg)');
+              });
+          };
+
+          function updateDuringScroll() {
+              animationFrameId = $.requestAnimationFrame(function () {
+                  col.updateItems(undefined, undefined, 0);
+                  updateDuringScroll();
+              });
+          }
+
+          // Update items on init
+          if (updateItems) col.updateItems(0, maxTranslate, 0);
+
+          var allowItemClick = true;
+          var isTouched, isMoved, touchStartY, touchCurrentY, touchStartTime, touchEndTime, startTranslate, returnTo, currentTranslate, prevTranslate, velocityTranslate, velocityTime;
+          function handleTouchStart (e) {
+              if (isMoved || isTouched) return;
+              e.preventDefault();
+              isTouched = true;
+              var position = $.getTouchPosition(e);
+              touchStartY = touchCurrentY = position.y;
+              touchStartTime = (new Date()).getTime();
+              
+              allowItemClick = true;
+              startTranslate = currentTranslate = $.getTranslate(col.wrapper[0], 'y');
+          }
+          function handleTouchMove (e) {
+              if (!isTouched) return;
+              e.preventDefault();
+              allowItemClick = false;
+              var position = $.getTouchPosition(e);
+              touchCurrentY = position.y;
+              if (!isMoved) {
+                  // First move
+                  $.cancelAnimationFrame(animationFrameId);
+                  isMoved = true;
+                  startTranslate = currentTranslate = $.getTranslate(col.wrapper[0], 'y');
+                  col.wrapper.transition(0);
+              }
+              e.preventDefault();
+
+              var diff = touchCurrentY - touchStartY;
+              currentTranslate = startTranslate + diff;
+              returnTo = undefined;
+
+              // Normalize translate
+              if (currentTranslate < minTranslate) {
+                  currentTranslate = minTranslate - Math.pow(minTranslate - currentTranslate, 0.8);
+                  returnTo = 'min';
+              }
+              if (currentTranslate > maxTranslate) {
+                  currentTranslate = maxTranslate + Math.pow(currentTranslate - maxTranslate, 0.8);
+                  returnTo = 'max';
+              }
+              // Transform wrapper
+              col.wrapper.transform('translate3d(0,' + currentTranslate + 'px,0)');
+
+              // Update items
+              col.updateItems(undefined, currentTranslate, 0, p.params.updateValuesOnTouchmove);
+              
+              // Calc velocity
+              velocityTranslate = currentTranslate - prevTranslate || currentTranslate;
+              velocityTime = (new Date()).getTime();
+              prevTranslate = currentTranslate;
+          }
+          function handleTouchEnd (e) {
+              if (!isTouched || !isMoved) {
+                  isTouched = isMoved = false;
+                  return;
+              }
+              isTouched = isMoved = false;
+              col.wrapper.transition('');
+              if (returnTo) {
+                  if (returnTo === 'min') {
+                      col.wrapper.transform('translate3d(0,' + minTranslate + 'px,0)');
+                  }
+                  else col.wrapper.transform('translate3d(0,' + maxTranslate + 'px,0)');
+              }
+              touchEndTime = new Date().getTime();
+              var velocity, newTranslate;
+              if (touchEndTime - touchStartTime > 300) {
+                  newTranslate = currentTranslate;
+              }
+              else {
+                  velocity = Math.abs(velocityTranslate / (touchEndTime - velocityTime));
+                  newTranslate = currentTranslate + velocityTranslate * p.params.momentumRatio;
+              }
+
+              newTranslate = Math.max(Math.min(newTranslate, maxTranslate), minTranslate);
+
+              // Active Index
+              var activeIndex = -Math.floor((newTranslate - maxTranslate)/itemHeight);
+
+              // Normalize translate
+              if (!p.params.freeMode) newTranslate = -activeIndex * itemHeight + maxTranslate;
+
+              // Transform wrapper
+              col.wrapper.transform('translate3d(0,' + (parseInt(newTranslate,10)) + 'px,0)');
+
+              // Update items
+              col.updateItems(activeIndex, newTranslate, '', true);
+
+              // Watch items
+              if (p.params.updateValuesOnMomentum) {
+                  updateDuringScroll();
+                  col.wrapper.transitionEnd(function(){
+                      $.cancelAnimationFrame(animationFrameId);
+                  });
+              }
+
+              // Allow click
+              setTimeout(function () {
+                  allowItemClick = true;
+              }, 100);
+          }
+
+          function handleClick(e) {
+              if (!allowItemClick) return;
+              $.cancelAnimationFrame(animationFrameId);
+              /*jshint validthis:true */
+              var value = $(this).attr('data-picker-value');
+              col.setValue(value);
+          }
+
+          col.initEvents = function (detach) {
+              var method = detach ? 'off' : 'on';
+              col.container[method]($.touchEvents.start, handleTouchStart);
+              col.container[method]($.touchEvents.move, handleTouchMove);
+              col.container[method]($.touchEvents.end, handleTouchEnd);
+              col.items[method]('click', handleClick);
+          };
+          col.destroyEvents = function () {
+              col.initEvents(true);
+          };
+
+          col.container[0].f7DestroyPickerCol = function () {
+              col.destroyEvents();
+          };
+
+          col.initEvents();
+
+      };
+      p.destroyPickerCol = function (colContainer) {
+          colContainer = $(colContainer);
+          if ('f7DestroyPickerCol' in colContainer[0]) colContainer[0].f7DestroyPickerCol();
+      };
+      // Resize cols
+      function resizeCols() {
+          if (!p.opened) return;
+          for (var i = 0; i < p.cols.length; i++) {
+              if (!p.cols[i].divider) {
+                  p.cols[i].calcSize();
+                  p.cols[i].setValue(p.cols[i].value, 0, false);
+              }
+          }
+      }
+      $(window).on('resize', resizeCols);
+
+      // HTML Layout
+      p.columnHTML = function (col, onlyItems) {
+          var columnItemsHTML = '';
+          var columnHTML = '';
+          if (col.divider) {
+              columnHTML += '<div class="picker-items-col picker-items-col-divider ' + (col.textAlign ? 'picker-items-col-' + col.textAlign : '') + ' ' + (col.cssClass || '') + '">' + col.content + '</div>';
+          }
+          else {
+              for (var j = 0; j < col.values.length; j++) {
+                  columnItemsHTML += '<div class="picker-item" data-picker-value="' + col.values[j] + '">' + (col.displayValues ? col.displayValues[j] : col.values[j]) + '</div>';
+              }
+              columnHTML += '<div class="picker-items-col ' + (col.textAlign ? 'picker-items-col-' + col.textAlign : '') + ' ' + (col.cssClass || '') + '"><div class="picker-items-col-wrapper">' + columnItemsHTML + '</div></div>';
+          }
+          return onlyItems ? columnItemsHTML : columnHTML;
+      };
+      p.layout = function () {
+          var pickerHTML = '';
+          var pickerClass = '';
+          var i;
+          p.cols = [];
+          var colsHTML = '';
+          for (i = 0; i < p.params.cols.length; i++) {
+              var col = p.params.cols[i];
+              colsHTML += p.columnHTML(p.params.cols[i]);
+              p.cols.push(col);
+          }
+          pickerClass = 'weui-picker-modal picker-columns ' + (p.params.cssClass || '') + (p.params.rotateEffect ? ' picker-3d' : '') + (p.params.cols.length === 1 ? ' picker-columns-single' : '');
+          pickerHTML =
+              '<div class="' + (pickerClass) + '">' +
+                  (p.params.toolbar ? p.params.toolbarTemplate.replace(/{{closeText}}/g, p.params.toolbarCloseText).replace(/{{title}}/g, p.params.title) : '') +
+                  '<div class="picker-modal-inner picker-items">' +
+                      colsHTML +
+                      '<div class="picker-center-highlight"></div>' +
+                  '</div>' +
+              '</div>';
+              
+          p.pickerHTML = pickerHTML;    
+      };
+
+      // Input Events
+      function openOnInput(e) {
+          e.preventDefault();
+          if (p.opened) return;
+          p.open();
+          if (p.params.scrollToInput && !isPopover()) {
+              var pageContent = p.input.parents('.content');
+              if (pageContent.length === 0) return;
+
+              var paddingTop = parseInt(pageContent.css('padding-top'), 10),
+                  paddingBottom = parseInt(pageContent.css('padding-bottom'), 10),
+                  pageHeight = pageContent[0].offsetHeight - paddingTop - p.container.height(),
+                  pageScrollHeight = pageContent[0].scrollHeight - paddingTop - p.container.height(),
+                  newPaddingBottom;
+              var inputTop = p.input.offset().top - paddingTop + p.input[0].offsetHeight;
+              if (inputTop > pageHeight) {
+                  var scrollTop = pageContent.scrollTop() + inputTop - pageHeight;
+                  if (scrollTop + pageHeight > pageScrollHeight) {
+                      newPaddingBottom = scrollTop + pageHeight - pageScrollHeight + paddingBottom;
+                      if (pageHeight === pageScrollHeight) {
+                          newPaddingBottom = p.container.height();
+                      }
+                      pageContent.css({'padding-bottom': (newPaddingBottom) + 'px'});
+                  }
+                  pageContent.scrollTop(scrollTop, 300);
+              }
+          }
+      }
+      function closeOnHTMLClick(e) {
+          if (inPopover()) return;
+          if (p.input && p.input.length > 0) {
+              if (e.target !== p.input[0] && $(e.target).parents('.weui-picker-modal').length === 0) p.close();
+          }
+          else {
+              if ($(e.target).parents('.weui-picker-modal').length === 0) p.close();   
+          }
+      }
+
+      if (p.params.input) {
+          p.input = $(p.params.input);
+          if (p.input.length > 0) {
+              if (p.params.inputReadOnly) p.input.prop('readOnly', true);
+              if (!p.inline) {
+                  p.input.on('click', openOnInput);    
+              }
+              if (p.params.inputReadOnly) {
+                  p.input.on('focus mousedown', function (e) {
+                      e.preventDefault();
+                  });
+              }
+          }
+              
+      }
+      
+      if (!p.inline) $('html').on('click', closeOnHTMLClick);
+
+      // Open
+      function onPickerClose() {
+          p.opened = false;
+          if (p.input && p.input.length > 0) p.input.parents('.page-content').css({'padding-bottom': ''});
+          if (p.params.onClose) p.params.onClose(p);
+
+          // Destroy events
+          p.container.find('.picker-items-col').each(function () {
+              p.destroyPickerCol(this);
+          });
+      }
+
+      p.opened = false;
+      p.open = function () {
+          var toPopover = isPopover();
+
+          if (!p.opened) {
+
+              // Layout
+              p.layout();
+
+              // Append
+              if (toPopover) {
+                  p.pickerHTML = '<div class="popover popover-picker-columns"><div class="popover-inner">' + p.pickerHTML + '</div></div>';
+                  p.popover = $.popover(p.pickerHTML, p.params.input, true);
+                  p.container = $(p.popover).find('.weui-picker-modal');
+                  $(p.popover).on('close', function () {
+                      onPickerClose();
+                  });
+              }
+              else if (p.inline) {
+                  p.container = $(p.pickerHTML);
+                  p.container.addClass('picker-modal-inline');
+                  $(p.params.container).append(p.container);
+              }
+              else {
+                  p.container = $($.openPicker(p.pickerHTML));
+                  $(p.container)
+                  .on('close', function () {
+                      onPickerClose();
+                  });
+              }
+
+              // Store picker instance
+              p.container[0].f7Picker = p;
+
+              // Init Events
+              p.container.find('.picker-items-col').each(function () {
+                  var updateItems = true;
+                  if ((!p.initialized && p.params.value) || (p.initialized && p.value)) updateItems = false;
+                  p.initPickerCol(this, updateItems);
+              });
+              
+              // Set value
+              if (!p.initialized) {
+                  if (p.params.value) {
+                      p.setValue(p.params.value, 0);
+                  }
+              }
+              else {
+                  if (p.value) p.setValue(p.value, 0);
+              }
+          }
+
+          // Set flag
+          p.opened = true;
+          p.initialized = true;
+
+          if (p.params.onOpen) p.params.onOpen(p);
+      };
+
+      // Close
+      p.close = function (force) {
+          if (!p.opened || p.inline) return;
+          if (inPopover()) {
+              $.closePicker(p.popover);
+              return;
+          }
+          else {
+              $.closePicker(p.container);
+              return;
+          }
+      };
+
+      // Destroy
+      p.destroy = function () {
+          p.close();
+          if (p.params.input && p.input.length > 0) {
+              p.input.off('click focus', openOnInput);
+              $(p.input).data('picker', null);
+          }
+          $('html').off('click', closeOnHTMLClick);
+          $(window).off('resize', resizeCols);
+      };
+
+      if (p.inline) {
+          p.open();
+      }
+
+      return p;
+  };
+
+  $(document).on("click", ".close-picker", function() {
+    var pickerToClose = $('.weui-picker-modal.weui-picker-modal-visible');
+    if (pickerToClose.length > 0) {
+      $.closePicker(pickerToClose);
+    }
+  });
+
+  //修复picker会滚动页面的bug
+  $(document).on($.touchEvents.move, ".picker-modal-inner", function(e) {
+    e.preventDefault();
+  });
+
+
+  $.openPicker = function(tpl, className, callback) {
+
+    if(typeof className === "function") {
+      callback = className;
+      className = undefined;
+    }
+
+    $.closePicker();
+
+    var container = $("<div class='weui-picker-container "+ (className || "") + "'></div>").appendTo(document.body);
+    container.show();
+
+    container.addClass("weui-picker-container-visible");
+
+    //关于布局的问题,如果直接放在body上,则做动画的时候会撑开body高度而导致滚动条变化。
+    var dialog = $(tpl).appendTo(container);
+    
+    dialog.width(); //通过取一次CSS值,强制浏览器不能把上下两行代码合并执行,因为合并之后会导致无法出现动画。
+
+    dialog.addClass("weui-picker-modal-visible");
+
+    callback && container.on("close", callback);
+
+    return dialog;
+  }
+
+  $.updatePicker = function(tpl) {
+    var container = $(".weui-picker-container-visible");
+    if(!container[0]) return false;
+
+    container.html("");
+
+    var dialog = $(tpl).appendTo(container);
+
+    dialog.addClass("weui-picker-modal-visible");
+
+    return dialog;
+  }
+
+  $.closePicker = function(container, callback) {
+    if(typeof container === "function") callback = container;
+    $(".weui-picker-modal-visible").removeClass("weui-picker-modal-visible").transitionEnd(function() {
+      $(this).parent().remove();
+      callback && callback();
+    }).trigger("close");
+  };
+
+  $.fn.picker = function(params) {
+    var args = arguments;
+    return this.each(function() {
+      if(!this) return;
+      var $this = $(this);
+      
+      var picker = $this.data("picker");
+      if(!picker) {
+        params = $.extend({ input: this }, params || {}) // https://github.com/lihongxun945/jquery-weui/issues/432
+        var inputValue = $this.val();
+        if(params.value === undefined && inputValue !== "") {
+          params.value = (params.cols && params.cols.length > 1) ? inputValue.split(" ") : [inputValue];
+        }
+        var p = $.extend({input: this}, params);
+        picker = new Picker(p);
+        $this.data("picker", picker);
+      }
+      if(typeof params === typeof "a") {
+        picker[params].apply(picker, Array.prototype.slice.call(args, 1));
+      }
+    });
+  };
+}($);
+
+/* global $:true */
++ function($) {
+  "use strict";
+
+  var defaults;
+
+  var selects = [];
+
+  var Select = function(input, config) {
+
+    var self = this;
+    this.config = config;
+
+    //init empty data
+    this.data = {
+      values: '',
+      titles: '',
+      origins: [],
+      length: 0
+    };
+
+    this.$input = $(input);
+    this.$input.prop("readOnly", true);
+
+    this.initConfig();
+
+    config = this.config;
+
+    this.$input.click($.proxy(this.open, this));
+    selects.push(this)
+  }
+
+  Select.prototype.initConfig = function() {
+    this.config = $.extend({}, defaults, this.config);
+
+    var config = this.config;
+
+    if(!config.items || !config.items.length) return;
+
+    config.items = config.items.map(function(d, i) {
+      if(typeof d == typeof "a") {
+        return {
+          title: d,
+          value: d
+        };
+      }
+
+      return d;
+    });
+
+
+    this.tpl = $.t7.compile("<div class='weui-picker-modal weui-select-modal'>" + config.toolbarTemplate + (config.multi ? config.checkboxTemplate : config.radioTemplate) + "</div>");
+
+    if(config.input !== undefined) this.$input.val(config.input);
+
+    this.parseInitValue();
+
+    this._init = true;
+  }
+
+  Select.prototype.updateInputValue = function(values, titles) {
+    var v, t;
+    if(this.config.multi) {
+      v = values.join(this.config.split);
+      t = titles.join(this.config.split);
+    } else {
+      v = values[0];
+      t = titles[0];
+    }
+
+    //caculate origin data
+    var origins = [];
+
+    this.config.items.forEach(function(d) {
+      values.each(function(i, dd) {
+        if(d.value == dd) origins.push(d);
+      });
+    });
+
+    this.$input.val(t).data("values", v);
+    this.$input.attr("value", t).attr("data-values", v);
+
+    var data = {
+      values: v,
+      titles: t,
+      valuesArray: values,
+      titlesArray: titles,
+      origins: origins,
+      length: origins.length
+    };
+    this.data = data;
+    this.$input.trigger("change", data);
+    this.config.onChange && this.config.onChange.call(this, data);
+  }
+
+  Select.prototype.parseInitValue = function() {
+    var value = this.$input.val();
+    var items = this.config.items;
+
+    //如果input为空,只有在第一次初始化的时候才保留默认选择。因为后来就是用户自己取消了全部选择,不能再为他选中默认值。
+    if( !this._init && (value === undefined || value == null || value === "")) return;
+
+    var titles = this.config.multi ? value.split(this.config.split) : [value];
+    for(var i=0;i<items.length;i++) {
+      items[i].checked = false;
+      for(var j=0;j<titles.length;j++) {
+        if(items[i].title === titles[j]) {
+          items[i].checked = true;
+        }
+      }
+    }
+  }
+
+  Select.prototype._bind = function(dialog) {
+    var self = this,
+        config = this.config;
+    dialog.on("change", function(e) {
+      var checked = dialog.find("input:checked");
+      var values = checked.map(function() {
+        return $(this).val();
+      });
+      var titles = checked.map(function() {
+        return $(this).data("title");
+      });
+      self.updateInputValue(values, titles);
+
+      if(config.autoClose && !config.multi) self.close();
+    })
+    .trigger('change')
+    .on("click", ".close-select", function() {
+      self.close();
+    });
+  }
+
+  //更新数据
+  Select.prototype.update = function(config) {
+    this.config = $.extend({}, this.config, config);
+    this.initConfig();
+    if(this._open) {
+      this._bind($.updatePicker(this.getHTML()));
+    }
+  }
+  
+  Select.prototype.open = function(values, titles) {
+
+    if(this._open) return;
+
+    // open picker 会默认关掉其他的,但是 onClose 不会被调用,所以这里先关掉其他select
+    for (var i = 0; i < selects.length; i++ ) {
+      var s = selects[i];
+      if (s === this) continue;
+      if (s._open) {
+        if(!s.close()) return false; // 其他的select由于某些条件限制关闭失败。
+      }
+    }
+
+    this.parseInitValue();
+
+    var config = this.config;
+
+    var dialog = this.dialog = $.openPicker(this.getHTML());
+    
+    this._bind(dialog);
+
+    this._open = true;
+    if(config.onOpen) config.onOpen(this);
+  }
+
+  Select.prototype.close = function(callback, force) {
+    if (!this._open) return false;
+    var self = this,
+        beforeClose = this.config.beforeClose;
+
+    if(typeof callback === typeof true) {
+      force === callback;
+    }
+    if(!force) {
+      if(beforeClose && typeof beforeClose === 'function' && beforeClose.call(this, this.data.values, this.data.titles) === false) {
+        return false
+      }
+      if(this.config.multi) {
+        if(this.config.min !== undefined && this.data.length < this.config.min) {
+          $.toast("请至少选择"+this.config.min+"个", "text");
+          return false
+        }
+        if(this.config.max !== undefined && this.data.length > this.config.max) {
+          $.toast("最多只能选择"+this.config.max+"个", "text");
+          return false
+        }
+      }
+    }
+    $.closePicker(function() {
+      self.onClose();
+      callback && callback();
+    });
+
+    return true
+  }
+
+  Select.prototype.onClose = function() {
+    this._open = false;
+    if(this.config.onClose) this.config.onClose(this);
+  }
+
+  Select.prototype.getHTML = function(callback) {
+    var config = this.config;
+    return this.tpl({
+      items: config.items,
+      title: config.title,
+      closeText: config.closeText
+    })
+  }
+
+
+  $.fn.select = function(params, args) {
+
+    return this.each(function() {
+      var $this = $(this);
+      if(!$this.data("weui-select")) $this.data("weui-select", new Select(this, params));
+
+      var select = $this.data("weui-select");
+
+      if(typeof params === typeof "a") select[params].call(select, args);
+
+      return select;
+    });
+  }
+
+  defaults = $.fn.select.prototype.defaults = {
+    items: [],
+    input: undefined, //输入框的初始值
+    title: "请选择",
+    multi: false,
+    closeText: "确定",
+    autoClose: true, //是否选择完成后自动关闭,只有单选模式下才有效
+    onChange: undefined, //function
+    beforeClose: undefined, // function 关闭之前,如果返回false则阻止关闭
+    onClose: undefined, //function
+    onOpen: undefined, //function
+    split: ",",  //多选模式下的分隔符
+    min: undefined, //多选模式下可用,最少选择数
+    max: undefined, //单选模式下可用,最多选择数
+    toolbarTemplate: '<div class="toolbar">\
+      <div class="toolbar-inner">\
+      <a href="javascript:;" class="picker-button close-select">{{closeText}}</a>\
+      <h1 class="title">{{title}}</h1>\
+      </div>\
+      </div>',
+    radioTemplate:
+      '<div class="weui-cells weui-cells_radio">\
+        {{#items}}\
+        <label class="weui-cell weui-check_label" for="weui-select-id-{{this.title}}">\
+          <div class="weui-cell__bd weui-cell_primary">\
+            <p>{{this.title}}</p>\
+          </div>\
+          <div class="weui-cell__ft">\
+            <input type="radio" class="weui-check" name="weui-select" id="weui-select-id-{{this.title}}" value="{{this.value}}" {{#if this.checked}}checked="checked"{{/if}} data-title="{{this.title}}">\
+            <span class="weui-icon-checked"></span>\
+          </div>\
+        </label>\
+        {{/items}}\
+      </div>',
+    checkboxTemplate:
+      '<div class="weui-cells weui-cells_checkbox">\
+        {{#items}}\
+        <label class="weui-cell weui-check_label" for="weui-select-id-{{this.title}}">\
+          <div class="weui-cell__bd weui-cell_primary">\
+            <p>{{this.title}}</p>\
+          </div>\
+          <div class="weui-cell__ft">\
+            <input type="checkbox" class="weui-check" name="weui-select" id="weui-select-id-{{this.title}}" value="{{this.value}}" {{#if this.checked}}checked="checked"{{/if}} data-title="{{this.title}}" >\
+            <span class="weui-icon-checked"></span>\
+          </div>\
+        </label>\
+        {{/items}}\
+      </div>',
+  }
+
+}($);
+
+/*======================================================
+************   Calendar   ************
+======================================================*/
+/* global $:true */
+/*jshint unused: false*/
++function ($) {
+  "use strict";
+  var rtl = false;
+  var defaults;
+  var isSameDate = function (a, b) {
+    var a = new Date(a),
+      b = new Date(b);
+    return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate()
+  }
+  var Calendar = function (params) {
+      var p = this;
+      params = params || {};
+      for (var def in defaults) {
+          if (typeof params[def] === 'undefined') {
+              params[def] = defaults[def];
+          }
+      }
+      p.params = params;
+      p.initialized = false;
+
+      // Inline flag
+      p.inline = p.params.container ? true : false;
+
+      // Is horizontal
+      p.isH = p.params.direction === 'horizontal';
+
+      // RTL inverter
+      var inverter = p.isH ? (rtl ? -1 : 1) : 1;
+
+      // Animating flag
+      p.animating = false;
+
+      // Should be converted to popover
+      function isPopover() {
+          var toPopover = false;
+          if (!p.params.convertToPopover && !p.params.onlyInPopover) return toPopover;
+          if (!p.inline && p.params.input) {
+              if (p.params.onlyInPopover) toPopover = true;
+              else {
+                  if ($.device.ios) {
+                      toPopover = $.device.ipad ? true : false;
+                  }
+                  else {
+                      if ($(window).width() >= 768) toPopover = true;
+                  }
+              }
+          } 
+          return toPopover; 
+      }
+      function inPopover() {
+          if (p.opened && p.container && p.container.length > 0 && p.container.parents('.popover').length > 0) return true;
+          else return false;
+      }
+
+      // Format date
+      function formatDate(date) {
+          date = new Date(date);
+          var year = date.getFullYear();
+          var month = date.getMonth();
+          var month1 = month + 1;
+          var day = date.getDate();
+          var weekDay = date.getDay();
+          return p.params.dateFormat
+              .replace(/yyyy/g, year)
+              .replace(/yy/g, (year + '').substring(2))
+              .replace(/mm/g, month1 < 10 ? '0' + month1 : month1)
+              .replace(/m/g, month1)
+              .replace(/MM/g, p.params.monthNames[month])
+              .replace(/M/g, p.params.monthNamesShort[month])
+              .replace(/dd/g, day < 10 ? '0' + day : day)
+              .replace(/d/g, day)
+              .replace(/DD/g, p.params.dayNames[weekDay])
+              .replace(/D/g, p.params.dayNamesShort[weekDay]);
+      }
+
+
+      // Value
+      p.addValue = function (value) {
+          if (p.params.multiple) {
+              if (!p.value) p.value = [];
+              var inValuesIndex;
+              for (var i = 0; i < p.value.length; i++) {
+                  if (isSameDate(value, p.value[i])) {
+                      inValuesIndex = i;
+                  }
+              }
+              if (typeof inValuesIndex === 'undefined') {
+                  p.value.push(value);
+              }
+              else {
+                  p.value.splice(inValuesIndex, 1);
+              }
+              p.updateValue();
+          }
+          else {
+              p.value = [value];
+              p.updateValue();
+          }
+      };
+      p.setValue = function (arrValues) {
+        var date = new Date(arrValues[0]);
+        p.setYearMonth(date.getFullYear(), date.getMonth());
+        p.addValue(+ date);
+      };
+      p.updateValue = function () {
+          p.wrapper.find('.picker-calendar-day-selected').removeClass('picker-calendar-day-selected');
+          var i, inputValue;
+          for (i = 0; i < p.value.length; i++) {
+              var valueDate = new Date(p.value[i]);
+              p.wrapper.find('.picker-calendar-day[data-date="' + valueDate.getFullYear() + '-' + valueDate.getMonth() + '-' + valueDate.getDate() + '"]').addClass('picker-calendar-day-selected');
+          }
+          if (p.params.onChange) {
+            p.params.onChange(p, p.value.map(formatDate), p.value.map(function (d) {
+              return + new Date(typeof d === typeof 'a' ? d.split(/\D/).filter(function (a) { return !!a; }).join("-") : d);
+            }));
+          }
+          if (p.input && p.input.length > 0) {
+              if (p.params.formatValue) inputValue = p.params.formatValue(p, p.value);
+              else {
+                  inputValue = [];
+                  for (i = 0; i < p.value.length; i++) {
+                      inputValue.push(formatDate(p.value[i]));
+                  }
+                  inputValue = inputValue.join(', ');
+              } 
+              $(p.input).val(inputValue);
+              $(p.input).trigger('change');
+          }
+      };
+
+      // Columns Handlers
+      p.initCalendarEvents = function () {
+          var col;
+          var allowItemClick = true;
+          var isTouched, isMoved, touchStartX, touchStartY, touchCurrentX, touchCurrentY, touchStartTime, touchEndTime, startTranslate, currentTranslate, wrapperWidth, wrapperHeight, percentage, touchesDiff, isScrolling;
+          function handleTouchStart (e) {
+              if (isMoved || isTouched) return;
+              // e.preventDefault();
+              isTouched = true;
+              var position = $.getTouchPosition(e);
+              touchStartX = touchCurrentY = position.x;
+              touchStartY = touchCurrentY = position.y;
+              touchStartTime = (new Date()).getTime();
+              percentage = 0;
+              allowItemClick = true;
+              isScrolling = undefined;
+              startTranslate = currentTranslate = p.monthsTranslate;
+          }
+          function handleTouchMove (e) {
+              if (!isTouched) return;
+              var position = $.getTouchPosition(e);
+              touchCurrentX = position.x;
+              touchCurrentY = position.y;
+              if (typeof isScrolling === 'undefined') {
+                  isScrolling = !!(isScrolling || Math.abs(touchCurrentY - touchStartY) > Math.abs(touchCurrentX - touchStartX));
+              }
+              if (p.isH && isScrolling) {
+                  isTouched = false;
+                  return;
+              }
+              e.preventDefault();
+              if (p.animating) {
+                  isTouched = false;
+                  return;   
+              }
+              allowItemClick = false;
+              if (!isMoved) {
+                  // First move
+                  isMoved = true;
+                  wrapperWidth = p.wrapper[0].offsetWidth;
+                  wrapperHeight = p.wrapper[0].offsetHeight;
+                  p.wrapper.transition(0);
+              }
+              e.preventDefault();
+
+              touchesDiff = p.isH ? touchCurrentX - touchStartX : touchCurrentY - touchStartY;
+              percentage = touchesDiff/(p.isH ? wrapperWidth : wrapperHeight);
+              currentTranslate = (p.monthsTranslate * inverter + percentage) * 100;
+
+              // Transform wrapper
+              p.wrapper.transform('translate3d(' + (p.isH ? currentTranslate : 0) + '%, ' + (p.isH ? 0 : currentTranslate) + '%, 0)');
+
+          }
+          function handleTouchEnd (e) {
+              if (!isTouched || !isMoved) {
+                  isTouched = isMoved = false;
+                  return;
+              }
+              isTouched = isMoved = false;
+              
+              touchEndTime = new Date().getTime();
+              if (touchEndTime - touchStartTime < 300) {
+                  if (Math.abs(touchesDiff) < 10) {
+                      p.resetMonth();
+                  }
+                  else if (touchesDiff >= 10) {
+                      if (rtl) p.nextMonth();
+                      else p.prevMonth();
+                  }
+                  else {
+                      if (rtl) p.prevMonth();
+                      else p.nextMonth();   
+                  }
+              }
+              else {
+                  if (percentage <= -0.5) {
+                      if (rtl) p.prevMonth();
+                      else p.nextMonth();
+                  }
+                  else if (percentage >= 0.5) {
+                      if (rtl) p.nextMonth();
+                      else p.prevMonth();
+                  }
+                  else {
+                      p.resetMonth();
+                  }
+              }
+
+              // Allow click
+              setTimeout(function () {
+                  allowItemClick = true;
+              }, 100);
+          }
+
+          function handleDayClick(e) {
+              if (!allowItemClick) return;
+              var day = $(e.target).parents('.picker-calendar-day');
+              if (day.length === 0 && $(e.target).hasClass('picker-calendar-day')) {
+                  day = $(e.target);
+              }
+              if (day.length === 0) return;
+              // if (day.hasClass('picker-calendar-day-selected') && !p.params.multiple) return;
+              if (day.hasClass('picker-calendar-day-disabled')) return;
+              if (day.hasClass('picker-calendar-day-next')) p.nextMonth();
+              if (day.hasClass('picker-calendar-day-prev')) p.prevMonth();
+              var dateYear = day.attr('data-year');
+              var dateMonth = day.attr('data-month');
+              var dateDay = day.attr('data-day');
+              if (p.params.onDayClick) {
+                  p.params.onDayClick(p, day[0], dateYear, dateMonth, dateDay);
+              }
+              p.addValue(new Date(dateYear, dateMonth, dateDay).getTime());
+              if (p.params.closeOnSelect && !p.params.multiple) p.close();
+          }
+
+          p.container.find('.picker-calendar-prev-month').on('click', p.prevMonth);
+          p.container.find('.picker-calendar-next-month').on('click', p.nextMonth);
+          p.container.find('.picker-calendar-prev-year').on('click', p.prevYear);
+          p.container.find('.picker-calendar-next-year').on('click', p.nextYear);
+          p.wrapper.on('click', handleDayClick);
+          if (p.params.touchMove) {
+              p.wrapper.on($.touchEvents.start, handleTouchStart);
+              p.wrapper.on($.touchEvents.move, handleTouchMove);
+              p.wrapper.on($.touchEvents.end, handleTouchEnd);
+          }
+              
+          p.container[0].f7DestroyCalendarEvents = function () {
+              p.container.find('.picker-calendar-prev-month').off('click', p.prevMonth);
+              p.container.find('.picker-calendar-next-month').off('click', p.nextMonth);
+              p.container.find('.picker-calendar-prev-year').off('click', p.prevYear);
+              p.container.find('.picker-calendar-next-year').off('click', p.nextYear);
+              p.wrapper.off('click', handleDayClick);
+              if (p.params.touchMove) {
+                  p.wrapper.off($.touchEvents.start, handleTouchStart);
+                  p.wrapper.off($.touchEvents.move, handleTouchMove);
+                  p.wrapper.off($.touchEvents.end, handleTouchEnd);
+              }
+          };
+          
+
+      };
+      p.destroyCalendarEvents = function (colContainer) {
+          if ('f7DestroyCalendarEvents' in p.container[0]) p.container[0].f7DestroyCalendarEvents();
+      };
+
+      // Calendar Methods
+      p.daysInMonth = function (date) {
+          var d = new Date(date);
+          return new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate();
+      };
+      p.monthHTML = function (date, offset) {
+          date = new Date(date);
+          var year = date.getFullYear(),
+              month = date.getMonth(),
+              day = date.getDate();
+          if (offset === 'next') {
+              if (month === 11) date = new Date(year + 1, 0);
+              else date = new Date(year, month + 1, 1);
+          }
+          if (offset === 'prev') {
+              if (month === 0) date = new Date(year - 1, 11);
+              else date = new Date(year, month - 1, 1);
+          }
+          if (offset === 'next' || offset === 'prev') {
+              month = date.getMonth();
+              year = date.getFullYear();
+          }
+          var daysInPrevMonth = p.daysInMonth(new Date(date.getFullYear(), date.getMonth()).getTime() - 10 * 24 * 60 * 60 * 1000),
+              daysInMonth = p.daysInMonth(date),
+              firstDayOfMonthIndex = new Date(date.getFullYear(), date.getMonth()).getDay();
+          if (firstDayOfMonthIndex === 0) firstDayOfMonthIndex = 7;
+          
+          var dayDate, currentValues = [], i, j,
+              rows = 6, cols = 7,
+              monthHTML = '',
+              dayIndex = 0 + (p.params.firstDay - 1),    
+              today = new Date().setHours(0,0,0,0),
+              minDate = p.params.minDate ? new Date(p.params.minDate).getTime() : null,
+              maxDate = p.params.maxDate ? new Date(p.params.maxDate).getTime() : null;
+
+          if (p.value && p.value.length) {
+              for (i = 0; i < p.value.length; i++) {
+                  currentValues.push(new Date(p.value[i]).setHours(0,0,0,0));
+              }
+          }
+              
+          for (i = 1; i <= rows; i++) {
+              var rowHTML = '';
+              var row = i;
+              for (j = 1; j <= cols; j++) {
+                  var col = j;
+                  dayIndex ++;
+                  var dayNumber = dayIndex - firstDayOfMonthIndex;
+                  var addClass = '';
+                  if (dayNumber < 0) {
+                      dayNumber = daysInPrevMonth + dayNumber + 1;
+                      addClass += ' picker-calendar-day-prev';
+                      dayDate = new Date(month - 1 < 0 ? year - 1 : year, month - 1 < 0 ? 11 : month - 1, dayNumber).getTime();
+                  }
+                  else {
+                      dayNumber = dayNumber + 1;
+                      if (dayNumber > daysInMonth) {
+                          dayNumber = dayNumber - daysInMonth;
+                          addClass += ' picker-calendar-day-next';
+                          dayDate = new Date(month + 1 > 11 ? year + 1 : year, month + 1 > 11 ? 0 : month + 1, dayNumber).getTime();
+                      }
+                      else {
+                          dayDate = new Date(year, month, dayNumber).getTime();    
+                      }
+                  }
+                  // Today
+                  if (dayDate === today) addClass += ' picker-calendar-day-today';
+                  // Selected
+                  if (currentValues.indexOf(dayDate) >= 0) addClass += ' picker-calendar-day-selected';
+                  // Weekend
+                  if (p.params.weekendDays.indexOf(col - 1) >= 0) {
+                      addClass += ' picker-calendar-day-weekend';
+                  }
+                  // Disabled
+                  if ((minDate && dayDate < minDate) || (maxDate && dayDate > maxDate)) {
+                      addClass += ' picker-calendar-day-disabled';   
+                  }
+
+                  dayDate = new Date(dayDate);
+                  var dayYear = dayDate.getFullYear();
+                  var dayMonth = dayDate.getMonth();
+                  rowHTML += '<div data-year="' + dayYear + '" data-month="' + dayMonth + '" data-day="' + dayNumber + '" class="picker-calendar-day' + (addClass) + '" data-date="' + (dayYear + '-' + dayMonth + '-' + dayNumber) + '"><span>'+dayNumber+'</span></div>';
+              }
+              monthHTML += '<div class="picker-calendar-row">' + rowHTML + '</div>';
+          }
+          monthHTML = '<div class="picker-calendar-month" data-year="' + year + '" data-month="' + month + '">' + monthHTML + '</div>';
+          return monthHTML;
+      };
+      p.animating = false;
+      p.updateCurrentMonthYear = function (dir) {
+          if (typeof dir === 'undefined') {
+              p.currentMonth = parseInt(p.months.eq(1).attr('data-month'), 10);
+              p.currentYear = parseInt(p.months.eq(1).attr('data-year'), 10);   
+          }
+          else {
+              p.currentMonth = parseInt(p.months.eq(dir === 'next' ? (p.months.length - 1) : 0).attr('data-month'), 10);
+              p.currentYear = parseInt(p.months.eq(dir === 'next' ? (p.months.length - 1) : 0).attr('data-year'), 10);
+          }
+          p.container.find('.current-month-value').text(p.params.monthNames[p.currentMonth]);
+          p.container.find('.current-year-value').text(p.currentYear);
+              
+      };
+      p.onMonthChangeStart = function (dir) {
+          p.updateCurrentMonthYear(dir);
+          p.months.removeClass('picker-calendar-month-current picker-calendar-month-prev picker-calendar-month-next');
+          var currentIndex = dir === 'next' ? p.months.length - 1 : 0;
+
+          p.months.eq(currentIndex).addClass('picker-calendar-month-current');
+          p.months.eq(dir === 'next' ? currentIndex - 1 : currentIndex + 1).addClass(dir === 'next' ? 'picker-calendar-month-prev' : 'picker-calendar-month-next');
+
+          if (p.params.onMonthYearChangeStart) {
+              p.params.onMonthYearChangeStart(p, p.currentYear, p.currentMonth);
+          }
+      };
+      p.onMonthChangeEnd = function (dir, rebuildBoth) {
+          p.animating = false;
+          var nextMonthHTML, prevMonthHTML, newMonthHTML;
+          p.wrapper.find('.picker-calendar-month:not(.picker-calendar-month-prev):not(.picker-calendar-month-current):not(.picker-calendar-month-next)').remove();
+          
+          if (typeof dir === 'undefined') {
+              dir = 'next';
+              rebuildBoth = true;
+          }
+          if (!rebuildBoth) {
+              newMonthHTML = p.monthHTML(new Date(p.currentYear, p.currentMonth), dir);
+          }
+          else {
+              p.wrapper.find('.picker-calendar-month-next, .picker-calendar-month-prev').remove();
+              prevMonthHTML = p.monthHTML(new Date(p.currentYear, p.currentMonth), 'prev');
+              nextMonthHTML = p.monthHTML(new Date(p.currentYear, p.currentMonth), 'next');
+          }
+          if (dir === 'next' || rebuildBoth) {
+              p.wrapper.append(newMonthHTML || nextMonthHTML);
+          }
+          if (dir === 'prev' || rebuildBoth) {
+              p.wrapper.prepend(newMonthHTML || prevMonthHTML);
+          }
+          p.months = p.wrapper.find('.picker-calendar-month');
+          p.setMonthsTranslate(p.monthsTranslate);
+          if (p.params.onMonthAdd) {
+              p.params.onMonthAdd(p, dir === 'next' ? p.months.eq(p.months.length - 1)[0] : p.months.eq(0)[0]);
+          }
+          if (p.params.onMonthYearChangeEnd) {
+              p.params.onMonthYearChangeEnd(p, p.currentYear, p.currentMonth);
+          }
+      };
+      p.setMonthsTranslate = function (translate) {
+          translate = translate || p.monthsTranslate || 0;
+          if (typeof p.monthsTranslate === 'undefined') p.monthsTranslate = translate;
+          p.months.removeClass('picker-calendar-month-current picker-calendar-month-prev picker-calendar-month-next');
+          var prevMonthTranslate = -(translate + 1) * 100 * inverter;
+          var currentMonthTranslate = -translate * 100 * inverter;
+          var nextMonthTranslate = -(translate - 1) * 100 * inverter;
+          p.months.eq(0).transform('translate3d(' + (p.isH ? prevMonthTranslate : 0) + '%, ' + (p.isH ? 0 : prevMonthTranslate) + '%, 0)').addClass('picker-calendar-month-prev');
+          p.months.eq(1).transform('translate3d(' + (p.isH ? currentMonthTranslate : 0) + '%, ' + (p.isH ? 0 : currentMonthTranslate) + '%, 0)').addClass('picker-calendar-month-current');
+          p.months.eq(2).transform('translate3d(' + (p.isH ? nextMonthTranslate : 0) + '%, ' + (p.isH ? 0 : nextMonthTranslate) + '%, 0)').addClass('picker-calendar-month-next');
+      };
+      p.nextMonth = function (transition) {
+          if (typeof transition === 'undefined' || typeof transition === 'object') {
+              transition = '';
+              if (!p.params.animate) transition = 0;
+          }
+          var nextMonth = parseInt(p.months.eq(p.months.length - 1).attr('data-month'), 10);
+          var nextYear = parseInt(p.months.eq(p.months.length - 1).attr('data-year'), 10);
+          var nextDate = new Date(nextYear, nextMonth);
+          var nextDateTime = nextDate.getTime();
+          var transitionEndCallback = p.animating ? false : true;
+          if (p.params.maxDate) {
+              if (nextDateTime > new Date(p.params.maxDate).getTime()) {
+                  return p.resetMonth();
+              }
+          }
+          p.monthsTranslate --;
+          if (nextMonth === p.currentMonth) {
+              var nextMonthTranslate = -(p.monthsTranslate) * 100 * inverter;
+              var nextMonthHTML = $(p.monthHTML(nextDateTime, 'next')).transform('translate3d(' + (p.isH ? nextMonthTranslate : 0) + '%, ' + (p.isH ? 0 : nextMonthTranslate) + '%, 0)').addClass('picker-calendar-month-next');
+              p.wrapper.append(nextMonthHTML[0]);
+              p.months = p.wrapper.find('.picker-calendar-month');
+              if (p.params.onMonthAdd) {
+                  p.params.onMonthAdd(p, p.months.eq(p.months.length - 1)[0]);
+              }
+          }
+          p.animating = true;
+          p.onMonthChangeStart('next');
+          var translate = (p.monthsTranslate * 100) * inverter;
+
+          p.wrapper.transition(transition).transform('translate3d(' + (p.isH ? translate : 0) + '%, ' + (p.isH ? 0 : translate) + '%, 0)');
+          if (transitionEndCallback) {
+              p.wrapper.transitionEnd(function () {
+                  p.onMonthChangeEnd('next');
+              });
+          }
+          if (!p.params.animate) {
+              p.onMonthChangeEnd('next');
+          }
+      };
+      p.prevMonth = function (transition) {
+          if (typeof transition === 'undefined' || typeof transition === 'object') {
+              transition = '';
+              if (!p.params.animate) transition = 0;
+          }
+          var prevMonth = parseInt(p.months.eq(0).attr('data-month'), 10);
+          var prevYear = parseInt(p.months.eq(0).attr('data-year'), 10);
+          var prevDate = new Date(prevYear, prevMonth + 1, -1);
+          var prevDateTime = prevDate.getTime();
+          var transitionEndCallback = p.animating ? false : true;
+          if (p.params.minDate) {
+              if (prevDateTime < new Date(p.params.minDate).getTime()) {
+                  return p.resetMonth();
+              }
+          }
+          p.monthsTranslate ++;
+          if (prevMonth === p.currentMonth) {
+              var prevMonthTranslate = -(p.monthsTranslate) * 100 * inverter;
+              var prevMonthHTML = $(p.monthHTML(prevDateTime, 'prev')).transform('translate3d(' + (p.isH ? prevMonthTranslate : 0) + '%, ' + (p.isH ? 0 : prevMonthTranslate) + '%, 0)').addClass('picker-calendar-month-prev');
+              p.wrapper.prepend(prevMonthHTML[0]);
+              p.months = p.wrapper.find('.picker-calendar-month');
+              if (p.params.onMonthAdd) {
+                  p.params.onMonthAdd(p, p.months.eq(0)[0]);
+              }
+          }
+          p.animating = true;
+          p.onMonthChangeStart('prev');
+          var translate = (p.monthsTranslate * 100) * inverter;
+          p.wrapper.transition(transition).transform('translate3d(' + (p.isH ? translate : 0) + '%, ' + (p.isH ? 0 : translate) + '%, 0)');
+          if (transitionEndCallback) {
+              p.wrapper.transitionEnd(function () {
+                  p.onMonthChangeEnd('prev');
+              });
+          }
+          if (!p.params.animate) {
+              p.onMonthChangeEnd('prev');
+          }
+      };
+      p.resetMonth = function (transition) {
+          if (typeof transition === 'undefined') transition = '';
+          var translate = (p.monthsTranslate * 100) * inverter;
+          p.wrapper.transition(transition).transform('translate3d(' + (p.isH ? translate : 0) + '%, ' + (p.isH ? 0 : translate) + '%, 0)');
+      };
+      p.setYearMonth = function (year, month, transition) {
+          if (typeof year === 'undefined') year = p.currentYear;
+          if (typeof month === 'undefined') month = p.currentMonth;
+          if (typeof transition === 'undefined' || typeof transition === 'object') {
+              transition = '';
+              if (!p.params.animate) transition = 0;
+          }
+          var targetDate;
+          if (year < p.currentYear) {
+              targetDate = new Date(year, month + 1, -1).getTime();
+          }
+          else {
+              targetDate = new Date(year, month).getTime();
+          }
+          if (p.params.maxDate && targetDate > new Date(p.params.maxDate).getTime()) {
+              return false;
+          }
+          if (p.params.minDate && targetDate < new Date(p.params.minDate).getTime()) {
+              return false;
+          }
+          var currentDate = new Date(p.currentYear, p.currentMonth).getTime();
+          var dir = targetDate > currentDate ? 'next' : 'prev';
+          var newMonthHTML = p.monthHTML(new Date(year, month));
+          p.monthsTranslate = p.monthsTranslate || 0;
+          var prevTranslate = p.monthsTranslate;
+          var monthTranslate, wrapperTranslate;
+          var transitionEndCallback = p.animating ? false : true;
+          if (targetDate > currentDate) {
+              // To next
+              p.monthsTranslate --;
+              if (!p.animating) p.months.eq(p.months.length - 1).remove();
+              p.wrapper.append(newMonthHTML);
+              p.months = p.wrapper.find('.picker-calendar-month');
+              monthTranslate = -(prevTranslate - 1) * 100 * inverter;
+              p.months.eq(p.months.length - 1).transform('translate3d(' + (p.isH ? monthTranslate : 0) + '%, ' + (p.isH ? 0 : monthTranslate) + '%, 0)').addClass('picker-calendar-month-next');
+          }
+          else {
+              // To prev
+              p.monthsTranslate ++;
+              if (!p.animating) p.months.eq(0).remove();
+              p.wrapper.prepend(newMonthHTML);
+              p.months = p.wrapper.find('.picker-calendar-month');
+              monthTranslate = -(prevTranslate + 1) * 100 * inverter;
+              p.months.eq(0).transform('translate3d(' + (p.isH ? monthTranslate : 0) + '%, ' + (p.isH ? 0 : monthTranslate) + '%, 0)').addClass('picker-calendar-month-prev');
+          }
+          if (p.params.onMonthAdd) {
+              p.params.onMonthAdd(p, dir === 'next' ? p.months.eq(p.months.length - 1)[0] : p.months.eq(0)[0]);
+          }
+          p.animating = true;
+          p.onMonthChangeStart(dir);
+          wrapperTranslate = (p.monthsTranslate * 100) * inverter;
+          p.wrapper.transition(transition).transform('translate3d(' + (p.isH ? wrapperTranslate : 0) + '%, ' + (p.isH ? 0 : wrapperTranslate) + '%, 0)');
+          if (transitionEndCallback) {
+             p.wrapper.transitionEnd(function () {
+                  p.onMonthChangeEnd(dir, true);
+              }); 
+          }
+          if (!p.params.animate) {
+              p.onMonthChangeEnd(dir);
+          }
+      };
+      p.nextYear = function () {
+          p.setYearMonth(p.currentYear + 1);
+      };
+      p.prevYear = function () {
+          p.setYearMonth(p.currentYear - 1);
+      };
+      
+
+      // HTML Layout
+      p.layout = function () {
+          var pickerHTML = '';
+          var pickerClass = '';
+          var i;
+          
+          var layoutDate = p.value && p.value.length ? p.value[0] : new Date().setHours(0,0,0,0);
+          var prevMonthHTML = p.monthHTML(layoutDate, 'prev');
+          var currentMonthHTML = p.monthHTML(layoutDate);
+          var nextMonthHTML = p.monthHTML(layoutDate, 'next');
+          var monthsHTML = '<div class="picker-calendar-months"><div class="picker-calendar-months-wrapper">' + (prevMonthHTML + currentMonthHTML + nextMonthHTML) + '</div></div>';
+          // Week days header
+          var weekHeaderHTML = '';
+          if (p.params.weekHeader) {
+              for (i = 0; i < 7; i++) {
+                  var weekDayIndex = (i + p.params.firstDay > 6) ? (i - 7 + p.params.firstDay) : (i + p.params.firstDay);
+                  var dayName = p.params.dayNamesShort[weekDayIndex];
+                  weekHeaderHTML += '<div class="picker-calendar-week-day ' + ((p.params.weekendDays.indexOf(weekDayIndex) >= 0) ? 'picker-calendar-week-day-weekend' : '') + '"> ' + dayName + '</div>';
+                  
+              }
+              weekHeaderHTML = '<div class="picker-calendar-week-days">' + weekHeaderHTML + '</div>';
+          }
+          pickerClass = 'weui-picker-calendar ' + (p.params.cssClass || '');
+          if(!p.inline) pickerClass = 'weui-picker-modal ' + pickerClass;
+          var toolbarHTML = p.params.toolbar ? p.params.toolbarTemplate.replace(/{{closeText}}/g, p.params.toolbarCloseText) : '';
+          if (p.params.toolbar) {
+              toolbarHTML = p.params.toolbarTemplate
+                  .replace(/{{closeText}}/g, p.params.toolbarCloseText)
+                  .replace(/{{monthPicker}}/g, (p.params.monthPicker ? p.params.monthPickerTemplate : ''))
+                  .replace(/{{yearPicker}}/g, (p.params.yearPicker ? p.params.yearPickerTemplate : ''));
+          }
+
+          pickerHTML =
+              '<div class="' + (pickerClass) + '">' +
+                  toolbarHTML +
+                  '<div class="picker-modal-inner">' +
+                      weekHeaderHTML +
+                      monthsHTML +
+                  '</div>' +
+              '</div>';
+              
+              
+          p.pickerHTML = pickerHTML;    
+      };
+
+      // Input Events
+      function openOnInput(e) {
+          e.preventDefault();
+          if (p.opened) return;
+          p.open();
+          if (p.params.scrollToInput && !isPopover()) {
+              var pageContent = p.input.parents('.page-content');
+              if (pageContent.length === 0) return;
+
+              var paddingTop = parseInt(pageContent.css('padding-top'), 10),
+                  paddingBottom = parseInt(pageContent.css('padding-bottom'), 10),
+                  pageHeight = pageContent[0].offsetHeight - paddingTop - p.container.height(),
+                  pageScrollHeight = pageContent[0].scrollHeight - paddingTop - p.container.height(),
+                  newPaddingBottom;
+
+              var inputTop = p.input.offset().top - paddingTop + p.input[0].offsetHeight;
+              if (inputTop > pageHeight) {
+                  var scrollTop = pageContent.scrollTop() + inputTop - pageHeight;
+                  if (scrollTop + pageHeight > pageScrollHeight) {
+                      newPaddingBottom = scrollTop + pageHeight - pageScrollHeight + paddingBottom;
+                      if (pageHeight === pageScrollHeight) {
+                          newPaddingBottom = p.container.height();
+                      }
+                      pageContent.css({'padding-bottom': (newPaddingBottom) + 'px'});
+                  }
+                  pageContent.scrollTop(scrollTop, 300);
+              }
+          }
+      }
+      function closeOnHTMLClick(e) {
+          if (inPopover()) return;
+          if (p.input && p.input.length > 0) {
+              if (e.target !== p.input[0] && $(e.target).parents('.weui-picker-modal').length === 0) p.close();
+          }
+          else {
+              if ($(e.target).parents('.weui-picker-modal').length === 0) p.close();   
+          }
+      }
+
+      if (p.params.input) {
+          p.input = $(p.params.input);
+          if (p.input.length > 0) {
+              if (p.params.inputReadOnly) p.input.prop('readOnly', true);
+              if (!p.inline) {
+                  p.input.on('click', openOnInput);    
+              }
+              if (p.params.inputReadOnly) {
+                  p.input.on('focus mousedown', function (e) {
+                      e.preventDefault();
+                  });
+              }
+          }
+              
+      }
+      
+      //iphone 上无法正确触发 click,会导致点击外面无法关闭
+      if (!p.inline) $(document).on('click touchend', closeOnHTMLClick);
+
+      // Open
+      function onPickerClose() {
+          p.opened = false;
+          if (p.input && p.input.length > 0) p.input.parents('.page-content').css({'padding-bottom': ''});
+          if (p.params.onClose) p.params.onClose(p);
+
+          // Destroy events
+          p.destroyCalendarEvents();
+      }
+
+      p.opened = false;
+      p.open = function () {
+          var toPopover = isPopover() && false;
+          var updateValue = false;
+          if (!p.opened) {
+              // Set date value
+              if (!p.value) {
+                  if (p.params.value) {
+                      p.value = p.params.value;
+                      updateValue = true;
+                  }
+              }
+
+              // Layout
+              p.layout();
+
+              // Append
+              if (toPopover) {
+                  p.pickerHTML = '<div class="popover popover-picker-calendar"><div class="popover-inner">' + p.pickerHTML + '</div></div>';
+                  p.popover = $.popover(p.pickerHTML, p.params.input, true);
+                  p.container = $(p.popover).find('.weui-picker-modal');
+                  $(p.popover).on('close', function () {
+                      onPickerClose();
+                  });
+              }
+              else if (p.inline) {
+                  p.container = $(p.pickerHTML);
+                  p.container.addClass('picker-modal-inline');
+                  $(p.params.container).append(p.container);
+              }
+              else {
+                  p.container = $($.openPicker(p.pickerHTML));
+                  $(p.container)
+                  .on('close', function () {
+                      onPickerClose();
+                  });
+              }
+
+              // Store calendar instance
+              p.container[0].f7Calendar = p;
+              p.wrapper = p.container.find('.picker-calendar-months-wrapper');
+
+              // Months
+              p.months = p.wrapper.find('.picker-calendar-month');
+
+              // Update current month and year
+              p.updateCurrentMonthYear();
+
+              // Set initial translate
+              p.monthsTranslate = 0;
+              p.setMonthsTranslate();
+
+              // Init events
+              p.initCalendarEvents();
+
+              // Update input value
+              if (updateValue) p.updateValue();
+              
+          }
+
+          // Set flag
+          p.opened = true;
+          p.initialized = true;
+          if (p.params.onMonthAdd) {
+              p.months.each(function () {
+                  p.params.onMonthAdd(p, this);
+              });
+          }
+          if (p.params.onOpen) p.params.onOpen(p);
+      };
+
+      // Close
+      p.close = function () {
+          if (!p.opened || p.inline) return;
+          p.animating = false;  //有可能还有动画没做完,因此animating设置还没改。
+          if (inPopover()) {
+              $.closePicker(p.popover);
+              return;
+          }
+          else {
+              $.closePicker(p.container);
+              return;
+          }
+      };
+
+      // Destroy
+      p.destroy = function () {
+          p.close();
+          if (p.params.input && p.input.length > 0) {
+              p.input.off('click focus', openOnInput);
+              p.input.data("calendar", null);
+          }
+          $('html').off('click', closeOnHTMLClick);
+      };
+
+      if (p.inline) {
+          p.open();
+      }
+
+      return p;
+  };
+
+  var format = function(d) {
+    return d < 10 ? "0"+d : d;
+  }
+
+
+  $.fn.calendar = function (params, args) {
+      params = params || {};
+      return this.each(function() {
+        var $this = $(this);
+        if(!$this[0]) return;
+        var p = {};
+        if($this[0].tagName.toUpperCase() === "INPUT") {
+          p.input = $this;
+        } else {
+          p.container = $this;
+        }
+
+        var calendar = $this.data("calendar");
+
+        if(!calendar) {
+          if(typeof params === typeof "a") {
+          } else {
+            if(!params.value && $this.val()) params.value = [$this.val()];
+            //默认显示今天
+            if(!params.value) {
+              var today = new Date();
+              params.value = [today.getFullYear() + "/" + format(today.getMonth() + 1) + "/" + format(today.getDate())];
+            }
+            calendar = $this.data("calendar", new Calendar($.extend(p, params)));
+          }
+        }
+
+        if(typeof params === typeof "a") {
+          calendar[params].call(calendar, args);
+        }
+      });
+  };
+
+  defaults = $.fn.calendar.prototype.defaults = {
+    value: undefined, // 通过JS赋值,注意是数组
+    monthNames: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
+    monthNamesShort: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
+    dayNames: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
+    dayNamesShort: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
+    firstDay: 1, // First day of the week, Monday
+    weekendDays: [0, 6], // Sunday and Saturday
+    multiple: false,
+    dateFormat: 'yyyy/mm/dd',
+    direction: 'horizontal', // or 'vertical'
+    minDate: null,
+    maxDate: null,
+    touchMove: true,
+    animate: true,
+    closeOnSelect: true,
+    monthPicker: true,
+    monthPickerTemplate: 
+        '<div class="picker-calendar-month-picker">' +
+            '<a href="javascript:;" class="link icon-only picker-calendar-prev-month"><i class="icon icon-prev"></i></a>' +
+            '<div class="current-month-value"></div>' +
+            '<a href="javascript:;" class="link icon-only picker-calendar-next-month"><i class="icon icon-next"></i></a>' +
+        '</div>',
+    yearPicker: true,
+    yearPickerTemplate: 
+        '<div class="picker-calendar-year-picker">' +
+            '<a href="javascript:;" class="link icon-only picker-calendar-prev-year"><i class="icon icon-prev"></i></a>' +
+            '<span class="current-year-value"></span>' +
+            '<a href="javascript:;" class="link icon-only picker-calendar-next-year"><i class="icon icon-next"></i></a>' +
+        '</div>',
+    weekHeader: true,
+    // Common settings
+    scrollToInput: true,
+    inputReadOnly: true,
+    convertToPopover: true,
+    onlyInPopover: false,
+    toolbar: true,
+    toolbarCloseText: 'Done',
+    toolbarTemplate: 
+        '<div class="toolbar">' +
+            '<div class="toolbar-inner">' +
+                '{{yearPicker}}' +
+                '{{monthPicker}}' +
+                // '<a href="#" class="link close-picker">{{closeText}}</a>' +
+            '</div>' +
+        '</div>',
+    /* Callbacks
+    onMonthAdd
+    onChange
+    onOpen
+    onClose
+    onDayClick
+    onMonthYearChangeStart
+    onMonthYearChangeEnd
+    */
+  };
+
+}($);
+
+/* global $:true */
+/* jshint unused:false*/
+
++ function($) {
+  "use strict";
+
+
+  var defaults;
+
+  var formatNumber = function (n) {
+    return n < 10 ? "0" + n : n;
+  }
+
+  var Datetime = function(input, params) {
+    this.input = $(input);
+    this.params = params || {};
+
+    this.initMonthes = params.monthes
+
+    this.initYears = params.years
+
+    var p = $.extend({}, params, this.getConfig());
+    $(this.input).picker(p);
+  }
+
+  Datetime.prototype = {
+    getDays : function(max) {
+      var days = [];
+      for(var i=1; i<= (max||31);i++) {
+        days.push(i < 10 ? "0"+i : i);
+      }
+      return days;
+    },
+
+    getDaysByMonthAndYear : function(month, year) {
+      var int_d = new Date(year, parseInt(month)+1-1, 1);
+      var d = new Date(int_d - 1);
+      return this.getDays(d.getDate());
+    },
+    getConfig: function() {
+      var today = new Date(),
+          params = this.params,
+          self = this,
+          lastValidValues;
+
+      var config = {
+        rotateEffect: false,  //为了性能
+        cssClass: 'datetime-picker',
+
+        value: [today.getFullYear(), formatNumber(today.getMonth()+1), formatNumber(today.getDate()), formatNumber(today.getHours()), (formatNumber(today.getMinutes()))],
+
+        onChange: function (picker, values, displayValues) {
+          var cols = picker.cols;
+          var days = self.getDaysByMonthAndYear(values[1], values[0]);
+          var currentValue = values[2];
+          if(currentValue > days.length) currentValue = days.length;
+          picker.cols[4].setValue(currentValue);
+
+          //check min and max
+          var current = new Date(values[0]+'-'+values[1]+'-'+values[2]);
+          var valid = true;
+          if(params.min) {
+            var min = new Date(typeof params.min === "function" ? params.min() : params.min);
+
+            if(current < +min) {
+              picker.setValue(lastValidValues);
+              valid = false;
+            } 
+          }
+          if(params.max) {
+            var max = new Date(typeof params.max === "function" ? params.max() : params.max);
+            if(current > +max) {
+              picker.setValue(lastValidValues);
+              valid = false;
+            }
+          }
+
+          valid && (lastValidValues = values);
+
+          if (self.params.onChange) {
+            self.params.onChange.apply(this, arguments);
+          }
+        },
+
+        formatValue: function (p, values, displayValues) {
+          return self.params.format(p, values, displayValues);
+        },
+
+        cols: [
+          {
+            values: this.initYears
+          },
+          {
+            divider: true,  // 这是一个分隔符
+            content: params.yearSplit
+          },
+          {
+            values: this.initMonthes
+          },
+          {
+            divider: true,  // 这是一个分隔符
+            content: params.monthSplit
+          },
+          {
+            values: (function () {
+              var dates = [];
+              for (var i=1; i<=31; i++) dates.push(formatNumber(i));
+              return dates;
+            })()
+          },
+          
+        ]
+      }
+
+      if (params.dateSplit) {
+        config.cols.push({
+          divider: true,
+          content: params.dateSplit
+        })
+      }
+
+      config.cols.push({
+        divider: true,
+        content: params.datetimeSplit
+      })
+
+      var times = self.params.times();
+      if (times && times.length) {
+        config.cols = config.cols.concat(times);
+      }
+
+      var inputValue = this.input.val();
+      if(inputValue) config.value = params.parse(inputValue);
+      if(this.params.value) {
+        this.input.val(this.params.value);
+        config.value = params.parse(this.params.value);
+      }
+
+      return config;
+    }
+  }
+
+  $.fn.datetimePicker = function(params) {
+    params = $.extend({}, defaults, params);
+    return this.each(function() {
+      if(!this) return;
+      var $this = $(this);
+      var datetime = $this.data("datetime");
+      if(!datetime) $this.data("datetime", new Datetime(this, params));
+      return datetime;
+    });
+  };
+
+  defaults = $.fn.datetimePicker.prototype.defaults = {
+    input: undefined, // 默认值
+    min: undefined, // YYYY-MM-DD 最大最小值只比较年月日,不比较时分秒
+    max: undefined,  // YYYY-MM-DD
+    yearSplit: '-',
+    monthSplit: '-',
+    dateSplit: '',  // 默认为空
+    datetimeSplit: ' ',  // 日期和时间之间的分隔符,不可为空
+    monthes: ('01 02 03 04 05 06 07 08 09 10 11 12').split(' '),
+    years: (function () {
+      var arr = [];
+      for (var i = 1950; i <= 2030; i++) { arr.push(i); }
+      return arr;
+    })(),
+    times: function () {
+      return [  // 自定义的时间
+        {
+          values: (function () {
+            var hours = [];
+            for (var i=0; i<24; i++) hours.push(formatNumber(i));
+            return hours;
+          })()
+        },
+        {
+          divider: true,  // 这是一个分隔符
+          content: ':'
+        },
+        {
+          values: (function () {
+            var minutes = [];
+            for (var i=0; i<60; i++) minutes.push(formatNumber(i));
+            return minutes;
+          })()
+        }
+      ];
+    },
+    format: function (p, values) { // 数组转换成字符串
+      return p.cols.map(function (col) {
+        return col.value || col.content;
+      }).join('');
+    },
+    parse: function (str) {
+      // 把字符串转换成数组,用来解析初始值
+      // 如果你的定制的初始值格式无法被这个默认函数解析,请自定义这个函数。比如你的时间是 '子时' 那么默认情况这个'时'会被当做分隔符而导致错误,所以你需要自己定义parse函数
+      // 默认兼容的分隔符
+      var t = str.split(this.datetimeSplit);
+      return t[0].split(/\D/).concat(t[1].split(/:|时|分|秒/)).filter(function (d) {
+        return !!d;
+      })
+    }
+  }
+
+}($);
+
+/*======================================================
+************   Picker   ************
+======================================================*/
+/* global $:true */
+
++ function($) {
+  "use strict";
+
+
+  //Popup 和 picker 之类的不要共用一个弹出方法,因为这样会导致 在 popup 中再弹出 picker 的时候会有问题。
+
+  $.openPopup = function(popup, className) {
+
+    $.closePopup();
+
+    popup = $(popup);
+    popup.show();
+    popup.width();
+    popup.addClass("weui-popup__container--visible");
+    var modal = popup.find(".weui-popup__modal");
+    modal.width();
+    modal.transitionEnd(function() {
+      modal.trigger("open");
+    });
+  }
+
+
+  $.closePopup = function(container, remove) {
+    container = $(container || ".weui-popup__container--visible");
+    container.find('.weui-popup__modal').transitionEnd(function() {
+      var $this = $(this);
+      $this.trigger("close");
+      container.hide();
+      remove && container.remove();
+    })
+    container.removeClass("weui-popup__container--visible")
+  };
+
+
+  $(document).on("click", ".close-popup, .weui-popup__overlay", function() {
+    $.closePopup();
+  })
+  .on("click", ".open-popup", function() {
+    $($(this).data("target")).popup();
+  })
+  .on("click", ".weui-popup__container", function(e) {
+    if($(e.target).hasClass("weui-popup__container")) $.closePopup();
+  })
+
+  $.fn.popup = function() {
+    return this.each(function() {
+      $.openPopup(this);
+    });
+  };
+
+}($);
+
+/* ===============================================================================
+************   Notification ************
+=============================================================================== */
+/* global $:true */
++function ($) {
+  "use strict";
+
+  var noti, defaults, timeout, start, diffX, diffY;
+
+  var touchStart = function(e) {
+    var p = $.getTouchPosition(e);
+    start = p;
+    diffX = diffY = 0;
+    noti.addClass("touching");
+  };
+  var touchMove = function(e) {
+    if(!start) return false;
+    e.preventDefault();
+    e.stopPropagation();
+    var p = $.getTouchPosition(e);
+    diffX = p.x - start.x;
+    diffY = p.y - start.y;
+    if(diffY > 0) {
+      diffY = Math.sqrt(diffY);
+    }
+
+    noti.css("transform", "translate3d(0, "+diffY+"px, 0)");
+  };
+  var touchEnd = function() {
+    noti.removeClass("touching");
+    noti.attr("style", "");
+    if(diffY < 0 && (Math.abs(diffY) > noti.height()*0.38)) {
+      $.closeNotification();
+    }
+
+    if(Math.abs(diffX) <= 1 && Math.abs(diffY) <= 1) {
+      noti.trigger("noti-click");
+    }
+
+    start = false;
+  };
+
+  var attachEvents = function(el) {
+    el.on($.touchEvents.start, touchStart);
+    el.on($.touchEvents.move, touchMove);
+    el.on($.touchEvents.end, touchEnd);
+  };
+
+  $.notification = $.noti = function(params) {
+    params = $.extend({}, defaults, params);
+    noti = $(".weui-notification");
+    if(!noti[0]) { // create a new notification
+      noti = $('<div class="weui-notification"></div>').appendTo(document.body);
+      attachEvents(noti);
+    }
+
+    noti.off("noti-click"); //the click event is not correct sometime: it will trigger when user is draging.
+    if(params.onClick) noti.on("noti-click", function() {
+      params.onClick(params.data);
+    });
+
+    noti.html($.t7.compile(params.tpl)(params));
+
+    noti.show();
+
+    noti.addClass("weui-notification--in");
+    noti.data("params", params);
+
+    var startTimeout = function() {
+      if(timeout) {
+        clearTimeout(timeout);
+        timeout = null;
+      }
+
+      timeout = setTimeout(function() {
+        if(noti.hasClass("weui-notification--touching")) {
+          startTimeout();
+        } else {
+          $.closeNotification();
+        }
+      }, params.time);
+    };
+
+    startTimeout();
+
+  };
+
+  $.closeNotification = function() {
+    timeout && clearTimeout(timeout);
+    timeout = null;
+    var noti = $(".weui-notification").removeClass("weui-notification--in").transitionEnd(function() {
+      $(this).remove();
+    });
+
+    if(noti[0]) {
+      var params = $(".weui-notification").data("params");
+      if(params && params.onClose) {
+        params.onClose(params.data);
+      }
+    }
+  };
+
+  defaults = $.noti.prototype.defaults = {
+    title: undefined,
+    text: undefined,
+    media: undefined,
+    time: 4000,
+    onClick: undefined,
+    onClose: undefined,
+    data: undefined,
+    tpl:  '<div class="weui-notification__inner">' +
+            '{{#if media}}<div class="weui-notification__media">{{media}}</div>{{/if}}' +
+            '<div class="weui-notification__content">' +
+            '{{#if title}}<div class="weui-notification__title">{{title}}</div>{{/if}}' +
+            '{{#if text}}<div class="weui-notification__text">{{text}}</div>{{/if}}' +
+            '</div>' +
+            '<div class="weui-notification__handle-bar"></div>' +
+          '</div>'
+  };
+
+}($);
+
++ function($) {
+  "use strict";
+
+  var timeout;
+
+  $.toptip = function(text, duration, type) {
+    if(!text) return;
+    if(typeof duration === typeof "a") {
+      type = duration;
+      duration = undefined;
+    }
+    duration = duration || 3000;
+    var className = type ? 'bg-' + type : 'bg-danger';
+    var $t = $('.weui-toptips').remove();
+    $t = $('<div class="weui-toptips"></div>').appendTo(document.body);
+    $t.html(text);
+    $t[0].className = 'weui-toptips ' + className
+
+    clearTimeout(timeout);
+
+    if(!$t.hasClass('weui-toptips_visible')) {
+      $t.show().width();
+      $t.addClass('weui-toptips_visible');
+    }
+
+    timeout = setTimeout(function() {
+      $t.removeClass('weui-toptips_visible').transitionEnd(function() {
+        $t.remove();
+      });
+    }, duration);
+  }
+}($);
+
+/* global $:true */
++ function($) {
+  "use strict";
+  var Slider = function (container, arg) {
+    this.container = $(container);
+    this.handler = this.container.find('.weui-slider__handler')
+    this.track = this.container.find('.weui-slider__track')
+    this.value = this.container.find('.weui-slider-box__value')
+    this.bind()
+    if (typeof arg === 'function') {
+      this.callback = arg
+    }
+  }
+
+  Slider.prototype.bind = function () {
+    this.container
+      .on($.touchEvents.start, $.proxy(this.touchStart, this))
+      .on($.touchEvents.end, $.proxy(this.touchEnd, this));
+    $(document.body).on($.touchEvents.move, $.proxy(this.touchMove, this)) // move even outside container
+  }
+
+  Slider.prototype.touchStart = function (e) {
+    e.preventDefault()
+    this.start = $.getTouchPosition(e)
+    this.width = this.container.find('.weui-slider__inner').width()
+    this.left = parseInt(this.container.find('.weui-slider__handler').css('left'))
+    this.touching = true
+  }
+
+  Slider.prototype.touchMove = function (e) {
+    if (!this.touching) return true
+    var p = $.getTouchPosition(e)
+    var distance = p.x - this.start.x
+    var left = distance + this.left
+    var per = parseInt(left / this.width * 100)
+    if (per < 0) per = 0
+    if (per > 100) per = 100
+    this.handler.css('left', per + '%')
+    this.track.css('width', per + '%')
+    this.value.text(per)
+    this.callback && this.callback.call(this, per)
+    this.container.trigger('change', per)
+  }
+
+  Slider.prototype.touchEnd = function (e) {
+    this.touching = false
+  }
+
+  $.fn.slider = function (arg) {
+    this.each(function () {
+      var $this = $(this)
+      var slider = $this.data('slider')
+      if (slider) return slider;
+      else $this.data('slider', new Slider(this, arg))
+    })
+  }
+}($);
+
+/* ===============================================================================
+************   Swipeout ************
+=============================================================================== */
+/* global $:true */
+
++function ($) {
+  "use strict";
+
+  var cache = [];
+  var TOUCHING = 'swipeout-touching'
+
+  var Swipeout = function(el) {
+    this.container = $(el);
+    this.mover = this.container.find('>.weui-cell__bd')
+    this.attachEvents();
+    cache.push(this)
+  }
+
+  Swipeout.prototype.touchStart = function(e) {
+    var p = $.getTouchPosition(e);
+    this.container.addClass(TOUCHING);
+    this.start = p;
+    this.startX = 0;
+    this.startTime = + new Date;
+    var transform =  this.mover.css('transform').match(/-?[\d\.]+/g)
+    if (transform && transform.length) this.startX = parseInt(transform[4])
+    this.diffX = this.diffY = 0;
+    this._closeOthers()
+    this.limit = this.container.find('>.weui-cell__ft').width() || 68; // 因为有的时候初始化的时候元素是隐藏的(比如在对话框内),所以在touchstart的时候计算宽度而不是初始化的时候
+  };
+
+  Swipeout.prototype.touchMove= function(e) {
+    if(!this.start) return true;
+    var p = $.getTouchPosition(e);
+    this.diffX = p.x - this.start.x;
+    this.diffY = p.y - this.start.y;
+    if (Math.abs(this.diffX) < Math.abs(this.diffY)) { // 说明是上下方向在拖动
+      this.close()
+      this.start = false
+      return true;
+    }
+    e.preventDefault();
+    e.stopPropagation();
+    var x = this.diffX + this.startX
+    if (x > 0) x = 0;
+    if (Math.abs(x) > this.limit) x = - (Math.pow(-(x+this.limit), .7) + this.limit)
+    this.mover.css("transform", "translate3d("+x+"px, 0, 0)");
+  };
+  Swipeout.prototype.touchEnd = function() {
+    if (!this.start) return true;
+    this.start = false;
+    var x = this.diffX + this.startX
+    var t = new Date - this.startTime;
+    if (this.diffX < -5 && t < 200) { // 向左快速滑动,则打开
+      this.open()
+    } else if (this.diffX >= 0 && t < 200) { // 向右快速滑动,或者单击,则关闭
+      this.close()
+    } else if (x > 0 || -x <= this.limit / 2) {
+      this.close()
+    } else {
+      this.open()
+    }
+  };
+
+
+  Swipeout.prototype.close = function() {
+    this.container.removeClass(TOUCHING);
+    this.mover.css("transform", "translate3d(0, 0, 0)");
+    this.container.trigger('swipeout-close');
+  }
+
+  Swipeout.prototype.open = function() {
+    this.container.removeClass(TOUCHING);
+    this._closeOthers()
+    this.mover.css("transform", "translate3d(" + (-this.limit) + "px, 0, 0)");
+    this.container.trigger('swipeout-open');
+  }
+
+  Swipeout.prototype.attachEvents = function() {
+    var el = this.mover;
+    el.on($.touchEvents.start, $.proxy(this.touchStart, this));
+    el.on($.touchEvents.move, $.proxy(this.touchMove, this));
+    el.on($.touchEvents.end, $.proxy(this.touchEnd, this));
+  }
+  Swipeout.prototype._closeOthers = function() {
+    //close others
+    var self = this
+    cache.forEach(function (s) {
+      if (s !== self) s.close()
+    })
+  }
+
+  var swipeout = function(el) {
+    return new Swipeout(el);
+  };
+
+  $.fn.swipeout = function (arg) {
+    return this.each(function() {
+      var $this = $(this)
+      var s = $this.data('swipeout') || swipeout(this);
+      $this.data('swipeout', s);
+
+      if (typeof arg === typeof 'a') {
+        s[arg]()
+      }
+    });
+  }
+
+  $('.weui-cell_swiped').swipeout() // auto init
+}($);
diff --git a/platforms/android/app/src/main/assets/www/js/lib/jquery-weui.min.js b/platforms/android/app/src/main/assets/www/js/lib/jquery-weui.min.js
new file mode 100755
index 0000000..28951e8
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/jquery-weui.min.js
@@ -0,0 +1,13 @@
+/** 
+* jQuery WeUI V1.2.1 
+* By 言川
+* http://lihongxun945.github.io/jquery-weui/
+ */
+!function(t){"use strict";t.fn.transitionEnd=function(t){function e(r){if(r.target===this)for(t.call(this,r),n=0;n<i.length;n++)a.off(i[n],e)}var n,i=["webkitTransitionEnd","transitionend","oTransitionEnd","MSTransitionEnd","msTransitionEnd"],a=this;if(t)for(n=0;n<i.length;n++)a.on(i[n],e);return this},t.support=function(){var t={touch:!!("ontouchstart"in window||window.DocumentTouch&&document instanceof window.DocumentTouch)};return t}(),t.touchEvents={start:t.support.touch?"touchstart":"mousedown",move:t.support.touch?"touchmove":"mousemove",end:t.support.touch?"touchend":"mouseup"},t.getTouchPosition=function(t){return t=t.originalEvent||t,"touchstart"===t.type||"touchmove"===t.type||"touchend"===t.type?{x:t.targetTouches[0].pageX,y:t.targetTouches[0].pageY}:{x:t.pageX,y:t.pageY}},t.fn.scrollHeight=function(){return this[0].scrollHeight},t.fn.transform=function(t){for(var e=0;e<this.length;e++){var n=this[e].style;n.webkitTransform=n.MsTransform=n.msTransform=n.MozTransform=n.OTransform=n.transform=t}return this},t.fn.transition=function(t){"string"!=typeof t&&(t+="ms");for(var e=0;e<this.length;e++){var n=this[e].style;n.webkitTransitionDuration=n.MsTransitionDuration=n.msTransitionDuration=n.MozTransitionDuration=n.OTransitionDuration=n.transitionDuration=t}return this},t.getTranslate=function(t,e){var n,i,a,r;return"undefined"==typeof e&&(e="x"),a=window.getComputedStyle(t,null),window.WebKitCSSMatrix?r=new WebKitCSSMatrix("none"===a.webkitTransform?"":a.webkitTransform):(r=a.MozTransform||a.OTransform||a.MsTransform||a.msTransform||a.transform||a.getPropertyValue("transform").replace("translate(","matrix(1, 0, 0, 1,"),n=r.toString().split(",")),"x"===e&&(i=window.WebKitCSSMatrix?r.m41:16===n.length?parseFloat(n[12]):parseFloat(n[4])),"y"===e&&(i=window.WebKitCSSMatrix?r.m42:16===n.length?parseFloat(n[13]):parseFloat(n[5])),i||0},t.requestAnimationFrame=function(t){return window.requestAnimationFrame?window.requestAnimationFrame(t):window.webkitRequestAnimationFrame?window.webkitRequestAnimationFrame(t):window.mozRequestAnimationFrame?window.mozRequestAnimationFrame(t):window.setTimeout(t,1e3/60)},t.cancelAnimationFrame=function(t){return window.cancelAnimationFrame?window.cancelAnimationFrame(t):window.webkitCancelAnimationFrame?window.webkitCancelAnimationFrame(t):window.mozCancelAnimationFrame?window.mozCancelAnimationFrame(t):window.clearTimeout(t)},t.fn.join=function(t){return this.toArray().join(t)}}($),+function(t){"use strict";t.Template7=t.t7=function(){function t(t){return"[object Array]"===Object.prototype.toString.apply(t)}function e(t){return"function"==typeof t}function n(t){var e,n,i,a=t.replace(/[{}#}]/g,"").split(" "),r=[];for(n=0;n<a.length;n++){var o=a[n];if(0===n)r.push(o);else if(0===o.indexOf('"'))if(2===o.match(/"/g).length)r.push(o);else{for(e=0,i=n+1;i<a.length;i++)if(o+=" "+a[i],a[i].indexOf('"')>=0){e=i,r.push(o);break}e&&(n=e)}else if(o.indexOf("=")>0){var s=o.split("="),c=s[0],l=s[1];if(2!==l.match(/"/g).length){for(e=0,i=n+1;i<a.length;i++)if(l+=" "+a[i],a[i].indexOf('"')>=0){e=i;break}e&&(n=e)}var u=[c,l.replace(/"/g,"")];r.push(u)}else r.push(o)}return r}function i(e){var i,a,r=[];if(!e)return[];var o=e.split(/({{[^{^}]*}})/);for(i=0;i<o.length;i++){var s=o[i];if(""!==s)if(s.indexOf("{{")<0)r.push({type:"plain",content:s});else{if(s.indexOf("{/")>=0)continue;if(s.indexOf("{#")<0&&s.indexOf(" ")<0&&s.indexOf("else")<0){r.push({type:"variable",contextName:s.replace(/[{}]/g,"")});continue}var c=n(s),l=c[0],u=[],p={};for(a=1;a<c.length;a++){var h=c[a];t(h)?p[h[0]]="false"!==h[1]&&h[1]:u.push(h)}if(s.indexOf("{#")>=0){var d,f="",m="",v=0,g=!1,w=!1,y=0;for(a=i+1;a<o.length;a++)if(o[a].indexOf("{{#")>=0&&y++,o[a].indexOf("{{/")>=0&&y--,o[a].indexOf("{{#"+l)>=0)f+=o[a],w&&(m+=o[a]),v++;else if(o[a].indexOf("{{/"+l)>=0){if(!(v>0)){d=a,g=!0;break}v--,f+=o[a],w&&(m+=o[a])}else o[a].indexOf("else")>=0&&0===y?w=!0:(w||(f+=o[a]),w&&(m+=o[a]));g&&(d&&(i=d),r.push({type:"helper",helperName:l,contextName:u,content:f,inverseContent:m,hash:p}))}else s.indexOf(" ")>0&&r.push({type:"helper",helperName:l,contextName:u,hash:p})}}return r}var a=function(t){function e(t,e){return t.content?o(t.content,e):function(){return""}}function n(t,e){return t.inverseContent?o(t.inverseContent,e):function(){return""}}function a(t,e){var n,i,a=0;if(0===t.indexOf("../")){a=t.split("../").length-1;var r=e.split("_")[1]-a;e="ctx_"+(r>=1?r:1),i=t.split("../")[a].split(".")}else 0===t.indexOf("@global")?(e="$.Template7.global",i=t.split("@global.")[1].split(".")):0===t.indexOf("@root")?(e="ctx_1",i=t.split("@root.")[1].split(".")):i=t.split(".");n=e;for(var o=0;o<i.length;o++){var s=i[o];0===s.indexOf("@")?o>0?n+="[(data && data."+s.replace("@","")+")]":n="(data && data."+t.replace("@","")+")":isFinite(s)?n+="["+s+"]":0===s.indexOf("this")?n=s.replace("this",e):n+="."+s}return n}function r(t,e){for(var n=[],i=0;i<t.length;i++)0===t[i].indexOf('"')?n.push(t[i]):n.push(a(t[i],e));return n.join(", ")}function o(t,o){if(o=o||1,t=t||s.template,"string"!=typeof t)throw new Error("Template7: Template must be a string");var c=i(t);if(0===c.length)return function(){return""};var l="ctx_"+o,u="(function ("+l+", data) {\n";1===o&&(u+="function isArray(arr){return Object.prototype.toString.apply(arr) === '[object Array]';}\n",u+="function isFunction(func){return (typeof func === 'function');}\n",u+='function c(val, ctx) {if (typeof val !== "undefined") {if (isFunction(val)) {return val.call(ctx);} else return val;} else return "";}\n'),u+="var r = '';\n";var p;for(p=0;p<c.length;p++){var h=c[p];if("plain"!==h.type){var d,f;if("variable"===h.type&&(d=a(h.contextName,l),u+="r += c("+d+", "+l+");"),"helper"===h.type)if(h.helperName in s.helpers)f=r(h.contextName,l),u+="r += ($.Template7.helpers."+h.helperName+").call("+l+", "+(f&&f+", ")+"{hash:"+JSON.stringify(h.hash)+", data: data || {}, fn: "+e(h,o+1)+", inverse: "+n(h,o+1)+", root: ctx_1});";else{if(h.contextName.length>0)throw new Error('Template7: Missing helper: "'+h.helperName+'"');d=a(h.helperName,l),u+="if ("+d+") {",u+="if (isArray("+d+")) {",u+="r += ($.Template7.helpers.each).call("+l+", "+d+", {hash:"+JSON.stringify(h.hash)+", data: data || {}, fn: "+e(h,o+1)+", inverse: "+n(h,o+1)+", root: ctx_1});",u+="}else {",u+="r += ($.Template7.helpers.with).call("+l+", "+d+", {hash:"+JSON.stringify(h.hash)+", data: data || {}, fn: "+e(h,o+1)+", inverse: "+n(h,o+1)+", root: ctx_1});",u+="}}"}}else u+="r +='"+h.content.replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/'/g,"\\'")+"';"}return u+="\nreturn r;})",eval.call(window,u)}var s=this;s.template=t,s.compile=function(t){return s.compiled||(s.compiled=o(t)),s.compiled}};a.prototype={options:{},helpers:{"if":function(t,n){return e(t)&&(t=t.call(this)),t?n.fn(this,n.data):n.inverse(this,n.data)},unless:function(t,n){return e(t)&&(t=t.call(this)),t?n.inverse(this,n.data):n.fn(this,n.data)},each:function(n,i){var a="",r=0;if(e(n)&&(n=n.call(this)),t(n)){for(i.hash.reverse&&(n=n.reverse()),r=0;r<n.length;r++)a+=i.fn(n[r],{first:0===r,last:r===n.length-1,index:r});i.hash.reverse&&(n=n.reverse())}else for(var o in n)r++,a+=i.fn(n[o],{key:o});return r>0?a:i.inverse(this)},"with":function(t,n){return e(t)&&(t=t.call(this)),n.fn(t)},join:function(t,n){return e(t)&&(t=t.call(this)),t.join(n.hash.delimiter||n.hash.delimeter)},js:function(t,e){var n;return n=t.indexOf("return")>=0?"(function(){"+t+"})":"(function(){return ("+t+")})",eval.call(this,n).call(this)},js_compare:function(t,e){var n;n=t.indexOf("return")>=0?"(function(){"+t+"})":"(function(){return ("+t+")})";var i=eval.call(this,n).call(this);return i?e.fn(this,e.data):e.inverse(this,e.data)}}};var r=function(t,e){if(2===arguments.length){var n=new a(t),i=n.compile()(e);return n=null,i}return new a(t)};return r.registerHelper=function(t,e){a.prototype.helpers[t]=e},r.unregisterHelper=function(t){a.prototype.helpers[t]=void 0,delete a.prototype.helpers[t]},r.compile=function(t,e){var n=new a(t,e);return n.compile()},r.options=a.prototype.options,r.helpers=a.prototype.helpers,r}()}($),/*! Hammer.JS - v2.0.8 - 2016-04-23
+ * http://hammerjs.github.io/
+ *
+ * Copyright (c) 2016 Jorik Tangelder;
+ * Licensed under the MIT license */
+function(t,e,n,i){"use strict";function a(t,e,n){return setTimeout(l(t,n),e)}function r(t,e,n){return!!Array.isArray(t)&&(o(t,n[e],n),!0)}function o(t,e,n){var a;if(t)if(t.forEach)t.forEach(e,n);else if(t.length!==i)for(a=0;a<t.length;)e.call(n,t[a],a,t),a++;else for(a in t)t.hasOwnProperty(a)&&e.call(n,t[a],a,t)}function s(e,n,i){var a="DEPRECATED METHOD: "+n+"\n"+i+" AT \n";return function(){var n=new Error("get-stack-trace"),i=n&&n.stack?n.stack.replace(/^[^\(]+?[\n$]/gm,"").replace(/^\s+at\s+/gm,"").replace(/^Object.<anonymous>\s*\(/gm,"{anonymous}()@"):"Unknown Stack Trace",r=t.console&&(t.console.warn||t.console.log);return r&&r.call(t.console,a,i),e.apply(this,arguments)}}function c(t,e,n){var i,a=e.prototype;i=t.prototype=Object.create(a),i.constructor=t,i._super=a,n&&pt(i,n)}function l(t,e){return function(){return t.apply(e,arguments)}}function u(t,e){return typeof t==ft?t.apply(e?e[0]||i:i,e):t}function p(t,e){return t===i?e:t}function h(t,e,n){o(v(e),function(e){t.addEventListener(e,n,!1)})}function d(t,e,n){o(v(e),function(e){t.removeEventListener(e,n,!1)})}function f(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1}function m(t,e){return t.indexOf(e)>-1}function v(t){return t.trim().split(/\s+/g)}function g(t,e,n){if(t.indexOf&&!n)return t.indexOf(e);for(var i=0;i<t.length;){if(n&&t[i][n]==e||!n&&t[i]===e)return i;i++}return-1}function w(t){return Array.prototype.slice.call(t,0)}function y(t,e,n){for(var i=[],a=[],r=0;r<t.length;){var o=e?t[r][e]:t[r];g(a,o)<0&&i.push(t[r]),a[r]=o,r++}return n&&(i=e?i.sort(function(t,n){return t[e]>n[e]}):i.sort()),i}function T(t,e){for(var n,a,r=e[0].toUpperCase()+e.slice(1),o=0;o<ht.length;){if(n=ht[o],a=n?n+r:e,a in t)return a;o++}return i}function k(){return Tt++}function x(e){var n=e.ownerDocument||e;return n.defaultView||n.parentWindow||t}function C(t,e){var n=this;this.manager=t,this.callback=e,this.element=t.element,this.target=t.options.inputTarget,this.domHandler=function(e){u(t.options.enable,[t])&&n.handler(e)},this.init()}function b(t){var e,n=t.options.inputClass;return new(e=n?n:Ct?F:bt?z:xt?j:N)(t,M)}function M(t,e,n){var i=n.pointers.length,a=n.changedPointers.length,r=e&Ot&&i-a===0,o=e&(It|Ht)&&i-a===0;n.isFirst=!!r,n.isFinal=!!o,r&&(t.session={}),n.eventType=e,_(t,n),t.emit("hammer.input",n),t.recognize(n),t.session.prevInput=n}function _(t,e){var n=t.session,i=e.pointers,a=i.length;n.firstInput||(n.firstInput=P(e)),a>1&&!n.firstMultiple?n.firstMultiple=P(e):1===a&&(n.firstMultiple=!1);var r=n.firstInput,o=n.firstMultiple,s=o?o.center:r.center,c=e.center=O(i);e.timeStamp=gt(),e.deltaTime=e.timeStamp-r.timeStamp,e.angle=S(s,c),e.distance=H(s,c),E(n,e),e.offsetDirection=I(e.deltaX,e.deltaY);var l=A(e.deltaTime,e.deltaX,e.deltaY);e.overallVelocityX=l.x,e.overallVelocityY=l.y,e.overallVelocity=vt(l.x)>vt(l.y)?l.x:l.y,e.scale=o?V(o.pointers,i):1,e.rotation=o?Y(o.pointers,i):0,e.maxPointers=n.prevInput?e.pointers.length>n.prevInput.maxPointers?e.pointers.length:n.prevInput.maxPointers:e.pointers.length,D(n,e);var u=t.element;f(e.srcEvent.target,u)&&(u=e.srcEvent.target),e.target=u}function E(t,e){var n=e.center,i=t.offsetDelta||{},a=t.prevDelta||{},r=t.prevInput||{};e.eventType!==Ot&&r.eventType!==It||(a=t.prevDelta={x:r.deltaX||0,y:r.deltaY||0},i=t.offsetDelta={x:n.x,y:n.y}),e.deltaX=a.x+(n.x-i.x),e.deltaY=a.y+(n.y-i.y)}function D(t,e){var n,a,r,o,s=t.lastInterval||e,c=e.timeStamp-s.timeStamp;if(e.eventType!=Ht&&(c>Pt||s.velocity===i)){var l=e.deltaX-s.deltaX,u=e.deltaY-s.deltaY,p=A(c,l,u);a=p.x,r=p.y,n=vt(p.x)>vt(p.y)?p.x:p.y,o=I(l,u),t.lastInterval=e}else n=s.velocity,a=s.velocityX,r=s.velocityY,o=s.direction;e.velocity=n,e.velocityX=a,e.velocityY=r,e.direction=o}function P(t){for(var e=[],n=0;n<t.pointers.length;)e[n]={clientX:mt(t.pointers[n].clientX),clientY:mt(t.pointers[n].clientY)},n++;return{timeStamp:gt(),pointers:e,center:O(e),deltaX:t.deltaX,deltaY:t.deltaY}}function O(t){var e=t.length;if(1===e)return{x:mt(t[0].clientX),y:mt(t[0].clientY)};for(var n=0,i=0,a=0;a<e;)n+=t[a].clientX,i+=t[a].clientY,a++;return{x:mt(n/e),y:mt(i/e)}}function A(t,e,n){return{x:e/t||0,y:n/t||0}}function I(t,e){return t===e?St:vt(t)>=vt(e)?t<0?Yt:Vt:e<0?Nt:Ft}function H(t,e,n){n||(n=Lt);var i=e[n[0]]-t[n[0]],a=e[n[1]]-t[n[1]];return Math.sqrt(i*i+a*a)}function S(t,e,n){n||(n=Lt);var i=e[n[0]]-t[n[0]],a=e[n[1]]-t[n[1]];return 180*Math.atan2(a,i)/Math.PI}function Y(t,e){return S(e[1],e[0],jt)+S(t[1],t[0],jt)}function V(t,e){return H(e[0],e[1],jt)/H(t[0],t[1],jt)}function N(){this.evEl=$t,this.evWin=Wt,this.pressed=!1,C.apply(this,arguments)}function F(){this.evEl=Bt,this.evWin=Gt,C.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function R(){this.evTarget=Zt,this.evWin=Qt,this.started=!1,C.apply(this,arguments)}function q(t,e){var n=w(t.touches),i=w(t.changedTouches);return e&(It|Ht)&&(n=y(n.concat(i),"identifier",!0)),[n,i]}function z(){this.evTarget=ee,this.targetIds={},C.apply(this,arguments)}function L(t,e){var n=w(t.touches),i=this.targetIds;if(e&(Ot|At)&&1===n.length)return i[n[0].identifier]=!0,[n,n];var a,r,o=w(t.changedTouches),s=[],c=this.target;if(r=n.filter(function(t){return f(t.target,c)}),e===Ot)for(a=0;a<r.length;)i[r[a].identifier]=!0,a++;for(a=0;a<o.length;)i[o[a].identifier]&&s.push(o[a]),e&(It|Ht)&&delete i[o[a].identifier],a++;return s.length?[y(r.concat(s),"identifier",!0),s]:void 0}function j(){C.apply(this,arguments);var t=l(this.handler,this);this.touch=new z(this.manager,t),this.mouse=new N(this.manager,t),this.primaryTouch=null,this.lastTouches=[]}function X(t,e){t&Ot?(this.primaryTouch=e.changedPointers[0].identifier,$.call(this,e)):t&(It|Ht)&&$.call(this,e)}function $(t){var e=t.changedPointers[0];if(e.identifier===this.primaryTouch){var n={x:e.clientX,y:e.clientY};this.lastTouches.push(n);var i=this.lastTouches,a=function(){var t=i.indexOf(n);t>-1&&i.splice(t,1)};setTimeout(a,ne)}}function W(t){for(var e=t.srcEvent.clientX,n=t.srcEvent.clientY,i=0;i<this.lastTouches.length;i++){var a=this.lastTouches[i],r=Math.abs(e-a.x),o=Math.abs(n-a.y);if(r<=ie&&o<=ie)return!0}return!1}function K(t,e){this.manager=t,this.set(e)}function U(t){if(m(t,le))return le;var e=m(t,ue),n=m(t,pe);return e&&n?le:e||n?e?ue:pe:m(t,ce)?ce:se}function B(){if(!re)return!1;var e={},n=t.CSS&&t.CSS.supports;return["auto","manipulation","pan-y","pan-x","pan-x pan-y","none"].forEach(function(i){e[i]=!n||t.CSS.supports("touch-action",i)}),e}function G(t){this.options=pt({},this.defaults,t||{}),this.id=k(),this.manager=null,this.options.enable=p(this.options.enable,!0),this.state=de,this.simultaneous={},this.requireFail=[]}function J(t){return t&we?"cancel":t&ve?"end":t&me?"move":t&fe?"start":""}function Z(t){return t==Ft?"down":t==Nt?"up":t==Yt?"left":t==Vt?"right":""}function Q(t,e){var n=e.manager;return n?n.get(t):t}function tt(){G.apply(this,arguments)}function et(){tt.apply(this,arguments),this.pX=null,this.pY=null}function nt(){tt.apply(this,arguments)}function it(){G.apply(this,arguments),this._timer=null,this._input=null}function at(){tt.apply(this,arguments)}function rt(){tt.apply(this,arguments)}function ot(){G.apply(this,arguments),this.pTime=!1,this.pCenter=!1,this._timer=null,this._input=null,this.count=0}function st(t,e){return e=e||{},e.recognizers=p(e.recognizers,st.defaults.preset),new ct(t,e)}function ct(t,e){this.options=pt({},st.defaults,e||{}),this.options.inputTarget=this.options.inputTarget||t,this.handlers={},this.session={},this.recognizers=[],this.oldCssProps={},this.element=t,this.input=b(this),this.touchAction=new K(this,this.options.touchAction),lt(this,!0),o(this.options.recognizers,function(t){var e=this.add(new t[0](t[1]));t[2]&&e.recognizeWith(t[2]),t[3]&&e.requireFailure(t[3])},this)}function lt(t,e){var n=t.element;if(n.style){var i;o(t.options.cssProps,function(a,r){i=T(n.style,r),e?(t.oldCssProps[i]=n.style[i],n.style[i]=a):n.style[i]=t.oldCssProps[i]||""}),e||(t.oldCssProps={})}}function ut(t,n){var i=e.createEvent("Event");i.initEvent(t,!0,!0),i.gesture=n,n.target.dispatchEvent(i)}var pt,ht=["","webkit","Moz","MS","ms","o"],dt=e.createElement("div"),ft="function",mt=Math.round,vt=Math.abs,gt=Date.now;pt="function"!=typeof Object.assign?function(t){if(t===i||null===t)throw new TypeError("Cannot convert undefined or null to object");for(var e=Object(t),n=1;n<arguments.length;n++){var a=arguments[n];if(a!==i&&null!==a)for(var r in a)a.hasOwnProperty(r)&&(e[r]=a[r])}return e}:Object.assign;var wt=s(function(t,e,n){for(var a=Object.keys(e),r=0;r<a.length;)(!n||n&&t[a[r]]===i)&&(t[a[r]]=e[a[r]]),r++;return t},"extend","Use `assign`."),yt=s(function(t,e){return wt(t,e,!0)},"merge","Use `assign`."),Tt=1,kt=/mobile|tablet|ip(ad|hone|od)|android/i,xt="ontouchstart"in t,Ct=T(t,"PointerEvent")!==i,bt=xt&&kt.test(navigator.userAgent),Mt="touch",_t="pen",Et="mouse",Dt="kinect",Pt=25,Ot=1,At=2,It=4,Ht=8,St=1,Yt=2,Vt=4,Nt=8,Ft=16,Rt=Yt|Vt,qt=Nt|Ft,zt=Rt|qt,Lt=["x","y"],jt=["clientX","clientY"];C.prototype={handler:function(){},init:function(){this.evEl&&h(this.element,this.evEl,this.domHandler),this.evTarget&&h(this.target,this.evTarget,this.domHandler),this.evWin&&h(x(this.element),this.evWin,this.domHandler)},destroy:function(){this.evEl&&d(this.element,this.evEl,this.domHandler),this.evTarget&&d(this.target,this.evTarget,this.domHandler),this.evWin&&d(x(this.element),this.evWin,this.domHandler)}};var Xt={mousedown:Ot,mousemove:At,mouseup:It},$t="mousedown",Wt="mousemove mouseup";c(N,C,{handler:function(t){var e=Xt[t.type];e&Ot&&0===t.button&&(this.pressed=!0),e&At&&1!==t.which&&(e=It),this.pressed&&(e&It&&(this.pressed=!1),this.callback(this.manager,e,{pointers:[t],changedPointers:[t],pointerType:Et,srcEvent:t}))}});var Kt={pointerdown:Ot,pointermove:At,pointerup:It,pointercancel:Ht,pointerout:Ht},Ut={2:Mt,3:_t,4:Et,5:Dt},Bt="pointerdown",Gt="pointermove pointerup pointercancel";t.MSPointerEvent&&!t.PointerEvent&&(Bt="MSPointerDown",Gt="MSPointerMove MSPointerUp MSPointerCancel"),c(F,C,{handler:function(t){var e=this.store,n=!1,i=t.type.toLowerCase().replace("ms",""),a=Kt[i],r=Ut[t.pointerType]||t.pointerType,o=r==Mt,s=g(e,t.pointerId,"pointerId");a&Ot&&(0===t.button||o)?s<0&&(e.push(t),s=e.length-1):a&(It|Ht)&&(n=!0),s<0||(e[s]=t,this.callback(this.manager,a,{pointers:e,changedPointers:[t],pointerType:r,srcEvent:t}),n&&e.splice(s,1))}});var Jt={touchstart:Ot,touchmove:At,touchend:It,touchcancel:Ht},Zt="touchstart",Qt="touchstart touchmove touchend touchcancel";c(R,C,{handler:function(t){var e=Jt[t.type];if(e===Ot&&(this.started=!0),this.started){var n=q.call(this,t,e);e&(It|Ht)&&n[0].length-n[1].length===0&&(this.started=!1),this.callback(this.manager,e,{pointers:n[0],changedPointers:n[1],pointerType:Mt,srcEvent:t})}}});var te={touchstart:Ot,touchmove:At,touchend:It,touchcancel:Ht},ee="touchstart touchmove touchend touchcancel";c(z,C,{handler:function(t){var e=te[t.type],n=L.call(this,t,e);n&&this.callback(this.manager,e,{pointers:n[0],changedPointers:n[1],pointerType:Mt,srcEvent:t})}});var ne=2500,ie=25;c(j,C,{handler:function(t,e,n){var i=n.pointerType==Mt,a=n.pointerType==Et;if(!(a&&n.sourceCapabilities&&n.sourceCapabilities.firesTouchEvents)){if(i)X.call(this,e,n);else if(a&&W.call(this,n))return;this.callback(t,e,n)}},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var ae=T(dt.style,"touchAction"),re=ae!==i,oe="compute",se="auto",ce="manipulation",le="none",ue="pan-x",pe="pan-y",he=B();K.prototype={set:function(t){t==oe&&(t=this.compute()),re&&this.manager.element.style&&he[t]&&(this.manager.element.style[ae]=t),this.actions=t.toLowerCase().trim()},update:function(){this.set(this.manager.options.touchAction)},compute:function(){var t=[];return o(this.manager.recognizers,function(e){u(e.options.enable,[e])&&(t=t.concat(e.getTouchAction()))}),U(t.join(" "))},preventDefaults:function(t){var e=t.srcEvent,n=t.offsetDirection;if(this.manager.session.prevented)return void e.preventDefault();var i=this.actions,a=m(i,le)&&!he[le],r=m(i,pe)&&!he[pe],o=m(i,ue)&&!he[ue];if(a){var s=1===t.pointers.length,c=t.distance<2,l=t.deltaTime<250;if(s&&c&&l)return}return o&&r?void 0:a||r&&n&Rt||o&&n&qt?this.preventSrc(e):void 0},preventSrc:function(t){this.manager.session.prevented=!0,t.preventDefault()}};var de=1,fe=2,me=4,ve=8,ge=ve,we=16,ye=32;G.prototype={defaults:{},set:function(t){return pt(this.options,t),this.manager&&this.manager.touchAction.update(),this},recognizeWith:function(t){if(r(t,"recognizeWith",this))return this;var e=this.simultaneous;return t=Q(t,this),e[t.id]||(e[t.id]=t,t.recognizeWith(this)),this},dropRecognizeWith:function(t){return r(t,"dropRecognizeWith",this)?this:(t=Q(t,this),delete this.simultaneous[t.id],this)},requireFailure:function(t){if(r(t,"requireFailure",this))return this;var e=this.requireFail;return t=Q(t,this),g(e,t)===-1&&(e.push(t),t.requireFailure(this)),this},dropRequireFailure:function(t){if(r(t,"dropRequireFailure",this))return this;t=Q(t,this);var e=g(this.requireFail,t);return e>-1&&this.requireFail.splice(e,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(t){return!!this.simultaneous[t.id]},emit:function(t){function e(e){n.manager.emit(e,t)}var n=this,i=this.state;i<ve&&e(n.options.event+J(i)),e(n.options.event),t.additionalEvent&&e(t.additionalEvent),i>=ve&&e(n.options.event+J(i))},tryEmit:function(t){return this.canEmit()?this.emit(t):void(this.state=ye)},canEmit:function(){for(var t=0;t<this.requireFail.length;){if(!(this.requireFail[t].state&(ye|de)))return!1;t++}return!0},recognize:function(t){var e=pt({},t);return u(this.options.enable,[this,e])?(this.state&(ge|we|ye)&&(this.state=de),this.state=this.process(e),void(this.state&(fe|me|ve|we)&&this.tryEmit(e))):(this.reset(),void(this.state=ye))},process:function(t){},getTouchAction:function(){},reset:function(){}},c(tt,G,{defaults:{pointers:1},attrTest:function(t){var e=this.options.pointers;return 0===e||t.pointers.length===e},process:function(t){var e=this.state,n=t.eventType,i=e&(fe|me),a=this.attrTest(t);return i&&(n&Ht||!a)?e|we:i||a?n&It?e|ve:e&fe?e|me:fe:ye}}),c(et,tt,{defaults:{event:"pan",threshold:10,pointers:1,direction:zt},getTouchAction:function(){var t=this.options.direction,e=[];return t&Rt&&e.push(pe),t&qt&&e.push(ue),e},directionTest:function(t){var e=this.options,n=!0,i=t.distance,a=t.direction,r=t.deltaX,o=t.deltaY;return a&e.direction||(e.direction&Rt?(a=0===r?St:r<0?Yt:Vt,n=r!=this.pX,i=Math.abs(t.deltaX)):(a=0===o?St:o<0?Nt:Ft,n=o!=this.pY,i=Math.abs(t.deltaY))),t.direction=a,n&&i>e.threshold&&a&e.direction},attrTest:function(t){return tt.prototype.attrTest.call(this,t)&&(this.state&fe||!(this.state&fe)&&this.directionTest(t))},emit:function(t){this.pX=t.deltaX,this.pY=t.deltaY;var e=Z(t.direction);e&&(t.additionalEvent=this.options.event+e),this._super.emit.call(this,t)}}),c(nt,tt,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[le]},attrTest:function(t){return this._super.attrTest.call(this,t)&&(Math.abs(t.scale-1)>this.options.threshold||this.state&fe)},emit:function(t){if(1!==t.scale){var e=t.scale<1?"in":"out";t.additionalEvent=this.options.event+e}this._super.emit.call(this,t)}}),c(it,G,{defaults:{event:"press",pointers:1,time:251,threshold:9},getTouchAction:function(){return[se]},process:function(t){var e=this.options,n=t.pointers.length===e.pointers,i=t.distance<e.threshold,r=t.deltaTime>e.time;if(this._input=t,!i||!n||t.eventType&(It|Ht)&&!r)this.reset();else if(t.eventType&Ot)this.reset(),this._timer=a(function(){this.state=ge,this.tryEmit()},e.time,this);else if(t.eventType&It)return ge;return ye},reset:function(){clearTimeout(this._timer)},emit:function(t){this.state===ge&&(t&&t.eventType&It?this.manager.emit(this.options.event+"up",t):(this._input.timeStamp=gt(),this.manager.emit(this.options.event,this._input)))}}),c(at,tt,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[le]},attrTest:function(t){return this._super.attrTest.call(this,t)&&(Math.abs(t.rotation)>this.options.threshold||this.state&fe)}}),c(rt,tt,{defaults:{event:"swipe",threshold:10,velocity:.3,direction:Rt|qt,pointers:1},getTouchAction:function(){return et.prototype.getTouchAction.call(this)},attrTest:function(t){var e,n=this.options.direction;return n&(Rt|qt)?e=t.overallVelocity:n&Rt?e=t.overallVelocityX:n&qt&&(e=t.overallVelocityY),this._super.attrTest.call(this,t)&&n&t.offsetDirection&&t.distance>this.options.threshold&&t.maxPointers==this.options.pointers&&vt(e)>this.options.velocity&&t.eventType&It},emit:function(t){var e=Z(t.offsetDirection);e&&this.manager.emit(this.options.event+e,t),this.manager.emit(this.options.event,t)}}),c(ot,G,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:9,posThreshold:10},getTouchAction:function(){return[ce]},process:function(t){var e=this.options,n=t.pointers.length===e.pointers,i=t.distance<e.threshold,r=t.deltaTime<e.time;if(this.reset(),t.eventType&Ot&&0===this.count)return this.failTimeout();if(i&&r&&n){if(t.eventType!=It)return this.failTimeout();var o=!this.pTime||t.timeStamp-this.pTime<e.interval,s=!this.pCenter||H(this.pCenter,t.center)<e.posThreshold;this.pTime=t.timeStamp,this.pCenter=t.center,s&&o?this.count+=1:this.count=1,this._input=t;var c=this.count%e.taps;if(0===c)return this.hasRequireFailures()?(this._timer=a(function(){this.state=ge,this.tryEmit()},e.interval,this),fe):ge}return ye},failTimeout:function(){return this._timer=a(function(){this.state=ye},this.options.interval,this),ye},reset:function(){clearTimeout(this._timer)},emit:function(){this.state==ge&&(this._input.tapCount=this.count,this.manager.emit(this.options.event,this._input))}}),st.VERSION="2.0.8",st.defaults={domEvents:!1,touchAction:oe,enable:!0,inputTarget:null,inputClass:null,preset:[[at,{enable:!1}],[nt,{enable:!1},["rotate"]],[rt,{direction:Rt}],[et,{direction:Rt},["swipe"]],[ot],[ot,{event:"doubletap",taps:2},["tap"]],[it]],cssProps:{userSelect:"none",touchSelect:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}};var Te=1,ke=2;ct.prototype={set:function(t){return pt(this.options,t),t.touchAction&&this.touchAction.update(),t.inputTarget&&(this.input.destroy(),this.input.target=t.inputTarget,this.input.init()),this},stop:function(t){this.session.stopped=t?ke:Te},recognize:function(t){var e=this.session;if(!e.stopped){this.touchAction.preventDefaults(t);var n,i=this.recognizers,a=e.curRecognizer;(!a||a&&a.state&ge)&&(a=e.curRecognizer=null);for(var r=0;r<i.length;)n=i[r],e.stopped===ke||a&&n!=a&&!n.canRecognizeWith(a)?n.reset():n.recognize(t),!a&&n.state&(fe|me|ve)&&(a=e.curRecognizer=n),r++}},get:function(t){if(t instanceof G)return t;for(var e=this.recognizers,n=0;n<e.length;n++)if(e[n].options.event==t)return e[n];return null},add:function(t){if(r(t,"add",this))return this;var e=this.get(t.options.event);return e&&this.remove(e),this.recognizers.push(t),t.manager=this,this.touchAction.update(),t},remove:function(t){if(r(t,"remove",this))return this;if(t=this.get(t)){var e=this.recognizers,n=g(e,t);n!==-1&&(e.splice(n,1),this.touchAction.update())}return this},on:function(t,e){if(t!==i&&e!==i){var n=this.handlers;return o(v(t),function(t){n[t]=n[t]||[],n[t].push(e)}),this}},off:function(t,e){if(t!==i){var n=this.handlers;return o(v(t),function(t){e?n[t]&&n[t].splice(g(n[t],e),1):delete n[t]}),this}},emit:function(t,e){this.options.domEvents&&ut(t,e);var n=this.handlers[t]&&this.handlers[t].slice();if(n&&n.length){e.type=t,e.preventDefault=function(){e.srcEvent.preventDefault()};for(var i=0;i<n.length;)n[i](e),i++}},destroy:function(){this.element&&lt(this,!1),this.handlers={},this.session={},this.input.destroy(),this.element=null}},pt(st,{INPUT_START:Ot,INPUT_MOVE:At,INPUT_END:It,INPUT_CANCEL:Ht,STATE_POSSIBLE:de,STATE_BEGAN:fe,STATE_CHANGED:me,STATE_ENDED:ve,STATE_RECOGNIZED:ge,STATE_CANCELLED:we,STATE_FAILED:ye,DIRECTION_NONE:St,DIRECTION_LEFT:Yt,DIRECTION_RIGHT:Vt,DIRECTION_UP:Nt,DIRECTION_DOWN:Ft,DIRECTION_HORIZONTAL:Rt,DIRECTION_VERTICAL:qt,DIRECTION_ALL:zt,Manager:ct,Input:C,TouchAction:K,TouchInput:z,MouseInput:N,PointerEventInput:F,TouchMouseInput:j,SingleTouchInput:R,Recognizer:G,AttrRecognizer:tt,Tap:ot,Pan:et,Swipe:rt,Pinch:nt,Rotate:at,Press:it,on:h,off:d,each:o,merge:yt,extend:wt,assign:pt,inherit:c,bindFn:l,prefixed:T});var xe="undefined"!=typeof t?t:"undefined"!=typeof self?self:{};xe.Hammer=st,"function"==typeof define&&define.amd?define(function(){return st}):"undefined"!=typeof module&&module.exports?module.exports=st:t[n]=st}(window,document,"Hammer"),+function(t){"use strict";var e;t.modal=function(n,i){n=t.extend({},e,n);var a=n.buttons,r=a.map(function(t,e){return'<a href="javascript:;" class="weui-dialog__btn '+(t.className||"")+'">'+t.text+"</a>"}).join(""),o='<div class="weui-dialog"><div class="weui-dialog__hd"><strong class="weui-dialog__title">'+n.title+"</strong></div>"+(n.text?'<div class="weui-dialog__bd">'+n.text+"</div>":"")+'<div class="weui-dialog__ft">'+r+"</div></div>",s=t.openModal(o,i);return s.find(".weui-dialog__btn").each(function(e,i){var r=t(i);r.click(function(){n.autoClose&&t.closeModal(),a[e].onClick&&a[e].onClick.call(s)})}),s},t.openModal=function(e,n){var i=t("<div class='weui-mask'></div>").appendTo(document.body);i.show();var a=t(e).appendTo(document.body);return n&&a.transitionEnd(function(){n.call(a)}),a.show(),i.addClass("weui-mask--visible"),a.addClass("weui-dialog--visible"),a},t.closeModal=function(){t(".weui-mask--visible").removeClass("weui-mask--visible").transitionEnd(function(){t(this).remove()}),t(".weui-dialog--visible").removeClass("weui-dialog--visible").transitionEnd(function(){t(this).remove()})},t.alert=function(n,i,a){var r;return"object"==typeof n?r=n:("function"==typeof i&&(a=arguments[1],i=void 0),r={text:n,title:i,onOK:a}),t.modal({text:r.text,title:r.title,buttons:[{text:e.buttonOK,className:"primary",onClick:r.onOK}]})},t.confirm=function(n,i,a,r){var o;return"object"==typeof n?o=n:("function"==typeof i&&(r=arguments[2],a=arguments[1],i=void 0),o={text:n,title:i,onOK:a,onCancel:r}),t.modal({text:o.text,title:o.title,buttons:[{text:e.buttonCancel,className:"default",onClick:o.onCancel},{text:e.buttonOK,className:"primary",onClick:o.onOK}]})},t.prompt=function(n,i,a,r,o){var s;"object"==typeof n?s=n:("function"==typeof i&&(o=arguments[3],r=arguments[2],a=arguments[1],i=void 0),s={text:n,title:i,input:o,onOK:a,onCancel:r,empty:!1});var c=t.modal({text:'<p class="weui-prompt-text">'+(s.text||"")+'</p><input type="text" class="weui-input weui-prompt-input" id="weui-prompt-input" value="'+(s.input||"")+'" />',title:s.title,autoClose:!1,buttons:[{text:e.buttonCancel,className:"default",onClick:function(){t.closeModal(),s.onCancel&&s.onCancel.call(c)}},{text:e.buttonOK,className:"primary",onClick:function(){var e=t("#weui-prompt-input").val();return s.empty||""!==e&&null!==e?(t.closeModal(),void(s.onOK&&s.onOK.call(c,e))):(c.find(".weui-prompt-input").focus()[0].select(),!1)}}]},function(){this.find(".weui-prompt-input").focus()[0].select()});return c},t.login=function(n,i,a,r,o,s){var c;"object"==typeof n?c=n:("function"==typeof i&&(s=arguments[4],o=arguments[3],r=arguments[2],a=arguments[1],i=void 0),c={text:n,title:i,username:o,password:s,onOK:a,onCancel:r});var l=t.modal({text:'<p class="weui-prompt-text">'+(c.text||"")+'</p><input type="text" class="weui-input weui-prompt-input" id="weui-prompt-username" value="'+(c.username||"")+'" placeholder="输入用户名" /><input type="password" class="weui-input weui-prompt-input" id="weui-prompt-password" value="'+(c.password||"")+'" placeholder="输入密码" />',title:c.title,autoClose:!1,buttons:[{text:e.buttonCancel,className:"default",onClick:function(){t.closeModal(),c.onCancel&&c.onCancel.call(l)}},{text:e.buttonOK,className:"primary",onClick:function(){var e=t("#weui-prompt-username").val(),n=t("#weui-prompt-password").val();return c.empty||""!==e&&null!==e?c.empty||""!==n&&null!==n?(t.closeModal(),void(c.onOK&&c.onOK.call(l,e,n))):(l.find("#weui-prompt-password").focus()[0].select(),!1):(l.find("#weui-prompt-username").focus()[0].select(),!1)}}]},function(){this.find("#weui-prompt-username").focus()[0].select()});return l},e=t.modal.prototype.defaults={title:"提示",text:void 0,buttonOK:"确定",buttonCancel:"取消",buttons:[{text:"确定",className:"primary"}],autoClose:!0}}($),+function(t){"use strict";var e=function(e,n){n=n||"";var i=(t("<div class='weui-mask_transparent'></div>").appendTo(document.body),'<div class="weui-toast '+n+'">'+e+"</div>"),a=t(i).appendTo(document.body);a.addClass("weui-toast--visible"),a.show()},n=function(e){t(".weui-mask_transparent").remove();var n=!1,i=t(".weui-toast--visible").removeClass("weui-toast--visible").transitionEnd(function(){var i=t(this);i.remove(),e&&e(),n=!0});setTimeout(function(){n||(i.remove(),e&&e())},1e3)};t.toast=function(t,a,r){"function"==typeof a&&(r=a);var o,s="weui-icon-success-no-circle",c=i.duration;"cancel"==a?(o="weui-toast_cancel",s="weui-icon-cancel"):"forbidden"==a?(o="weui-toast--forbidden",s="weui-icon-warn"):"text"==a?o="weui-toast--text":"number"==typeof a&&(c=a),e('<i class="'+s+' weui-icon_toast"></i><p class="weui-toast_content">'+(t||"已经完成")+"</p>",o),setTimeout(function(){n(r)},c)},t.showLoading=function(t){var n='<div class="weui_loading">';n+='<i class="weui-loading weui-icon_toast"></i>',n+="</div>",n+='<p class="weui-toast_content">'+(t||"数据加载中")+"</p>",e(n,"weui_loading_toast")},t.hideLoading=function(){n()};var i=t.toast.prototype.defaults={duration:2500}}($),+function(t){"use strict";var e,n=function(e){var n=t("<div class='weui-mask weui-actions_mask'></div>").appendTo(document.body),i=e.actions||[],a=i.map(function(t,e){return'<div class="weui-actionsheet__cell '+(t.className||"")+'">'+t.text+"</div>"}).join(""),r="";e.title&&(r='<div class="weui-actionsheet__title"><p class="weui-actionsheet__title-text">'+e.title+"</p></div>");var o='<div class="weui-actionsheet " id="weui-actionsheet">'+r+'<div class="weui-actionsheet__menu">'+a+'</div><div class="weui-actionsheet__action"><div class="weui-actionsheet__cell weui-actionsheet_cancel">取消</div></div></div>',s=t(o).appendTo(document.body);s.find(".weui-actionsheet__menu .weui-actionsheet__cell, .weui-actionsheet__action .weui-actionsheet__cell").each(function(n,a){t(a).click(function(){t.closeActions(),e.onClose&&e.onClose(),i[n]&&i[n].onClick&&i[n].onClick()})}),n.show(),s.show(),n.addClass("weui-mask--visible"),s.addClass("weui-actionsheet_toggle")},i=function(){t(".weui-mask").removeClass("weui-mask--visible").transitionEnd(function(){t(this).remove()}),t(".weui-actionsheet").removeClass("weui-actionsheet_toggle").transitionEnd(function(){t(this).remove()})};t.actions=function(i){i=t.extend({},e,i),n(i)},t.closeActions=function(){i()},t(document).on("click",".weui-actions_mask",function(){t.closeActions()});var e=t.actions.prototype.defaults={title:void 0,onClose:void 0}}($),+function(t){"use strict";var e=function(n,i){"function"==typeof i&&(i={onRefresh:i}),"string"==typeof i&&(i=void 0),this.opt=t.extend(e.defaults,i||{}),this.container=t(n),this.attachEvents()};e.defaults={distance:50,onRefresh:void 0,onPull:void 0},e.prototype.touchStart=function(e){if(!this.container.hasClass("refreshing")){var n=t.getTouchPosition(e);this.start=n,this.diffX=this.diffY=0}},e.prototype.touchMove=function(e){if(!this.container.hasClass("refreshing")){if(!this.start)return!1;if(!(this.container.scrollTop()>0)){var n=t.getTouchPosition(e);return this.diffX=n.x-this.start.x,this.diffY=n.y-this.start.y,Math.abs(this.diffX)>Math.abs(this.diffY)||void(this.diffY<0||(this.container.addClass("touching"),e.preventDefault(),e.stopPropagation(),this.diffY=Math.pow(this.diffY,.75),this.container.css("transform","translate3d(0, "+this.diffY+"px, 0)"),this.triggerPull(this.diffY)))}}},e.prototype.touchEnd=function(){this.start=!1,this.diffY<=0||this.container.hasClass("refreshing")||(this.container.removeClass("touching"),this.container.removeClass("pull-down pull-up"),this.container.css("transform",""),Math.abs(this.diffY)<=this.opt.distance||this.triggerPullToRefresh())},e.prototype.triggerPullToRefresh=function(){this.triggerPull(this.opt.distance),this.container.removeClass("pull-up").addClass("refreshing"),this.opt.onRefresh&&this.opt.onRefresh.call(this),this.container.trigger("pull-to-refresh")},e.prototype.triggerPull=function(t){t<this.opt.distance?this.container.removeClass("pull-up").addClass("pull-down"):this.container.removeClass("pull-down").addClass("pull-up"),this.opt.onPull&&this.opt.onPull.call(this,Math.floor(t/this.opt.distance*100)),this.container.trigger("pull")},e.prototype.pullToRefreshDone=function(){this.container.removeClass("refreshing")},e.prototype.attachEvents=function(){var e=this.container;e.addClass("weui-pull-to-refresh"),e.on(t.touchEvents.start,t.proxy(this.touchStart,this)),e.on(t.touchEvents.move,t.proxy(this.touchMove,this)),e.on(t.touchEvents.end,t.proxy(this.touchEnd,this))};var n=function(e){t(e).removeClass("refreshing")};t.fn.pullToRefresh=function(n){return this.each(function(){var i=t(this),a=i.data("ptr");a||i.data("ptr",a=new e(this,n)),"string"==typeof n&&a[n].call(a)})},t.fn.pullToRefreshDone=function(){return this.each(function(){n(this)})}}($),+function(t){"use strict";var e=function(e){var n,i=e[0].tagName.toUpperCase();n="BODY"===i||"HTML"===i?e.scrollTop()||t(window).scrollTop():e.scrollTop();var a=e.scrollHeight()-(t(window).height()+n);return console.log(a),a},n=function(e,n){this.container=t(e),this.container.data("infinite",this),this.distance=n||50,this.attachEvents()};n.prototype.scroll=function(){this.container;this._check()},n.prototype.attachEvents=function(e){var n=this.container,i="BODY"===n[0].tagName.toUpperCase()?t(document):n;i[e?"off":"on"]("scroll",t.proxy(this.scroll,this))},n.prototype.detachEvents=function(t){this.attachEvents(!0)},n.prototype._check=function(){var t=e(this.container);Math.abs(t)<=this.distance&&this.container.trigger("infinite")};t.fn.infinite=function(t){return this.each(function(){new n(this,t)})},t.fn.destroyInfinite=function(){return this.each(function(){var e=t(this).data("infinite");e&&e.detachEvents&&e.detachEvents()})}}($),+function(t){"use strict";var e="weui-bar__item--on",n=function(n){var i=t(n);if(!i.hasClass(e)){var a=i.attr("href");if(/^#/.test(a)){i.parent().find("."+e).removeClass(e),i.addClass(e);var r=i.parents(".weui-tab").find(".weui-tab__bd");r.find(".weui-tab__bd-item--active").removeClass("weui-tab__bd-item--active"),t(a).addClass("weui-tab__bd-item--active")}}};t.showTab=n,t(document).on("click",".weui-navbar__item, .weui-tabbar__item",function(i){var a=t(i.currentTarget),r=a.attr("href");a.hasClass(e)||/^#/.test(r)&&(i.preventDefault(),n(a))})}($),+function(t){"use strict";t(document).on("click touchstart",".weui-search-bar__label",function(e){t(e.target).parents(".weui-search-bar").addClass("weui-search-bar_focusing").find("input").focus()}).on("click",".weui-search-bar__cancel-btn",function(e){t(e.target).parents(".weui-search-bar").removeClass("weui-search-bar_focusing").find(".weui-search-bar__input").val("").blur()}).on("click",".weui-icon-clear",function(e){t(e.target).parents(".weui-search-bar").find(".weui-search-bar__input").val("").focus()})}($),function(t){"use strict";var e={},n=navigator.userAgent,i=n.match(/(Android);?[\s\/]+([\d.]+)?/),a=n.match(/(iPad).*OS\s([\d_]+)/),r=n.match(/(iPod)(.*OS\s([\d_]+))?/),o=!a&&n.match(/(iPhone\sOS)\s([\d_]+)/);if(e.ios=e.android=e.iphone=e.ipad=e.androidChrome=!1,i&&(e.os="android",e.osVersion=i[2],e.android=!0,e.androidChrome=n.toLowerCase().indexOf("chrome")>=0),(a||o||r)&&(e.os="ios",e.ios=!0),o&&!r&&(e.osVersion=o[2].replace(/_/g,"."),e.iphone=!0),a&&(e.osVersion=a[2].replace(/_/g,"."),e.ipad=!0),r&&(e.osVersion=r[3]?r[3].replace(/_/g,"."):null,e.iphone=!0),e.ios&&e.osVersion&&n.indexOf("Version/")>=0&&"10"===e.osVersion.split(".")[0]&&(e.osVersion=n.toLowerCase().split("version/")[1].split(" ")[0]),
+e.webView=(o||a||r)&&n.match(/.*AppleWebKit(?!.*Safari)/i),e.os&&"ios"===e.os){var s=e.osVersion.split(".");e.minimalUi=!e.webView&&(r||o)&&(1*s[0]===7?1*s[1]>=1:1*s[0]>7)&&t('meta[name="viewport"]').length>0&&t('meta[name="viewport"]').attr("content").indexOf("minimal-ui")>=0}var c=t(window).width(),l=t(window).height();e.statusBar=!1,e.webView&&c*l===screen.width*screen.height?e.statusBar=!0:e.statusBar=!1;var u=[];if(e.pixelRatio=window.devicePixelRatio||1,u.push("pixel-ratio-"+Math.floor(e.pixelRatio)),e.pixelRatio>=2&&u.push("retina"),e.os&&(u.push(e.os,e.os+"-"+e.osVersion.split(".")[0],e.os+"-"+e.osVersion.replace(/\./g,"-")),"ios"===e.os))for(var p=parseInt(e.osVersion.split(".")[0],10),h=p-1;h>=6;h--)u.push("ios-gt-"+h);e.statusBar?u.push("with-statusbar-overlay"):t("html").removeClass("with-statusbar-overlay"),u.length>0&&t("html").addClass(u.join(" ")),t.device=e}($),+function(t){"use strict";var e=function(e){function n(){var e=!1;return c.params.convertToPopover||c.params.onlyInPopover?(!c.inline&&c.params.input&&(c.params.onlyInPopover?e=!0:t.device.ios?e=!!t.device.ipad:t(window).width()>=768&&(e=!0)),e):e}function i(){return!!(c.opened&&c.container&&c.container.length>0&&c.container.parents(".popover").length>0)}function a(){if(c.opened)for(var t=0;t<c.cols.length;t++)c.cols[t].divider||(c.cols[t].calcSize(),c.cols[t].setValue(c.cols[t].value,0,!1))}function r(t){if(t.preventDefault(),!c.opened&&(c.open(),c.params.scrollToInput&&!n())){var e=c.input.parents(".content");if(0===e.length)return;var i,a=parseInt(e.css("padding-top"),10),r=parseInt(e.css("padding-bottom"),10),o=e[0].offsetHeight-a-c.container.height(),s=e[0].scrollHeight-a-c.container.height(),l=c.input.offset().top-a+c.input[0].offsetHeight;if(l>o){var u=e.scrollTop()+l-o;u+o>s&&(i=u+o-s+r,o===s&&(i=c.container.height()),e.css({"padding-bottom":i+"px"})),e.scrollTop(u,300)}}}function o(e){i()||(c.input&&c.input.length>0?e.target!==c.input[0]&&0===t(e.target).parents(".weui-picker-modal").length&&c.close():0===t(e.target).parents(".weui-picker-modal").length&&c.close())}function s(){c.opened=!1,c.input&&c.input.length>0&&c.input.parents(".page-content").css({"padding-bottom":""}),c.params.onClose&&c.params.onClose(c),c.container.find(".picker-items-col").each(function(){c.destroyPickerCol(this)})}var c=this,l={updateValuesOnMomentum:!1,updateValuesOnTouchmove:!0,rotateEffect:!1,momentumRatio:7,freeMode:!1,scrollToInput:!0,inputReadOnly:!0,toolbar:!0,toolbarCloseText:"完成",title:"请选择",toolbarTemplate:'<div class="toolbar">          <div class="toolbar-inner">          <a href="javascript:;" class="picker-button close-picker">{{closeText}}</a>          <h1 class="title">{{title}}</h1>          </div>          </div>'};e=e||{};for(var u in l)"undefined"==typeof e[u]&&(e[u]=l[u]);c.params=e,c.cols=[],c.initialized=!1,c.inline=!!c.params.container;var p=t.device.ios||navigator.userAgent.toLowerCase().indexOf("safari")>=0&&navigator.userAgent.toLowerCase().indexOf("chrome")<0&&!t.device.android;return c.setValue=function(t,e){for(var n=0,i=0;i<c.cols.length;i++)c.cols[i]&&!c.cols[i].divider&&(c.cols[i].setValue(t[n],e),n++)},c.updateValue=function(){for(var e=[],n=[],i=0;i<c.cols.length;i++)c.cols[i].divider||(e.push(c.cols[i].value),n.push(c.cols[i].displayValue));e.indexOf(void 0)>=0||(c.value=e,c.displayValue=n,c.params.onChange&&c.params.onChange(c,c.value,c.displayValue),c.input&&c.input.length>0&&(t(c.input).val(c.params.formatValue?c.params.formatValue(c,c.value,c.displayValue):c.value.join(" ")),t(c.input).trigger("change")))},c.initPickerCol=function(e,n){function i(){w=t.requestAnimationFrame(function(){h.updateItems(void 0,void 0,0),i()})}function a(e){if(!T&&!y){e.preventDefault(),y=!0;var n=t.getTouchPosition(e);k=x=n.y,C=(new Date).getTime(),A=!0,M=E=t.getTranslate(h.wrapper[0],"y")}}function r(e){if(y){e.preventDefault(),A=!1;var n=t.getTouchPosition(e);x=n.y,T||(t.cancelAnimationFrame(w),T=!0,M=E=t.getTranslate(h.wrapper[0],"y"),h.wrapper.transition(0)),e.preventDefault();var i=x-k;E=M+i,_=void 0,E<v&&(E=v-Math.pow(v-E,.8),_="min"),E>g&&(E=g+Math.pow(E-g,.8),_="max"),h.wrapper.transform("translate3d(0,"+E+"px,0)"),h.updateItems(void 0,E,0,c.params.updateValuesOnTouchmove),P=E-D||E,O=(new Date).getTime(),D=E}}function o(e){if(!y||!T)return void(y=T=!1);y=T=!1,h.wrapper.transition(""),_&&("min"===_?h.wrapper.transform("translate3d(0,"+v+"px,0)"):h.wrapper.transform("translate3d(0,"+g+"px,0)")),b=(new Date).getTime();var n,a;b-C>300?a=E:(n=Math.abs(P/(b-O)),a=E+P*c.params.momentumRatio),a=Math.max(Math.min(a,g),v);var r=-Math.floor((a-g)/f);c.params.freeMode||(a=-r*f+g),h.wrapper.transform("translate3d(0,"+parseInt(a,10)+"px,0)"),h.updateItems(r,a,"",!0),c.params.updateValuesOnMomentum&&(i(),h.wrapper.transitionEnd(function(){t.cancelAnimationFrame(w)})),setTimeout(function(){A=!0},100)}function s(e){if(A){t.cancelAnimationFrame(w);var n=t(this).attr("data-picker-value");h.setValue(n)}}var l=t(e),u=l.index(),h=c.cols[u];if(!h.divider){h.container=l,h.wrapper=h.container.find(".picker-items-col-wrapper"),h.items=h.wrapper.find(".picker-item");var d,f,m,v,g;h.replaceValues=function(t,e){h.destroyEvents(),h.values=t,h.displayValues=e;var n=c.columnHTML(h,!0);h.wrapper.html(n),h.items=h.wrapper.find(".picker-item"),h.calcSize(),h.setValue(h.values[0]||"",0,!0),h.initEvents()},h.calcSize=function(){if(h.values.length){c.params.rotateEffect&&(h.container.removeClass("picker-items-col-absolute"),h.width||h.container.css({width:""}));var e,n;e=0,n=h.container[0].offsetHeight,d=h.wrapper[0].offsetHeight,f=h.items[0].offsetHeight,m=f*h.items.length,v=n/2-m+f/2,g=n/2-f/2,h.width&&(e=h.width,parseInt(e,10)===e&&(e+="px"),h.container.css({width:e})),c.params.rotateEffect&&(h.width||(h.items.each(function(){var n=t(this);n.css({width:"auto"}),e=Math.max(e,n[0].offsetWidth),n.css({width:""})}),h.container.css({width:e+2+"px"})),h.container.addClass("picker-items-col-absolute"))}},h.calcSize(),h.wrapper.transform("translate3d(0,"+g+"px,0)").transition(0);var w;h.setValue=function(e,n,a){"undefined"==typeof n&&(n="");var r=h.wrapper.find('.picker-item[data-picker-value="'+e+'"]').index();if("undefined"==typeof r||r===-1)return void(h.value=h.displayValue=e);var o=-r*f+g;h.wrapper.transition(n),h.wrapper.transform("translate3d(0,"+o+"px,0)"),c.params.updateValuesOnMomentum&&h.activeIndex&&h.activeIndex!==r&&(t.cancelAnimationFrame(w),h.wrapper.transitionEnd(function(){t.cancelAnimationFrame(w)}),i()),h.updateItems(r,o,n,a)},h.updateItems=function(e,n,i,a){"undefined"==typeof n&&(n=t.getTranslate(h.wrapper[0],"y")),"undefined"==typeof e&&(e=-Math.round((n-g)/f)),e<0&&(e=0),e>=h.items.length&&(e=h.items.length-1);var r=h.activeIndex;h.activeIndex=e,h.wrapper.find(".picker-selected").removeClass("picker-selected"),c.params.rotateEffect&&h.items.transition(i);var o=h.items.eq(e).addClass("picker-selected").transform("");if((a||"undefined"==typeof a)&&(h.value=o.attr("data-picker-value"),h.displayValue=h.displayValues?h.displayValues[e]:h.value,r!==e&&(h.onChange&&h.onChange(c,h.value,h.displayValue),c.updateValue())),c.params.rotateEffect){(n-(Math.floor((n-g)/f)*f+g))/f;h.items.each(function(){var e=t(this),i=e.index()*f,a=g-n,r=i-a,o=r/f,s=Math.ceil(h.height/f/2)+1,c=-18*o;c>180&&(c=180),c<-180&&(c=-180),Math.abs(o)>s?e.addClass("picker-item-far"):e.removeClass("picker-item-far"),e.transform("translate3d(0, "+(-n+g)+"px, "+(p?-110:0)+"px) rotateX("+c+"deg)")})}},n&&h.updateItems(0,g,0);var y,T,k,x,C,b,M,_,E,D,P,O,A=!0;h.initEvents=function(e){var n=e?"off":"on";h.container[n](t.touchEvents.start,a),h.container[n](t.touchEvents.move,r),h.container[n](t.touchEvents.end,o),h.items[n]("click",s)},h.destroyEvents=function(){h.initEvents(!0)},h.container[0].f7DestroyPickerCol=function(){h.destroyEvents()},h.initEvents()}},c.destroyPickerCol=function(e){e=t(e),"f7DestroyPickerCol"in e[0]&&e[0].f7DestroyPickerCol()},t(window).on("resize",a),c.columnHTML=function(t,e){var n="",i="";if(t.divider)i+='<div class="picker-items-col picker-items-col-divider '+(t.textAlign?"picker-items-col-"+t.textAlign:"")+" "+(t.cssClass||"")+'">'+t.content+"</div>";else{for(var a=0;a<t.values.length;a++)n+='<div class="picker-item" data-picker-value="'+t.values[a]+'">'+(t.displayValues?t.displayValues[a]:t.values[a])+"</div>";i+='<div class="picker-items-col '+(t.textAlign?"picker-items-col-"+t.textAlign:"")+" "+(t.cssClass||"")+'"><div class="picker-items-col-wrapper">'+n+"</div></div>"}return e?n:i},c.layout=function(){var t,e="",n="";c.cols=[];var i="";for(t=0;t<c.params.cols.length;t++){var a=c.params.cols[t];i+=c.columnHTML(c.params.cols[t]),c.cols.push(a)}n="weui-picker-modal picker-columns "+(c.params.cssClass||"")+(c.params.rotateEffect?" picker-3d":"")+(1===c.params.cols.length?" picker-columns-single":""),e='<div class="'+n+'">'+(c.params.toolbar?c.params.toolbarTemplate.replace(/{{closeText}}/g,c.params.toolbarCloseText).replace(/{{title}}/g,c.params.title):"")+'<div class="picker-modal-inner picker-items">'+i+'<div class="picker-center-highlight"></div></div></div>',c.pickerHTML=e},c.params.input&&(c.input=t(c.params.input),c.input.length>0&&(c.params.inputReadOnly&&c.input.prop("readOnly",!0),c.inline||c.input.on("click",r),c.params.inputReadOnly&&c.input.on("focus mousedown",function(t){t.preventDefault()}))),c.inline||t("html").on("click",o),c.opened=!1,c.open=function(){var e=n();c.opened||(c.layout(),e?(c.pickerHTML='<div class="popover popover-picker-columns"><div class="popover-inner">'+c.pickerHTML+"</div></div>",c.popover=t.popover(c.pickerHTML,c.params.input,!0),c.container=t(c.popover).find(".weui-picker-modal"),t(c.popover).on("close",function(){s()})):c.inline?(c.container=t(c.pickerHTML),c.container.addClass("picker-modal-inline"),t(c.params.container).append(c.container)):(c.container=t(t.openPicker(c.pickerHTML)),t(c.container).on("close",function(){s()})),c.container[0].f7Picker=c,c.container.find(".picker-items-col").each(function(){var t=!0;(!c.initialized&&c.params.value||c.initialized&&c.value)&&(t=!1),c.initPickerCol(this,t)}),c.initialized?c.value&&c.setValue(c.value,0):c.params.value&&c.setValue(c.params.value,0)),c.opened=!0,c.initialized=!0,c.params.onOpen&&c.params.onOpen(c)},c.close=function(e){if(c.opened&&!c.inline)return i()?void t.closePicker(c.popover):void t.closePicker(c.container)},c.destroy=function(){c.close(),c.params.input&&c.input.length>0&&(c.input.off("click focus",r),t(c.input).data("picker",null)),t("html").off("click",o),t(window).off("resize",a)},c.inline&&c.open(),c};t(document).on("click",".close-picker",function(){var e=t(".weui-picker-modal.weui-picker-modal-visible");e.length>0&&t.closePicker(e)}),t(document).on(t.touchEvents.move,".picker-modal-inner",function(t){t.preventDefault()}),t.openPicker=function(e,n,i){"function"==typeof n&&(i=n,n=void 0),t.closePicker();var a=t("<div class='weui-picker-container "+(n||"")+"'></div>").appendTo(document.body);a.show(),a.addClass("weui-picker-container-visible");var r=t(e).appendTo(a);return r.width(),r.addClass("weui-picker-modal-visible"),i&&a.on("close",i),r},t.updatePicker=function(e){var n=t(".weui-picker-container-visible");if(!n[0])return!1;n.html("");var i=t(e).appendTo(n);return i.addClass("weui-picker-modal-visible"),i},t.closePicker=function(e,n){"function"==typeof e&&(n=e),t(".weui-picker-modal-visible").removeClass("weui-picker-modal-visible").transitionEnd(function(){t(this).parent().remove(),n&&n()}).trigger("close")},t.fn.picker=function(n){var i=arguments;return this.each(function(){if(this){var a=t(this),r=a.data("picker");if(!r){n=t.extend({input:this},n||{});var o=a.val();void 0===n.value&&""!==o&&(n.value=n.cols&&n.cols.length>1?o.split(" "):[o]);var s=t.extend({input:this},n);r=new e(s),a.data("picker",r)}"string"==typeof n&&r[n].apply(r,Array.prototype.slice.call(i,1))}})}}($),+function(t){"use strict";var e,n=[],i=function(e,i){this.config=i,this.data={values:"",titles:"",origins:[],length:0},this.$input=t(e),this.$input.prop("readOnly",!0),this.initConfig(),i=this.config,this.$input.click(t.proxy(this.open,this)),n.push(this)};i.prototype.initConfig=function(){this.config=t.extend({},e,this.config);var n=this.config;n.items&&n.items.length&&(n.items=n.items.map(function(t,e){return"string"==typeof t?{title:t,value:t}:t}),this.tpl=t.t7.compile("<div class='weui-picker-modal weui-select-modal'>"+n.toolbarTemplate+(n.multi?n.checkboxTemplate:n.radioTemplate)+"</div>"),void 0!==n.input&&this.$input.val(n.input),this.parseInitValue(),this._init=!0)},i.prototype.updateInputValue=function(t,e){var n,i;this.config.multi?(n=t.join(this.config.split),i=e.join(this.config.split)):(n=t[0],i=e[0]);var a=[];this.config.items.forEach(function(e){t.each(function(t,n){e.value==n&&a.push(e)})}),this.$input.val(i).data("values",n),this.$input.attr("value",i).attr("data-values",n);var r={values:n,titles:i,valuesArray:t,titlesArray:e,origins:a,length:a.length};this.data=r,this.$input.trigger("change",r),this.config.onChange&&this.config.onChange.call(this,r)},i.prototype.parseInitValue=function(){var t=this.$input.val(),e=this.config.items;if(this._init||void 0!==t&&null!=t&&""!==t)for(var n=this.config.multi?t.split(this.config.split):[t],i=0;i<e.length;i++){e[i].checked=!1;for(var a=0;a<n.length;a++)e[i].title===n[a]&&(e[i].checked=!0)}},i.prototype._bind=function(e){var n=this,i=this.config;e.on("change",function(a){var r=e.find("input:checked"),o=r.map(function(){return t(this).val()}),s=r.map(function(){return t(this).data("title")});n.updateInputValue(o,s),i.autoClose&&!i.multi&&n.close()}).trigger("change").on("click",".close-select",function(){n.close()})},i.prototype.update=function(e){this.config=t.extend({},this.config,e),this.initConfig(),this._open&&this._bind(t.updatePicker(this.getHTML()))},i.prototype.open=function(e,i){if(!this._open){for(var a=0;a<n.length;a++){var r=n[a];if(r!==this&&r._open&&!r.close())return!1}this.parseInitValue();var o=this.config,s=this.dialog=t.openPicker(this.getHTML());this._bind(s),this._open=!0,o.onOpen&&o.onOpen(this)}},i.prototype.close=function(e,n){if(!this._open)return!1;var i=this,a=this.config.beforeClose;if(!n){if(a&&"function"==typeof a&&a.call(this,this.data.values,this.data.titles)===!1)return!1;if(this.config.multi){if(void 0!==this.config.min&&this.data.length<this.config.min)return t.toast("请至少选择"+this.config.min+"个","text"),!1;if(void 0!==this.config.max&&this.data.length>this.config.max)return t.toast("最多只能选择"+this.config.max+"个","text"),!1}}return t.closePicker(function(){i.onClose(),e&&e()}),!0},i.prototype.onClose=function(){this._open=!1,this.config.onClose&&this.config.onClose(this)},i.prototype.getHTML=function(t){var e=this.config;return this.tpl({items:e.items,title:e.title,closeText:e.closeText})},t.fn.select=function(e,n){return this.each(function(){var a=t(this);a.data("weui-select")||a.data("weui-select",new i(this,e));var r=a.data("weui-select");return"string"==typeof e&&r[e].call(r,n),r})},e=t.fn.select.prototype.defaults={items:[],input:void 0,title:"请选择",multi:!1,closeText:"确定",autoClose:!0,onChange:void 0,beforeClose:void 0,onClose:void 0,onOpen:void 0,split:",",min:void 0,max:void 0,toolbarTemplate:'<div class="toolbar">      <div class="toolbar-inner">      <a href="javascript:;" class="picker-button close-select">{{closeText}}</a>      <h1 class="title">{{title}}</h1>      </div>      </div>',radioTemplate:'<div class="weui-cells weui-cells_radio">        {{#items}}        <label class="weui-cell weui-check_label" for="weui-select-id-{{this.title}}">          <div class="weui-cell__bd weui-cell_primary">            <p>{{this.title}}</p>          </div>          <div class="weui-cell__ft">            <input type="radio" class="weui-check" name="weui-select" id="weui-select-id-{{this.title}}" value="{{this.value}}" {{#if this.checked}}checked="checked"{{/if}} data-title="{{this.title}}">            <span class="weui-icon-checked"></span>          </div>        </label>        {{/items}}      </div>',checkboxTemplate:'<div class="weui-cells weui-cells_checkbox">        {{#items}}        <label class="weui-cell weui-check_label" for="weui-select-id-{{this.title}}">          <div class="weui-cell__bd weui-cell_primary">            <p>{{this.title}}</p>          </div>          <div class="weui-cell__ft">            <input type="checkbox" class="weui-check" name="weui-select" id="weui-select-id-{{this.title}}" value="{{this.value}}" {{#if this.checked}}checked="checked"{{/if}} data-title="{{this.title}}" >            <span class="weui-icon-checked"></span>          </div>        </label>        {{/items}}      </div>'}}($),+function(t){"use strict";var e,n=!1,i=function(t,e){var t=new Date(t),e=new Date(e);return t.getFullYear()===e.getFullYear()&&t.getMonth()===e.getMonth()&&t.getDate()===e.getDate()},a=function(a){function r(){var e=!1;return p.params.convertToPopover||p.params.onlyInPopover?(!p.inline&&p.params.input&&(p.params.onlyInPopover?e=!0:t.device.ios?e=!!t.device.ipad:t(window).width()>=768&&(e=!0)),e):e}function o(){return!!(p.opened&&p.container&&p.container.length>0&&p.container.parents(".popover").length>0)}function s(t){t=new Date(t);var e=t.getFullYear(),n=t.getMonth(),i=n+1,a=t.getDate(),r=t.getDay();return p.params.dateFormat.replace(/yyyy/g,e).replace(/yy/g,(e+"").substring(2)).replace(/mm/g,i<10?"0"+i:i).replace(/m/g,i).replace(/MM/g,p.params.monthNames[n]).replace(/M/g,p.params.monthNamesShort[n]).replace(/dd/g,a<10?"0"+a:a).replace(/d/g,a).replace(/DD/g,p.params.dayNames[r]).replace(/D/g,p.params.dayNamesShort[r])}function c(t){if(t.preventDefault(),!p.opened&&(p.open(),p.params.scrollToInput&&!r())){var e=p.input.parents(".page-content");if(0===e.length)return;var n,i=parseInt(e.css("padding-top"),10),a=parseInt(e.css("padding-bottom"),10),o=e[0].offsetHeight-i-p.container.height(),s=e[0].scrollHeight-i-p.container.height(),c=p.input.offset().top-i+p.input[0].offsetHeight;if(c>o){var l=e.scrollTop()+c-o;l+o>s&&(n=l+o-s+a,o===s&&(n=p.container.height()),e.css({"padding-bottom":n+"px"})),e.scrollTop(l,300)}}}function l(e){o()||(p.input&&p.input.length>0?e.target!==p.input[0]&&0===t(e.target).parents(".weui-picker-modal").length&&p.close():0===t(e.target).parents(".weui-picker-modal").length&&p.close())}function u(){p.opened=!1,p.input&&p.input.length>0&&p.input.parents(".page-content").css({"padding-bottom":""}),p.params.onClose&&p.params.onClose(p),p.destroyCalendarEvents()}var p=this;a=a||{};for(var h in e)"undefined"==typeof a[h]&&(a[h]=e[h]);p.params=a,p.initialized=!1,p.inline=!!p.params.container,p.isH="horizontal"===p.params.direction;var d=p.isH&&n?-1:1;return p.animating=!1,p.addValue=function(t){if(p.params.multiple){p.value||(p.value=[]);for(var e,n=0;n<p.value.length;n++)i(t,p.value[n])&&(e=n);"undefined"==typeof e?p.value.push(t):p.value.splice(e,1),p.updateValue()}else p.value=[t],p.updateValue()},p.setValue=function(t){var e=new Date(t[0]);p.setYearMonth(e.getFullYear(),e.getMonth()),p.addValue(+e)},p.updateValue=function(){p.wrapper.find(".picker-calendar-day-selected").removeClass("picker-calendar-day-selected");var e,n;for(e=0;e<p.value.length;e++){var i=new Date(p.value[e]);p.wrapper.find('.picker-calendar-day[data-date="'+i.getFullYear()+"-"+i.getMonth()+"-"+i.getDate()+'"]').addClass("picker-calendar-day-selected")}if(p.params.onChange&&p.params.onChange(p,p.value.map(s),p.value.map(function(t){return+new Date("string"==typeof t?t.split(/\D/).filter(function(t){return!!t}).join("-"):t)})),p.input&&p.input.length>0){if(p.params.formatValue)n=p.params.formatValue(p,p.value);else{for(n=[],e=0;e<p.value.length;e++)n.push(s(p.value[e]));n=n.join(", ")}t(p.input).val(n),t(p.input).trigger("change")}},p.initCalendarEvents=function(){function e(e){if(!s&&!o){o=!0;var n=t.getTouchPosition(e);c=h=n.x,l=h=n.y,f=(new Date).getTime(),T=0,C=!0,x=void 0,v=g=p.monthsTranslate}}function i(e){if(o){var n=t.getTouchPosition(e);if(u=n.x,h=n.y,"undefined"==typeof x&&(x=!!(x||Math.abs(h-l)>Math.abs(u-c))),p.isH&&x)return void(o=!1);if(e.preventDefault(),p.animating)return void(o=!1);C=!1,s||(s=!0,w=p.wrapper[0].offsetWidth,y=p.wrapper[0].offsetHeight,p.wrapper.transition(0)),e.preventDefault(),k=p.isH?u-c:h-l,T=k/(p.isH?w:y),g=100*(p.monthsTranslate*d+T),p.wrapper.transform("translate3d("+(p.isH?g:0)+"%, "+(p.isH?0:g)+"%, 0)")}}function a(t){return o&&s?(o=s=!1,m=(new Date).getTime(),m-f<300?Math.abs(k)<10?p.resetMonth():k>=10?n?p.nextMonth():p.prevMonth():n?p.prevMonth():p.nextMonth():T<=-.5?n?p.prevMonth():p.nextMonth():T>=.5?n?p.nextMonth():p.prevMonth():p.resetMonth(),void setTimeout(function(){C=!0},100)):void(o=s=!1)}function r(e){if(C){var n=t(e.target).parents(".picker-calendar-day");if(0===n.length&&t(e.target).hasClass("picker-calendar-day")&&(n=t(e.target)),0!==n.length&&!n.hasClass("picker-calendar-day-disabled")){n.hasClass("picker-calendar-day-next")&&p.nextMonth(),n.hasClass("picker-calendar-day-prev")&&p.prevMonth();var i=n.attr("data-year"),a=n.attr("data-month"),r=n.attr("data-day");p.params.onDayClick&&p.params.onDayClick(p,n[0],i,a,r),p.addValue(new Date(i,a,r).getTime()),p.params.closeOnSelect&&!p.params.multiple&&p.close()}}}var o,s,c,l,u,h,f,m,v,g,w,y,T,k,x,C=!0;p.container.find(".picker-calendar-prev-month").on("click",p.prevMonth),p.container.find(".picker-calendar-next-month").on("click",p.nextMonth),p.container.find(".picker-calendar-prev-year").on("click",p.prevYear),p.container.find(".picker-calendar-next-year").on("click",p.nextYear),p.wrapper.on("click",r),p.params.touchMove&&(p.wrapper.on(t.touchEvents.start,e),p.wrapper.on(t.touchEvents.move,i),p.wrapper.on(t.touchEvents.end,a)),p.container[0].f7DestroyCalendarEvents=function(){p.container.find(".picker-calendar-prev-month").off("click",p.prevMonth),p.container.find(".picker-calendar-next-month").off("click",p.nextMonth),p.container.find(".picker-calendar-prev-year").off("click",p.prevYear),p.container.find(".picker-calendar-next-year").off("click",p.nextYear),p.wrapper.off("click",r),p.params.touchMove&&(p.wrapper.off(t.touchEvents.start,e),p.wrapper.off(t.touchEvents.move,i),p.wrapper.off(t.touchEvents.end,a))}},p.destroyCalendarEvents=function(t){"f7DestroyCalendarEvents"in p.container[0]&&p.container[0].f7DestroyCalendarEvents()},p.daysInMonth=function(t){var e=new Date(t);return new Date(e.getFullYear(),e.getMonth()+1,0).getDate()},p.monthHTML=function(t,e){t=new Date(t);var n=t.getFullYear(),i=t.getMonth();t.getDate();"next"===e&&(t=11===i?new Date(n+1,0):new Date(n,i+1,1)),"prev"===e&&(t=0===i?new Date(n-1,11):new Date(n,i-1,1)),"next"!==e&&"prev"!==e||(i=t.getMonth(),n=t.getFullYear());var a=p.daysInMonth(new Date(t.getFullYear(),t.getMonth()).getTime()-864e6),r=p.daysInMonth(t),o=new Date(t.getFullYear(),t.getMonth()).getDay();0===o&&(o=7);var s,c,l,u=[],h=6,d=7,f="",m=0+(p.params.firstDay-1),v=(new Date).setHours(0,0,0,0),g=p.params.minDate?new Date(p.params.minDate).getTime():null,w=p.params.maxDate?new Date(p.params.maxDate).getTime():null;if(p.value&&p.value.length)for(c=0;c<p.value.length;c++)u.push(new Date(p.value[c]).setHours(0,0,0,0));for(c=1;c<=h;c++){var y="";for(l=1;l<=d;l++){var T=l;m++;var k=m-o,x="";k<0?(k=a+k+1,x+=" picker-calendar-day-prev",s=new Date(i-1<0?n-1:n,i-1<0?11:i-1,k).getTime()):(k+=1,k>r?(k-=r,x+=" picker-calendar-day-next",s=new Date(i+1>11?n+1:n,i+1>11?0:i+1,k).getTime()):s=new Date(n,i,k).getTime()),s===v&&(x+=" picker-calendar-day-today"),u.indexOf(s)>=0&&(x+=" picker-calendar-day-selected"),p.params.weekendDays.indexOf(T-1)>=0&&(x+=" picker-calendar-day-weekend"),(g&&s<g||w&&s>w)&&(x+=" picker-calendar-day-disabled"),s=new Date(s);var C=s.getFullYear(),b=s.getMonth();y+='<div data-year="'+C+'" data-month="'+b+'" data-day="'+k+'" class="picker-calendar-day'+x+'" data-date="'+(C+"-"+b+"-"+k)+'"><span>'+k+"</span></div>"}f+='<div class="picker-calendar-row">'+y+"</div>"}return f='<div class="picker-calendar-month" data-year="'+n+'" data-month="'+i+'">'+f+"</div>"},p.animating=!1,p.updateCurrentMonthYear=function(t){"undefined"==typeof t?(p.currentMonth=parseInt(p.months.eq(1).attr("data-month"),10),p.currentYear=parseInt(p.months.eq(1).attr("data-year"),10)):(p.currentMonth=parseInt(p.months.eq("next"===t?p.months.length-1:0).attr("data-month"),10),p.currentYear=parseInt(p.months.eq("next"===t?p.months.length-1:0).attr("data-year"),10)),p.container.find(".current-month-value").text(p.params.monthNames[p.currentMonth]),p.container.find(".current-year-value").text(p.currentYear)},p.onMonthChangeStart=function(t){p.updateCurrentMonthYear(t),p.months.removeClass("picker-calendar-month-current picker-calendar-month-prev picker-calendar-month-next");var e="next"===t?p.months.length-1:0;p.months.eq(e).addClass("picker-calendar-month-current"),p.months.eq("next"===t?e-1:e+1).addClass("next"===t?"picker-calendar-month-prev":"picker-calendar-month-next"),p.params.onMonthYearChangeStart&&p.params.onMonthYearChangeStart(p,p.currentYear,p.currentMonth)},p.onMonthChangeEnd=function(t,e){p.animating=!1;var n,i,a;p.wrapper.find(".picker-calendar-month:not(.picker-calendar-month-prev):not(.picker-calendar-month-current):not(.picker-calendar-month-next)").remove(),"undefined"==typeof t&&(t="next",e=!0),e?(p.wrapper.find(".picker-calendar-month-next, .picker-calendar-month-prev").remove(),i=p.monthHTML(new Date(p.currentYear,p.currentMonth),"prev"),n=p.monthHTML(new Date(p.currentYear,p.currentMonth),"next")):a=p.monthHTML(new Date(p.currentYear,p.currentMonth),t),("next"===t||e)&&p.wrapper.append(a||n),("prev"===t||e)&&p.wrapper.prepend(a||i),p.months=p.wrapper.find(".picker-calendar-month"),p.setMonthsTranslate(p.monthsTranslate),p.params.onMonthAdd&&p.params.onMonthAdd(p,"next"===t?p.months.eq(p.months.length-1)[0]:p.months.eq(0)[0]),p.params.onMonthYearChangeEnd&&p.params.onMonthYearChangeEnd(p,p.currentYear,p.currentMonth)},p.setMonthsTranslate=function(t){t=t||p.monthsTranslate||0,"undefined"==typeof p.monthsTranslate&&(p.monthsTranslate=t),p.months.removeClass("picker-calendar-month-current picker-calendar-month-prev picker-calendar-month-next");var e=100*-(t+1)*d,n=100*-t*d,i=100*-(t-1)*d;p.months.eq(0).transform("translate3d("+(p.isH?e:0)+"%, "+(p.isH?0:e)+"%, 0)").addClass("picker-calendar-month-prev"),p.months.eq(1).transform("translate3d("+(p.isH?n:0)+"%, "+(p.isH?0:n)+"%, 0)").addClass("picker-calendar-month-current"),p.months.eq(2).transform("translate3d("+(p.isH?i:0)+"%, "+(p.isH?0:i)+"%, 0)").addClass("picker-calendar-month-next")},p.nextMonth=function(e){"undefined"!=typeof e&&"object"!=typeof e||(e="",p.params.animate||(e=0));var n=parseInt(p.months.eq(p.months.length-1).attr("data-month"),10),i=parseInt(p.months.eq(p.months.length-1).attr("data-year"),10),a=new Date(i,n),r=a.getTime(),o=!p.animating;if(p.params.maxDate&&r>new Date(p.params.maxDate).getTime())return p.resetMonth();if(p.monthsTranslate--,n===p.currentMonth){var s=100*-p.monthsTranslate*d,c=t(p.monthHTML(r,"next")).transform("translate3d("+(p.isH?s:0)+"%, "+(p.isH?0:s)+"%, 0)").addClass("picker-calendar-month-next");p.wrapper.append(c[0]),p.months=p.wrapper.find(".picker-calendar-month"),p.params.onMonthAdd&&p.params.onMonthAdd(p,p.months.eq(p.months.length-1)[0])}p.animating=!0,p.onMonthChangeStart("next");var l=100*p.monthsTranslate*d;p.wrapper.transition(e).transform("translate3d("+(p.isH?l:0)+"%, "+(p.isH?0:l)+"%, 0)"),o&&p.wrapper.transitionEnd(function(){p.onMonthChangeEnd("next")}),p.params.animate||p.onMonthChangeEnd("next")},p.prevMonth=function(e){"undefined"!=typeof e&&"object"!=typeof e||(e="",p.params.animate||(e=0));var n=parseInt(p.months.eq(0).attr("data-month"),10),i=parseInt(p.months.eq(0).attr("data-year"),10),a=new Date(i,n+1,(-1)),r=a.getTime(),o=!p.animating;if(p.params.minDate&&r<new Date(p.params.minDate).getTime())return p.resetMonth();if(p.monthsTranslate++,n===p.currentMonth){var s=100*-p.monthsTranslate*d,c=t(p.monthHTML(r,"prev")).transform("translate3d("+(p.isH?s:0)+"%, "+(p.isH?0:s)+"%, 0)").addClass("picker-calendar-month-prev");p.wrapper.prepend(c[0]),p.months=p.wrapper.find(".picker-calendar-month"),p.params.onMonthAdd&&p.params.onMonthAdd(p,p.months.eq(0)[0])}p.animating=!0,p.onMonthChangeStart("prev");var l=100*p.monthsTranslate*d;p.wrapper.transition(e).transform("translate3d("+(p.isH?l:0)+"%, "+(p.isH?0:l)+"%, 0)"),o&&p.wrapper.transitionEnd(function(){p.onMonthChangeEnd("prev")}),p.params.animate||p.onMonthChangeEnd("prev")},p.resetMonth=function(t){"undefined"==typeof t&&(t="");var e=100*p.monthsTranslate*d;p.wrapper.transition(t).transform("translate3d("+(p.isH?e:0)+"%, "+(p.isH?0:e)+"%, 0)")},p.setYearMonth=function(t,e,n){"undefined"==typeof t&&(t=p.currentYear),"undefined"==typeof e&&(e=p.currentMonth),"undefined"!=typeof n&&"object"!=typeof n||(n="",p.params.animate||(n=0));var i;if(i=t<p.currentYear?new Date(t,e+1,(-1)).getTime():new Date(t,e).getTime(),p.params.maxDate&&i>new Date(p.params.maxDate).getTime())return!1;if(p.params.minDate&&i<new Date(p.params.minDate).getTime())return!1;var a=new Date(p.currentYear,p.currentMonth).getTime(),r=i>a?"next":"prev",o=p.monthHTML(new Date(t,e));p.monthsTranslate=p.monthsTranslate||0;var s,c,l=p.monthsTranslate,u=!p.animating;i>a?(p.monthsTranslate--,p.animating||p.months.eq(p.months.length-1).remove(),p.wrapper.append(o),p.months=p.wrapper.find(".picker-calendar-month"),s=100*-(l-1)*d,p.months.eq(p.months.length-1).transform("translate3d("+(p.isH?s:0)+"%, "+(p.isH?0:s)+"%, 0)").addClass("picker-calendar-month-next")):(p.monthsTranslate++,p.animating||p.months.eq(0).remove(),p.wrapper.prepend(o),p.months=p.wrapper.find(".picker-calendar-month"),s=100*-(l+1)*d,p.months.eq(0).transform("translate3d("+(p.isH?s:0)+"%, "+(p.isH?0:s)+"%, 0)").addClass("picker-calendar-month-prev")),p.params.onMonthAdd&&p.params.onMonthAdd(p,"next"===r?p.months.eq(p.months.length-1)[0]:p.months.eq(0)[0]),p.animating=!0,p.onMonthChangeStart(r),c=100*p.monthsTranslate*d,p.wrapper.transition(n).transform("translate3d("+(p.isH?c:0)+"%, "+(p.isH?0:c)+"%, 0)"),u&&p.wrapper.transitionEnd(function(){p.onMonthChangeEnd(r,!0)}),p.params.animate||p.onMonthChangeEnd(r)},p.nextYear=function(){p.setYearMonth(p.currentYear+1)},p.prevYear=function(){p.setYearMonth(p.currentYear-1)},p.layout=function(){var t,e="",n="",i=p.value&&p.value.length?p.value[0]:(new Date).setHours(0,0,0,0),a=p.monthHTML(i,"prev"),r=p.monthHTML(i),o=p.monthHTML(i,"next"),s='<div class="picker-calendar-months"><div class="picker-calendar-months-wrapper">'+(a+r+o)+"</div></div>",c="";if(p.params.weekHeader){for(t=0;t<7;t++){var l=t+p.params.firstDay>6?t-7+p.params.firstDay:t+p.params.firstDay,u=p.params.dayNamesShort[l];c+='<div class="picker-calendar-week-day '+(p.params.weekendDays.indexOf(l)>=0?"picker-calendar-week-day-weekend":"")+'"> '+u+"</div>"}c='<div class="picker-calendar-week-days">'+c+"</div>"}n="weui-picker-calendar "+(p.params.cssClass||""),p.inline||(n="weui-picker-modal "+n);var h=p.params.toolbar?p.params.toolbarTemplate.replace(/{{closeText}}/g,p.params.toolbarCloseText):"";p.params.toolbar&&(h=p.params.toolbarTemplate.replace(/{{closeText}}/g,p.params.toolbarCloseText).replace(/{{monthPicker}}/g,p.params.monthPicker?p.params.monthPickerTemplate:"").replace(/{{yearPicker}}/g,p.params.yearPicker?p.params.yearPickerTemplate:"")),e='<div class="'+n+'">'+h+'<div class="picker-modal-inner">'+c+s+"</div></div>",p.pickerHTML=e},p.params.input&&(p.input=t(p.params.input),p.input.length>0&&(p.params.inputReadOnly&&p.input.prop("readOnly",!0),p.inline||p.input.on("click",c),p.params.inputReadOnly&&p.input.on("focus mousedown",function(t){t.preventDefault()}))),p.inline||t(document).on("click touchend",l),p.opened=!1,p.open=function(){var e=r()&&!1,n=!1;p.opened||(p.value||p.params.value&&(p.value=p.params.value,n=!0),p.layout(),e?(p.pickerHTML='<div class="popover popover-picker-calendar"><div class="popover-inner">'+p.pickerHTML+"</div></div>",p.popover=t.popover(p.pickerHTML,p.params.input,!0),p.container=t(p.popover).find(".weui-picker-modal"),
+t(p.popover).on("close",function(){u()})):p.inline?(p.container=t(p.pickerHTML),p.container.addClass("picker-modal-inline"),t(p.params.container).append(p.container)):(p.container=t(t.openPicker(p.pickerHTML)),t(p.container).on("close",function(){u()})),p.container[0].f7Calendar=p,p.wrapper=p.container.find(".picker-calendar-months-wrapper"),p.months=p.wrapper.find(".picker-calendar-month"),p.updateCurrentMonthYear(),p.monthsTranslate=0,p.setMonthsTranslate(),p.initCalendarEvents(),n&&p.updateValue()),p.opened=!0,p.initialized=!0,p.params.onMonthAdd&&p.months.each(function(){p.params.onMonthAdd(p,this)}),p.params.onOpen&&p.params.onOpen(p)},p.close=function(){if(p.opened&&!p.inline)return p.animating=!1,o()?void t.closePicker(p.popover):void t.closePicker(p.container)},p.destroy=function(){p.close(),p.params.input&&p.input.length>0&&(p.input.off("click focus",c),p.input.data("calendar",null)),t("html").off("click",l)},p.inline&&p.open(),p},r=function(t){return t<10?"0"+t:t};t.fn.calendar=function(e,n){return e=e||{},this.each(function(){var i=t(this);if(i[0]){var o={};"INPUT"===i[0].tagName.toUpperCase()?o.input=i:o.container=i;var s=i.data("calendar");if(!s)if("string"==typeof e);else{if(!e.value&&i.val()&&(e.value=[i.val()]),!e.value){var c=new Date;e.value=[c.getFullYear()+"/"+r(c.getMonth()+1)+"/"+r(c.getDate())]}s=i.data("calendar",new a(t.extend(o,e)))}"string"==typeof e&&s[e].call(s,n)}})},e=t.fn.calendar.prototype.defaults={value:void 0,monthNames:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],monthNamesShort:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],dayNames:["周日","周一","周二","周三","周四","周五","周六"],dayNamesShort:["周日","周一","周二","周三","周四","周五","周六"],firstDay:1,weekendDays:[0,6],multiple:!1,dateFormat:"yyyy/mm/dd",direction:"horizontal",minDate:null,maxDate:null,touchMove:!0,animate:!0,closeOnSelect:!0,monthPicker:!0,monthPickerTemplate:'<div class="picker-calendar-month-picker"><a href="javascript:;" class="link icon-only picker-calendar-prev-month"><i class="icon icon-prev"></i></a><div class="current-month-value"></div><a href="javascript:;" class="link icon-only picker-calendar-next-month"><i class="icon icon-next"></i></a></div>',yearPicker:!0,yearPickerTemplate:'<div class="picker-calendar-year-picker"><a href="javascript:;" class="link icon-only picker-calendar-prev-year"><i class="icon icon-prev"></i></a><span class="current-year-value"></span><a href="javascript:;" class="link icon-only picker-calendar-next-year"><i class="icon icon-next"></i></a></div>',weekHeader:!0,scrollToInput:!0,inputReadOnly:!0,convertToPopover:!0,onlyInPopover:!1,toolbar:!0,toolbarCloseText:"Done",toolbarTemplate:'<div class="toolbar"><div class="toolbar-inner">{{yearPicker}}{{monthPicker}}</div></div>'}}($),+function(t){"use strict";var e,n=function(t){return t<10?"0"+t:t},i=function(e,n){this.input=t(e),this.params=n||{},this.initMonthes=n.monthes,this.initYears=n.years;var i=t.extend({},n,this.getConfig());t(this.input).picker(i)};i.prototype={getDays:function(t){for(var e=[],n=1;n<=(t||31);n++)e.push(n<10?"0"+n:n);return e},getDaysByMonthAndYear:function(t,e){var n=new Date(e,parseInt(t)+1-1,1),i=new Date(n-1);return this.getDays(i.getDate())},getConfig:function(){var t,e=new Date,i=this.params,a=this,r={rotateEffect:!1,cssClass:"datetime-picker",value:[e.getFullYear(),n(e.getMonth()+1),n(e.getDate()),n(e.getHours()),n(e.getMinutes())],onChange:function(e,n,r){var o=(e.cols,a.getDaysByMonthAndYear(n[1],n[0])),s=n[2];s>o.length&&(s=o.length),e.cols[4].setValue(s);var c=new Date(n[0]+"-"+n[1]+"-"+n[2]),l=!0;if(i.min){var u=new Date("function"==typeof i.min?i.min():i.min);c<+u&&(e.setValue(t),l=!1)}if(i.max){var p=new Date("function"==typeof i.max?i.max():i.max);c>+p&&(e.setValue(t),l=!1)}l&&(t=n),a.params.onChange&&a.params.onChange.apply(this,arguments)},formatValue:function(t,e,n){return a.params.format(t,e,n)},cols:[{values:this.initYears},{divider:!0,content:i.yearSplit},{values:this.initMonthes},{divider:!0,content:i.monthSplit},{values:function(){for(var t=[],e=1;e<=31;e++)t.push(n(e));return t}()}]};i.dateSplit&&r.cols.push({divider:!0,content:i.dateSplit}),r.cols.push({divider:!0,content:i.datetimeSplit});var o=a.params.times();o&&o.length&&(r.cols=r.cols.concat(o));var s=this.input.val();return s&&(r.value=i.parse(s)),this.params.value&&(this.input.val(this.params.value),r.value=i.parse(this.params.value)),r}},t.fn.datetimePicker=function(n){return n=t.extend({},e,n),this.each(function(){if(this){var e=t(this),a=e.data("datetime");return a||e.data("datetime",new i(this,n)),a}})},e=t.fn.datetimePicker.prototype.defaults={input:void 0,min:void 0,max:void 0,yearSplit:"-",monthSplit:"-",dateSplit:"",datetimeSplit:" ",monthes:"01 02 03 04 05 06 07 08 09 10 11 12".split(" "),years:function(){for(var t=[],e=1950;e<=2030;e++)t.push(e);return t}(),times:function(){return[{values:function(){for(var t=[],e=0;e<24;e++)t.push(n(e));return t}()},{divider:!0,content:":"},{values:function(){for(var t=[],e=0;e<60;e++)t.push(n(e));return t}()}]},format:function(t,e){return t.cols.map(function(t){return t.value||t.content}).join("")},parse:function(t){var e=t.split(this.datetimeSplit);return e[0].split(/\D/).concat(e[1].split(/:|时|分|秒/)).filter(function(t){return!!t})}}}($),+function(t){"use strict";t.openPopup=function(e,n){t.closePopup(),e=t(e),e.show(),e.width(),e.addClass("weui-popup__container--visible");var i=e.find(".weui-popup__modal");i.width(),i.transitionEnd(function(){i.trigger("open")})},t.closePopup=function(e,n){e=t(e||".weui-popup__container--visible"),e.find(".weui-popup__modal").transitionEnd(function(){var i=t(this);i.trigger("close"),e.hide(),n&&e.remove()}),e.removeClass("weui-popup__container--visible")},t(document).on("click",".close-popup, .weui-popup__overlay",function(){t.closePopup()}).on("click",".open-popup",function(){t(t(this).data("target")).popup()}).on("click",".weui-popup__container",function(e){t(e.target).hasClass("weui-popup__container")&&t.closePopup()}),t.fn.popup=function(){return this.each(function(){t.openPopup(this)})}}($),+function(t){"use strict";var e,n,i,a,r,o,s=function(n){var i=t.getTouchPosition(n);a=i,r=o=0,e.addClass("touching")},c=function(n){if(!a)return!1;n.preventDefault(),n.stopPropagation();var i=t.getTouchPosition(n);r=i.x-a.x,o=i.y-a.y,o>0&&(o=Math.sqrt(o)),e.css("transform","translate3d(0, "+o+"px, 0)")},l=function(){e.removeClass("touching"),e.attr("style",""),o<0&&Math.abs(o)>.38*e.height()&&t.closeNotification(),Math.abs(r)<=1&&Math.abs(o)<=1&&e.trigger("noti-click"),a=!1},u=function(e){e.on(t.touchEvents.start,s),e.on(t.touchEvents.move,c),e.on(t.touchEvents.end,l)};t.notification=t.noti=function(a){a=t.extend({},n,a),e=t(".weui-notification"),e[0]||(e=t('<div class="weui-notification"></div>').appendTo(document.body),u(e)),e.off("noti-click"),a.onClick&&e.on("noti-click",function(){a.onClick(a.data)}),e.html(t.t7.compile(a.tpl)(a)),e.show(),e.addClass("weui-notification--in"),e.data("params",a);var r=function(){i&&(clearTimeout(i),i=null),i=setTimeout(function(){e.hasClass("weui-notification--touching")?r():t.closeNotification()},a.time)};r()},t.closeNotification=function(){i&&clearTimeout(i),i=null;var e=t(".weui-notification").removeClass("weui-notification--in").transitionEnd(function(){t(this).remove()});if(e[0]){var n=t(".weui-notification").data("params");n&&n.onClose&&n.onClose(n.data)}},n=t.noti.prototype.defaults={title:void 0,text:void 0,media:void 0,time:4e3,onClick:void 0,onClose:void 0,data:void 0,tpl:'<div class="weui-notification__inner">{{#if media}}<div class="weui-notification__media">{{media}}</div>{{/if}}<div class="weui-notification__content">{{#if title}}<div class="weui-notification__title">{{title}}</div>{{/if}}{{#if text}}<div class="weui-notification__text">{{text}}</div>{{/if}}</div><div class="weui-notification__handle-bar"></div></div>'}}($),+function(t){"use strict";var e;t.toptip=function(n,i,a){if(n){"string"==typeof i&&(a=i,i=void 0),i=i||3e3;var r=a?"bg-"+a:"bg-danger",o=t(".weui-toptips").remove();o=t('<div class="weui-toptips"></div>').appendTo(document.body),o.html(n),o[0].className="weui-toptips "+r,clearTimeout(e),o.hasClass("weui-toptips_visible")||(o.show().width(),o.addClass("weui-toptips_visible")),e=setTimeout(function(){o.removeClass("weui-toptips_visible").transitionEnd(function(){o.remove()})},i)}}}($),+function(t){"use strict";var e=function(e,n){this.container=t(e),this.handler=this.container.find(".weui-slider__handler"),this.track=this.container.find(".weui-slider__track"),this.value=this.container.find(".weui-slider-box__value"),this.bind(),"function"==typeof n&&(this.callback=n)};e.prototype.bind=function(){this.container.on(t.touchEvents.start,t.proxy(this.touchStart,this)).on(t.touchEvents.end,t.proxy(this.touchEnd,this)),t(document.body).on(t.touchEvents.move,t.proxy(this.touchMove,this))},e.prototype.touchStart=function(e){e.preventDefault(),this.start=t.getTouchPosition(e),this.width=this.container.find(".weui-slider__inner").width(),this.left=parseInt(this.container.find(".weui-slider__handler").css("left")),this.touching=!0},e.prototype.touchMove=function(e){if(!this.touching)return!0;var n=t.getTouchPosition(e),i=n.x-this.start.x,a=i+this.left,r=parseInt(a/this.width*100);r<0&&(r=0),r>100&&(r=100),this.handler.css("left",r+"%"),this.track.css("width",r+"%"),this.value.text(r),this.callback&&this.callback.call(this,r),this.container.trigger("change",r)},e.prototype.touchEnd=function(t){this.touching=!1},t.fn.slider=function(n){this.each(function(){var i=t(this),a=i.data("slider");return a?a:void i.data("slider",new e(this,n))})}}($),+function(t){"use strict";var e=[],n="swipeout-touching",i=function(n){this.container=t(n),this.mover=this.container.find(">.weui-cell__bd"),this.attachEvents(),e.push(this)};i.prototype.touchStart=function(e){var i=t.getTouchPosition(e);this.container.addClass(n),this.start=i,this.startX=0,this.startTime=+new Date;var a=this.mover.css("transform").match(/-?[\d\.]+/g);a&&a.length&&(this.startX=parseInt(a[4])),this.diffX=this.diffY=0,this._closeOthers(),this.limit=this.container.find(">.weui-cell__ft").width()||68},i.prototype.touchMove=function(e){if(!this.start)return!0;var n=t.getTouchPosition(e);if(this.diffX=n.x-this.start.x,this.diffY=n.y-this.start.y,Math.abs(this.diffX)<Math.abs(this.diffY))return this.close(),this.start=!1,!0;e.preventDefault(),e.stopPropagation();var i=this.diffX+this.startX;i>0&&(i=0),Math.abs(i)>this.limit&&(i=-(Math.pow(-(i+this.limit),.7)+this.limit)),this.mover.css("transform","translate3d("+i+"px, 0, 0)")},i.prototype.touchEnd=function(){if(!this.start)return!0;this.start=!1;var t=this.diffX+this.startX,e=new Date-this.startTime;this.diffX<-5&&e<200?this.open():this.diffX>=0&&e<200?this.close():t>0||-t<=this.limit/2?this.close():this.open()},i.prototype.close=function(){this.container.removeClass(n),this.mover.css("transform","translate3d(0, 0, 0)"),this.container.trigger("swipeout-close")},i.prototype.open=function(){this.container.removeClass(n),this._closeOthers(),this.mover.css("transform","translate3d("+-this.limit+"px, 0, 0)"),this.container.trigger("swipeout-open")},i.prototype.attachEvents=function(){var e=this.mover;e.on(t.touchEvents.start,t.proxy(this.touchStart,this)),e.on(t.touchEvents.move,t.proxy(this.touchMove,this)),e.on(t.touchEvents.end,t.proxy(this.touchEnd,this))},i.prototype._closeOthers=function(){var t=this;e.forEach(function(e){e!==t&&e.close()})};var a=function(t){return new i(t)};t.fn.swipeout=function(e){return this.each(function(){var n=t(this),i=n.data("swipeout")||a(this);n.data("swipeout",i),"string"==typeof e&&i[e]()})},t(".weui-cell_swiped").swipeout()}($);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/jquery.mobile-1.4.5.min.js b/platforms/android/app/src/main/assets/www/js/lib/jquery.mobile-1.4.5.min.js
new file mode 100755
index 0000000..5b1a9a1
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/jquery.mobile-1.4.5.min.js
@@ -0,0 +1,10 @@
+/*! jQuery Mobile 1.4.5 | Git HEADhash: 68e55e7 <> 2014-10-31T17:33:30Z | (c) 2010, 2014 jQuery Foundation, Inc. | jquery.org/license */
+
+!function(a,b,c){"function"==typeof define&&define.amd?define(["jquery"],function(d){return c(d,a,b),d.mobile}):c(a.jQuery,a,b)}(this,document,function(a,b,c){!function(a){a.mobile={}}(a),function(a,b){function d(b,c){var d,f,g,h=b.nodeName.toLowerCase();return"area"===h?(d=b.parentNode,f=d.name,b.href&&f&&"map"===d.nodeName.toLowerCase()?(g=a("img[usemap=#"+f+"]")[0],!!g&&e(g)):!1):(/input|select|textarea|button|object/.test(h)?!b.disabled:"a"===h?b.href||c:c)&&e(b)}function e(b){return a.expr.filters.visible(b)&&!a(b).parents().addBack().filter(function(){return"hidden"===a.css(this,"visibility")}).length}var f=0,g=/^ui-id-\d+$/;a.ui=a.ui||{},a.extend(a.ui,{version:"c0ab71056b936627e8a7821f03c044aec6280a40",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),a.fn.extend({focus:function(b){return function(c,d){return"number"==typeof c?this.each(function(){var b=this;setTimeout(function(){a(b).focus(),d&&d.call(b)},c)}):b.apply(this,arguments)}}(a.fn.focus),scrollParent:function(){var b;return b=a.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.css(this,"position"))&&/(auto|scroll)/.test(a.css(this,"overflow")+a.css(this,"overflow-y")+a.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(a.css(this,"overflow")+a.css(this,"overflow-y")+a.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!b.length?a(this[0].ownerDocument||c):b},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++f)})},removeUniqueId:function(){return this.each(function(){g.test(this.id)&&a(this).removeAttr("id")})}}),a.extend(a.expr[":"],{data:a.expr.createPseudo?a.expr.createPseudo(function(b){return function(c){return!!a.data(c,b)}}):function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return d(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var c=a.attr(b,"tabindex"),e=isNaN(c);return(e||c>=0)&&d(b,!e)}}),a("<a>").outerWidth(1).jquery||a.each(["Width","Height"],function(c,d){function e(b,c,d,e){return a.each(f,function(){c-=parseFloat(a.css(b,"padding"+this))||0,d&&(c-=parseFloat(a.css(b,"border"+this+"Width"))||0),e&&(c-=parseFloat(a.css(b,"margin"+this))||0)}),c}var f="Width"===d?["Left","Right"]:["Top","Bottom"],g=d.toLowerCase(),h={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){return c===b?h["inner"+d].call(this):this.each(function(){a(this).css(g,e(this,c)+"px")})},a.fn["outer"+d]=function(b,c){return"number"!=typeof b?h["outer"+d].call(this,b):this.each(function(){a(this).css(g,e(this,b,!0,c)+"px")})}}),a.fn.addBack||(a.fn.addBack=function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}),a("<a>").data("a-b","a").removeData("a-b").data("a-b")&&(a.fn.removeData=function(b){return function(c){return arguments.length?b.call(this,a.camelCase(c)):b.call(this)}}(a.fn.removeData)),a.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),a.support.selectstart="onselectstart"in c.createElement("div"),a.fn.extend({disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")},zIndex:function(d){if(d!==b)return this.css("zIndex",d);if(this.length)for(var e,f,g=a(this[0]);g.length&&g[0]!==c;){if(e=g.css("position"),("absolute"===e||"relative"===e||"fixed"===e)&&(f=parseInt(g.css("zIndex"),10),!isNaN(f)&&0!==f))return f;g=g.parent()}return 0}}),a.ui.plugin={add:function(b,c,d){var e,f=a.ui[b].prototype;for(e in d)f.plugins[e]=f.plugins[e]||[],f.plugins[e].push([c,d[e]])},call:function(a,b,c,d){var e,f=a.plugins[b];if(f&&(d||a.element[0].parentNode&&11!==a.element[0].parentNode.nodeType))for(e=0;e<f.length;e++)a.options[f[e][0]]&&f[e][1].apply(a.element,c)}}}(a),function(a,b){var d=function(b,c){var d=b.parent(),e=[],f=function(){var b=a(this),c=a.mobile.toolbar&&b.data("mobile-toolbar")?b.toolbar("option"):{position:b.attr("data-"+a.mobile.ns+"position"),updatePagePadding:b.attr("data-"+a.mobile.ns+"update-page-padding")!==!1};return!("fixed"===c.position&&c.updatePagePadding===!0)},g=d.children(":jqmData(role='header')").filter(f),h=b.children(":jqmData(role='header')"),i=d.children(":jqmData(role='footer')").filter(f),j=b.children(":jqmData(role='footer')");return 0===h.length&&g.length>0&&(e=e.concat(g.toArray())),0===j.length&&i.length>0&&(e=e.concat(i.toArray())),a.each(e,function(b,d){c-=a(d).outerHeight()}),Math.max(0,c)};a.extend(a.mobile,{window:a(b),document:a(c),keyCode:a.ui.keyCode,behaviors:{},silentScroll:function(c){"number"!==a.type(c)&&(c=a.mobile.defaultHomeScroll),a.event.special.scrollstart.enabled=!1,setTimeout(function(){b.scrollTo(0,c),a.mobile.document.trigger("silentscroll",{x:0,y:c})},20),setTimeout(function(){a.event.special.scrollstart.enabled=!0},150)},getClosestBaseUrl:function(b){var c=a(b).closest(".ui-page").jqmData("url"),d=a.mobile.path.documentBase.hrefNoHash;return a.mobile.dynamicBaseEnabled&&c&&a.mobile.path.isPath(c)||(c=d),a.mobile.path.makeUrlAbsolute(c,d)},removeActiveLinkClass:function(b){!a.mobile.activeClickedLink||a.mobile.activeClickedLink.closest("."+a.mobile.activePageClass).length&&!b||a.mobile.activeClickedLink.removeClass(a.mobile.activeBtnClass),a.mobile.activeClickedLink=null},getInheritedTheme:function(a,b){for(var c,d,e=a[0],f="",g=/ui-(bar|body|overlay)-([a-z])\b/;e&&(c=e.className||"",!(c&&(d=g.exec(c))&&(f=d[2])));)e=e.parentNode;return f||b||"a"},enhanceable:function(a){return this.haveParents(a,"enhance")},hijackable:function(a){return this.haveParents(a,"ajax")},haveParents:function(b,c){if(!a.mobile.ignoreContentEnabled)return b;var d,e,f,g,h,i=b.length,j=a();for(g=0;i>g;g++){for(e=b.eq(g),f=!1,d=b[g];d;){if(h=d.getAttribute?d.getAttribute("data-"+a.mobile.ns+c):"","false"===h){f=!0;break}d=d.parentNode}f||(j=j.add(e))}return j},getScreenHeight:function(){return b.innerHeight||a.mobile.window.height()},resetActivePageHeight:function(b){var c=a("."+a.mobile.activePageClass),e=c.height(),f=c.outerHeight(!0);b=d(c,"number"==typeof b?b:a.mobile.getScreenHeight()),c.css("min-height",""),c.height()<b&&c.css("min-height",b-(f-e))},loading:function(){var b=this.loading._widget||a(a.mobile.loader.prototype.defaultHtml).loader(),c=b.loader.apply(b,arguments);return this.loading._widget=b,c}}),a.addDependents=function(b,c){var d=a(b),e=d.jqmData("dependents")||a();d.jqmData("dependents",a(e).add(c))},a.fn.extend({removeWithDependents:function(){a.removeWithDependents(this)},enhanceWithin:function(){var b,c={},d=a.mobile.page.prototype.keepNativeSelector(),e=this;a.mobile.nojs&&a.mobile.nojs(this),a.mobile.links&&a.mobile.links(this),a.mobile.degradeInputsWithin&&a.mobile.degradeInputsWithin(this),a.fn.buttonMarkup&&this.find(a.fn.buttonMarkup.initSelector).not(d).jqmEnhanceable().buttonMarkup(),a.fn.fieldcontain&&this.find(":jqmData(role='fieldcontain')").not(d).jqmEnhanceable().fieldcontain(),a.each(a.mobile.widgets,function(b,f){if(f.initSelector){var g=a.mobile.enhanceable(e.find(f.initSelector));g.length>0&&(g=g.not(d)),g.length>0&&(c[f.prototype.widgetName]=g)}});for(b in c)c[b][b]();return this},addDependents:function(b){a.addDependents(this,b)},getEncodedText:function(){return a("<a>").text(this.text()).html()},jqmEnhanceable:function(){return a.mobile.enhanceable(this)},jqmHijackable:function(){return a.mobile.hijackable(this)}}),a.removeWithDependents=function(b){var c=a(b);(c.jqmData("dependents")||a()).remove(),c.remove()},a.addDependents=function(b,c){var d=a(b),e=d.jqmData("dependents")||a();d.jqmData("dependents",a(e).add(c))},a.find.matches=function(b,c){return a.find(b,null,null,c)},a.find.matchesSelector=function(b,c){return a.find(c,null,null,[b]).length>0}}(a,this),function(a){a.extend(a.mobile,{version:"1.4.5",subPageUrlKey:"ui-page",hideUrlBar:!0,keepNative:":jqmData(role='none'), :jqmData(role='nojs')",activePageClass:"ui-page-active",activeBtnClass:"ui-btn-active",focusClass:"ui-focus",ajaxEnabled:!0,hashListeningEnabled:!0,linkBindingEnabled:!0,defaultPageTransition:"fade",maxTransitionWidth:!1,minScrollBack:0,defaultDialogTransition:"pop",pageLoadErrorMessage:"Error Loading Page",pageLoadErrorMessageTheme:"a",phonegapNavigationEnabled:!1,autoInitializePage:!0,pushStateEnabled:!0,ignoreContentEnabled:!1,buttonMarkup:{hoverDelay:200},dynamicBaseEnabled:!0,pageContainer:a(),allowCrossDomainPages:!1,dialogHashKey:"&ui-state=dialog"})}(a,this),function(a,b){var c=0,d=Array.prototype.slice,e=a.cleanData;a.cleanData=function(b){for(var c,d=0;null!=(c=b[d]);d++)try{a(c).triggerHandler("remove")}catch(f){}e(b)},a.widget=function(b,c,d){var e,f,g,h,i={},j=b.split(".")[0];return b=b.split(".")[1],e=j+"-"+b,d||(d=c,c=a.Widget),a.expr[":"][e.toLowerCase()]=function(b){return!!a.data(b,e)},a[j]=a[j]||{},f=a[j][b],g=a[j][b]=function(a,b){return this._createWidget?void(arguments.length&&this._createWidget(a,b)):new g(a,b)},a.extend(g,f,{version:d.version,_proto:a.extend({},d),_childConstructors:[]}),h=new c,h.options=a.widget.extend({},h.options),a.each(d,function(b,d){return a.isFunction(d)?void(i[b]=function(){var a=function(){return c.prototype[b].apply(this,arguments)},e=function(a){return c.prototype[b].apply(this,a)};return function(){var b,c=this._super,f=this._superApply;return this._super=a,this._superApply=e,b=d.apply(this,arguments),this._super=c,this._superApply=f,b}}()):void(i[b]=d)}),g.prototype=a.widget.extend(h,{widgetEventPrefix:f?h.widgetEventPrefix||b:b},i,{constructor:g,namespace:j,widgetName:b,widgetFullName:e}),f?(a.each(f._childConstructors,function(b,c){var d=c.prototype;a.widget(d.namespace+"."+d.widgetName,g,c._proto)}),delete f._childConstructors):c._childConstructors.push(g),a.widget.bridge(b,g),g},a.widget.extend=function(c){for(var e,f,g=d.call(arguments,1),h=0,i=g.length;i>h;h++)for(e in g[h])f=g[h][e],g[h].hasOwnProperty(e)&&f!==b&&(c[e]=a.isPlainObject(f)?a.isPlainObject(c[e])?a.widget.extend({},c[e],f):a.widget.extend({},f):f);return c},a.widget.bridge=function(c,e){var f=e.prototype.widgetFullName||c;a.fn[c]=function(g){var h="string"==typeof g,i=d.call(arguments,1),j=this;return g=!h&&i.length?a.widget.extend.apply(null,[g].concat(i)):g,this.each(h?function(){var d,e=a.data(this,f);return"instance"===g?(j=e,!1):e?a.isFunction(e[g])&&"_"!==g.charAt(0)?(d=e[g].apply(e,i),d!==e&&d!==b?(j=d&&d.jquery?j.pushStack(d.get()):d,!1):void 0):a.error("no such method '"+g+"' for "+c+" widget instance"):a.error("cannot call methods on "+c+" prior to initialization; attempted to call method '"+g+"'")}:function(){var b=a.data(this,f);b?b.option(g||{})._init():a.data(this,f,new e(g,this))}),j}},a.Widget=function(){},a.Widget._childConstructors=[],a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(b,d){d=a(d||this.defaultElement||this)[0],this.element=a(d),this.uuid=c++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=a.widget.extend({},this.options,this._getCreateOptions(),b),this.bindings=a(),this.hoverable=a(),this.focusable=a(),d!==this&&(a.data(d,this.widgetFullName,this),this._on(!0,this.element,{remove:function(a){a.target===d&&this.destroy()}}),this.document=a(d.style?d.ownerDocument:d.document||d),this.window=a(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:a.noop,_getCreateEventData:a.noop,_create:a.noop,_init:a.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetFullName).removeData(a.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:a.noop,widget:function(){return this.element},option:function(c,d){var e,f,g,h=c;if(0===arguments.length)return a.widget.extend({},this.options);if("string"==typeof c)if(h={},e=c.split("."),c=e.shift(),e.length){for(f=h[c]=a.widget.extend({},this.options[c]),g=0;g<e.length-1;g++)f[e[g]]=f[e[g]]||{},f=f[e[g]];if(c=e.pop(),d===b)return f[c]===b?null:f[c];f[c]=d}else{if(d===b)return this.options[c]===b?null:this.options[c];h[c]=d}return this._setOptions(h),this},_setOptions:function(a){var b;for(b in a)this._setOption(b,a[b]);return this},_setOption:function(a,b){return this.options[a]=b,"disabled"===a&&(this.widget().toggleClass(this.widgetFullName+"-disabled",!!b),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_on:function(b,c,d){var e,f=this;"boolean"!=typeof b&&(d=c,c=b,b=!1),d?(c=e=a(c),this.bindings=this.bindings.add(c)):(d=c,c=this.element,e=this.widget()),a.each(d,function(d,g){function h(){return b||f.options.disabled!==!0&&!a(this).hasClass("ui-state-disabled")?("string"==typeof g?f[g]:g).apply(f,arguments):void 0}"string"!=typeof g&&(h.guid=g.guid=g.guid||h.guid||a.guid++);var i=d.match(/^(\w+)\s*(.*)$/),j=i[1]+f.eventNamespace,k=i[2];k?e.delegate(k,j,h):c.bind(j,h)})},_off:function(a,b){b=(b||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,a.unbind(b).undelegate(b)},_delay:function(a,b){function c(){return("string"==typeof a?d[a]:a).apply(d,arguments)}var d=this;return setTimeout(c,b||0)},_hoverable:function(b){this.hoverable=this.hoverable.add(b),this._on(b,{mouseenter:function(b){a(b.currentTarget).addClass("ui-state-hover")},mouseleave:function(b){a(b.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(b){this.focusable=this.focusable.add(b),this._on(b,{focusin:function(b){a(b.currentTarget).addClass("ui-state-focus")},focusout:function(b){a(b.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(b,c,d){var e,f,g=this.options[b];if(d=d||{},c=a.Event(c),c.type=(b===this.widgetEventPrefix?b:this.widgetEventPrefix+b).toLowerCase(),c.target=this.element[0],f=c.originalEvent)for(e in f)e in c||(c[e]=f[e]);return this.element.trigger(c,d),!(a.isFunction(g)&&g.apply(this.element[0],[c].concat(d))===!1||c.isDefaultPrevented())}},a.each({show:"fadeIn",hide:"fadeOut"},function(b,c){a.Widget.prototype["_"+b]=function(d,e,f){"string"==typeof e&&(e={effect:e});var g,h=e?e===!0||"number"==typeof e?c:e.effect||c:b;e=e||{},"number"==typeof e&&(e={duration:e}),g=!a.isEmptyObject(e),e.complete=f,e.delay&&d.delay(e.delay),g&&a.effects&&a.effects.effect[h]?d[b](e):h!==b&&d[h]?d[h](e.duration,e.easing,f):d.queue(function(c){a(this)[b](),f&&f.call(d[0]),c()})}})}(a),function(a,b,c){var d={},e=a.find,f=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,g=/:jqmData\(([^)]*)\)/g;a.extend(a.mobile,{ns:"",getAttribute:function(b,c){var d;b=b.jquery?b[0]:b,b&&b.getAttribute&&(d=b.getAttribute("data-"+a.mobile.ns+c));try{d="true"===d?!0:"false"===d?!1:"null"===d?null:+d+""===d?+d:f.test(d)?JSON.parse(d):d}catch(e){}return d},nsNormalizeDict:d,nsNormalize:function(b){return d[b]||(d[b]=a.camelCase(a.mobile.ns+b))},closestPageData:function(a){return a.closest(":jqmData(role='page'), :jqmData(role='dialog')").data("mobile-page")}}),a.fn.jqmData=function(b,d){var e;return"undefined"!=typeof b&&(b&&(b=a.mobile.nsNormalize(b)),e=arguments.length<2||d===c?this.data(b):this.data(b,d)),e},a.jqmData=function(b,c,d){var e;return"undefined"!=typeof c&&(e=a.data(b,c?a.mobile.nsNormalize(c):c,d)),e},a.fn.jqmRemoveData=function(b){return this.removeData(a.mobile.nsNormalize(b))},a.jqmRemoveData=function(b,c){return a.removeData(b,a.mobile.nsNormalize(c))},a.find=function(b,c,d,f){return b.indexOf(":jqmData")>-1&&(b=b.replace(g,"[data-"+(a.mobile.ns||"")+"$1]")),e.call(this,b,c,d,f)},a.extend(a.find,e)}(a,this),function(a){var b=/[A-Z]/g,c=function(a){return"-"+a.toLowerCase()};a.extend(a.Widget.prototype,{_getCreateOptions:function(){var d,e,f=this.element[0],g={};if(!a.mobile.getAttribute(f,"defaults"))for(d in this.options)e=a.mobile.getAttribute(f,d.replace(b,c)),null!=e&&(g[d]=e);return g}}),a.mobile.widget=a.Widget}(a),function(a){var b="ui-loader",c=a("html");a.widget("mobile.loader",{options:{theme:"a",textVisible:!1,html:"",text:"loading"},defaultHtml:"<div class='"+b+"'><span class='ui-icon-loading'></span><h1></h1></div>",fakeFixLoader:function(){var b=a("."+a.mobile.activeBtnClass).first();this.element.css({top:a.support.scrollTop&&this.window.scrollTop()+this.window.height()/2||b.length&&b.offset().top||100})},checkLoaderPosition:function(){var b=this.element.offset(),c=this.window.scrollTop(),d=a.mobile.getScreenHeight();(b.top<c||b.top-c>d)&&(this.element.addClass("ui-loader-fakefix"),this.fakeFixLoader(),this.window.unbind("scroll",this.checkLoaderPosition).bind("scroll",a.proxy(this.fakeFixLoader,this)))},resetHtml:function(){this.element.html(a(this.defaultHtml).html())},show:function(d,e,f){var g,h,i;this.resetHtml(),"object"===a.type(d)?(i=a.extend({},this.options,d),d=i.theme):(i=this.options,d=d||i.theme),h=e||(i.text===!1?"":i.text),c.addClass("ui-loading"),g=i.textVisible,this.element.attr("class",b+" ui-corner-all ui-body-"+d+" ui-loader-"+(g||e||d.text?"verbose":"default")+(i.textonly||f?" ui-loader-textonly":"")),i.html?this.element.html(i.html):this.element.find("h1").text(h),this.element.appendTo(a(a.mobile.pagecontainer?":mobile-pagecontainer":"body")),this.checkLoaderPosition(),this.window.bind("scroll",a.proxy(this.checkLoaderPosition,this))},hide:function(){c.removeClass("ui-loading"),this.options.text&&this.element.removeClass("ui-loader-fakefix"),this.window.unbind("scroll",this.fakeFixLoader),this.window.unbind("scroll",this.checkLoaderPosition)}})}(a,this),function(a,b,d){"$:nomunge";function e(a){return a=a||location.href,"#"+a.replace(/^[^#]*#?(.*)$/,"$1")}var f,g="hashchange",h=c,i=a.event.special,j=h.documentMode,k="on"+g in b&&(j===d||j>7);a.fn[g]=function(a){return a?this.bind(g,a):this.trigger(g)},a.fn[g].delay=50,i[g]=a.extend(i[g],{setup:function(){return k?!1:void a(f.start)},teardown:function(){return k?!1:void a(f.stop)}}),f=function(){function c(){var d=e(),h=n(j);d!==j?(m(j=d,h),a(b).trigger(g)):h!==j&&(location.href=location.href.replace(/#.*/,"")+h),f=setTimeout(c,a.fn[g].delay)}var f,i={},j=e(),l=function(a){return a},m=l,n=l;return i.start=function(){f||c()},i.stop=function(){f&&clearTimeout(f),f=d},b.attachEvent&&!b.addEventListener&&!k&&function(){var b,d;i.start=function(){b||(d=a.fn[g].src,d=d&&d+e(),b=a('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){d||m(e()),c()}).attr("src",d||"javascript:0").insertAfter("body")[0].contentWindow,h.onpropertychange=function(){try{"title"===event.propertyName&&(b.document.title=h.title)}catch(a){}})},i.stop=l,n=function(){return e(b.location.href)},m=function(c,d){var e=b.document,f=a.fn[g].domain;c!==d&&(e.title=h.title,e.open(),f&&e.write('<script>document.domain="'+f+'"</script>'),e.close(),b.location.hash=c)}}(),i}()}(a,this),function(a){b.matchMedia=b.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='&shy;<style media="'+a+'"> #mq-test-1 { width: 42px; }</style>',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(c),a.mobile.media=function(a){return b.matchMedia(a).matches}}(a),function(a){var b={touch:"ontouchend"in c};a.mobile.support=a.mobile.support||{},a.extend(a.support,b),a.extend(a.mobile.support,b)}(a),function(a){a.extend(a.support,{orientation:"orientation"in b&&"onorientationchange"in b})}(a),function(a,d){function e(a){var b,c=a.charAt(0).toUpperCase()+a.substr(1),e=(a+" "+o.join(c+" ")+c).split(" ");for(b in e)if(n[e[b]]!==d)return!0}function f(){var c=b,d=!(!c.document.createElementNS||!c.document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect||c.opera&&-1===navigator.userAgent.indexOf("Chrome")),e=function(b){b&&d||a("html").addClass("ui-nosvg")},f=new c.Image;f.onerror=function(){e(!1)},f.onload=function(){e(1===f.width&&1===f.height)},f.src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="}function g(){var e,f,g,h="transform-3d",i=a.mobile.media("(-"+o.join("-"+h+"),(-")+"-"+h+"),("+h+")");if(i)return!!i;e=c.createElement("div"),f={MozTransform:"-moz-transform",transform:"transform"},m.append(e);for(g in f)e.style[g]!==d&&(e.style[g]="translate3d( 100px, 1px, 1px )",i=b.getComputedStyle(e).getPropertyValue(f[g]));return!!i&&"none"!==i}function h(){var b,c,d=location.protocol+"//"+location.host+location.pathname+"ui-dir/",e=a("head base"),f=null,g="";return e.length?g=e.attr("href"):e=f=a("<base>",{href:d}).appendTo("head"),b=a("<a href='testurl' />").prependTo(m),c=b[0].href,e[0].href=g||location.pathname,f&&f.remove(),0===c.indexOf(d)}function i(){var a,d=c.createElement("x"),e=c.documentElement,f=b.getComputedStyle;return"pointerEvents"in d.style?(d.style.pointerEvents="auto",d.style.pointerEvents="x",e.appendChild(d),a=f&&"auto"===f(d,"").pointerEvents,e.removeChild(d),!!a):!1}function j(){var a=c.createElement("div");return"undefined"!=typeof a.getBoundingClientRect}function k(){var a=b,c=navigator.userAgent,d=navigator.platform,e=c.match(/AppleWebKit\/([0-9]+)/),f=!!e&&e[1],g=c.match(/Fennec\/([0-9]+)/),h=!!g&&g[1],i=c.match(/Opera Mobi\/([0-9]+)/),j=!!i&&i[1];return(d.indexOf("iPhone")>-1||d.indexOf("iPad")>-1||d.indexOf("iPod")>-1)&&f&&534>f||a.operamini&&"[object OperaMini]"==={}.toString.call(a.operamini)||i&&7458>j||c.indexOf("Android")>-1&&f&&533>f||h&&6>h||"palmGetResource"in b&&f&&534>f||c.indexOf("MeeGo")>-1&&c.indexOf("NokiaBrowser/8.5.0")>-1?!1:!0}var l,m=a("<body>").prependTo("html"),n=m[0].style,o=["Webkit","Moz","O"],p="palmGetResource"in b,q=b.operamini&&"[object OperaMini]"==={}.toString.call(b.operamini),r=b.blackberry&&!e("-webkit-transform");a.extend(a.mobile,{browser:{}}),a.mobile.browser.oldIE=function(){var a=3,b=c.createElement("div"),d=b.all||[];do b.innerHTML="<!--[if gt IE "+ ++a+"]><br><![endif]-->";while(d[0]);return a>4?a:!a}(),a.extend(a.support,{pushState:"pushState"in history&&"replaceState"in history&&!(b.navigator.userAgent.indexOf("Firefox")>=0&&b.top!==b)&&-1===b.navigator.userAgent.search(/CriOS/),mediaquery:a.mobile.media("only all"),cssPseudoElement:!!e("content"),touchOverflow:!!e("overflowScrolling"),cssTransform3d:g(),boxShadow:!!e("boxShadow")&&!r,fixedPosition:k(),scrollTop:("pageXOffset"in b||"scrollTop"in c.documentElement||"scrollTop"in m[0])&&!p&&!q,dynamicBaseTag:h(),cssPointerEvents:i(),boundingRect:j(),inlineSVG:f}),m.remove(),l=function(){var a=b.navigator.userAgent;return a.indexOf("Nokia")>-1&&(a.indexOf("Symbian/3")>-1||a.indexOf("Series60/5")>-1)&&a.indexOf("AppleWebKit")>-1&&a.match(/(BrowserNG|NokiaBrowser)\/7\.[0-3]/)}(),a.mobile.gradeA=function(){return(a.support.mediaquery&&a.support.cssPseudoElement||a.mobile.browser.oldIE&&a.mobile.browser.oldIE>=8)&&(a.support.boundingRect||null!==a.fn.jquery.match(/1\.[0-7+]\.[0-9+]?/))},a.mobile.ajaxBlacklist=b.blackberry&&!b.WebKitPoint||q||l,l&&a(function(){a("head link[rel='stylesheet']").attr("rel","alternate stylesheet").attr("rel","stylesheet")}),a.support.boxShadow||a("html").addClass("ui-noboxshadow")}(a),function(a,b){var c,d=a.mobile.window,e=function(){};a.event.special.beforenavigate={setup:function(){d.on("navigate",e)},teardown:function(){d.off("navigate",e)}},a.event.special.navigate=c={bound:!1,pushStateEnabled:!0,originalEventName:b,isPushStateEnabled:function(){return a.support.pushState&&a.mobile.pushStateEnabled===!0&&this.isHashChangeEnabled()},isHashChangeEnabled:function(){return a.mobile.hashListeningEnabled===!0},popstate:function(b){var c=new a.Event("navigate"),e=new a.Event("beforenavigate"),f=b.originalEvent.state||{};e.originalEvent=b,d.trigger(e),e.isDefaultPrevented()||(b.historyState&&a.extend(f,b.historyState),c.originalEvent=b,setTimeout(function(){d.trigger(c,{state:f})},0))},hashchange:function(b){var c=new a.Event("navigate"),e=new a.Event("beforenavigate");e.originalEvent=b,d.trigger(e),e.isDefaultPrevented()||(c.originalEvent=b,d.trigger(c,{state:b.hashchangeState||{}}))},setup:function(){c.bound||(c.bound=!0,c.isPushStateEnabled()?(c.originalEventName="popstate",d.bind("popstate.navigate",c.popstate)):c.isHashChangeEnabled()&&(c.originalEventName="hashchange",d.bind("hashchange.navigate",c.hashchange)))}}}(a),function(a,c){var d,e,f="&ui-state=dialog";a.mobile.path=d={uiStateKey:"&ui-state",urlParseRE:/^\s*(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,getLocation:function(a){var b=this.parseUrl(a||location.href),c=a?b:location,d=b.hash;return d="#"===d?"":d,c.protocol+b.doubleSlash+c.host+(""!==c.protocol&&"/"!==c.pathname.substring(0,1)?"/":"")+c.pathname+c.search+d},getDocumentUrl:function(b){return b?a.extend({},d.documentUrl):d.documentUrl.href},parseLocation:function(){return this.parseUrl(this.getLocation())},parseUrl:function(b){if("object"===a.type(b))return b;var c=d.urlParseRE.exec(b||"")||[];return{href:c[0]||"",hrefNoHash:c[1]||"",hrefNoSearch:c[2]||"",domain:c[3]||"",protocol:c[4]||"",doubleSlash:c[5]||"",authority:c[6]||"",username:c[8]||"",password:c[9]||"",host:c[10]||"",hostname:c[11]||"",port:c[12]||"",pathname:c[13]||"",directory:c[14]||"",filename:c[15]||"",search:c[16]||"",hash:c[17]||""}},makePathAbsolute:function(a,b){var c,d,e,f;if(a&&"/"===a.charAt(0))return a;for(a=a||"",b=b?b.replace(/^\/|(\/[^\/]*|[^\/]+)$/g,""):"",c=b?b.split("/"):[],d=a.split("/"),e=0;e<d.length;e++)switch(f=d[e]){case".":break;case"..":c.length&&c.pop();break;default:c.push(f)}return"/"+c.join("/")},isSameDomain:function(a,b){return d.parseUrl(a).domain.toLowerCase()===d.parseUrl(b).domain.toLowerCase()},isRelativeUrl:function(a){return""===d.parseUrl(a).protocol},isAbsoluteUrl:function(a){return""!==d.parseUrl(a).protocol},makeUrlAbsolute:function(a,b){if(!d.isRelativeUrl(a))return a;b===c&&(b=this.documentBase);var e=d.parseUrl(a),f=d.parseUrl(b),g=e.protocol||f.protocol,h=e.protocol?e.doubleSlash:e.doubleSlash||f.doubleSlash,i=e.authority||f.authority,j=""!==e.pathname,k=d.makePathAbsolute(e.pathname||f.filename,f.pathname),l=e.search||!j&&f.search||"",m=e.hash;return g+h+i+k+l+m},addSearchParams:function(b,c){var e=d.parseUrl(b),f="object"==typeof c?a.param(c):c,g=e.search||"?";return e.hrefNoSearch+g+("?"!==g.charAt(g.length-1)?"&":"")+f+(e.hash||"")},convertUrlToDataUrl:function(a){var c=a,e=d.parseUrl(a);return d.isEmbeddedPage(e)?c=e.hash.split(f)[0].replace(/^#/,"").replace(/\?.*$/,""):d.isSameDomain(e,this.documentBase)&&(c=e.hrefNoHash.replace(this.documentBase.domain,"").split(f)[0]),b.decodeURIComponent(c)},get:function(a){return a===c&&(a=d.parseLocation().hash),d.stripHash(a).replace(/[^\/]*\.[^\/*]+$/,"")},set:function(a){location.hash=a},isPath:function(a){return/\//.test(a)},clean:function(a){return a.replace(this.documentBase.domain,"")},stripHash:function(a){return a.replace(/^#/,"")},stripQueryParams:function(a){return a.replace(/\?.*$/,"")},cleanHash:function(a){return d.stripHash(a.replace(/\?.*$/,"").replace(f,""))},isHashValid:function(a){return/^#[^#]+$/.test(a)},isExternal:function(a){var b=d.parseUrl(a);return!(!b.protocol||b.domain.toLowerCase()===this.documentUrl.domain.toLowerCase())},hasProtocol:function(a){return/^(:?\w+:)/.test(a)},isEmbeddedPage:function(a){var b=d.parseUrl(a);return""!==b.protocol?!this.isPath(b.hash)&&b.hash&&(b.hrefNoHash===this.documentUrl.hrefNoHash||this.documentBaseDiffers&&b.hrefNoHash===this.documentBase.hrefNoHash):/^#/.test(b.href)},squash:function(a,b){var c,e,f,g,h,i=this.isPath(a),j=this.parseUrl(a),k=j.hash,l="";return b||(i?b=d.getLocation():(h=d.getDocumentUrl(!0),b=d.isPath(h.hash)?d.squash(h.href):h.href)),e=i?d.stripHash(a):a,e=d.isPath(j.hash)?d.stripHash(j.hash):e,g=e.indexOf(this.uiStateKey),g>-1&&(l=e.slice(g),e=e.slice(0,g)),c=d.makeUrlAbsolute(e,b),f=this.parseUrl(c).search,i?((d.isPath(k)||0===k.replace("#","").indexOf(this.uiStateKey))&&(k=""),l&&-1===k.indexOf(this.uiStateKey)&&(k+=l),-1===k.indexOf("#")&&""!==k&&(k="#"+k),c=d.parseUrl(c),c=c.protocol+c.doubleSlash+c.host+c.pathname+f+k):c+=c.indexOf("#")>-1?l:"#"+l,c},isPreservableHash:function(a){return 0===a.replace("#","").indexOf(this.uiStateKey)},hashToSelector:function(a){var b="#"===a.substring(0,1);return b&&(a=a.substring(1)),(b?"#":"")+a.replace(/([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g,"\\$1")},getFilePath:function(a){return a&&a.split(f)[0]},isFirstPageUrl:function(b){var e=d.parseUrl(d.makeUrlAbsolute(b,this.documentBase)),f=e.hrefNoHash===this.documentUrl.hrefNoHash||this.documentBaseDiffers&&e.hrefNoHash===this.documentBase.hrefNoHash,g=a.mobile.firstPage,h=g&&g[0]?g[0].id:c;return f&&(!e.hash||"#"===e.hash||h&&e.hash.replace(/^#/,"")===h)},isPermittedCrossDomainRequest:function(b,c){return a.mobile.allowCrossDomainPages&&("file:"===b.protocol||"content:"===b.protocol)&&-1!==c.search(/^https?:/)}},d.documentUrl=d.parseLocation(),e=a("head").find("base"),d.documentBase=e.length?d.parseUrl(d.makeUrlAbsolute(e.attr("href"),d.documentUrl.href)):d.documentUrl,d.documentBaseDiffers=d.documentUrl.hrefNoHash!==d.documentBase.hrefNoHash,d.getDocumentBase=function(b){return b?a.extend({},d.documentBase):d.documentBase.href},a.extend(a.mobile,{getDocumentUrl:d.getDocumentUrl,getDocumentBase:d.getDocumentBase})}(a),function(a,b){a.mobile.History=function(a,b){this.stack=a||[],this.activeIndex=b||0},a.extend(a.mobile.History.prototype,{getActive:function(){return this.stack[this.activeIndex]},getLast:function(){return this.stack[this.previousIndex]},getNext:function(){return this.stack[this.activeIndex+1]},getPrev:function(){return this.stack[this.activeIndex-1]},add:function(a,b){b=b||{},this.getNext()&&this.clearForward(),b.hash&&-1===b.hash.indexOf("#")&&(b.hash="#"+b.hash),b.url=a,this.stack.push(b),this.activeIndex=this.stack.length-1},clearForward:function(){this.stack=this.stack.slice(0,this.activeIndex+1)},find:function(a,b,c){b=b||this.stack;var d,e,f,g=b.length;for(e=0;g>e;e++)if(d=b[e],(decodeURIComponent(a)===decodeURIComponent(d.url)||decodeURIComponent(a)===decodeURIComponent(d.hash))&&(f=e,c))return f;return f},closest:function(a){var c,d=this.activeIndex;return c=this.find(a,this.stack.slice(0,d)),c===b&&(c=this.find(a,this.stack.slice(d),!0),c=c===b?c:c+d),c},direct:function(c){var d=this.closest(c.url),e=this.activeIndex;d!==b&&(this.activeIndex=d,this.previousIndex=e),e>d?(c.present||c.back||a.noop)(this.getActive(),"back"):d>e?(c.present||c.forward||a.noop)(this.getActive(),"forward"):d===b&&c.missing&&c.missing(this.getActive())}})}(a),function(a){var d=a.mobile.path,e=location.href;a.mobile.Navigator=function(b){this.history=b,this.ignoreInitialHashChange=!0,a.mobile.window.bind({"popstate.history":a.proxy(this.popstate,this),"hashchange.history":a.proxy(this.hashchange,this)})},a.extend(a.mobile.Navigator.prototype,{squash:function(e,f){var g,h,i=d.isPath(e)?d.stripHash(e):e;return h=d.squash(e),g=a.extend({hash:i,url:h},f),b.history.replaceState(g,g.title||c.title,h),g},hash:function(a,b){var c,e,f,g;return c=d.parseUrl(a),e=d.parseLocation(),e.pathname+e.search===c.pathname+c.search?f=c.hash?c.hash:c.pathname+c.search:d.isPath(a)?(g=d.parseUrl(b),f=g.pathname+g.search+(d.isPreservableHash(g.hash)?g.hash.replace("#",""):"")):f=a,f},go:function(e,f,g){var h,i,j,k,l=a.event.special.navigate.isPushStateEnabled();
+i=d.squash(e),j=this.hash(e,i),g&&j!==d.stripHash(d.parseLocation().hash)&&(this.preventNextHashChange=g),this.preventHashAssignPopState=!0,b.location.hash=j,this.preventHashAssignPopState=!1,h=a.extend({url:i,hash:j,title:c.title},f),l&&(k=new a.Event("popstate"),k.originalEvent={type:"popstate",state:null},this.squash(e,h),g||(this.ignorePopState=!0,a.mobile.window.trigger(k))),this.history.add(h.url,h)},popstate:function(b){var c,f;if(a.event.special.navigate.isPushStateEnabled())return this.preventHashAssignPopState?(this.preventHashAssignPopState=!1,void b.stopImmediatePropagation()):this.ignorePopState?void(this.ignorePopState=!1):!b.originalEvent.state&&1===this.history.stack.length&&this.ignoreInitialHashChange&&(this.ignoreInitialHashChange=!1,location.href===e)?void b.preventDefault():(c=d.parseLocation().hash,!b.originalEvent.state&&c?(f=this.squash(c),this.history.add(f.url,f),void(b.historyState=f)):void this.history.direct({url:(b.originalEvent.state||{}).url||c,present:function(c,d){b.historyState=a.extend({},c),b.historyState.direction=d}}))},hashchange:function(b){var e,f;if(a.event.special.navigate.isHashChangeEnabled()&&!a.event.special.navigate.isPushStateEnabled()){if(this.preventNextHashChange)return this.preventNextHashChange=!1,void b.stopImmediatePropagation();e=this.history,f=d.parseLocation().hash,this.history.direct({url:f,present:function(c,d){b.hashchangeState=a.extend({},c),b.hashchangeState.direction=d},missing:function(){e.add(f,{hash:f,title:c.title})}})}}})}(a),function(a){a.mobile.navigate=function(b,c,d){a.mobile.navigate.navigator.go(b,c,d)},a.mobile.navigate.history=new a.mobile.History,a.mobile.navigate.navigator=new a.mobile.Navigator(a.mobile.navigate.history);var b=a.mobile.path.parseLocation();a.mobile.navigate.history.add(b.href,{hash:b.hash})}(a),function(a,b){var d={animation:{},transition:{}},e=c.createElement("a"),f=["","webkit-","moz-","o-"];a.each(["animation","transition"],function(c,g){var h=0===c?g+"-name":g;a.each(f,function(c,f){return e.style[a.camelCase(f+h)]!==b?(d[g].prefix=f,!1):void 0}),d[g].duration=a.camelCase(d[g].prefix+g+"-duration"),d[g].event=a.camelCase(d[g].prefix+g+"-end"),""===d[g].prefix&&(d[g].event=d[g].event.toLowerCase())}),a.support.cssTransitions=d.transition.prefix!==b,a.support.cssAnimations=d.animation.prefix!==b,a(e).remove(),a.fn.animationComplete=function(e,f,g){var h,i,j=this,k=function(){clearTimeout(h),e.apply(this,arguments)},l=f&&"animation"!==f?"transition":"animation";return a.support.cssTransitions&&"transition"===l||a.support.cssAnimations&&"animation"===l?(g===b&&(a(this).context!==c&&(i=3e3*parseFloat(a(this).css(d[l].duration))),(0===i||i===b||isNaN(i))&&(i=a.fn.animationComplete.defaultDuration)),h=setTimeout(function(){a(j).off(d[l].event,k),e.apply(j)},i),a(this).one(d[l].event,k)):(setTimeout(a.proxy(e,this),0),a(this))},a.fn.animationComplete.defaultDuration=1e3}(a),function(a,b,c,d){function e(a){for(;a&&"undefined"!=typeof a.originalEvent;)a=a.originalEvent;return a}function f(b,c){var f,g,h,i,j,k,l,m,n,o=b.type;if(b=a.Event(b),b.type=c,f=b.originalEvent,g=a.event.props,o.search(/^(mouse|click)/)>-1&&(g=E),f)for(l=g.length,i;l;)i=g[--l],b[i]=f[i];if(o.search(/mouse(down|up)|click/)>-1&&!b.which&&(b.which=1),-1!==o.search(/^touch/)&&(h=e(f),o=h.touches,j=h.changedTouches,k=o&&o.length?o[0]:j&&j.length?j[0]:d))for(m=0,n=C.length;n>m;m++)i=C[m],b[i]=k[i];return b}function g(b){for(var c,d,e={};b;){c=a.data(b,z);for(d in c)c[d]&&(e[d]=e.hasVirtualBinding=!0);b=b.parentNode}return e}function h(b,c){for(var d;b;){if(d=a.data(b,z),d&&(!c||d[c]))return b;b=b.parentNode}return null}function i(){M=!1}function j(){M=!0}function k(){Q=0,K.length=0,L=!1,j()}function l(){i()}function m(){n(),G=setTimeout(function(){G=0,k()},a.vmouse.resetTimerDuration)}function n(){G&&(clearTimeout(G),G=0)}function o(b,c,d){var e;return(d&&d[b]||!d&&h(c.target,b))&&(e=f(c,b),a(c.target).trigger(e)),e}function p(b){var c,d=a.data(b.target,A);L||Q&&Q===d||(c=o("v"+b.type,b),c&&(c.isDefaultPrevented()&&b.preventDefault(),c.isPropagationStopped()&&b.stopPropagation(),c.isImmediatePropagationStopped()&&b.stopImmediatePropagation()))}function q(b){var c,d,f,h=e(b).touches;h&&1===h.length&&(c=b.target,d=g(c),d.hasVirtualBinding&&(Q=P++,a.data(c,A,Q),n(),l(),J=!1,f=e(b).touches[0],H=f.pageX,I=f.pageY,o("vmouseover",b,d),o("vmousedown",b,d)))}function r(a){M||(J||o("vmousecancel",a,g(a.target)),J=!0,m())}function s(b){if(!M){var c=e(b).touches[0],d=J,f=a.vmouse.moveDistanceThreshold,h=g(b.target);J=J||Math.abs(c.pageX-H)>f||Math.abs(c.pageY-I)>f,J&&!d&&o("vmousecancel",b,h),o("vmousemove",b,h),m()}}function t(a){if(!M){j();var b,c,d=g(a.target);o("vmouseup",a,d),J||(b=o("vclick",a,d),b&&b.isDefaultPrevented()&&(c=e(a).changedTouches[0],K.push({touchID:Q,x:c.clientX,y:c.clientY}),L=!0)),o("vmouseout",a,d),J=!1,m()}}function u(b){var c,d=a.data(b,z);if(d)for(c in d)if(d[c])return!0;return!1}function v(){}function w(b){var c=b.substr(1);return{setup:function(){u(this)||a.data(this,z,{});var d=a.data(this,z);d[b]=!0,F[b]=(F[b]||0)+1,1===F[b]&&O.bind(c,p),a(this).bind(c,v),N&&(F.touchstart=(F.touchstart||0)+1,1===F.touchstart&&O.bind("touchstart",q).bind("touchend",t).bind("touchmove",s).bind("scroll",r))},teardown:function(){--F[b],F[b]||O.unbind(c,p),N&&(--F.touchstart,F.touchstart||O.unbind("touchstart",q).unbind("touchmove",s).unbind("touchend",t).unbind("scroll",r));var d=a(this),e=a.data(this,z);e&&(e[b]=!1),d.unbind(c,v),u(this)||d.removeData(z)}}}var x,y,z="virtualMouseBindings",A="virtualTouchID",B="vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split(" "),C="clientX clientY pageX pageY screenX screenY".split(" "),D=a.event.mouseHooks?a.event.mouseHooks.props:[],E=a.event.props.concat(D),F={},G=0,H=0,I=0,J=!1,K=[],L=!1,M=!1,N="addEventListener"in c,O=a(c),P=1,Q=0;for(a.vmouse={moveDistanceThreshold:10,clickDistanceThreshold:10,resetTimerDuration:1500},y=0;y<B.length;y++)a.event.special[B[y]]=w(B[y]);N&&c.addEventListener("click",function(b){var c,d,e,f,g,h,i=K.length,j=b.target;if(i)for(c=b.clientX,d=b.clientY,x=a.vmouse.clickDistanceThreshold,e=j;e;){for(f=0;i>f;f++)if(g=K[f],h=0,e===j&&Math.abs(g.x-c)<x&&Math.abs(g.y-d)<x||a.data(e,A)===g.touchID)return b.preventDefault(),void b.stopPropagation();e=e.parentNode}},!0)}(a,b,c),function(a,b,d){function e(b,c,e,f){var g=e.type;e.type=c,f?a.event.trigger(e,d,b):a.event.dispatch.call(b,e),e.type=g}var f=a(c),g=a.mobile.support.touch,h="touchmove scroll",i=g?"touchstart":"mousedown",j=g?"touchend":"mouseup",k=g?"touchmove":"mousemove";a.each("touchstart touchmove touchend tap taphold swipe swipeleft swiperight scrollstart scrollstop".split(" "),function(b,c){a.fn[c]=function(a){return a?this.bind(c,a):this.trigger(c)},a.attrFn&&(a.attrFn[c]=!0)}),a.event.special.scrollstart={enabled:!0,setup:function(){function b(a,b){c=b,e(f,c?"scrollstart":"scrollstop",a)}var c,d,f=this,g=a(f);g.bind(h,function(e){a.event.special.scrollstart.enabled&&(c||b(e,!0),clearTimeout(d),d=setTimeout(function(){b(e,!1)},50))})},teardown:function(){a(this).unbind(h)}},a.event.special.tap={tapholdThreshold:750,emitTapOnTaphold:!0,setup:function(){var b=this,c=a(b),d=!1;c.bind("vmousedown",function(g){function h(){clearTimeout(k)}function i(){h(),c.unbind("vclick",j).unbind("vmouseup",h),f.unbind("vmousecancel",i)}function j(a){i(),d||l!==a.target?d&&a.preventDefault():e(b,"tap",a)}if(d=!1,g.which&&1!==g.which)return!1;var k,l=g.target;c.bind("vmouseup",h).bind("vclick",j),f.bind("vmousecancel",i),k=setTimeout(function(){a.event.special.tap.emitTapOnTaphold||(d=!0),e(b,"taphold",a.Event("taphold",{target:l}))},a.event.special.tap.tapholdThreshold)})},teardown:function(){a(this).unbind("vmousedown").unbind("vclick").unbind("vmouseup"),f.unbind("vmousecancel")}},a.event.special.swipe={scrollSupressionThreshold:30,durationThreshold:1e3,horizontalDistanceThreshold:30,verticalDistanceThreshold:30,getLocation:function(a){var c=b.pageXOffset,d=b.pageYOffset,e=a.clientX,f=a.clientY;return 0===a.pageY&&Math.floor(f)>Math.floor(a.pageY)||0===a.pageX&&Math.floor(e)>Math.floor(a.pageX)?(e-=c,f-=d):(f<a.pageY-d||e<a.pageX-c)&&(e=a.pageX-c,f=a.pageY-d),{x:e,y:f}},start:function(b){var c=b.originalEvent.touches?b.originalEvent.touches[0]:b,d=a.event.special.swipe.getLocation(c);return{time:(new Date).getTime(),coords:[d.x,d.y],origin:a(b.target)}},stop:function(b){var c=b.originalEvent.touches?b.originalEvent.touches[0]:b,d=a.event.special.swipe.getLocation(c);return{time:(new Date).getTime(),coords:[d.x,d.y]}},handleSwipe:function(b,c,d,f){if(c.time-b.time<a.event.special.swipe.durationThreshold&&Math.abs(b.coords[0]-c.coords[0])>a.event.special.swipe.horizontalDistanceThreshold&&Math.abs(b.coords[1]-c.coords[1])<a.event.special.swipe.verticalDistanceThreshold){var g=b.coords[0]>c.coords[0]?"swipeleft":"swiperight";return e(d,"swipe",a.Event("swipe",{target:f,swipestart:b,swipestop:c}),!0),e(d,g,a.Event(g,{target:f,swipestart:b,swipestop:c}),!0),!0}return!1},eventInProgress:!1,setup:function(){var b,c=this,d=a(c),e={};b=a.data(this,"mobile-events"),b||(b={length:0},a.data(this,"mobile-events",b)),b.length++,b.swipe=e,e.start=function(b){if(!a.event.special.swipe.eventInProgress){a.event.special.swipe.eventInProgress=!0;var d,g=a.event.special.swipe.start(b),h=b.target,i=!1;e.move=function(b){g&&!b.isDefaultPrevented()&&(d=a.event.special.swipe.stop(b),i||(i=a.event.special.swipe.handleSwipe(g,d,c,h),i&&(a.event.special.swipe.eventInProgress=!1)),Math.abs(g.coords[0]-d.coords[0])>a.event.special.swipe.scrollSupressionThreshold&&b.preventDefault())},e.stop=function(){i=!0,a.event.special.swipe.eventInProgress=!1,f.off(k,e.move),e.move=null},f.on(k,e.move).one(j,e.stop)}},d.on(i,e.start)},teardown:function(){var b,c;b=a.data(this,"mobile-events"),b&&(c=b.swipe,delete b.swipe,b.length--,0===b.length&&a.removeData(this,"mobile-events")),c&&(c.start&&a(this).off(i,c.start),c.move&&f.off(k,c.move),c.stop&&f.off(j,c.stop))}},a.each({scrollstop:"scrollstart",taphold:"tap",swipeleft:"swipe.left",swiperight:"swipe.right"},function(b,c){a.event.special[b]={setup:function(){a(this).bind(c,a.noop)},teardown:function(){a(this).unbind(c)}}})}(a,this),function(a){a.event.special.throttledresize={setup:function(){a(this).bind("resize",f)},teardown:function(){a(this).unbind("resize",f)}};var b,c,d,e=250,f=function(){c=(new Date).getTime(),d=c-g,d>=e?(g=c,a(this).trigger("throttledresize")):(b&&clearTimeout(b),b=setTimeout(f,e-d))},g=0}(a),function(a,b){function d(){var a=e();a!==f&&(f=a,l.trigger(m))}var e,f,g,h,i,j,k,l=a(b),m="orientationchange",n={0:!0,180:!0};a.support.orientation&&(i=b.innerWidth||l.width(),j=b.innerHeight||l.height(),k=50,g=i>j&&i-j>k,h=n[b.orientation],(g&&h||!g&&!h)&&(n={"-90":!0,90:!0})),a.event.special.orientationchange=a.extend({},a.event.special.orientationchange,{setup:function(){return a.support.orientation&&!a.event.special.orientationchange.disabled?!1:(f=e(),void l.bind("throttledresize",d))},teardown:function(){return a.support.orientation&&!a.event.special.orientationchange.disabled?!1:void l.unbind("throttledresize",d)},add:function(a){var b=a.handler;a.handler=function(a){return a.orientation=e(),b.apply(this,arguments)}}}),a.event.special.orientationchange.orientation=e=function(){var d=!0,e=c.documentElement;return d=a.support.orientation?n[b.orientation]:e&&e.clientWidth/e.clientHeight<1.1,d?"portrait":"landscape"},a.fn[m]=function(a){return a?this.bind(m,a):this.trigger(m)},a.attrFn&&(a.attrFn[m]=!0)}(a,this),function(a){var b=a("head").children("base"),c={element:b.length?b:a("<base>",{href:a.mobile.path.documentBase.hrefNoHash}).prependTo(a("head")),linkSelector:"[src], link[href], a[rel='external'], :jqmData(ajax='false'), a[target]",set:function(b){a.mobile.dynamicBaseEnabled&&a.support.dynamicBaseTag&&c.element.attr("href",a.mobile.path.makeUrlAbsolute(b,a.mobile.path.documentBase))},rewrite:function(b,d){var e=a.mobile.path.get(b);d.find(c.linkSelector).each(function(b,c){var d=a(c).is("[href]")?"href":a(c).is("[src]")?"src":"action",f=a.mobile.path.parseLocation(),g=a(c).attr(d);g=g.replace(f.protocol+f.doubleSlash+f.host+f.pathname,""),/^(\w+:|#|\/)/.test(g)||a(c).attr(d,e+g)})},reset:function(){c.element.attr("href",a.mobile.path.documentBase.hrefNoSearch)}};a.mobile.base=c}(a),function(a,b){a.mobile.widgets={};var c=a.widget,d=a.mobile.keepNative;a.widget=function(c){return function(){var d=c.apply(this,arguments),e=d.prototype.widgetName;return d.initSelector=d.prototype.initSelector!==b?d.prototype.initSelector:":jqmData(role='"+e+"')",a.mobile.widgets[e]=d,d}}(a.widget),a.extend(a.widget,c),a.mobile.document.on("create",function(b){a(b.target).enhanceWithin()}),a.widget("mobile.page",{options:{theme:"a",domCache:!1,keepNativeDefault:a.mobile.keepNative,contentTheme:null,enhanced:!1},_createWidget:function(){a.Widget.prototype._createWidget.apply(this,arguments),this._trigger("init")},_create:function(){return this._trigger("beforecreate")===!1?!1:(this.options.enhanced||this._enhance(),this._on(this.element,{pagebeforehide:"removeContainerBackground",pagebeforeshow:"_handlePageBeforeShow"}),this.element.enhanceWithin(),void("dialog"===a.mobile.getAttribute(this.element[0],"role")&&a.mobile.dialog&&this.element.dialog()))},_enhance:function(){var c="data-"+a.mobile.ns,d=this;this.options.role&&this.element.attr("data-"+a.mobile.ns+"role",this.options.role),this.element.attr("tabindex","0").addClass("ui-page ui-page-theme-"+this.options.theme),this.element.find("["+c+"role='content']").each(function(){var e=a(this),f=this.getAttribute(c+"theme")||b;d.options.contentTheme=f||d.options.contentTheme||d.options.dialog&&d.options.theme||"dialog"===d.element.jqmData("role")&&d.options.theme,e.addClass("ui-content"),d.options.contentTheme&&e.addClass("ui-body-"+d.options.contentTheme),e.attr("role","main").addClass("ui-content")})},bindRemove:function(b){var c=this.element;!c.data("mobile-page").options.domCache&&c.is(":jqmData(external-page='true')")&&c.bind("pagehide.remove",b||function(b,c){if(!c.samePage){var d=a(this),e=new a.Event("pageremove");d.trigger(e),e.isDefaultPrevented()||d.removeWithDependents()}})},_setOptions:function(c){c.theme!==b&&this.element.removeClass("ui-page-theme-"+this.options.theme).addClass("ui-page-theme-"+c.theme),c.contentTheme!==b&&this.element.find("[data-"+a.mobile.ns+"='content']").removeClass("ui-body-"+this.options.contentTheme).addClass("ui-body-"+c.contentTheme)},_handlePageBeforeShow:function(){this.setContainerBackground()},removeContainerBackground:function(){this.element.closest(":mobile-pagecontainer").pagecontainer({theme:"none"})},setContainerBackground:function(a){this.element.parent().pagecontainer({theme:a||this.options.theme})},keepNativeSelector:function(){var b=this.options,c=a.trim(b.keepNative||""),e=a.trim(a.mobile.keepNative),f=a.trim(b.keepNativeDefault),g=d===e?"":e,h=""===g?f:"";return(c?[c]:[]).concat(g?[g]:[]).concat(h?[h]:[]).join(", ")}})}(a),function(a,d){a.widget("mobile.pagecontainer",{options:{theme:"a"},initSelector:!1,_create:function(){this._trigger("beforecreate"),this.setLastScrollEnabled=!0,this._on(this.window,{navigate:"_disableRecordScroll",scrollstop:"_delayedRecordScroll"}),this._on(this.window,{navigate:"_filterNavigateEvents"}),this._on({pagechange:"_afterContentChange"}),this.window.one("navigate",a.proxy(function(){this.setLastScrollEnabled=!0},this))},_setOptions:function(a){a.theme!==d&&"none"!==a.theme?this.element.removeClass("ui-overlay-"+this.options.theme).addClass("ui-overlay-"+a.theme):a.theme!==d&&this.element.removeClass("ui-overlay-"+this.options.theme),this._super(a)},_disableRecordScroll:function(){this.setLastScrollEnabled=!1},_enableRecordScroll:function(){this.setLastScrollEnabled=!0},_afterContentChange:function(){this.setLastScrollEnabled=!0,this._off(this.window,"scrollstop"),this._on(this.window,{scrollstop:"_delayedRecordScroll"})},_recordScroll:function(){if(this.setLastScrollEnabled){var a,b,c,d=this._getActiveHistory();d&&(a=this._getScroll(),b=this._getMinScroll(),c=this._getDefaultScroll(),d.lastScroll=b>a?c:a)}},_delayedRecordScroll:function(){setTimeout(a.proxy(this,"_recordScroll"),100)},_getScroll:function(){return this.window.scrollTop()},_getMinScroll:function(){return a.mobile.minScrollBack},_getDefaultScroll:function(){return a.mobile.defaultHomeScroll},_filterNavigateEvents:function(b,c){var d;b.originalEvent&&b.originalEvent.isDefaultPrevented()||(d=b.originalEvent.type.indexOf("hashchange")>-1?c.state.hash:c.state.url,d||(d=this._getHash()),d&&"#"!==d&&0!==d.indexOf("#"+a.mobile.path.uiStateKey)||(d=location.href),this._handleNavigate(d,c.state))},_getHash:function(){return a.mobile.path.parseLocation().hash},getActivePage:function(){return this.activePage},_getInitialContent:function(){return a.mobile.firstPage},_getHistory:function(){return a.mobile.navigate.history},_getActiveHistory:function(){return this._getHistory().getActive()},_getDocumentBase:function(){return a.mobile.path.documentBase},back:function(){this.go(-1)},forward:function(){this.go(1)},go:function(c){if(a.mobile.hashListeningEnabled)b.history.go(c);else{var d=a.mobile.navigate.history.activeIndex,e=d+parseInt(c,10),f=a.mobile.navigate.history.stack[e].url,g=c>=1?"forward":"back";a.mobile.navigate.history.activeIndex=e,a.mobile.navigate.history.previousIndex=d,this.change(f,{direction:g,changeHash:!1,fromHashChange:!0})}},_handleDestination:function(b){var c;return"string"===a.type(b)&&(b=a.mobile.path.stripHash(b)),b&&(c=this._getHistory(),b=a.mobile.path.isPath(b)?b:a.mobile.path.makeUrlAbsolute("#"+b,this._getDocumentBase())),b||this._getInitialContent()},_transitionFromHistory:function(a,b){var c=this._getHistory(),d="back"===a?c.getLast():c.getActive();return d&&d.transition||b},_handleDialog:function(b,c){var d,e,f=this.getActivePage();return f&&!f.data("mobile-dialog")?("back"===c.direction?this.back():this.forward(),!1):(d=c.pageUrl,e=this._getActiveHistory(),a.extend(b,{role:e.role,transition:this._transitionFromHistory(c.direction,b.transition),reverse:"back"===c.direction}),d)},_handleNavigate:function(b,c){var d=a.mobile.path.stripHash(b),e=this._getHistory(),f=0===e.stack.length?"none":this._transitionFromHistory(c.direction),g={changeHash:!1,fromHashChange:!0,reverse:"back"===c.direction};a.extend(g,c,{transition:f}),e.activeIndex>0&&d.indexOf(a.mobile.dialogHashKey)>-1&&(d=this._handleDialog(g,c),d===!1)||this._changeContent(this._handleDestination(d),g)},_changeContent:function(b,c){a.mobile.changePage(b,c)},_getBase:function(){return a.mobile.base},_getNs:function(){return a.mobile.ns},_enhance:function(a,b){return a.page({role:b})},_include:function(a,b){a.appendTo(this.element),this._enhance(a,b.role),a.page("bindRemove")},_find:function(b){var c,d=this._createFileUrl(b),e=this._createDataUrl(b),f=this._getInitialContent();return c=this.element.children("[data-"+this._getNs()+"url='"+a.mobile.path.hashToSelector(e)+"']"),0===c.length&&e&&!a.mobile.path.isPath(e)&&(c=this.element.children(a.mobile.path.hashToSelector("#"+e)).attr("data-"+this._getNs()+"url",e).jqmData("url",e)),0===c.length&&a.mobile.path.isFirstPageUrl(d)&&f&&f.parent().length&&(c=a(f)),c},_getLoader:function(){return a.mobile.loading()},_showLoading:function(b,c,d,e){this._loadMsg||(this._loadMsg=setTimeout(a.proxy(function(){this._getLoader().loader("show",c,d,e),this._loadMsg=0},this),b))},_hideLoading:function(){clearTimeout(this._loadMsg),this._loadMsg=0,this._getLoader().loader("hide")},_showError:function(){this._hideLoading(),this._showLoading(0,a.mobile.pageLoadErrorMessageTheme,a.mobile.pageLoadErrorMessage,!0),setTimeout(a.proxy(this,"_hideLoading"),1500)},_parse:function(b,c){var d,e=a("<div></div>");return e.get(0).innerHTML=b,d=e.find(":jqmData(role='page'), :jqmData(role='dialog')").first(),d.length||(d=a("<div data-"+this._getNs()+"role='page'>"+(b.split(/<\/?body[^>]*>/gim)[1]||"")+"</div>")),d.attr("data-"+this._getNs()+"url",this._createDataUrl(c)).attr("data-"+this._getNs()+"external-page",!0),d},_setLoadedTitle:function(b,c){var d=c.match(/<title[^>]*>([^<]*)/)&&RegExp.$1;d&&!b.jqmData("title")&&(d=a("<div>"+d+"</div>").text(),b.jqmData("title",d))},_isRewritableBaseTag:function(){return a.mobile.dynamicBaseEnabled&&!a.support.dynamicBaseTag},_createDataUrl:function(b){return a.mobile.path.convertUrlToDataUrl(b)},_createFileUrl:function(b){return a.mobile.path.getFilePath(b)},_triggerWithDeprecated:function(b,c,d){var e=a.Event("page"+b),f=a.Event(this.widgetName+b);return(d||this.element).trigger(e,c),this._trigger(b,f,c),{deprecatedEvent:e,event:f}},_loadSuccess:function(b,c,e,f){var g=this._createFileUrl(b);return a.proxy(function(h,i,j){var k,l=new RegExp("(<[^>]+\\bdata-"+this._getNs()+"role=[\"']?page[\"']?[^>]*>)"),m=new RegExp("\\bdata-"+this._getNs()+"url=[\"']?([^\"'>]*)[\"']?");l.test(h)&&RegExp.$1&&m.test(RegExp.$1)&&RegExp.$1&&(g=a.mobile.path.getFilePath(a("<div>"+RegExp.$1+"</div>").text()),g=this.window[0].encodeURIComponent(g)),e.prefetch===d&&this._getBase().set(g),k=this._parse(h,g),this._setLoadedTitle(k,h),c.xhr=j,c.textStatus=i,c.page=k,c.content=k,c.toPage=k,this._triggerWithDeprecated("load",c).event.isDefaultPrevented()||(this._isRewritableBaseTag()&&k&&this._getBase().rewrite(g,k),this._include(k,e),e.showLoadMsg&&this._hideLoading(),f.resolve(b,e,k))},this)},_loadDefaults:{type:"get",data:d,reloadPage:!1,reload:!1,role:d,showLoadMsg:!1,loadMsgDelay:50},load:function(b,c){var e,f,g,h,i=c&&c.deferred||a.Deferred(),j=c&&c.reload===d&&c.reloadPage!==d?{reload:c.reloadPage}:{},k=a.extend({},this._loadDefaults,c,j),l=null,m=a.mobile.path.makeUrlAbsolute(b,this._findBaseWithDefault());return k.data&&"get"===k.type&&(m=a.mobile.path.addSearchParams(m,k.data),k.data=d),k.data&&"post"===k.type&&(k.reload=!0),e=this._createFileUrl(m),f=this._createDataUrl(m),l=this._find(m),0===l.length&&a.mobile.path.isEmbeddedPage(e)&&!a.mobile.path.isFirstPageUrl(e)?(i.reject(m,k),i.promise()):(this._getBase().reset(),l.length&&!k.reload?(this._enhance(l,k.role),i.resolve(m,k,l),k.prefetch||this._getBase().set(b),i.promise()):(h={url:b,absUrl:m,toPage:b,prevPage:c?c.fromPage:d,dataUrl:f,deferred:i,options:k},g=this._triggerWithDeprecated("beforeload",h),g.deprecatedEvent.isDefaultPrevented()||g.event.isDefaultPrevented()?i.promise():(k.showLoadMsg&&this._showLoading(k.loadMsgDelay),k.prefetch===d&&this._getBase().reset(),a.mobile.allowCrossDomainPages||a.mobile.path.isSameDomain(a.mobile.path.documentUrl,m)?(a.ajax({url:e,type:k.type,data:k.data,contentType:k.contentType,dataType:"html",success:this._loadSuccess(m,h,k,i),error:this._loadError(m,h,k,i)}),i.promise()):(i.reject(m,k),i.promise()))))},_loadError:function(b,c,d,e){return a.proxy(function(f,g,h){this._getBase().set(a.mobile.path.get()),c.xhr=f,c.textStatus=g,c.errorThrown=h;var i=this._triggerWithDeprecated("loadfailed",c);i.deprecatedEvent.isDefaultPrevented()||i.event.isDefaultPrevented()||(d.showLoadMsg&&this._showError(),e.reject(b,d))},this)},_getTransitionHandler:function(b){return b=a.mobile._maybeDegradeTransition(b),a.mobile.transitionHandlers[b]||a.mobile.defaultTransitionHandler},_triggerCssTransitionEvents:function(b,c,d){var e=!1;d=d||"",c&&(b[0]===c[0]&&(e=!0),this._triggerWithDeprecated(d+"hide",{nextPage:b,toPage:b,prevPage:c,samePage:e},c)),this._triggerWithDeprecated(d+"show",{prevPage:c||a(""),toPage:b},b)},_cssTransition:function(b,c,d){var e,f,g=d.transition,h=d.reverse,i=d.deferred;this._triggerCssTransitionEvents(b,c,"before"),this._hideLoading(),e=this._getTransitionHandler(g),f=new e(g,h,b,c).transition(),f.done(a.proxy(function(){this._triggerCssTransitionEvents(b,c)},this)),f.done(function(){i.resolve.apply(i,arguments)})},_releaseTransitionLock:function(){f=!1,e.length>0&&a.mobile.changePage.apply(null,e.pop())},_removeActiveLinkClass:function(b){a.mobile.removeActiveLinkClass(b)},_loadUrl:function(b,c,d){d.target=b,d.deferred=a.Deferred(),this.load(b,d),d.deferred.done(a.proxy(function(a,b,d){f=!1,b.absUrl=c.absUrl,this.transition(d,c,b)},this)),d.deferred.fail(a.proxy(function(){this._removeActiveLinkClass(!0),this._releaseTransitionLock(),this._triggerWithDeprecated("changefailed",c)},this))},_triggerPageBeforeChange:function(b,c,d){var e;return c.prevPage=this.activePage,a.extend(c,{toPage:b,options:d}),c.absUrl="string"===a.type(b)?a.mobile.path.makeUrlAbsolute(b,this._findBaseWithDefault()):d.absUrl,e=this._triggerWithDeprecated("beforechange",c),e.event.isDefaultPrevented()||e.deprecatedEvent.isDefaultPrevented()?!1:!0},change:function(b,c){if(f)return void e.unshift(arguments);var d=a.extend({},a.mobile.changePage.defaults,c),g={};d.fromPage=d.fromPage||this.activePage,this._triggerPageBeforeChange(b,g,d)&&(b=g.toPage,"string"===a.type(b)?(f=!0,this._loadUrl(b,g,d)):this.transition(b,g,d))},transition:function(b,g,h){var i,j,k,l,m,n,o,p,q,r,s,t,u,v;if(f)return void e.unshift([b,h]);if(this._triggerPageBeforeChange(b,g,h)&&(g.prevPage=h.fromPage,v=this._triggerWithDeprecated("beforetransition",g),!v.deprecatedEvent.isDefaultPrevented()&&!v.event.isDefaultPrevented())){if(f=!0,b[0]!==a.mobile.firstPage[0]||h.dataUrl||(h.dataUrl=a.mobile.path.documentUrl.hrefNoHash),i=h.fromPage,j=h.dataUrl&&a.mobile.path.convertUrlToDataUrl(h.dataUrl)||b.jqmData("url"),k=j,l=a.mobile.path.getFilePath(j),m=a.mobile.navigate.history.getActive(),n=0===a.mobile.navigate.history.activeIndex,o=0,p=c.title,q=("dialog"===h.role||"dialog"===b.jqmData("role"))&&b.jqmData("dialog")!==!0,i&&i[0]===b[0]&&!h.allowSamePageTransition)return f=!1,this._triggerWithDeprecated("transition",g),this._triggerWithDeprecated("change",g),void(h.fromHashChange&&a.mobile.navigate.history.direct({url:j}));b.page({role:h.role}),h.fromHashChange&&(o="back"===h.direction?-1:1);try{c.activeElement&&"body"!==c.activeElement.nodeName.toLowerCase()?a(c.activeElement).blur():a("input:focus, textarea:focus, select:focus").blur()}catch(w){}r=!1,q&&m&&(m.url&&m.url.indexOf(a.mobile.dialogHashKey)>-1&&this.activePage&&!this.activePage.hasClass("ui-dialog")&&a.mobile.navigate.history.activeIndex>0&&(h.changeHash=!1,r=!0),j=m.url||"",j+=!r&&j.indexOf("#")>-1?a.mobile.dialogHashKey:"#"+a.mobile.dialogHashKey),s=m?b.jqmData("title")||b.children(":jqmData(role='header')").find(".ui-title").text():p,s&&p===c.title&&(p=s),b.jqmData("title")||b.jqmData("title",p),h.transition=h.transition||(o&&!n?m.transition:d)||(q?a.mobile.defaultDialogTransition:a.mobile.defaultPageTransition),!o&&r&&(a.mobile.navigate.history.getActive().pageUrl=k),j&&!h.fromHashChange&&(!a.mobile.path.isPath(j)&&j.indexOf("#")<0&&(j="#"+j),t={transition:h.transition,title:p,pageUrl:k,role:h.role},h.changeHash!==!1&&a.mobile.hashListeningEnabled?a.mobile.navigate(this.window[0].encodeURI(j),t,!0):b[0]!==a.mobile.firstPage[0]&&a.mobile.navigate.history.add(j,t)),c.title=p,a.mobile.activePage=b,this.activePage=b,h.reverse=h.reverse||0>o,u=a.Deferred(),this._cssTransition(b,i,{transition:h.transition,reverse:h.reverse,deferred:u}),u.done(a.proxy(function(c,d,e,f,i){a.mobile.removeActiveLinkClass(),h.duplicateCachedPage&&h.duplicateCachedPage.remove(),i||a.mobile.focusPage(b),this._releaseTransitionLock(),this._triggerWithDeprecated("transition",g),this._triggerWithDeprecated("change",g)},this))}},_findBaseWithDefault:function(){var b=this.activePage&&a.mobile.getClosestBaseUrl(this.activePage);return b||a.mobile.path.documentBase.hrefNoHash}}),a.mobile.navreadyDeferred=a.Deferred();var e=[],f=!1}(a),function(a,d){function e(a){for(;a&&("string"!=typeof a.nodeName||"a"!==a.nodeName.toLowerCase());)a=a.parentNode;return a}var f=a.Deferred(),g=a.Deferred(),h=function(){g.resolve(),g=null},i=a.mobile.path.documentUrl,j=null;a.mobile.loadPage=function(b,c){var d;return c=c||{},d=c.pageContainer||a.mobile.pageContainer,c.deferred=a.Deferred(),d.pagecontainer("load",b,c),c.deferred.promise()},a.mobile.back=function(){var c=b.navigator;this.phonegapNavigationEnabled&&c&&c.app&&c.app.backHistory?c.app.backHistory():a.mobile.pageContainer.pagecontainer("back")},a.mobile.focusPage=function(a){var b=a.find("[autofocus]"),c=a.find(".ui-title:eq(0)");return b.length?void b.focus():void(c.length?c.focus():a.focus())},a.mobile._maybeDegradeTransition=a.mobile._maybeDegradeTransition||function(a){return a},a.mobile.changePage=function(b,c){a.mobile.pageContainer.pagecontainer("change",b,c)},a.mobile.changePage.defaults={transition:d,reverse:!1,changeHash:!0,fromHashChange:!1,role:d,duplicateCachedPage:d,pageContainer:d,showLoadMsg:!0,dataUrl:d,fromPage:d,allowSamePageTransition:!1},a.mobile._registerInternalEvents=function(){var c=function(b,c){var d,e,f,g,h=!0;return!a.mobile.ajaxEnabled||b.is(":jqmData(ajax='false')")||!b.jqmHijackable().length||b.attr("target")?!1:(d=j&&j.attr("formaction")||b.attr("action"),g=(b.attr("method")||"get").toLowerCase(),d||(d=a.mobile.getClosestBaseUrl(b),"get"===g&&(d=a.mobile.path.parseUrl(d).hrefNoSearch),d===a.mobile.path.documentBase.hrefNoHash&&(d=i.hrefNoSearch)),d=a.mobile.path.makeUrlAbsolute(d,a.mobile.getClosestBaseUrl(b)),a.mobile.path.isExternal(d)&&!a.mobile.path.isPermittedCrossDomainRequest(i,d)?!1:(c||(e=b.serializeArray(),j&&j[0].form===b[0]&&(f=j.attr("name"),f&&(a.each(e,function(a,b){return b.name===f?(f="",!1):void 0}),f&&e.push({name:f,value:j.attr("value")}))),h={url:d,options:{type:g,data:a.param(e),transition:b.jqmData("transition"),reverse:"reverse"===b.jqmData("direction"),reloadPage:!0}}),h))};a.mobile.document.delegate("form","submit",function(b){var d;b.isDefaultPrevented()||(d=c(a(this)),d&&(a.mobile.changePage(d.url,d.options),b.preventDefault()))}),a.mobile.document.bind("vclick",function(b){var d,f,g=b.target,h=!1;if(!(b.which>1)&&a.mobile.linkBindingEnabled){if(j=a(g),a.data(g,"mobile-button")){if(!c(a(g).closest("form"),!0))return;g.parentNode&&(g=g.parentNode)}else{if(g=e(g),!g||"#"===a.mobile.path.parseUrl(g.getAttribute("href")||"#").hash)return;if(!a(g).jqmHijackable().length)return}~g.className.indexOf("ui-link-inherit")?g.parentNode&&(f=a.data(g.parentNode,"buttonElements")):f=a.data(g,"buttonElements"),f?g=f.outer:h=!0,d=a(g),h&&(d=d.closest(".ui-btn")),d.length>0&&!d.hasClass("ui-state-disabled")&&(a.mobile.removeActiveLinkClass(!0),a.mobile.activeClickedLink=d,a.mobile.activeClickedLink.addClass(a.mobile.activeBtnClass))}}),a.mobile.document.bind("click",function(c){if(a.mobile.linkBindingEnabled&&!c.isDefaultPrevented()){var f,g,h,j,k,l,m,n=e(c.target),o=a(n),p=function(){b.setTimeout(function(){a.mobile.removeActiveLinkClass(!0)},200)};if(a.mobile.activeClickedLink&&a.mobile.activeClickedLink[0]===c.target.parentNode&&p(),n&&!(c.which>1)&&o.jqmHijackable().length){if(o.is(":jqmData(rel='back')"))return a.mobile.back(),!1;if(f=a.mobile.getClosestBaseUrl(o),g=a.mobile.path.makeUrlAbsolute(o.attr("href")||"#",f),!a.mobile.ajaxEnabled&&!a.mobile.path.isEmbeddedPage(g))return void p();if(!(-1===g.search("#")||a.mobile.path.isExternal(g)&&a.mobile.path.isAbsoluteUrl(g))){if(g=g.replace(/[^#]*#/,""),!g)return void c.preventDefault();g=a.mobile.path.isPath(g)?a.mobile.path.makeUrlAbsolute(g,f):a.mobile.path.makeUrlAbsolute("#"+g,i.hrefNoHash)}if(h=o.is("[rel='external']")||o.is(":jqmData(ajax='false')")||o.is("[target]"),j=h||a.mobile.path.isExternal(g)&&!a.mobile.path.isPermittedCrossDomainRequest(i,g))return void p();k=o.jqmData("transition"),l="reverse"===o.jqmData("direction")||o.jqmData("back"),m=o.attr("data-"+a.mobile.ns+"rel")||d,a.mobile.changePage(g,{transition:k,reverse:l,role:m,link:o}),c.preventDefault()}}}),a.mobile.document.delegate(".ui-page","pageshow.prefetch",function(){var b=[];a(this).find("a:jqmData(prefetch)").each(function(){var c=a(this),d=c.attr("href");d&&-1===a.inArray(d,b)&&(b.push(d),a.mobile.loadPage(d,{role:c.attr("data-"+a.mobile.ns+"rel"),prefetch:!0}))})}),a.mobile.pageContainer.pagecontainer(),a.mobile.document.bind("pageshow",function(){g?g.done(a.mobile.resetActivePageHeight):a.mobile.resetActivePageHeight()
+}),a.mobile.window.bind("throttledresize",a.mobile.resetActivePageHeight)},a(function(){f.resolve()}),"complete"===c.readyState?h():a.mobile.window.load(h),a.when(f,a.mobile.navreadyDeferred).done(function(){a.mobile._registerInternalEvents()})}(a),function(a,b){a.mobile.Transition=function(){this.init.apply(this,arguments)},a.extend(a.mobile.Transition.prototype,{toPreClass:" ui-page-pre-in",init:function(b,c,d,e){a.extend(this,{name:b,reverse:c,$to:d,$from:e,deferred:new a.Deferred})},cleanFrom:function(){this.$from.removeClass(a.mobile.activePageClass+" out in reverse "+this.name).height("")},beforeDoneIn:function(){},beforeDoneOut:function(){},beforeStartOut:function(){},doneIn:function(){this.beforeDoneIn(),this.$to.removeClass("out in reverse "+this.name).height(""),this.toggleViewportClass(),a.mobile.window.scrollTop()!==this.toScroll&&this.scrollPage(),this.sequential||this.$to.addClass(a.mobile.activePageClass),this.deferred.resolve(this.name,this.reverse,this.$to,this.$from,!0)},doneOut:function(a,b,c,d){this.beforeDoneOut(),this.startIn(a,b,c,d)},hideIn:function(a){this.$to.css("z-index",-10),a.call(this),this.$to.css("z-index","")},scrollPage:function(){a.event.special.scrollstart.enabled=!1,(a.mobile.hideUrlBar||this.toScroll!==a.mobile.defaultHomeScroll)&&b.scrollTo(0,this.toScroll),setTimeout(function(){a.event.special.scrollstart.enabled=!0},150)},startIn:function(b,c,d,e){this.hideIn(function(){this.$to.addClass(a.mobile.activePageClass+this.toPreClass),e||a.mobile.focusPage(this.$to),this.$to.height(b+this.toScroll),d||this.scrollPage()}),this.$to.removeClass(this.toPreClass).addClass(this.name+" in "+c),d?this.doneIn():this.$to.animationComplete(a.proxy(function(){this.doneIn()},this))},startOut:function(b,c,d){this.beforeStartOut(b,c,d),this.$from.height(b+a.mobile.window.scrollTop()).addClass(this.name+" out"+c)},toggleViewportClass:function(){a.mobile.pageContainer.toggleClass("ui-mobile-viewport-transitioning viewport-"+this.name)},transition:function(){var b,c=this.reverse?" reverse":"",d=a.mobile.getScreenHeight(),e=a.mobile.maxTransitionWidth!==!1&&a.mobile.window.width()>a.mobile.maxTransitionWidth;return this.toScroll=a.mobile.navigate.history.getActive().lastScroll||a.mobile.defaultHomeScroll,b=!a.support.cssTransitions||!a.support.cssAnimations||e||!this.name||"none"===this.name||Math.max(a.mobile.window.scrollTop(),this.toScroll)>a.mobile.getMaxScrollForTransition(),this.toggleViewportClass(),this.$from&&!b?this.startOut(d,c,b):this.doneOut(d,c,b,!0),this.deferred.promise()}})}(a,this),function(a){a.mobile.SerialTransition=function(){this.init.apply(this,arguments)},a.extend(a.mobile.SerialTransition.prototype,a.mobile.Transition.prototype,{sequential:!0,beforeDoneOut:function(){this.$from&&this.cleanFrom()},beforeStartOut:function(b,c,d){this.$from.animationComplete(a.proxy(function(){this.doneOut(b,c,d)},this))}})}(a),function(a){a.mobile.ConcurrentTransition=function(){this.init.apply(this,arguments)},a.extend(a.mobile.ConcurrentTransition.prototype,a.mobile.Transition.prototype,{sequential:!1,beforeDoneIn:function(){this.$from&&this.cleanFrom()},beforeStartOut:function(a,b,c){this.doneOut(a,b,c)}})}(a),function(a){var b=function(){return 3*a.mobile.getScreenHeight()};a.mobile.transitionHandlers={sequential:a.mobile.SerialTransition,simultaneous:a.mobile.ConcurrentTransition},a.mobile.defaultTransitionHandler=a.mobile.transitionHandlers.sequential,a.mobile.transitionFallbacks={},a.mobile._maybeDegradeTransition=function(b){return b&&!a.support.cssTransform3d&&a.mobile.transitionFallbacks[b]&&(b=a.mobile.transitionFallbacks[b]),b},a.mobile.getMaxScrollForTransition=a.mobile.getMaxScrollForTransition||b}(a),function(a){a.mobile.transitionFallbacks.flip="fade"}(a,this),function(a){a.mobile.transitionFallbacks.flow="fade"}(a,this),function(a){a.mobile.transitionFallbacks.pop="fade"}(a,this),function(a){a.mobile.transitionHandlers.slide=a.mobile.transitionHandlers.simultaneous,a.mobile.transitionFallbacks.slide="fade"}(a,this),function(a){a.mobile.transitionFallbacks.slidedown="fade"}(a,this),function(a){a.mobile.transitionFallbacks.slidefade="fade"}(a,this),function(a){a.mobile.transitionFallbacks.slideup="fade"}(a,this),function(a){a.mobile.transitionFallbacks.turn="fade"}(a,this),function(a){a.mobile.degradeInputs={color:!1,date:!1,datetime:!1,"datetime-local":!1,email:!1,month:!1,number:!1,range:"number",search:"text",tel:!1,time:!1,url:!1,week:!1},a.mobile.page.prototype.options.degradeInputs=a.mobile.degradeInputs,a.mobile.degradeInputsWithin=function(b){b=a(b),b.find("input").not(a.mobile.page.prototype.keepNativeSelector()).each(function(){var b,c,d,e,f=a(this),g=this.getAttribute("type"),h=a.mobile.degradeInputs[g]||"text";a.mobile.degradeInputs[g]&&(b=a("<div>").html(f.clone()).html(),c=b.indexOf(" type=")>-1,d=c?/\s+type=["']?\w+['"]?/:/\/?>/,e=' type="'+h+'" data-'+a.mobile.ns+'type="'+g+'"'+(c?"":">"),f.replaceWith(b.replace(d,e)))})}}(a),function(a,b,c){a.widget("mobile.page",a.mobile.page,{options:{closeBtn:"left",closeBtnText:"Close",overlayTheme:"a",corners:!0,dialog:!1},_create:function(){this._super(),this.options.dialog&&(a.extend(this,{_inner:this.element.children(),_headerCloseButton:null}),this.options.enhanced||this._setCloseBtn(this.options.closeBtn))},_enhance:function(){this._super(),this.options.dialog&&this.element.addClass("ui-dialog").wrapInner(a("<div/>",{role:"dialog","class":"ui-dialog-contain ui-overlay-shadow"+(this.options.corners?" ui-corner-all":"")}))},_setOptions:function(b){var d,e,f=this.options;b.corners!==c&&this._inner.toggleClass("ui-corner-all",!!b.corners),b.overlayTheme!==c&&a.mobile.activePage[0]===this.element[0]&&(f.overlayTheme=b.overlayTheme,this._handlePageBeforeShow()),b.closeBtnText!==c&&(d=f.closeBtn,e=b.closeBtnText),b.closeBtn!==c&&(d=b.closeBtn),d&&this._setCloseBtn(d,e),this._super(b)},_handlePageBeforeShow:function(){this.options.overlayTheme&&this.options.dialog?(this.removeContainerBackground(),this.setContainerBackground(this.options.overlayTheme)):this._super()},_setCloseBtn:function(b,c){var d,e=this._headerCloseButton;b="left"===b?"left":"right"===b?"right":"none","none"===b?e&&(e.remove(),e=null):e?(e.removeClass("ui-btn-left ui-btn-right").addClass("ui-btn-"+b),c&&e.text(c)):(d=this._inner.find(":jqmData(role='header')").first(),e=a("<a></a>",{href:"#","class":"ui-btn ui-corner-all ui-icon-delete ui-btn-icon-notext ui-btn-"+b}).attr("data-"+a.mobile.ns+"rel","back").text(c||this.options.closeBtnText||"").prependTo(d)),this._headerCloseButton=e}})}(a,this),function(a,b,c){a.widget("mobile.dialog",{options:{closeBtn:"left",closeBtnText:"Close",overlayTheme:"a",corners:!0},_handlePageBeforeShow:function(){this._isCloseable=!0,this.options.overlayTheme&&this.element.page("removeContainerBackground").page("setContainerBackground",this.options.overlayTheme)},_handlePageBeforeHide:function(){this._isCloseable=!1},_handleVClickSubmit:function(b){var c,d=a(b.target).closest("vclick"===b.type?"a":"form");d.length&&!d.jqmData("transition")&&(c={},c["data-"+a.mobile.ns+"transition"]=(a.mobile.navigate.history.getActive()||{}).transition||a.mobile.defaultDialogTransition,c["data-"+a.mobile.ns+"direction"]="reverse",d.attr(c))},_create:function(){var b=this.element,c=this.options;b.addClass("ui-dialog").wrapInner(a("<div/>",{role:"dialog","class":"ui-dialog-contain ui-overlay-shadow"+(c.corners?" ui-corner-all":"")})),a.extend(this,{_isCloseable:!1,_inner:b.children(),_headerCloseButton:null}),this._on(b,{vclick:"_handleVClickSubmit",submit:"_handleVClickSubmit",pagebeforeshow:"_handlePageBeforeShow",pagebeforehide:"_handlePageBeforeHide"}),this._setCloseBtn(c.closeBtn)},_setOptions:function(b){var d,e,f=this.options;b.corners!==c&&this._inner.toggleClass("ui-corner-all",!!b.corners),b.overlayTheme!==c&&a.mobile.activePage[0]===this.element[0]&&(f.overlayTheme=b.overlayTheme,this._handlePageBeforeShow()),b.closeBtnText!==c&&(d=f.closeBtn,e=b.closeBtnText),b.closeBtn!==c&&(d=b.closeBtn),d&&this._setCloseBtn(d,e),this._super(b)},_setCloseBtn:function(b,c){var d,e=this._headerCloseButton;b="left"===b?"left":"right"===b?"right":"none","none"===b?e&&(e.remove(),e=null):e?(e.removeClass("ui-btn-left ui-btn-right").addClass("ui-btn-"+b),c&&e.text(c)):(d=this._inner.find(":jqmData(role='header')").first(),e=a("<a></a>",{role:"button",href:"#","class":"ui-btn ui-corner-all ui-icon-delete ui-btn-icon-notext ui-btn-"+b}).text(c||this.options.closeBtnText||"").prependTo(d),this._on(e,{click:"close"})),this._headerCloseButton=e},close:function(){var b=a.mobile.navigate.history;this._isCloseable&&(this._isCloseable=!1,a.mobile.hashListeningEnabled&&b.activeIndex>0?a.mobile.back():a.mobile.pageContainer.pagecontainer("back"))}})}(a,this),function(a,b){var c=/([A-Z])/g,d=function(a){return"ui-btn-icon-"+(null===a?"left":a)};a.widget("mobile.collapsible",{options:{enhanced:!1,expandCueText:null,collapseCueText:null,collapsed:!0,heading:"h1,h2,h3,h4,h5,h6,legend",collapsedIcon:null,expandedIcon:null,iconpos:null,theme:null,contentTheme:null,inset:null,corners:null,mini:null},_create:function(){var b=this.element,c={accordion:b.closest(":jqmData(role='collapsible-set'),:jqmData(role='collapsibleset')"+(a.mobile.collapsibleset?", :mobile-collapsibleset":"")).addClass("ui-collapsible-set")};this._ui=c,this._renderedOptions=this._getOptions(this.options),this.options.enhanced?(c.heading=this.element.children(".ui-collapsible-heading"),c.content=c.heading.next(),c.anchor=c.heading.children(),c.status=c.anchor.children(".ui-collapsible-heading-status")):this._enhance(b,c),this._on(c.heading,{tap:function(){c.heading.find("a").first().addClass(a.mobile.activeBtnClass)},click:function(a){this._handleExpandCollapse(!c.heading.hasClass("ui-collapsible-heading-collapsed")),a.preventDefault(),a.stopPropagation()}})},_getOptions:function(b){var d,e=this._ui.accordion,f=this._ui.accordionWidget;b=a.extend({},b),e.length&&!f&&(this._ui.accordionWidget=f=e.data("mobile-collapsibleset"));for(d in b)b[d]=null!=b[d]?b[d]:f?f.options[d]:e.length?a.mobile.getAttribute(e[0],d.replace(c,"-$1").toLowerCase()):null,null==b[d]&&(b[d]=a.mobile.collapsible.defaults[d]);return b},_themeClassFromOption:function(a,b){return b?"none"===b?"":a+b:""},_enhance:function(b,c){var e,f=this._renderedOptions,g=this._themeClassFromOption("ui-body-",f.contentTheme);return b.addClass("ui-collapsible "+(f.inset?"ui-collapsible-inset ":"")+(f.inset&&f.corners?"ui-corner-all ":"")+(g?"ui-collapsible-themed-content ":"")),c.originalHeading=b.children(this.options.heading).first(),c.content=b.wrapInner("<div class='ui-collapsible-content "+g+"'></div>").children(".ui-collapsible-content"),c.heading=c.originalHeading,c.heading.is("legend")&&(c.heading=a("<div role='heading'>"+c.heading.html()+"</div>"),c.placeholder=a("<div><!-- placeholder for legend --></div>").insertBefore(c.originalHeading),c.originalHeading.remove()),e=f.collapsed?f.collapsedIcon?"ui-icon-"+f.collapsedIcon:"":f.expandedIcon?"ui-icon-"+f.expandedIcon:"",c.status=a("<span class='ui-collapsible-heading-status'></span>"),c.anchor=c.heading.detach().addClass("ui-collapsible-heading").append(c.status).wrapInner("<a href='#' class='ui-collapsible-heading-toggle'></a>").find("a").first().addClass("ui-btn "+(e?e+" ":"")+(e?d(f.iconpos)+" ":"")+this._themeClassFromOption("ui-btn-",f.theme)+" "+(f.mini?"ui-mini ":"")),c.heading.insertBefore(c.content),this._handleExpandCollapse(this.options.collapsed),c},refresh:function(){this._applyOptions(this.options),this._renderedOptions=this._getOptions(this.options)},_applyOptions:function(a){var c,e,f,g,h,i=this.element,j=this._renderedOptions,k=this._ui,l=k.anchor,m=k.status,n=this._getOptions(a);a.collapsed!==b&&this._handleExpandCollapse(a.collapsed),c=i.hasClass("ui-collapsible-collapsed"),c?n.expandCueText!==b&&m.text(n.expandCueText):n.collapseCueText!==b&&m.text(n.collapseCueText),h=n.collapsedIcon!==b?n.collapsedIcon!==!1:j.collapsedIcon!==!1,(n.iconpos!==b||n.collapsedIcon!==b||n.expandedIcon!==b)&&(l.removeClass([d(j.iconpos)].concat(j.expandedIcon?["ui-icon-"+j.expandedIcon]:[]).concat(j.collapsedIcon?["ui-icon-"+j.collapsedIcon]:[]).join(" ")),h&&l.addClass([d(n.iconpos!==b?n.iconpos:j.iconpos)].concat(c?["ui-icon-"+(n.collapsedIcon!==b?n.collapsedIcon:j.collapsedIcon)]:["ui-icon-"+(n.expandedIcon!==b?n.expandedIcon:j.expandedIcon)]).join(" "))),n.theme!==b&&(f=this._themeClassFromOption("ui-btn-",j.theme),e=this._themeClassFromOption("ui-btn-",n.theme),l.removeClass(f).addClass(e)),n.contentTheme!==b&&(f=this._themeClassFromOption("ui-body-",j.contentTheme),e=this._themeClassFromOption("ui-body-",n.contentTheme),k.content.removeClass(f).addClass(e)),n.inset!==b&&(i.toggleClass("ui-collapsible-inset",n.inset),g=!(!n.inset||!n.corners&&!j.corners)),n.corners!==b&&(g=!(!n.corners||!n.inset&&!j.inset)),g!==b&&i.toggleClass("ui-corner-all",g),n.mini!==b&&l.toggleClass("ui-mini",n.mini)},_setOptions:function(a){this._applyOptions(a),this._super(a),this._renderedOptions=this._getOptions(this.options)},_handleExpandCollapse:function(b){var c=this._renderedOptions,d=this._ui;d.status.text(b?c.expandCueText:c.collapseCueText),d.heading.toggleClass("ui-collapsible-heading-collapsed",b).find("a").first().toggleClass("ui-icon-"+c.expandedIcon,!b).toggleClass("ui-icon-"+c.collapsedIcon,b||c.expandedIcon===c.collapsedIcon).removeClass(a.mobile.activeBtnClass),this.element.toggleClass("ui-collapsible-collapsed",b),d.content.toggleClass("ui-collapsible-content-collapsed",b).attr("aria-hidden",b).trigger("updatelayout"),this.options.collapsed=b,this._trigger(b?"collapse":"expand")},expand:function(){this._handleExpandCollapse(!1)},collapse:function(){this._handleExpandCollapse(!0)},_destroy:function(){var a=this._ui,b=this.options;b.enhanced||(a.placeholder?(a.originalHeading.insertBefore(a.placeholder),a.placeholder.remove(),a.heading.remove()):(a.status.remove(),a.heading.removeClass("ui-collapsible-heading ui-collapsible-heading-collapsed").children().contents().unwrap()),a.anchor.contents().unwrap(),a.content.contents().unwrap(),this.element.removeClass("ui-collapsible ui-collapsible-collapsed ui-collapsible-themed-content ui-collapsible-inset ui-corner-all"))}}),a.mobile.collapsible.defaults={expandCueText:" click to expand contents",collapseCueText:" click to collapse contents",collapsedIcon:"plus",contentTheme:"inherit",expandedIcon:"minus",iconpos:"left",inset:!0,corners:!0,theme:"inherit",mini:!1}}(a),function(a){function b(b){var d,e=b.length,f=[];for(d=0;e>d;d++)b[d].className.match(c)||f.push(b[d]);return a(f)}var c=/\bui-screen-hidden\b/;a.mobile.behaviors.addFirstLastClasses={_getVisibles:function(a,c){var d;return c?d=b(a):(d=a.filter(":visible"),0===d.length&&(d=b(a))),d},_addFirstLastClasses:function(a,b,c){a.removeClass("ui-first-child ui-last-child"),b.eq(0).addClass("ui-first-child").end().last().addClass("ui-last-child"),c||this.element.trigger("updatelayout")},_removeFirstLastClasses:function(a){a.removeClass("ui-first-child ui-last-child")}}}(a),function(a,b){var c=":mobile-collapsible, "+a.mobile.collapsible.initSelector;a.widget("mobile.collapsibleset",a.extend({initSelector:":jqmData(role='collapsible-set'),:jqmData(role='collapsibleset')",options:a.extend({enhanced:!1},a.mobile.collapsible.defaults),_handleCollapsibleExpand:function(b){var c=a(b.target).closest(".ui-collapsible");c.parent().is(":mobile-collapsibleset, :jqmData(role='collapsible-set')")&&c.siblings(".ui-collapsible:not(.ui-collapsible-collapsed)").collapsible("collapse")},_create:function(){var b=this.element,c=this.options;a.extend(this,{_classes:""}),c.enhanced||(b.addClass("ui-collapsible-set "+this._themeClassFromOption("ui-group-theme-",c.theme)+" "+(c.corners&&c.inset?"ui-corner-all ":"")),this.element.find(a.mobile.collapsible.initSelector).collapsible()),this._on(b,{collapsibleexpand:"_handleCollapsibleExpand"})},_themeClassFromOption:function(a,b){return b?"none"===b?"":a+b:""},_init:function(){this._refresh(!0),this.element.children(c).filter(":jqmData(collapsed='false')").collapsible("expand")},_setOptions:function(a){var c,d,e=this.element,f=this._themeClassFromOption("ui-group-theme-",a.theme);return f&&e.removeClass(this._themeClassFromOption("ui-group-theme-",this.options.theme)).addClass(f),a.inset!==b&&(d=!(!a.inset||!a.corners&&!this.options.corners)),a.corners!==b&&(d=!(!a.corners||!a.inset&&!this.options.inset)),d!==b&&e.toggleClass("ui-corner-all",d),c=this._super(a),this.element.children(":mobile-collapsible").collapsible("refresh"),c},_destroy:function(){var a=this.element;this._removeFirstLastClasses(a.children(c)),a.removeClass("ui-collapsible-set ui-corner-all "+this._themeClassFromOption("ui-group-theme-",this.options.theme)).children(":mobile-collapsible").collapsible("destroy")},_refresh:function(b){var d=this.element.children(c);this.element.find(a.mobile.collapsible.initSelector).not(".ui-collapsible").collapsible(),this._addFirstLastClasses(d,this._getVisibles(d,b),b)},refresh:function(){this._refresh(!1)}},a.mobile.behaviors.addFirstLastClasses))}(a),function(a){a.fn.fieldcontain=function(){return this.addClass("ui-field-contain")}}(a),function(a){a.fn.grid=function(b){return this.each(function(){var c,d,e=a(this),f=a.extend({grid:null},b),g=e.children(),h={solo:1,a:2,b:3,c:4,d:5},i=f.grid;if(!i)if(g.length<=5)for(d in h)h[d]===g.length&&(i=d);else i="a",e.addClass("ui-grid-duo");c=h[i],e.addClass("ui-grid-"+i),g.filter(":nth-child("+c+"n+1)").addClass("ui-block-a"),c>1&&g.filter(":nth-child("+c+"n+2)").addClass("ui-block-b"),c>2&&g.filter(":nth-child("+c+"n+3)").addClass("ui-block-c"),c>3&&g.filter(":nth-child("+c+"n+4)").addClass("ui-block-d"),c>4&&g.filter(":nth-child("+c+"n+5)").addClass("ui-block-e")})}}(a),function(a,b){a.widget("mobile.navbar",{options:{iconpos:"top",grid:null},_create:function(){var d=this.element,e=d.find("a, button"),f=e.filter(":jqmData(icon)").length?this.options.iconpos:b;d.addClass("ui-navbar").attr("role","navigation").find("ul").jqmEnhanceable().grid({grid:this.options.grid}),e.each(function(){var b=a.mobile.getAttribute(this,"icon"),c=a.mobile.getAttribute(this,"theme"),d="ui-btn";c&&(d+=" ui-btn-"+c),b&&(d+=" ui-icon-"+b+" ui-btn-icon-"+f),a(this).addClass(d)}),d.delegate("a","vclick",function(){var b=a(this);b.hasClass("ui-state-disabled")||b.hasClass("ui-disabled")||b.hasClass(a.mobile.activeBtnClass)||(e.removeClass(a.mobile.activeBtnClass),b.addClass(a.mobile.activeBtnClass),a(c).one("pagehide",function(){b.removeClass(a.mobile.activeBtnClass)}))}),d.closest(".ui-page").bind("pagebeforeshow",function(){e.filter(".ui-state-persist").addClass(a.mobile.activeBtnClass)})}})}(a),function(a){var b=a.mobile.getAttribute;a.widget("mobile.listview",a.extend({options:{theme:null,countTheme:null,dividerTheme:null,icon:"carat-r",splitIcon:"carat-r",splitTheme:null,corners:!0,shadow:!0,inset:!1},_create:function(){var a=this,b="";b+=a.options.inset?" ui-listview-inset":"",a.options.inset&&(b+=a.options.corners?" ui-corner-all":"",b+=a.options.shadow?" ui-shadow":""),a.element.addClass(" ui-listview"+b),a.refresh(!0)},_findFirstElementByTagName:function(a,b,c,d){var e={};for(e[c]=e[d]=!0;a;){if(e[a.nodeName])return a;a=a[b]}return null},_addThumbClasses:function(b){var c,d,e=b.length;for(c=0;e>c;c++)d=a(this._findFirstElementByTagName(b[c].firstChild,"nextSibling","img","IMG")),d.length&&a(this._findFirstElementByTagName(d[0].parentNode,"parentNode","li","LI")).addClass(d.hasClass("ui-li-icon")?"ui-li-has-icon":"ui-li-has-thumb")},_getChildrenByTagName:function(b,c,d){var e=[],f={};for(f[c]=f[d]=!0,b=b.firstChild;b;)f[b.nodeName]&&e.push(b),b=b.nextSibling;return a(e)},_beforeListviewRefresh:a.noop,_afterListviewRefresh:a.noop,refresh:function(c){var d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x=this.options,y=this.element,z=!!a.nodeName(y[0],"ol"),A=y.attr("start"),B={},C=y.find(".ui-li-count"),D=b(y[0],"counttheme")||this.options.countTheme,E=D?"ui-body-"+D:"ui-body-inherit";for(x.theme&&y.addClass("ui-group-theme-"+x.theme),z&&(A||0===A)&&(n=parseInt(A,10)-1,y.css("counter-reset","listnumbering "+n)),this._beforeListviewRefresh(),w=this._getChildrenByTagName(y[0],"li","LI"),e=0,f=w.length;f>e;e++)g=w.eq(e),h="",(c||g[0].className.search(/\bui-li-static\b|\bui-li-divider\b/)<0)&&(l=this._getChildrenByTagName(g[0],"a","A"),m="list-divider"===b(g[0],"role"),p=g.attr("value"),i=b(g[0],"theme"),l.length&&l[0].className.search(/\bui-btn\b/)<0&&!m?(j=b(g[0],"icon"),k=j===!1?!1:j||x.icon,l.removeClass("ui-link"),d="ui-btn",i&&(d+=" ui-btn-"+i),l.length>1?(h="ui-li-has-alt",q=l.last(),r=b(q[0],"theme")||x.splitTheme||b(g[0],"theme",!0),s=r?" ui-btn-"+r:"",t=b(q[0],"icon")||b(g[0],"icon")||x.splitIcon,u="ui-btn ui-btn-icon-notext ui-icon-"+t+s,q.attr("title",a.trim(q.getEncodedText())).addClass(u).empty(),l=l.first()):k&&(d+=" ui-btn-icon-right ui-icon-"+k),l.addClass(d)):m?(v=b(g[0],"theme")||x.dividerTheme||x.theme,h="ui-li-divider ui-bar-"+(v?v:"inherit"),g.attr("role","heading")):l.length<=0&&(h="ui-li-static ui-body-"+(i?i:"inherit")),z&&p&&(o=parseInt(p,10)-1,g.css("counter-reset","listnumbering "+o))),B[h]||(B[h]=[]),B[h].push(g[0]);for(h in B)a(B[h]).addClass(h);C.each(function(){a(this).closest("li").addClass("ui-li-has-count")}),E&&C.not("[class*='ui-body-']").addClass(E),this._addThumbClasses(w),this._addThumbClasses(w.find(".ui-btn")),this._afterListviewRefresh(),this._addFirstLastClasses(w,this._getVisibles(w,c),c)}},a.mobile.behaviors.addFirstLastClasses))}(a),function(a){function b(b){var c=a.trim(b.text())||null;return c?c=c.slice(0,1).toUpperCase():null}a.widget("mobile.listview",a.mobile.listview,{options:{autodividers:!1,autodividersSelector:b},_beforeListviewRefresh:function(){this.options.autodividers&&(this._replaceDividers(),this._superApply(arguments))},_replaceDividers:function(){var b,d,e,f,g,h=null,i=this.element;for(i.children("li:jqmData(role='list-divider')").remove(),d=i.children("li"),b=0;b<d.length;b++)e=d[b],f=this.options.autodividersSelector(a(e)),f&&h!==f&&(g=c.createElement("li"),g.appendChild(c.createTextNode(f)),g.setAttribute("data-"+a.mobile.ns+"role","list-divider"),e.parentNode.insertBefore(g,e)),h=f}})}(a),function(a){var b=/(^|\s)ui-li-divider($|\s)/,c=/(^|\s)ui-screen-hidden($|\s)/;a.widget("mobile.listview",a.mobile.listview,{options:{hideDividers:!1},_afterListviewRefresh:function(){var a,d,e,f=!0;if(this._superApply(arguments),this.options.hideDividers)for(a=this._getChildrenByTagName(this.element[0],"li","LI"),d=a.length-1;d>-1;d--)e=a[d],e.className.match(b)?(f&&(e.className=e.className+" ui-screen-hidden"),f=!0):e.className.match(c)||(f=!1)}})}(a),function(a){a.mobile.nojs=function(b){a(":jqmData(role='nojs')",b).addClass("ui-nojs")}}(a),function(a){a.mobile.behaviors.formReset={_handleFormReset:function(){this._on(this.element.closest("form"),{reset:function(){this._delay("_reset")}})}}}(a),function(a,b){var c=a.mobile.path.hashToSelector;a.widget("mobile.checkboxradio",a.extend({initSelector:"input:not( :jqmData(role='flipswitch' ) )[type='checkbox'],input[type='radio']:not( :jqmData(role='flipswitch' ))",options:{theme:"inherit",mini:!1,wrapperClass:null,enhanced:!1,iconpos:"left"},_create:function(){var b=this.element,c=this.options,d=function(a,b){return a.jqmData(b)||a.closest("form, fieldset").jqmData(b)},e=this.options.enhanced?{element:this.element.siblings("label"),isParent:!1}:this._findLabel(),f=b[0].type,g="ui-"+f+"-on",h="ui-"+f+"-off";("checkbox"===f||"radio"===f)&&(this.element[0].disabled&&(this.options.disabled=!0),c.iconpos=d(b,"iconpos")||e.element.attr("data-"+a.mobile.ns+"iconpos")||c.iconpos,c.mini=d(b,"mini")||c.mini,a.extend(this,{input:b,label:e.element,labelIsParent:e.isParent,inputtype:f,checkedClass:g,uncheckedClass:h}),this.options.enhanced||this._enhance(),this._on(e.element,{vmouseover:"_handleLabelVMouseOver",vclick:"_handleLabelVClick"}),this._on(b,{vmousedown:"_cacheVals",vclick:"_handleInputVClick",focus:"_handleInputFocus",blur:"_handleInputBlur"}),this._handleFormReset(),this.refresh())},_findLabel:function(){var b,d,e,f=this.element,g=f[0].labels;return g&&g.length>0?(d=a(g[0]),e=a.contains(d[0],f[0])):(b=f.closest("label"),e=b.length>0,d=e?b:a(this.document[0].getElementsByTagName("label")).filter("[for='"+c(f[0].id)+"']").first()),{element:d,isParent:e}},_enhance:function(){this.label.addClass("ui-btn ui-corner-all"),this.labelIsParent?this.input.add(this.label).wrapAll(this._wrapper()):(this.element.wrap(this._wrapper()),this.element.parent().prepend(this.label)),this._setOptions({theme:this.options.theme,iconpos:this.options.iconpos,mini:this.options.mini})},_wrapper:function(){return a("<div class='"+(this.options.wrapperClass?this.options.wrapperClass:"")+" ui-"+this.inputtype+(this.options.disabled?" ui-state-disabled":"")+"' ></div>")},_handleInputFocus:function(){this.label.addClass(a.mobile.focusClass)},_handleInputBlur:function(){this.label.removeClass(a.mobile.focusClass)},_handleInputVClick:function(){this.element.prop("checked",this.element.is(":checked")),this._getInputSet().not(this.element).prop("checked",!1),this._updateAll(!0)},_handleLabelVMouseOver:function(a){this.label.parent().hasClass("ui-state-disabled")&&a.stopPropagation()},_handleLabelVClick:function(a){var b=this.element;return b.is(":disabled")?void a.preventDefault():(this._cacheVals(),b.prop("checked","radio"===this.inputtype&&!0||!b.prop("checked")),b.triggerHandler("click"),this._getInputSet().not(b).prop("checked",!1),this._updateAll(),!1)},_cacheVals:function(){this._getInputSet().each(function(){a(this).attr("data-"+a.mobile.ns+"cacheVal",this.checked)})},_getInputSet:function(){var b,d,e=this.element[0],f=e.name,g=e.form,h=this.element.parents().last().get(0),i=this.element;return f&&"radio"===this.inputtype&&h&&(b="input[type='radio'][name='"+c(f)+"']",g?(d=g.getAttribute("id"),d&&(i=a(b+"[form='"+c(d)+"']",h)),i=a(g).find(b).filter(function(){return this.form===g}).add(i)):i=a(b,h).filter(function(){return!this.form})),i},_updateAll:function(b){var c=this;this._getInputSet().each(function(){var d=a(this);!this.checked&&"checkbox"!==c.inputtype||b||d.trigger("change")}).checkboxradio("refresh")},_reset:function(){this.refresh()},_hasIcon:function(){var b,c,d=a.mobile.controlgroup;return d&&(b=this.element.closest(":mobile-controlgroup,"+d.prototype.initSelector),b.length>0)?(c=a.data(b[0],"mobile-controlgroup"),"horizontal"!==(c?c.options.type:b.attr("data-"+a.mobile.ns+"type"))):!0},refresh:function(){var b=this.element[0].checked,c=a.mobile.activeBtnClass,d="ui-btn-icon-"+this.options.iconpos,e=[],f=[];this._hasIcon()?(f.push(c),e.push(d)):(f.push(d),(b?e:f).push(c)),b?(e.push(this.checkedClass),f.push(this.uncheckedClass)):(e.push(this.uncheckedClass),f.push(this.checkedClass)),this.widget().toggleClass("ui-state-disabled",this.element.prop("disabled")),this.label.addClass(e.join(" ")).removeClass(f.join(" "))},widget:function(){return this.label.parent()},_setOptions:function(a){var c=this.label,d=this.options,e=this.widget(),f=this._hasIcon();a.disabled!==b&&(this.input.prop("disabled",!!a.disabled),e.toggleClass("ui-state-disabled",!!a.disabled)),a.mini!==b&&e.toggleClass("ui-mini",!!a.mini),a.theme!==b&&c.removeClass("ui-btn-"+d.theme).addClass("ui-btn-"+a.theme),a.wrapperClass!==b&&e.removeClass(d.wrapperClass).addClass(a.wrapperClass),a.iconpos!==b&&f?c.removeClass("ui-btn-icon-"+d.iconpos).addClass("ui-btn-icon-"+a.iconpos):f||c.removeClass("ui-btn-icon-"+d.iconpos),this._super(a)}},a.mobile.behaviors.formReset))}(a),function(a,b){a.widget("mobile.button",{initSelector:"input[type='button'], input[type='submit'], input[type='reset']",options:{theme:null,icon:null,iconpos:"left",iconshadow:!1,corners:!0,shadow:!0,inline:null,mini:null,wrapperClass:null,enhanced:!1},_create:function(){this.element.is(":disabled")&&(this.options.disabled=!0),this.options.enhanced||this._enhance(),a.extend(this,{wrapper:this.element.parent()}),this._on({focus:function(){this.widget().addClass(a.mobile.focusClass)},blur:function(){this.widget().removeClass(a.mobile.focusClass)}}),this.refresh(!0)},_enhance:function(){this.element.wrap(this._button())},_button:function(){var b=this.options,c=this._getIconClasses(this.options);return a("<div class='ui-btn ui-input-btn"+(b.wrapperClass?" "+b.wrapperClass:"")+(b.theme?" ui-btn-"+b.theme:"")+(b.corners?" ui-corner-all":"")+(b.shadow?" ui-shadow":"")+(b.inline?" ui-btn-inline":"")+(b.mini?" ui-mini":"")+(b.disabled?" ui-state-disabled":"")+(c?" "+c:"")+"' >"+this.element.val()+"</div>")},widget:function(){return this.wrapper},_destroy:function(){this.element.insertBefore(this.wrapper),this.wrapper.remove()},_getIconClasses:function(a){return a.icon?"ui-icon-"+a.icon+(a.iconshadow?" ui-shadow-icon":"")+" ui-btn-icon-"+a.iconpos:""},_setOptions:function(c){var d=this.widget();c.theme!==b&&d.removeClass(this.options.theme).addClass("ui-btn-"+c.theme),c.corners!==b&&d.toggleClass("ui-corner-all",c.corners),c.shadow!==b&&d.toggleClass("ui-shadow",c.shadow),c.inline!==b&&d.toggleClass("ui-btn-inline",c.inline),c.mini!==b&&d.toggleClass("ui-mini",c.mini),c.disabled!==b&&(this.element.prop("disabled",c.disabled),d.toggleClass("ui-state-disabled",c.disabled)),(c.icon!==b||c.iconshadow!==b||c.iconpos!==b)&&d.removeClass(this._getIconClasses(this.options)).addClass(this._getIconClasses(a.extend({},this.options,c))),this._super(c)},refresh:function(b){var c,d=this.element.prop("disabled");this.options.icon&&"notext"===this.options.iconpos&&this.element.attr("title")&&this.element.attr("title",this.element.val()),b||(c=this.element.detach(),a(this.wrapper).text(this.element.val()).append(c)),this.options.disabled!==d&&this._setOptions({disabled:d})}})}(a),function(a){var b=a("meta[name=viewport]"),c=b.attr("content"),d=c+",maximum-scale=1, user-scalable=no",e=c+",maximum-scale=10, user-scalable=yes",f=/(user-scalable[\s]*=[\s]*no)|(maximum-scale[\s]*=[\s]*1)[$,\s]/.test(c);a.mobile.zoom=a.extend({},{enabled:!f,locked:!1,disable:function(c){f||a.mobile.zoom.locked||(b.attr("content",d),a.mobile.zoom.enabled=!1,a.mobile.zoom.locked=c||!1)},enable:function(c){f||a.mobile.zoom.locked&&c!==!0||(b.attr("content",e),a.mobile.zoom.enabled=!0,a.mobile.zoom.locked=!1)},restore:function(){f||(b.attr("content",c),a.mobile.zoom.enabled=!0)}})}(a),function(a,b){a.widget("mobile.textinput",{initSelector:"input[type='text'],input[type='search'],:jqmData(type='search'),input[type='number'],:jqmData(type='number'),input[type='password'],input[type='email'],input[type='url'],input[type='tel'],textarea,input[type='time'],input[type='date'],input[type='month'],input[type='week'],input[type='datetime'],input[type='datetime-local'],input[type='color'],input:not([type]),input[type='file']",options:{theme:null,corners:!0,mini:!1,preventFocusZoom:/iPhone|iPad|iPod/.test(navigator.platform)&&navigator.userAgent.indexOf("AppleWebKit")>-1,wrapperClass:"",enhanced:!1},_create:function(){var b=this.options,c=this.element.is("[type='search'], :jqmData(type='search')"),d="TEXTAREA"===this.element[0].tagName,e=this.element.is("[data-"+(a.mobile.ns||"")+"type='range']"),f=(this.element.is("input")||this.element.is("[data-"+(a.mobile.ns||"")+"type='search']"))&&!e;this.element.prop("disabled")&&(b.disabled=!0),a.extend(this,{classes:this._classesFromOptions(),isSearch:c,isTextarea:d,isRange:e,inputNeedsWrap:f}),this._autoCorrect(),b.enhanced||this._enhance(),this._on({focus:"_handleFocus",blur:"_handleBlur"})},refresh:function(){this.setOptions({disabled:this.element.is(":disabled")})},_enhance:function(){var a=[];this.isTextarea&&a.push("ui-input-text"),(this.isTextarea||this.isRange)&&a.push("ui-shadow-inset"),this.inputNeedsWrap?this.element.wrap(this._wrap()):a=a.concat(this.classes),this.element.addClass(a.join(" "))},widget:function(){return this.inputNeedsWrap?this.element.parent():this.element},_classesFromOptions:function(){var a=this.options,b=[];return b.push("ui-body-"+(null===a.theme?"inherit":a.theme)),a.corners&&b.push("ui-corner-all"),a.mini&&b.push("ui-mini"),a.disabled&&b.push("ui-state-disabled"),a.wrapperClass&&b.push(a.wrapperClass),b
+},_wrap:function(){return a("<div class='"+(this.isSearch?"ui-input-search ":"ui-input-text ")+this.classes.join(" ")+" ui-shadow-inset'></div>")},_autoCorrect:function(){"undefined"==typeof this.element[0].autocorrect||a.support.touchOverflow||(this.element[0].setAttribute("autocorrect","off"),this.element[0].setAttribute("autocomplete","off"))},_handleBlur:function(){this.widget().removeClass(a.mobile.focusClass),this.options.preventFocusZoom&&a.mobile.zoom.enable(!0)},_handleFocus:function(){this.options.preventFocusZoom&&a.mobile.zoom.disable(!0),this.widget().addClass(a.mobile.focusClass)},_setOptions:function(a){var c=this.widget();this._super(a),(a.disabled!==b||a.mini!==b||a.corners!==b||a.theme!==b||a.wrapperClass!==b)&&(c.removeClass(this.classes.join(" ")),this.classes=this._classesFromOptions(),c.addClass(this.classes.join(" "))),a.disabled!==b&&this.element.prop("disabled",!!a.disabled)},_destroy:function(){this.options.enhanced||(this.inputNeedsWrap&&this.element.unwrap(),this.element.removeClass("ui-input-text "+this.classes.join(" ")))}})}(a),function(a,d){a.widget("mobile.slider",a.extend({initSelector:"input[type='range'], :jqmData(type='range'), :jqmData(role='slider')",widgetEventPrefix:"slide",options:{theme:null,trackTheme:null,corners:!0,mini:!1,highlight:!1},_create:function(){var e,f,g,h,i,j,k,l,m,n,o=this,p=this.element,q=this.options.trackTheme||a.mobile.getAttribute(p[0],"theme"),r=q?" ui-bar-"+q:" ui-bar-inherit",s=this.options.corners||p.jqmData("corners")?" ui-corner-all":"",t=this.options.mini||p.jqmData("mini")?" ui-mini":"",u=p[0].nodeName.toLowerCase(),v="select"===u,w=p.parent().is(":jqmData(role='rangeslider')"),x=v?"ui-slider-switch":"",y=p.attr("id"),z=a("[for='"+y+"']"),A=z.attr("id")||y+"-label",B=v?0:parseFloat(p.attr("min")),C=v?p.find("option").length-1:parseFloat(p.attr("max")),D=b.parseFloat(p.attr("step")||1),E=c.createElement("a"),F=a(E),G=c.createElement("div"),H=a(G),I=this.options.highlight&&!v?function(){var b=c.createElement("div");return b.className="ui-slider-bg "+a.mobile.activeBtnClass,a(b).prependTo(H)}():!1;if(z.attr("id",A),this.isToggleSwitch=v,E.setAttribute("href","#"),G.setAttribute("role","application"),G.className=[this.isToggleSwitch?"ui-slider ui-slider-track ui-shadow-inset ":"ui-slider-track ui-shadow-inset ",x,r,s,t].join(""),E.className="ui-slider-handle",G.appendChild(E),F.attr({role:"slider","aria-valuemin":B,"aria-valuemax":C,"aria-valuenow":this._value(),"aria-valuetext":this._value(),title:this._value(),"aria-labelledby":A}),a.extend(this,{slider:H,handle:F,control:p,type:u,step:D,max:C,min:B,valuebg:I,isRangeslider:w,dragging:!1,beforeStart:null,userModified:!1,mouseMoved:!1}),v){for(k=p.attr("tabindex"),k&&F.attr("tabindex",k),p.attr("tabindex","-1").focus(function(){a(this).blur(),F.focus()}),f=c.createElement("div"),f.className="ui-slider-inneroffset",g=0,h=G.childNodes.length;h>g;g++)f.appendChild(G.childNodes[g]);for(G.appendChild(f),F.addClass("ui-slider-handle-snapping"),e=p.find("option"),i=0,j=e.length;j>i;i++)l=i?"a":"b",m=i?" "+a.mobile.activeBtnClass:"",n=c.createElement("span"),n.className=["ui-slider-label ui-slider-label-",l,m].join(""),n.setAttribute("role","img"),n.appendChild(c.createTextNode(e[i].innerHTML)),a(n).prependTo(H);o._labels=a(".ui-slider-label",H)}p.addClass(v?"ui-slider-switch":"ui-slider-input"),this._on(p,{change:"_controlChange",keyup:"_controlKeyup",blur:"_controlBlur",vmouseup:"_controlVMouseUp"}),H.bind("vmousedown",a.proxy(this._sliderVMouseDown,this)).bind("vclick",!1),this._on(c,{vmousemove:"_preventDocumentDrag"}),this._on(H.add(c),{vmouseup:"_sliderVMouseUp"}),H.insertAfter(p),v||w||(f=this.options.mini?"<div class='ui-slider ui-mini'>":"<div class='ui-slider'>",p.add(H).wrapAll(f)),this._on(this.handle,{vmousedown:"_handleVMouseDown",keydown:"_handleKeydown",keyup:"_handleKeyup"}),this.handle.bind("vclick",!1),this._handleFormReset(),this.refresh(d,d,!0)},_setOptions:function(a){a.theme!==d&&this._setTheme(a.theme),a.trackTheme!==d&&this._setTrackTheme(a.trackTheme),a.corners!==d&&this._setCorners(a.corners),a.mini!==d&&this._setMini(a.mini),a.highlight!==d&&this._setHighlight(a.highlight),a.disabled!==d&&this._setDisabled(a.disabled),this._super(a)},_controlChange:function(a){return this._trigger("controlchange",a)===!1?!1:void(this.mouseMoved||this.refresh(this._value(),!0))},_controlKeyup:function(){this.refresh(this._value(),!0,!0)},_controlBlur:function(){this.refresh(this._value(),!0)},_controlVMouseUp:function(){this._checkedRefresh()},_handleVMouseDown:function(){this.handle.focus()},_handleKeydown:function(b){var c=this._value();if(!this.options.disabled){switch(b.keyCode){case a.mobile.keyCode.HOME:case a.mobile.keyCode.END:case a.mobile.keyCode.PAGE_UP:case a.mobile.keyCode.PAGE_DOWN:case a.mobile.keyCode.UP:case a.mobile.keyCode.RIGHT:case a.mobile.keyCode.DOWN:case a.mobile.keyCode.LEFT:b.preventDefault(),this._keySliding||(this._keySliding=!0,this.handle.addClass("ui-state-active"))}switch(b.keyCode){case a.mobile.keyCode.HOME:this.refresh(this.min);break;case a.mobile.keyCode.END:this.refresh(this.max);break;case a.mobile.keyCode.PAGE_UP:case a.mobile.keyCode.UP:case a.mobile.keyCode.RIGHT:this.refresh(c+this.step);break;case a.mobile.keyCode.PAGE_DOWN:case a.mobile.keyCode.DOWN:case a.mobile.keyCode.LEFT:this.refresh(c-this.step)}}},_handleKeyup:function(){this._keySliding&&(this._keySliding=!1,this.handle.removeClass("ui-state-active"))},_sliderVMouseDown:function(a){return this.options.disabled||1!==a.which&&0!==a.which&&a.which!==d?!1:this._trigger("beforestart",a)===!1?!1:(this.dragging=!0,this.userModified=!1,this.mouseMoved=!1,this.isToggleSwitch&&(this.beforeStart=this.element[0].selectedIndex),this.refresh(a),this._trigger("start"),!1)},_sliderVMouseUp:function(){return this.dragging?(this.dragging=!1,this.isToggleSwitch&&(this.handle.addClass("ui-slider-handle-snapping"),this.refresh(this.mouseMoved?this.userModified?0===this.beforeStart?1:0:this.beforeStart:0===this.beforeStart?1:0)),this.mouseMoved=!1,this._trigger("stop"),!1):void 0},_preventDocumentDrag:function(a){return this._trigger("drag",a)===!1?!1:this.dragging&&!this.options.disabled?(this.mouseMoved=!0,this.isToggleSwitch&&this.handle.removeClass("ui-slider-handle-snapping"),this.refresh(a),this.userModified=this.beforeStart!==this.element[0].selectedIndex,!1):void 0},_checkedRefresh:function(){this.value!==this._value()&&this.refresh(this._value())},_value:function(){return this.isToggleSwitch?this.element[0].selectedIndex:parseFloat(this.element.val())},_reset:function(){this.refresh(d,!1,!0)},refresh:function(b,d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z=this,A=a.mobile.getAttribute(this.element[0],"theme"),B=this.options.theme||A,C=B?" ui-btn-"+B:"",D=this.options.trackTheme||A,E=D?" ui-bar-"+D:" ui-bar-inherit",F=this.options.corners?" ui-corner-all":"",G=this.options.mini?" ui-mini":"";if(z.slider[0].className=[this.isToggleSwitch?"ui-slider ui-slider-switch ui-slider-track ui-shadow-inset":"ui-slider-track ui-shadow-inset",E,F,G].join(""),(this.options.disabled||this.element.prop("disabled"))&&this.disable(),this.value=this._value(),this.options.highlight&&!this.isToggleSwitch&&0===this.slider.find(".ui-slider-bg").length&&(this.valuebg=function(){var b=c.createElement("div");return b.className="ui-slider-bg "+a.mobile.activeBtnClass,a(b).prependTo(z.slider)}()),this.handle.addClass("ui-btn"+C+" ui-shadow"),l=this.element,m=!this.isToggleSwitch,n=m?[]:l.find("option"),o=m?parseFloat(l.attr("min")):0,p=m?parseFloat(l.attr("max")):n.length-1,q=m&&parseFloat(l.attr("step"))>0?parseFloat(l.attr("step")):1,"object"==typeof b){if(h=b,i=8,f=this.slider.offset().left,g=this.slider.width(),j=g/((p-o)/q),!this.dragging||h.pageX<f-i||h.pageX>f+g+i)return;k=j>1?(h.pageX-f)/g*100:Math.round((h.pageX-f)/g*100)}else null==b&&(b=m?parseFloat(l.val()||0):l[0].selectedIndex),k=(parseFloat(b)-o)/(p-o)*100;if(!isNaN(k)&&(r=k/100*(p-o)+o,s=(r-o)%q,t=r-s,2*Math.abs(s)>=q&&(t+=s>0?q:-q),u=100/((p-o)/q),r=parseFloat(t.toFixed(5)),"undefined"==typeof j&&(j=g/((p-o)/q)),j>1&&m&&(k=(r-o)*u*(1/q)),0>k&&(k=0),k>100&&(k=100),o>r&&(r=o),r>p&&(r=p),this.handle.css("left",k+"%"),this.handle[0].setAttribute("aria-valuenow",m?r:n.eq(r).attr("value")),this.handle[0].setAttribute("aria-valuetext",m?r:n.eq(r).getEncodedText()),this.handle[0].setAttribute("title",m?r:n.eq(r).getEncodedText()),this.valuebg&&this.valuebg.css("width",k+"%"),this._labels&&(v=this.handle.width()/this.slider.width()*100,w=k&&v+(100-v)*k/100,x=100===k?0:Math.min(v+100-w,100),this._labels.each(function(){var b=a(this).hasClass("ui-slider-label-a");a(this).width((b?w:x)+"%")})),!e)){if(y=!1,m?(y=parseFloat(l.val())!==r,l.val(r)):(y=l[0].selectedIndex!==r,l[0].selectedIndex=r),this._trigger("beforechange",b)===!1)return!1;!d&&y&&l.trigger("change")}},_setHighlight:function(a){a=!!a,a?(this.options.highlight=!!a,this.refresh()):this.valuebg&&(this.valuebg.remove(),this.valuebg=!1)},_setTheme:function(a){this.handle.removeClass("ui-btn-"+this.options.theme).addClass("ui-btn-"+a);var b=this.options.theme?this.options.theme:"inherit",c=a?a:"inherit";this.control.removeClass("ui-body-"+b).addClass("ui-body-"+c)},_setTrackTheme:function(a){var b=this.options.trackTheme?this.options.trackTheme:"inherit",c=a?a:"inherit";this.slider.removeClass("ui-body-"+b).addClass("ui-body-"+c)},_setMini:function(a){a=!!a,this.isToggleSwitch||this.isRangeslider||(this.slider.parent().toggleClass("ui-mini",a),this.element.toggleClass("ui-mini",a)),this.slider.toggleClass("ui-mini",a)},_setCorners:function(a){this.slider.toggleClass("ui-corner-all",a),this.isToggleSwitch||this.control.toggleClass("ui-corner-all",a)},_setDisabled:function(a){a=!!a,this.element.prop("disabled",a),this.slider.toggleClass("ui-state-disabled",a).attr("aria-disabled",a),this.element.toggleClass("ui-state-disabled",a)}},a.mobile.behaviors.formReset))}(a),function(a){function b(){return c||(c=a("<div></div>",{"class":"ui-slider-popup ui-shadow ui-corner-all"})),c.clone()}var c;a.widget("mobile.slider",a.mobile.slider,{options:{popupEnabled:!1,showValue:!1},_create:function(){this._super(),a.extend(this,{_currentValue:null,_popup:null,_popupVisible:!1}),this._setOption("popupEnabled",this.options.popupEnabled),this._on(this.handle,{vmousedown:"_showPopup"}),this._on(this.slider.add(this.document),{vmouseup:"_hidePopup"}),this._refresh()},_positionPopup:function(){var a=this.handle.offset();this._popup.offset({left:a.left+(this.handle.width()-this._popup.width())/2,top:a.top-this._popup.outerHeight()-5})},_setOption:function(a,c){this._super(a,c),"showValue"===a?this.handle.html(c&&!this.options.mini?this._value():""):"popupEnabled"===a&&c&&!this._popup&&(this._popup=b().addClass("ui-body-"+(this.options.theme||"a")).hide().insertBefore(this.element))},refresh:function(){this._super.apply(this,arguments),this._refresh()},_refresh:function(){var a,b=this.options;b.popupEnabled&&this.handle.removeAttr("title"),a=this._value(),a!==this._currentValue&&(this._currentValue=a,b.popupEnabled&&this._popup&&(this._positionPopup(),this._popup.html(a)),b.showValue&&!this.options.mini&&this.handle.html(a))},_showPopup:function(){this.options.popupEnabled&&!this._popupVisible&&(this.handle.html(""),this._popup.show(),this._positionPopup(),this._popupVisible=!0)},_hidePopup:function(){var a=this.options;a.popupEnabled&&this._popupVisible&&(a.showValue&&!a.mini&&this.handle.html(this._value()),this._popup.hide(),this._popupVisible=!1)}})}(a),function(a,b){a.widget("mobile.flipswitch",a.extend({options:{onText:"On",offText:"Off",theme:null,enhanced:!1,wrapperClass:null,corners:!0,mini:!1},_create:function(){this.options.enhanced?a.extend(this,{flipswitch:this.element.parent(),on:this.element.find(".ui-flipswitch-on").eq(0),off:this.element.find(".ui-flipswitch-off").eq(0),type:this.element.get(0).tagName}):this._enhance(),this._handleFormReset(),this._originalTabIndex=this.element.attr("tabindex"),null!=this._originalTabIndex&&this.on.attr("tabindex",this._originalTabIndex),this.element.attr("tabindex","-1"),this._on({focus:"_handleInputFocus"}),this.element.is(":disabled")&&this._setOptions({disabled:!0}),this._on(this.flipswitch,{click:"_toggle",swipeleft:"_left",swiperight:"_right"}),this._on(this.on,{keydown:"_keydown"}),this._on({change:"refresh"})},_handleInputFocus:function(){this.on.focus()},widget:function(){return this.flipswitch},_left:function(){this.flipswitch.removeClass("ui-flipswitch-active"),"SELECT"===this.type?this.element.get(0).selectedIndex=0:this.element.prop("checked",!1),this.element.trigger("change")},_right:function(){this.flipswitch.addClass("ui-flipswitch-active"),"SELECT"===this.type?this.element.get(0).selectedIndex=1:this.element.prop("checked",!0),this.element.trigger("change")},_enhance:function(){var b=a("<div>"),c=this.options,d=this.element,e=c.theme?c.theme:"inherit",f=a("<a></a>",{href:"#"}),g=a("<span></span>"),h=d.get(0).tagName,i="INPUT"===h?c.onText:d.find("option").eq(1).text(),j="INPUT"===h?c.offText:d.find("option").eq(0).text();f.addClass("ui-flipswitch-on ui-btn ui-shadow ui-btn-inherit").text(i),g.addClass("ui-flipswitch-off").text(j),b.addClass("ui-flipswitch ui-shadow-inset ui-bar-"+e+" "+(c.wrapperClass?c.wrapperClass:"")+" "+(d.is(":checked")||d.find("option").eq(1).is(":selected")?"ui-flipswitch-active":"")+(d.is(":disabled")?" ui-state-disabled":"")+(c.corners?" ui-corner-all":"")+(c.mini?" ui-mini":"")).append(f,g),d.addClass("ui-flipswitch-input").after(b).appendTo(b),a.extend(this,{flipswitch:b,on:f,off:g,type:h})},_reset:function(){this.refresh()},refresh:function(){var a,b=this.flipswitch.hasClass("ui-flipswitch-active")?"_right":"_left";a="SELECT"===this.type?this.element.get(0).selectedIndex>0?"_right":"_left":this.element.prop("checked")?"_right":"_left",a!==b&&this[a]()},_toggle:function(){var a=this.flipswitch.hasClass("ui-flipswitch-active")?"_left":"_right";this[a]()},_keydown:function(b){b.which===a.mobile.keyCode.LEFT?this._left():b.which===a.mobile.keyCode.RIGHT?this._right():b.which===a.mobile.keyCode.SPACE&&(this._toggle(),b.preventDefault())},_setOptions:function(a){if(a.theme!==b){var c=a.theme?a.theme:"inherit",d=a.theme?a.theme:"inherit";this.widget().removeClass("ui-bar-"+c).addClass("ui-bar-"+d)}a.onText!==b&&this.on.text(a.onText),a.offText!==b&&this.off.text(a.offText),a.disabled!==b&&this.widget().toggleClass("ui-state-disabled",a.disabled),a.mini!==b&&this.widget().toggleClass("ui-mini",a.mini),a.corners!==b&&this.widget().toggleClass("ui-corner-all",a.corners),this._super(a)},_destroy:function(){this.options.enhanced||(null!=this._originalTabIndex?this.element.attr("tabindex",this._originalTabIndex):this.element.removeAttr("tabindex"),this.on.remove(),this.off.remove(),this.element.unwrap(),this.flipswitch.remove(),this.removeClass("ui-flipswitch-input"))}},a.mobile.behaviors.formReset))}(a),function(a,b){a.widget("mobile.rangeslider",a.extend({options:{theme:null,trackTheme:null,corners:!0,mini:!1,highlight:!0},_create:function(){var b=this.element,c=this.options.mini?"ui-rangeslider ui-mini":"ui-rangeslider",d=b.find("input").first(),e=b.find("input").last(),f=b.find("label").first(),g=a.data(d.get(0),"mobile-slider")||a.data(d.slider().get(0),"mobile-slider"),h=a.data(e.get(0),"mobile-slider")||a.data(e.slider().get(0),"mobile-slider"),i=g.slider,j=h.slider,k=g.handle,l=a("<div class='ui-rangeslider-sliders' />").appendTo(b);d.addClass("ui-rangeslider-first"),e.addClass("ui-rangeslider-last"),b.addClass(c),i.appendTo(l),j.appendTo(l),f.insertBefore(b),k.prependTo(j),a.extend(this,{_inputFirst:d,_inputLast:e,_sliderFirst:i,_sliderLast:j,_label:f,_targetVal:null,_sliderTarget:!1,_sliders:l,_proxy:!1}),this.refresh(),this._on(this.element.find("input.ui-slider-input"),{slidebeforestart:"_slidebeforestart",slidestop:"_slidestop",slidedrag:"_slidedrag",slidebeforechange:"_change",blur:"_change",keyup:"_change"}),this._on({mousedown:"_change"}),this._on(this.element.closest("form"),{reset:"_handleReset"}),this._on(k,{vmousedown:"_dragFirstHandle"})},_handleReset:function(){var a=this;setTimeout(function(){a._updateHighlight()},0)},_dragFirstHandle:function(b){return a.data(this._inputFirst.get(0),"mobile-slider").dragging=!0,a.data(this._inputFirst.get(0),"mobile-slider").refresh(b),a.data(this._inputFirst.get(0),"mobile-slider")._trigger("start"),!1},_slidedrag:function(b){var c=a(b.target).is(this._inputFirst),d=c?this._inputLast:this._inputFirst;return this._sliderTarget=!1,"first"===this._proxy&&c||"last"===this._proxy&&!c?(a.data(d.get(0),"mobile-slider").dragging=!0,a.data(d.get(0),"mobile-slider").refresh(b),!1):void 0},_slidestop:function(b){var c=a(b.target).is(this._inputFirst);this._proxy=!1,this.element.find("input").trigger("vmouseup"),this._sliderFirst.css("z-index",c?1:"")},_slidebeforestart:function(b){this._sliderTarget=!1,a(b.originalEvent.target).hasClass("ui-slider-track")&&(this._sliderTarget=!0,this._targetVal=a(b.target).val())},_setOptions:function(a){a.theme!==b&&this._setTheme(a.theme),a.trackTheme!==b&&this._setTrackTheme(a.trackTheme),a.mini!==b&&this._setMini(a.mini),a.highlight!==b&&this._setHighlight(a.highlight),a.disabled!==b&&this._setDisabled(a.disabled),this._super(a),this.refresh()},refresh:function(){var a=this.element,b=this.options;(this._inputFirst.is(":disabled")||this._inputLast.is(":disabled"))&&(this.options.disabled=!0),a.find("input").slider({theme:b.theme,trackTheme:b.trackTheme,disabled:b.disabled,corners:b.corners,mini:b.mini,highlight:b.highlight}).slider("refresh"),this._updateHighlight()},_change:function(b){if("keyup"===b.type)return this._updateHighlight(),!1;var c=this,d=parseFloat(this._inputFirst.val(),10),e=parseFloat(this._inputLast.val(),10),f=a(b.target).hasClass("ui-rangeslider-first"),g=f?this._inputFirst:this._inputLast,h=f?this._inputLast:this._inputFirst;if(this._inputFirst.val()>this._inputLast.val()&&"mousedown"===b.type&&!a(b.target).hasClass("ui-slider-handle"))g.blur();else if("mousedown"===b.type)return;return d>e&&!this._sliderTarget?(g.val(f?e:d).slider("refresh"),this._trigger("normalize")):d>e&&(g.val(this._targetVal).slider("refresh"),setTimeout(function(){h.val(f?d:e).slider("refresh"),a.data(h.get(0),"mobile-slider").handle.focus(),c._sliderFirst.css("z-index",f?"":1),c._trigger("normalize")},0),this._proxy=f?"first":"last"),d===e?(a.data(g.get(0),"mobile-slider").handle.css("z-index",1),a.data(h.get(0),"mobile-slider").handle.css("z-index",0)):(a.data(h.get(0),"mobile-slider").handle.css("z-index",""),a.data(g.get(0),"mobile-slider").handle.css("z-index","")),this._updateHighlight(),d>=e?!1:void 0},_updateHighlight:function(){var b=parseInt(a.data(this._inputFirst.get(0),"mobile-slider").handle.get(0).style.left,10),c=parseInt(a.data(this._inputLast.get(0),"mobile-slider").handle.get(0).style.left,10),d=c-b;this.element.find(".ui-slider-bg").css({"margin-left":b+"%",width:d+"%"})},_setTheme:function(a){this._inputFirst.slider("option","theme",a),this._inputLast.slider("option","theme",a)},_setTrackTheme:function(a){this._inputFirst.slider("option","trackTheme",a),this._inputLast.slider("option","trackTheme",a)},_setMini:function(a){this._inputFirst.slider("option","mini",a),this._inputLast.slider("option","mini",a),this.element.toggleClass("ui-mini",!!a)},_setHighlight:function(a){this._inputFirst.slider("option","highlight",a),this._inputLast.slider("option","highlight",a)},_setDisabled:function(a){this._inputFirst.prop("disabled",a),this._inputLast.prop("disabled",a)},_destroy:function(){this._label.prependTo(this.element),this.element.removeClass("ui-rangeslider ui-mini"),this._inputFirst.after(this._sliderFirst),this._inputLast.after(this._sliderLast),this._sliders.remove(),this.element.find("input").removeClass("ui-rangeslider-first ui-rangeslider-last").slider("destroy")}},a.mobile.behaviors.formReset))}(a),function(a,b){a.widget("mobile.textinput",a.mobile.textinput,{options:{clearBtn:!1,clearBtnText:"Clear text"},_create:function(){this._super(),this.isSearch&&(this.options.clearBtn=!0),this.options.clearBtn&&this.inputNeedsWrap&&this._addClearBtn()},clearButton:function(){return a("<a href='#' tabindex='-1' aria-hidden='true' class='ui-input-clear ui-btn ui-icon-delete ui-btn-icon-notext ui-corner-all'></a>").attr("title",this.options.clearBtnText).text(this.options.clearBtnText)},_clearBtnClick:function(a){this.element.val("").focus().trigger("change"),this._clearBtn.addClass("ui-input-clear-hidden"),a.preventDefault()},_addClearBtn:function(){this.options.enhanced||this._enhanceClear(),a.extend(this,{_clearBtn:this.widget().find("a.ui-input-clear")}),this._bindClearEvents(),this._toggleClear()},_enhanceClear:function(){this.clearButton().appendTo(this.widget()),this.widget().addClass("ui-input-has-clear")},_bindClearEvents:function(){this._on(this._clearBtn,{click:"_clearBtnClick"}),this._on({keyup:"_toggleClear",change:"_toggleClear",input:"_toggleClear",focus:"_toggleClear",blur:"_toggleClear",cut:"_toggleClear",paste:"_toggleClear"})},_unbindClear:function(){this._off(this._clearBtn,"click"),this._off(this.element,"keyup change input focus blur cut paste")},_setOptions:function(a){this._super(a),a.clearBtn===b||this.element.is("textarea, :jqmData(type='range')")||(a.clearBtn?this._addClearBtn():this._destroyClear()),a.clearBtnText!==b&&this._clearBtn!==b&&this._clearBtn.text(a.clearBtnText).attr("title",a.clearBtnText)},_toggleClear:function(){this._delay("_toggleClearClass",0)},_toggleClearClass:function(){this._clearBtn.toggleClass("ui-input-clear-hidden",!this.element.val())},_destroyClear:function(){this.widget().removeClass("ui-input-has-clear"),this._unbindClear(),this._clearBtn.remove()},_destroy:function(){this._super(),this.options.clearBtn&&this._destroyClear()}})}(a),function(a,b){a.widget("mobile.textinput",a.mobile.textinput,{options:{autogrow:!0,keyupTimeoutBuffer:100},_create:function(){this._super(),this.options.autogrow&&this.isTextarea&&this._autogrow()},_autogrow:function(){this.element.addClass("ui-textinput-autogrow"),this._on({keyup:"_timeout",change:"_timeout",input:"_timeout",paste:"_timeout"}),this._on(!0,this.document,{pageshow:"_handleShow",popupbeforeposition:"_handleShow",updatelayout:"_handleShow",panelopen:"_handleShow"})},_handleShow:function(b){a.contains(b.target,this.element[0])&&this.element.is(":visible")&&("popupbeforeposition"!==b.type&&this.element.addClass("ui-textinput-autogrow-resize").animationComplete(a.proxy(function(){this.element.removeClass("ui-textinput-autogrow-resize")},this),"transition"),this._prepareHeightUpdate())},_unbindAutogrow:function(){this.element.removeClass("ui-textinput-autogrow"),this._off(this.element,"keyup change input paste"),this._off(this.document,"pageshow popupbeforeposition updatelayout panelopen")},keyupTimeout:null,_prepareHeightUpdate:function(a){this.keyupTimeout&&clearTimeout(this.keyupTimeout),a===b?this._updateHeight():this.keyupTimeout=this._delay("_updateHeight",a)},_timeout:function(){this._prepareHeightUpdate(this.options.keyupTimeoutBuffer)},_updateHeight:function(){var a,b,c,d,e,f,g,h,i,j=this.window.scrollTop();this.keyupTimeout=0,"onpage"in this.element[0]||this.element.css({height:0,"min-height":0,"max-height":0}),d=this.element[0].scrollHeight,e=this.element[0].clientHeight,f=parseFloat(this.element.css("border-top-width")),g=parseFloat(this.element.css("border-bottom-width")),h=f+g,i=d+h+15,0===e&&(a=parseFloat(this.element.css("padding-top")),b=parseFloat(this.element.css("padding-bottom")),c=a+b,i+=c),this.element.css({height:i,"min-height":"","max-height":""}),this.window.scrollTop(j)},refresh:function(){this.options.autogrow&&this.isTextarea&&this._updateHeight()},_setOptions:function(a){this._super(a),a.autogrow!==b&&this.isTextarea&&(a.autogrow?this._autogrow():this._unbindAutogrow())}})}(a),function(a){a.widget("mobile.selectmenu",a.extend({initSelector:"select:not( :jqmData(role='slider')):not( :jqmData(role='flipswitch') )",options:{theme:null,icon:"carat-d",iconpos:"right",inline:!1,corners:!0,shadow:!0,iconshadow:!1,overlayTheme:null,dividerTheme:null,hidePlaceholderMenuItems:!0,closeText:"Close",nativeMenu:!0,preventFocusZoom:/iPhone|iPad|iPod/.test(navigator.platform)&&navigator.userAgent.indexOf("AppleWebKit")>-1,mini:!1},_button:function(){return a("<div/>")},_setDisabled:function(a){return this.element.attr("disabled",a),this.button.attr("aria-disabled",a),this._setOption("disabled",a)},_focusButton:function(){var a=this;setTimeout(function(){a.button.focus()},40)},_selectOptions:function(){return this.select.find("option")},_preExtension:function(){var b=this.options.inline||this.element.jqmData("inline"),c=this.options.mini||this.element.jqmData("mini"),d="";~this.element[0].className.indexOf("ui-btn-left")&&(d=" ui-btn-left"),~this.element[0].className.indexOf("ui-btn-right")&&(d=" ui-btn-right"),b&&(d+=" ui-btn-inline"),c&&(d+=" ui-mini"),this.select=this.element.removeClass("ui-btn-left ui-btn-right").wrap("<div class='ui-select"+d+"'>"),this.selectId=this.select.attr("id")||"select-"+this.uuid,this.buttonId=this.selectId+"-button",this.label=a("label[for='"+this.selectId+"']"),this.isMultiple=this.select[0].multiple},_destroy:function(){var a=this.element.parents(".ui-select");a.length>0&&(a.is(".ui-btn-left, .ui-btn-right")&&this.element.addClass(a.hasClass("ui-btn-left")?"ui-btn-left":"ui-btn-right"),this.element.insertAfter(a),a.remove())},_create:function(){this._preExtension(),this.button=this._button();var c=this,d=this.options,e=d.icon?d.iconpos||this.select.jqmData("iconpos"):!1,f=this.button.insertBefore(this.select).attr("id",this.buttonId).addClass("ui-btn"+(d.icon?" ui-icon-"+d.icon+" ui-btn-icon-"+e+(d.iconshadow?" ui-shadow-icon":""):"")+(d.theme?" ui-btn-"+d.theme:"")+(d.corners?" ui-corner-all":"")+(d.shadow?" ui-shadow":""));this.setButtonText(),d.nativeMenu&&b.opera&&b.opera.version&&f.addClass("ui-select-nativeonly"),this.isMultiple&&(this.buttonCount=a("<span>").addClass("ui-li-count ui-body-inherit").hide().appendTo(f.addClass("ui-li-has-count"))),(d.disabled||this.element.attr("disabled"))&&this.disable(),this.select.change(function(){c.refresh(),d.nativeMenu&&c._delay(function(){c.select.blur()})}),this._handleFormReset(),this._on(this.button,{keydown:"_handleKeydown"}),this.build()},build:function(){var b=this;this.select.appendTo(b.button).bind("vmousedown",function(){b.button.addClass(a.mobile.activeBtnClass)}).bind("focus",function(){b.button.addClass(a.mobile.focusClass)}).bind("blur",function(){b.button.removeClass(a.mobile.focusClass)}).bind("focus vmouseover",function(){b.button.trigger("vmouseover")}).bind("vmousemove",function(){b.button.removeClass(a.mobile.activeBtnClass)}).bind("change blur vmouseout",function(){b.button.trigger("vmouseout").removeClass(a.mobile.activeBtnClass)}),b.button.bind("vmousedown",function(){b.options.preventFocusZoom&&a.mobile.zoom.disable(!0)}),b.label.bind("click focus",function(){b.options.preventFocusZoom&&a.mobile.zoom.disable(!0)}),b.select.bind("focus",function(){b.options.preventFocusZoom&&a.mobile.zoom.disable(!0)}),b.button.bind("mouseup",function(){b.options.preventFocusZoom&&setTimeout(function(){a.mobile.zoom.enable(!0)},0)}),b.select.bind("blur",function(){b.options.preventFocusZoom&&a.mobile.zoom.enable(!0)})},selected:function(){return this._selectOptions().filter(":selected")},selectedIndices:function(){var a=this;return this.selected().map(function(){return a._selectOptions().index(this)}).get()},setButtonText:function(){var b=this,d=this.selected(),e=this.placeholder,f=a(c.createElement("span"));this.button.children("span").not(".ui-li-count").remove().end().end().prepend(function(){return e=d.length?d.map(function(){return a(this).text()}).get().join(", "):b.placeholder,e?f.text(e):f.html("&#160;"),f.addClass(b.select.attr("class")).addClass(d.attr("class")).removeClass("ui-screen-hidden")}())},setButtonCount:function(){var a=this.selected();this.isMultiple&&this.buttonCount[a.length>1?"show":"hide"]().text(a.length)},_handleKeydown:function(){this._delay("_refreshButton")},_reset:function(){this.refresh()},_refreshButton:function(){this.setButtonText(),this.setButtonCount()},refresh:function(){this._refreshButton()},open:a.noop,close:a.noop,disable:function(){this._setDisabled(!0),this.button.addClass("ui-state-disabled")},enable:function(){this._setDisabled(!1),this.button.removeClass("ui-state-disabled")}},a.mobile.behaviors.formReset))}(a),function(a){a.mobile.links=function(b){a(b).find("a").jqmEnhanceable().filter(":jqmData(rel='popup')[href][href!='']").each(function(){var a=this,b=a.getAttribute("href").substring(1);b&&(a.setAttribute("aria-haspopup",!0),a.setAttribute("aria-owns",b),a.setAttribute("aria-expanded",!1))}).end().not(".ui-btn, :jqmData(role='none'), :jqmData(role='nojs')").addClass("ui-link")}}(a),function(a,c){function d(a,b,c,d){var e=d;return e=b>a?c+(a-b)/2:Math.min(Math.max(c,d-b/2),c+a-b)}function e(a){return{x:a.scrollLeft(),y:a.scrollTop(),cx:a[0].innerWidth||a.width(),cy:a[0].innerHeight||a.height()}}a.widget("mobile.popup",{options:{wrapperClass:null,theme:null,overlayTheme:null,shadow:!0,corners:!0,transition:"none",positionTo:"origin",tolerance:null,closeLinkSelector:"a:jqmData(rel='back')",closeLinkEvents:"click.popup",navigateEvents:"navigate.popup",closeEvents:"navigate.popup pagebeforechange.popup",dismissible:!0,enhanced:!1,history:!a.mobile.browser.oldIE},_handleDocumentVmousedown:function(b){this._isOpen&&a.contains(this._ui.container[0],b.target)&&this._ignoreResizeEvents()},_create:function(){var b=this.element,c=b.attr("id"),d=this.options;d.history=d.history&&a.mobile.ajaxEnabled&&a.mobile.hashListeningEnabled,this._on(this.document,{vmousedown:"_handleDocumentVmousedown"}),a.extend(this,{_scrollTop:0,_page:b.closest(".ui-page"),_ui:null,_fallbackTransition:"",_currentTransition:!1,_prerequisites:null,_isOpen:!1,_tolerance:null,_resizeData:null,_ignoreResizeTo:0,_orientationchangeInProgress:!1}),0===this._page.length&&(this._page=a("body")),d.enhanced?this._ui={container:b.parent(),screen:b.parent().prev(),placeholder:a(this.document[0].getElementById(c+"-placeholder"))}:(this._ui=this._enhance(b,c),this._applyTransition(d.transition)),this._setTolerance(d.tolerance)._ui.focusElement=this._ui.container,this._on(this._ui.screen,{vclick:"_eatEventAndClose"}),this._on(this.window,{orientationchange:a.proxy(this,"_handleWindowOrientationchange"),resize:a.proxy(this,"_handleWindowResize"),keyup:a.proxy(this,"_handleWindowKeyUp")}),this._on(this.document,{focusin:"_handleDocumentFocusIn"})},_enhance:function(b,c){var d=this.options,e=d.wrapperClass,f={screen:a("<div class='ui-screen-hidden ui-popup-screen "+this._themeClassFromOption("ui-overlay-",d.overlayTheme)+"'></div>"),placeholder:a("<div style='display: none;'><!-- placeholder --></div>"),container:a("<div class='ui-popup-container ui-popup-hidden ui-popup-truncate"+(e?" "+e:"")+"'></div>")},g=this.document[0].createDocumentFragment();return g.appendChild(f.screen[0]),g.appendChild(f.container[0]),c&&(f.screen.attr("id",c+"-screen"),f.container.attr("id",c+"-popup"),f.placeholder.attr("id",c+"-placeholder").html("<!-- placeholder for "+c+" -->")),this._page[0].appendChild(g),f.placeholder.insertAfter(b),b.detach().addClass("ui-popup "+this._themeClassFromOption("ui-body-",d.theme)+" "+(d.shadow?"ui-overlay-shadow ":"")+(d.corners?"ui-corner-all ":"")).appendTo(f.container),f},_eatEventAndClose:function(a){return a.preventDefault(),a.stopImmediatePropagation(),this.options.dismissible&&this.close(),!1},_resizeScreen:function(){var a=this._ui.screen,b=this._ui.container.outerHeight(!0),c=a.removeAttr("style").height(),d=this.document.height()-1;d>c?a.height(d):b>c&&a.height(b)},_handleWindowKeyUp:function(b){return this._isOpen&&b.keyCode===a.mobile.keyCode.ESCAPE?this._eatEventAndClose(b):void 0},_expectResizeEvent:function(){var a=e(this.window);
+if(this._resizeData){if(a.x===this._resizeData.windowCoordinates.x&&a.y===this._resizeData.windowCoordinates.y&&a.cx===this._resizeData.windowCoordinates.cx&&a.cy===this._resizeData.windowCoordinates.cy)return!1;clearTimeout(this._resizeData.timeoutId)}return this._resizeData={timeoutId:this._delay("_resizeTimeout",200),windowCoordinates:a},!0},_resizeTimeout:function(){this._isOpen?this._expectResizeEvent()||(this._ui.container.hasClass("ui-popup-hidden")&&(this._ui.container.removeClass("ui-popup-hidden ui-popup-truncate"),this.reposition({positionTo:"window"}),this._ignoreResizeEvents()),this._resizeScreen(),this._resizeData=null,this._orientationchangeInProgress=!1):(this._resizeData=null,this._orientationchangeInProgress=!1)},_stopIgnoringResizeEvents:function(){this._ignoreResizeTo=0},_ignoreResizeEvents:function(){this._ignoreResizeTo&&clearTimeout(this._ignoreResizeTo),this._ignoreResizeTo=this._delay("_stopIgnoringResizeEvents",1e3)},_handleWindowResize:function(){this._isOpen&&0===this._ignoreResizeTo&&(!this._expectResizeEvent()&&!this._orientationchangeInProgress||this._ui.container.hasClass("ui-popup-hidden")||this._ui.container.addClass("ui-popup-hidden ui-popup-truncate").removeAttr("style"))},_handleWindowOrientationchange:function(){!this._orientationchangeInProgress&&this._isOpen&&0===this._ignoreResizeTo&&(this._expectResizeEvent(),this._orientationchangeInProgress=!0)},_handleDocumentFocusIn:function(b){var c,d=b.target,e=this._ui;if(this._isOpen){if(d!==e.container[0]){if(c=a(d),!a.contains(e.container[0],d))return a(this.document[0].activeElement).one("focus",a.proxy(function(){this._safelyBlur(d)},this)),e.focusElement.focus(),b.preventDefault(),b.stopImmediatePropagation(),!1;e.focusElement[0]===e.container[0]&&(e.focusElement=c)}this._ignoreResizeEvents()}},_themeClassFromOption:function(a,b){return b?"none"===b?"":a+b:a+"inherit"},_applyTransition:function(b){return b&&(this._ui.container.removeClass(this._fallbackTransition),"none"!==b&&(this._fallbackTransition=a.mobile._maybeDegradeTransition(b),"none"===this._fallbackTransition&&(this._fallbackTransition=""),this._ui.container.addClass(this._fallbackTransition))),this},_setOptions:function(a){var b=this.options,d=this.element,e=this._ui.screen;return a.wrapperClass!==c&&this._ui.container.removeClass(b.wrapperClass).addClass(a.wrapperClass),a.theme!==c&&d.removeClass(this._themeClassFromOption("ui-body-",b.theme)).addClass(this._themeClassFromOption("ui-body-",a.theme)),a.overlayTheme!==c&&(e.removeClass(this._themeClassFromOption("ui-overlay-",b.overlayTheme)).addClass(this._themeClassFromOption("ui-overlay-",a.overlayTheme)),this._isOpen&&e.addClass("in")),a.shadow!==c&&d.toggleClass("ui-overlay-shadow",a.shadow),a.corners!==c&&d.toggleClass("ui-corner-all",a.corners),a.transition!==c&&(this._currentTransition||this._applyTransition(a.transition)),a.tolerance!==c&&this._setTolerance(a.tolerance),a.disabled!==c&&a.disabled&&this.close(),this._super(a)},_setTolerance:function(b){var d,e={t:30,r:15,b:30,l:15};if(b!==c)switch(d=String(b).split(","),a.each(d,function(a,b){d[a]=parseInt(b,10)}),d.length){case 1:isNaN(d[0])||(e.t=e.r=e.b=e.l=d[0]);break;case 2:isNaN(d[0])||(e.t=e.b=d[0]),isNaN(d[1])||(e.l=e.r=d[1]);break;case 4:isNaN(d[0])||(e.t=d[0]),isNaN(d[1])||(e.r=d[1]),isNaN(d[2])||(e.b=d[2]),isNaN(d[3])||(e.l=d[3])}return this._tolerance=e,this},_clampPopupWidth:function(a){var b,c=e(this.window),d={x:this._tolerance.l,y:c.y+this._tolerance.t,cx:c.cx-this._tolerance.l-this._tolerance.r,cy:c.cy-this._tolerance.t-this._tolerance.b};return a||this._ui.container.css("max-width",d.cx),b={cx:this._ui.container.outerWidth(!0),cy:this._ui.container.outerHeight(!0)},{rc:d,menuSize:b}},_calculateFinalLocation:function(a,b){var c,e=b.rc,f=b.menuSize;return c={left:d(e.cx,f.cx,e.x,a.x),top:d(e.cy,f.cy,e.y,a.y)},c.top=Math.max(0,c.top),c.top-=Math.min(c.top,Math.max(0,c.top+f.cy-this.document.height())),c},_placementCoords:function(a){return this._calculateFinalLocation(a,this._clampPopupWidth())},_createPrerequisites:function(b,c,d){var e,f=this;e={screen:a.Deferred(),container:a.Deferred()},e.screen.then(function(){e===f._prerequisites&&b()}),e.container.then(function(){e===f._prerequisites&&c()}),a.when(e.screen,e.container).done(function(){e===f._prerequisites&&(f._prerequisites=null,d())}),f._prerequisites=e},_animate:function(b){return this._ui.screen.removeClass(b.classToRemove).addClass(b.screenClassToAdd),b.prerequisites.screen.resolve(),b.transition&&"none"!==b.transition&&(b.applyTransition&&this._applyTransition(b.transition),this._fallbackTransition)?void this._ui.container.addClass(b.containerClassToAdd).removeClass(b.classToRemove).animationComplete(a.proxy(b.prerequisites.container,"resolve")):(this._ui.container.removeClass(b.classToRemove),void b.prerequisites.container.resolve())},_desiredCoords:function(b){var c,d=null,f=e(this.window),g=b.x,h=b.y,i=b.positionTo;if(i&&"origin"!==i)if("window"===i)g=f.cx/2+f.x,h=f.cy/2+f.y;else{try{d=a(i)}catch(j){d=null}d&&(d.filter(":visible"),0===d.length&&(d=null))}return d&&(c=d.offset(),g=c.left+d.outerWidth()/2,h=c.top+d.outerHeight()/2),("number"!==a.type(g)||isNaN(g))&&(g=f.cx/2+f.x),("number"!==a.type(h)||isNaN(h))&&(h=f.cy/2+f.y),{x:g,y:h}},_reposition:function(a){a={x:a.x,y:a.y,positionTo:a.positionTo},this._trigger("beforeposition",c,a),this._ui.container.offset(this._placementCoords(this._desiredCoords(a)))},reposition:function(a){this._isOpen&&this._reposition(a)},_safelyBlur:function(b){b!==this.window[0]&&"body"!==b.nodeName.toLowerCase()&&a(b).blur()},_openPrerequisitesComplete:function(){var b=this.element.attr("id"),c=this._ui.container.find(":focusable").first();this._ui.container.addClass("ui-popup-active"),this._isOpen=!0,this._resizeScreen(),a.contains(this._ui.container[0],this.document[0].activeElement)||this._safelyBlur(this.document[0].activeElement),c.length>0&&(this._ui.focusElement=c),this._ignoreResizeEvents(),b&&this.document.find("[aria-haspopup='true'][aria-owns='"+b+"']").attr("aria-expanded",!0),this._trigger("afteropen")},_open:function(b){var c=a.extend({},this.options,b),d=function(){var a=navigator.userAgent,b=a.match(/AppleWebKit\/([0-9\.]+)/),c=!!b&&b[1],d=a.match(/Android (\d+(?:\.\d+))/),e=!!d&&d[1],f=a.indexOf("Chrome")>-1;return null!==d&&"4.0"===e&&c&&c>534.13&&!f?!0:!1}();this._createPrerequisites(a.noop,a.noop,a.proxy(this,"_openPrerequisitesComplete")),this._currentTransition=c.transition,this._applyTransition(c.transition),this._ui.screen.removeClass("ui-screen-hidden"),this._ui.container.removeClass("ui-popup-truncate"),this._reposition(c),this._ui.container.removeClass("ui-popup-hidden"),this.options.overlayTheme&&d&&this.element.closest(".ui-page").addClass("ui-popup-open"),this._animate({additionalCondition:!0,transition:c.transition,classToRemove:"",screenClassToAdd:"in",containerClassToAdd:"in",applyTransition:!1,prerequisites:this._prerequisites})},_closePrerequisiteScreen:function(){this._ui.screen.removeClass("out").addClass("ui-screen-hidden")},_closePrerequisiteContainer:function(){this._ui.container.removeClass("reverse out").addClass("ui-popup-hidden ui-popup-truncate").removeAttr("style")},_closePrerequisitesDone:function(){var b=this._ui.container,d=this.element.attr("id");a.mobile.popup.active=c,a(":focus",b[0]).add(b[0]).blur(),d&&this.document.find("[aria-haspopup='true'][aria-owns='"+d+"']").attr("aria-expanded",!1),this._trigger("afterclose")},_close:function(b){this._ui.container.removeClass("ui-popup-active"),this._page.removeClass("ui-popup-open"),this._isOpen=!1,this._createPrerequisites(a.proxy(this,"_closePrerequisiteScreen"),a.proxy(this,"_closePrerequisiteContainer"),a.proxy(this,"_closePrerequisitesDone")),this._animate({additionalCondition:this._ui.screen.hasClass("in"),transition:b?"none":this._currentTransition,classToRemove:"in",screenClassToAdd:"out",containerClassToAdd:"reverse out",applyTransition:!0,prerequisites:this._prerequisites})},_unenhance:function(){this.options.enhanced||(this._setOptions({theme:a.mobile.popup.prototype.options.theme}),this.element.detach().insertAfter(this._ui.placeholder).removeClass("ui-popup ui-overlay-shadow ui-corner-all ui-body-inherit"),this._ui.screen.remove(),this._ui.container.remove(),this._ui.placeholder.remove())},_destroy:function(){return a.mobile.popup.active===this?(this.element.one("popupafterclose",a.proxy(this,"_unenhance")),this.close()):this._unenhance(),this},_closePopup:function(c,d){var e,f,g=this.options,h=!1;c&&c.isDefaultPrevented()||a.mobile.popup.active!==this||(b.scrollTo(0,this._scrollTop),c&&"pagebeforechange"===c.type&&d&&(e="string"==typeof d.toPage?d.toPage:d.toPage.jqmData("url"),e=a.mobile.path.parseUrl(e),f=e.pathname+e.search+e.hash,this._myUrl!==a.mobile.path.makeUrlAbsolute(f)?h=!0:c.preventDefault()),this.window.off(g.closeEvents),this.element.undelegate(g.closeLinkSelector,g.closeLinkEvents),this._close(h))},_bindContainerClose:function(){this.window.on(this.options.closeEvents,a.proxy(this,"_closePopup"))},widget:function(){return this._ui.container},open:function(b){var c,d,e,f,g,h,i=this,j=this.options;return a.mobile.popup.active||j.disabled?this:(a.mobile.popup.active=this,this._scrollTop=this.window.scrollTop(),j.history?(h=a.mobile.navigate.history,d=a.mobile.dialogHashKey,e=a.mobile.activePage,f=e?e.hasClass("ui-dialog"):!1,this._myUrl=c=h.getActive().url,(g=c.indexOf(d)>-1&&!f&&h.activeIndex>0)?(i._open(b),i._bindContainerClose(),this):(-1!==c.indexOf(d)||f?c=a.mobile.path.parseLocation().hash+d:c+=c.indexOf("#")>-1?d:"#"+d,this.window.one("beforenavigate",function(a){a.preventDefault(),i._open(b),i._bindContainerClose()}),this.urlAltered=!0,a.mobile.navigate(c,{role:"dialog"}),this)):(i._open(b),i._bindContainerClose(),i.element.delegate(j.closeLinkSelector,j.closeLinkEvents,function(a){i.close(),a.preventDefault()}),this))},close:function(){return a.mobile.popup.active!==this?this:(this._scrollTop=this.window.scrollTop(),this.options.history&&this.urlAltered?(a.mobile.back(),this.urlAltered=!1):this._closePopup(),this)}}),a.mobile.popup.handleLink=function(b){var c,d=a.mobile.path,e=a(d.hashToSelector(d.parseUrl(b.attr("href")).hash)).first();e.length>0&&e.data("mobile-popup")&&(c=b.offset(),e.popup("open",{x:c.left+b.outerWidth()/2,y:c.top+b.outerHeight()/2,transition:b.jqmData("transition"),positionTo:b.jqmData("position-to")})),setTimeout(function(){b.removeClass(a.mobile.activeBtnClass)},300)},a.mobile.document.on("pagebeforechange",function(b,c){"popup"===c.options.role&&(a.mobile.popup.handleLink(c.options.link),b.preventDefault())})}(a),function(a,b){var d=".ui-disabled,.ui-state-disabled,.ui-li-divider,.ui-screen-hidden,:jqmData(role='placeholder')",e=function(a,b,c){var e=a[c+"All"]().not(d).first();e.length&&(b.blur().attr("tabindex","-1"),e.find("a").first().focus())};a.widget("mobile.selectmenu",a.mobile.selectmenu,{_create:function(){var a=this.options;return a.nativeMenu=a.nativeMenu||this.element.parents(":jqmData(role='popup'),:mobile-popup").length>0,this._super()},_handleSelectFocus:function(){this.element.blur(),this.button.focus()},_handleKeydown:function(a){this._super(a),this._handleButtonVclickKeydown(a)},_handleButtonVclickKeydown:function(b){this.options.disabled||this.isOpen||this.options.nativeMenu||("vclick"===b.type||b.keyCode&&(b.keyCode===a.mobile.keyCode.ENTER||b.keyCode===a.mobile.keyCode.SPACE))&&(this._decideFormat(),"overlay"===this.menuType?this.button.attr("href","#"+this.popupId).attr("data-"+(a.mobile.ns||"")+"rel","popup"):this.button.attr("href","#"+this.dialogId).attr("data-"+(a.mobile.ns||"")+"rel","dialog"),this.isOpen=!0)},_handleListFocus:function(b){var c="focusin"===b.type?{tabindex:"0",event:"vmouseover"}:{tabindex:"-1",event:"vmouseout"};a(b.target).attr("tabindex",c.tabindex).trigger(c.event)},_handleListKeydown:function(b){var c=a(b.target),d=c.closest("li");switch(b.keyCode){case 38:return e(d,c,"prev"),!1;case 40:return e(d,c,"next"),!1;case 13:case 32:return c.trigger("click"),!1}},_handleMenuPageHide:function(){this._delayedTrigger(),this.thisPage.page("bindRemove")},_handleHeaderCloseClick:function(){return"overlay"===this.menuType?(this.close(),!1):void 0},_handleListItemClick:function(b){var c=a(b.target).closest("li"),d=this.select[0].selectedIndex,e=a.mobile.getAttribute(c,"option-index"),f=this._selectOptions().eq(e)[0];f.selected=this.isMultiple?!f.selected:!0,this.isMultiple&&c.find("a").toggleClass("ui-checkbox-on",f.selected).toggleClass("ui-checkbox-off",!f.selected),this.isMultiple||d===e||(this._triggerChange=!0),this.isMultiple?(this.select.trigger("change"),this.list.find("li:not(.ui-li-divider)").eq(e).find("a").first().focus()):this.close(),b.preventDefault()},build:function(){var c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v=this.options;return v.nativeMenu?this._super():(c=this.selectId,d=c+"-listbox",e=c+"-dialog",f=this.label,g=this.element.closest(".ui-page"),h=this.element[0].multiple,i=c+"-menu",j=v.theme?" data-"+a.mobile.ns+"theme='"+v.theme+"'":"",k=v.overlayTheme||v.theme||null,l=k?" data-"+a.mobile.ns+"overlay-theme='"+k+"'":"",m=v.dividerTheme&&h?" data-"+a.mobile.ns+"divider-theme='"+v.dividerTheme+"'":"",n=a("<div data-"+a.mobile.ns+"role='dialog' class='ui-selectmenu' id='"+e+"'"+j+l+"><div data-"+a.mobile.ns+"role='header'><div class='ui-title'></div></div><div data-"+a.mobile.ns+"role='content'></div></div>"),o=a("<div"+j+l+" id='"+d+"' class='ui-selectmenu'></div>").insertAfter(this.select).popup(),p=a("<ul class='ui-selectmenu-list' id='"+i+"' role='listbox' aria-labelledby='"+this.buttonId+"'"+j+m+"></ul>").appendTo(o),q=a("<div class='ui-header ui-bar-"+(v.theme?v.theme:"inherit")+"'></div>").prependTo(o),r=a("<h1 class='ui-title'></h1>").appendTo(q),this.isMultiple&&(u=a("<a>",{role:"button",text:v.closeText,href:"#","class":"ui-btn ui-corner-all ui-btn-left ui-btn-icon-notext ui-icon-delete"}).appendTo(q)),a.extend(this,{selectId:c,menuId:i,popupId:d,dialogId:e,thisPage:g,menuPage:n,label:f,isMultiple:h,theme:v.theme,listbox:o,list:p,header:q,headerTitle:r,headerClose:u,menuPageContent:s,menuPageClose:t,placeholder:""}),this.refresh(),this._origTabIndex===b&&(this._origTabIndex=null===this.select[0].getAttribute("tabindex")?!1:this.select.attr("tabindex")),this.select.attr("tabindex","-1"),this._on(this.select,{focus:"_handleSelectFocus"}),this._on(this.button,{vclick:"_handleButtonVclickKeydown"}),this.list.attr("role","listbox"),this._on(this.list,{focusin:"_handleListFocus",focusout:"_handleListFocus",keydown:"_handleListKeydown","click li:not(.ui-disabled,.ui-state-disabled,.ui-li-divider)":"_handleListItemClick"}),this._on(this.menuPage,{pagehide:"_handleMenuPageHide"}),this._on(this.listbox,{popupafterclose:"_popupClosed"}),this.isMultiple&&this._on(this.headerClose,{click:"_handleHeaderCloseClick"}),this)},_popupClosed:function(){this.close(),this._delayedTrigger()},_delayedTrigger:function(){this._triggerChange&&this.element.trigger("change"),this._triggerChange=!1},_isRebuildRequired:function(){var a=this.list.find("li"),b=this._selectOptions().not(".ui-screen-hidden");return b.text()!==a.text()},selected:function(){return this._selectOptions().filter(":selected:not( :jqmData(placeholder='true') )")},refresh:function(b){var c,d;return this.options.nativeMenu?this._super(b):(c=this,(b||this._isRebuildRequired())&&c._buildList(),d=this.selectedIndices(),c.setButtonText(),c.setButtonCount(),void c.list.find("li:not(.ui-li-divider)").find("a").removeClass(a.mobile.activeBtnClass).end().attr("aria-selected",!1).each(function(b){var e=a(this);a.inArray(b,d)>-1?(e.attr("aria-selected",!0),c.isMultiple?e.find("a").removeClass("ui-checkbox-off").addClass("ui-checkbox-on"):e.hasClass("ui-screen-hidden")?e.next().find("a").addClass(a.mobile.activeBtnClass):e.find("a").addClass(a.mobile.activeBtnClass)):c.isMultiple&&e.find("a").removeClass("ui-checkbox-on").addClass("ui-checkbox-off")}))},close:function(){if(!this.options.disabled&&this.isOpen){var a=this;"page"===a.menuType?(a.menuPage.dialog("close"),a.list.appendTo(a.listbox)):a.listbox.popup("close"),a._focusButton(),a.isOpen=!1}},open:function(){this.button.click()},_focusMenuItem:function(){var b=this.list.find("a."+a.mobile.activeBtnClass);0===b.length&&(b=this.list.find("li:not("+d+") a.ui-btn")),b.first().focus()},_decideFormat:function(){var b=this,c=this.window,d=b.list.parent(),e=d.outerHeight(),f=c.scrollTop(),g=b.button.offset().top,h=c.height();e>h-80||!a.support.scrollTop?(b.menuPage.appendTo(a.mobile.pageContainer).page(),b.menuPageContent=b.menuPage.find(".ui-content"),b.menuPageClose=b.menuPage.find(".ui-header a"),b.thisPage.unbind("pagehide.remove"),0===f&&g>h&&b.thisPage.one("pagehide",function(){a(this).jqmData("lastScroll",g)}),b.menuPage.one({pageshow:a.proxy(this,"_focusMenuItem"),pagehide:a.proxy(this,"close")}),b.menuType="page",b.menuPageContent.append(b.list),b.menuPage.find("div .ui-title").text(b.label.getEncodedText()||b.placeholder)):(b.menuType="overlay",b.listbox.one({popupafteropen:a.proxy(this,"_focusMenuItem")}))},_buildList:function(){var b,d,e,f,g,h,i,j,k,l,m,n,o,p,q=this,r=this.options,s=this.placeholder,t=!0,u="false",v="data-"+a.mobile.ns,w=v+"option-index",x=v+"icon",y=v+"role",z=v+"placeholder",A=c.createDocumentFragment(),B=!1;for(q.list.empty().filter(".ui-listview").listview("destroy"),b=this._selectOptions(),d=b.length,e=this.select[0],g=0;d>g;g++,B=!1)h=b[g],i=a(h),i.hasClass("ui-screen-hidden")||(j=h.parentNode,m=[],k=i.text(),l=c.createElement("a"),l.setAttribute("href","#"),l.appendChild(c.createTextNode(k)),j!==e&&"optgroup"===j.nodeName.toLowerCase()&&(n=j.getAttribute("label"),n!==f&&(o=c.createElement("li"),o.setAttribute(y,"list-divider"),o.setAttribute("role","option"),o.setAttribute("tabindex","-1"),o.appendChild(c.createTextNode(n)),A.appendChild(o),f=n)),!t||h.getAttribute("value")&&0!==k.length&&!i.jqmData("placeholder")||(t=!1,B=!0,null===h.getAttribute(z)&&(this._removePlaceholderAttr=!0),h.setAttribute(z,!0),r.hidePlaceholderMenuItems&&m.push("ui-screen-hidden"),s!==k&&(s=q.placeholder=k)),p=c.createElement("li"),h.disabled&&(m.push("ui-state-disabled"),p.setAttribute("aria-disabled",!0)),p.setAttribute(w,g),p.setAttribute(x,u),B&&p.setAttribute(z,!0),p.className=m.join(" "),p.setAttribute("role","option"),l.setAttribute("tabindex","-1"),this.isMultiple&&a(l).addClass("ui-btn ui-checkbox-off ui-btn-icon-right"),p.appendChild(l),A.appendChild(p));q.list[0].appendChild(A),this.isMultiple||s.length?this.headerTitle.text(this.placeholder):this.header.addClass("ui-screen-hidden"),q.list.listview()},_button:function(){return this.options.nativeMenu?this._super():a("<a>",{href:"#",role:"button",id:this.buttonId,"aria-haspopup":"true","aria-owns":this.menuId})},_destroy:function(){this.options.nativeMenu||(this.close(),this._origTabIndex!==b&&(this._origTabIndex!==!1?this.select.attr("tabindex",this._origTabIndex):this.select.removeAttr("tabindex")),this._removePlaceholderAttr&&this._selectOptions().removeAttr("data-"+a.mobile.ns+"placeholder"),this.listbox.remove(),this.menuPage.remove()),this._super()}})}(a),function(a,b){function c(a,b){var c=b?b:[];return c.push("ui-btn"),a.theme&&c.push("ui-btn-"+a.theme),a.icon&&(c=c.concat(["ui-icon-"+a.icon,"ui-btn-icon-"+a.iconpos]),a.iconshadow&&c.push("ui-shadow-icon")),a.inline&&c.push("ui-btn-inline"),a.shadow&&c.push("ui-shadow"),a.corners&&c.push("ui-corner-all"),a.mini&&c.push("ui-mini"),c}function d(a){var c,d,e,g=!1,h=!0,i={icon:"",inline:!1,shadow:!1,corners:!1,iconshadow:!1,mini:!1},j=[];for(a=a.split(" "),c=0;c<a.length;c++)e=!0,d=f[a[c]],d!==b?(e=!1,i[d]=!0):0===a[c].indexOf("ui-btn-icon-")?(e=!1,h=!1,i.iconpos=a[c].substring(12)):0===a[c].indexOf("ui-icon-")?(e=!1,i.icon=a[c].substring(8)):0===a[c].indexOf("ui-btn-")&&8===a[c].length?(e=!1,i.theme=a[c].substring(7)):"ui-btn"===a[c]&&(e=!1,g=!0),e&&j.push(a[c]);return h&&(i.icon=""),{options:i,unknownClasses:j,alreadyEnhanced:g}}function e(a){return"-"+a.toLowerCase()}var f={"ui-shadow":"shadow","ui-corner-all":"corners","ui-btn-inline":"inline","ui-shadow-icon":"iconshadow","ui-mini":"mini"},g=function(){var c=a.mobile.getAttribute.apply(this,arguments);return null==c?b:c},h=/[A-Z]/g;a.fn.buttonMarkup=function(f,i){var j,k,l,m,n,o=a.fn.buttonMarkup.defaults;for(j=0;j<this.length;j++){if(l=this[j],k=i?{alreadyEnhanced:!1,unknownClasses:[]}:d(l.className),m=a.extend({},k.alreadyEnhanced?k.options:{},f),!k.alreadyEnhanced)for(n in o)m[n]===b&&(m[n]=g(l,n.replace(h,e)));l.className=c(a.extend({},o,m),k.unknownClasses).join(" "),"button"!==l.tagName.toLowerCase()&&l.setAttribute("role","button")}return this},a.fn.buttonMarkup.defaults={icon:"",iconpos:"left",theme:null,inline:!1,shadow:!0,corners:!0,iconshadow:!1,mini:!1},a.extend(a.fn.buttonMarkup,{initSelector:"a:jqmData(role='button'), .ui-bar > a, .ui-bar > :jqmData(role='controlgroup') > a, button:not(:jqmData(role='navbar') button)"})}(a),function(a,b){a.widget("mobile.controlgroup",a.extend({options:{enhanced:!1,theme:null,shadow:!1,corners:!0,excludeInvisible:!0,type:"vertical",mini:!1},_create:function(){var b=this.element,c=this.options,d=a.mobile.page.prototype.keepNativeSelector();a.fn.buttonMarkup&&this.element.find(a.fn.buttonMarkup.initSelector).not(d).buttonMarkup(),a.each(this._childWidgets,a.proxy(function(b,c){a.mobile[c]&&this.element.find(a.mobile[c].initSelector).not(d)[c]()},this)),a.extend(this,{_ui:null,_initialRefresh:!0}),this._ui=c.enhanced?{groupLegend:b.children(".ui-controlgroup-label").children(),childWrapper:b.children(".ui-controlgroup-controls")}:this._enhance()},_childWidgets:["checkboxradio","selectmenu","button"],_themeClassFromOption:function(a){return a?"none"===a?"":"ui-group-theme-"+a:""},_enhance:function(){var b=this.element,c=this.options,d={groupLegend:b.children("legend"),childWrapper:b.addClass("ui-controlgroup ui-controlgroup-"+("horizontal"===c.type?"horizontal":"vertical")+" "+this._themeClassFromOption(c.theme)+" "+(c.corners?"ui-corner-all ":"")+(c.mini?"ui-mini ":"")).wrapInner("<div class='ui-controlgroup-controls "+(c.shadow===!0?"ui-shadow":"")+"'></div>").children()};return d.groupLegend.length>0&&a("<div role='heading' class='ui-controlgroup-label'></div>").append(d.groupLegend).prependTo(b),d},_init:function(){this.refresh()},_setOptions:function(a){var c,d,e=this.element;return a.type!==b&&(e.removeClass("ui-controlgroup-horizontal ui-controlgroup-vertical").addClass("ui-controlgroup-"+("horizontal"===a.type?"horizontal":"vertical")),c=!0),a.theme!==b&&e.removeClass(this._themeClassFromOption(this.options.theme)).addClass(this._themeClassFromOption(a.theme)),a.corners!==b&&e.toggleClass("ui-corner-all",a.corners),a.mini!==b&&e.toggleClass("ui-mini",a.mini),a.shadow!==b&&this._ui.childWrapper.toggleClass("ui-shadow",a.shadow),a.excludeInvisible!==b&&(this.options.excludeInvisible=a.excludeInvisible,c=!0),d=this._super(a),c&&this.refresh(),d},container:function(){return this._ui.childWrapper},refresh:function(){var b=this.container(),c=b.find(".ui-btn").not(".ui-slider-handle"),d=this._initialRefresh;a.mobile.checkboxradio&&b.find(":mobile-checkboxradio").checkboxradio("refresh"),this._addFirstLastClasses(c,this.options.excludeInvisible?this._getVisibles(c,d):c,d),this._initialRefresh=!1},_destroy:function(){var a,b,c=this.options;return c.enhanced?this:(a=this._ui,b=this.element.removeClass("ui-controlgroup ui-controlgroup-horizontal ui-controlgroup-vertical ui-corner-all ui-mini "+this._themeClassFromOption(c.theme)).find(".ui-btn").not(".ui-slider-handle"),this._removeFirstLastClasses(b),a.groupLegend.unwrap(),void a.childWrapper.children().unwrap())}},a.mobile.behaviors.addFirstLastClasses))}(a),function(a,b){a.widget("mobile.toolbar",{initSelector:":jqmData(role='footer'), :jqmData(role='header')",options:{theme:null,addBackBtn:!1,backBtnTheme:null,backBtnText:"Back"},_create:function(){var b,c,d=this.element.is(":jqmData(role='header')")?"header":"footer",e=this.element.closest(".ui-page");0===e.length&&(e=!1,this._on(this.document,{pageshow:"refresh"})),a.extend(this,{role:d,page:e,leftbtn:b,rightbtn:c}),this.element.attr("role","header"===d?"banner":"contentinfo").addClass("ui-"+d),this.refresh(),this._setOptions(this.options)},_setOptions:function(a){if(a.addBackBtn!==b&&this._updateBackButton(),null!=a.backBtnTheme&&this.element.find(".ui-toolbar-back-btn").addClass("ui-btn ui-btn-"+a.backBtnTheme),a.backBtnText!==b&&this.element.find(".ui-toolbar-back-btn .ui-btn-text").text(a.backBtnText),a.theme!==b){var c=this.options.theme?this.options.theme:"inherit",d=a.theme?a.theme:"inherit";this.element.removeClass("ui-bar-"+c).addClass("ui-bar-"+d)}this._super(a)},refresh:function(){"header"===this.role&&this._addHeaderButtonClasses(),this.page||(this._setRelative(),"footer"===this.role?this.element.appendTo("body"):"header"===this.role&&this._updateBackButton()),this._addHeadingClasses(),this._btnMarkup()},_setRelative:function(){a("[data-"+a.mobile.ns+"role='page']").css({position:"relative"})},_btnMarkup:function(){this.element.children("a").filter(":not([data-"+a.mobile.ns+"role='none'])").attr("data-"+a.mobile.ns+"role","button"),this.element.trigger("create")},_addHeaderButtonClasses:function(){var a=this.element.children("a, button");this.leftbtn=a.hasClass("ui-btn-left")&&!a.hasClass("ui-toolbar-back-btn"),this.rightbtn=a.hasClass("ui-btn-right"),this.leftbtn=this.leftbtn||a.eq(0).not(".ui-btn-right,.ui-toolbar-back-btn").addClass("ui-btn-left").length,this.rightbtn=this.rightbtn||a.eq(1).addClass("ui-btn-right").length},_updateBackButton:function(){var b,c=this.options,d=c.backBtnTheme||c.theme;b=this._backButton=this._backButton||{},this.options.addBackBtn&&"header"===this.role&&a(".ui-page").length>1&&(this.page?this.page[0].getAttribute("data-"+a.mobile.ns+"url")!==a.mobile.path.stripHash(location.hash):a.mobile.navigate&&a.mobile.navigate.history&&a.mobile.navigate.history.activeIndex>0)&&!this.leftbtn?b.attached||(this.backButton=b.element=(b.element||a("<a role='button' href='javascript:void(0);' class='ui-btn ui-corner-all ui-shadow ui-btn-left "+(d?"ui-btn-"+d+" ":"")+"ui-toolbar-back-btn ui-icon-carat-l ui-btn-icon-left' data-"+a.mobile.ns+"rel='back'>"+c.backBtnText+"</a>")).prependTo(this.element),b.attached=!0):b.element&&(b.element.detach(),b.attached=!1)},_addHeadingClasses:function(){this.element.children("h1, h2, h3, h4, h5, h6").addClass("ui-title").attr({role:"heading","aria-level":"1"})},_destroy:function(){var a;this.element.children("h1, h2, h3, h4, h5, h6").removeClass("ui-title").removeAttr("role").removeAttr("aria-level"),"header"===this.role&&(this.element.children("a, button").removeClass("ui-btn-left ui-btn-right ui-btn ui-shadow ui-corner-all"),this.backButton&&this.backButton.remove()),a=this.options.theme?this.options.theme:"inherit",this.element.removeClass("ui-bar-"+a),this.element.removeClass("ui-"+this.role).removeAttr("role")}})}(a),function(a,b){a.widget("mobile.toolbar",a.mobile.toolbar,{options:{position:null,visibleOnPageShow:!0,disablePageZoom:!0,transition:"slide",fullscreen:!1,tapToggle:!0,tapToggleBlacklist:"a, button, input, select, textarea, .ui-header-fixed, .ui-footer-fixed, .ui-flipswitch, .ui-popup, .ui-panel, .ui-panel-dismiss-open",hideDuringFocus:"input, textarea, select",updatePagePadding:!0,trackPersistentToolbars:!0,supportBlacklist:function(){return!a.support.fixedPosition}},_create:function(){this._super(),this.pagecontainer=a(":mobile-pagecontainer"),"fixed"!==this.options.position||this.options.supportBlacklist()||this._makeFixed()},_makeFixed:function(){this.element.addClass("ui-"+this.role+"-fixed"),this.updatePagePadding(),this._addTransitionClass(),this._bindPageEvents(),this._bindToggleHandlers()},_setOptions:function(c){if("fixed"===c.position&&"fixed"!==this.options.position&&this._makeFixed(),"fixed"===this.options.position&&!this.options.supportBlacklist()){var d=this.page?this.page:a(".ui-page-active").length>0?a(".ui-page-active"):a(".ui-page").eq(0);c.fullscreen!==b&&(c.fullscreen?(this.element.addClass("ui-"+this.role+"-fullscreen"),d.addClass("ui-page-"+this.role+"-fullscreen")):(this.element.removeClass("ui-"+this.role+"-fullscreen"),d.removeClass("ui-page-"+this.role+"-fullscreen").addClass("ui-page-"+this.role+"-fixed")))}this._super(c)},_addTransitionClass:function(){var a=this.options.transition;a&&"none"!==a&&("slide"===a&&(a=this.element.hasClass("ui-header")?"slidedown":"slideup"),this.element.addClass(a))},_bindPageEvents:function(){var a=this.page?this.element.closest(".ui-page"):this.document;this._on(a,{pagebeforeshow:"_handlePageBeforeShow",webkitAnimationStart:"_handleAnimationStart",animationstart:"_handleAnimationStart",updatelayout:"_handleAnimationStart",pageshow:"_handlePageShow",pagebeforehide:"_handlePageBeforeHide"})},_handlePageBeforeShow:function(){var b=this.options;b.disablePageZoom&&a.mobile.zoom.disable(!0),b.visibleOnPageShow||this.hide(!0)},_handleAnimationStart:function(){this.options.updatePagePadding&&this.updatePagePadding(this.page?this.page:".ui-page-active")},_handlePageShow:function(){this.updatePagePadding(this.page?this.page:".ui-page-active"),this.options.updatePagePadding&&this._on(this.window,{throttledresize:"updatePagePadding"})},_handlePageBeforeHide:function(b,c){var d,e,f,g,h=this.options;h.disablePageZoom&&a.mobile.zoom.enable(!0),h.updatePagePadding&&this._off(this.window,"throttledresize"),h.trackPersistentToolbars&&(d=a(".ui-footer-fixed:jqmData(id)",this.page),e=a(".ui-header-fixed:jqmData(id)",this.page),f=d.length&&c.nextPage&&a(".ui-footer-fixed:jqmData(id='"+d.jqmData("id")+"')",c.nextPage)||a(),g=e.length&&c.nextPage&&a(".ui-header-fixed:jqmData(id='"+e.jqmData("id")+"')",c.nextPage)||a(),(f.length||g.length)&&(f.add(g).appendTo(a.mobile.pageContainer),c.nextPage.one("pageshow",function(){g.prependTo(this),f.appendTo(this)})))},_visible:!0,updatePagePadding:function(c){var d=this.element,e="header"===this.role,f=parseFloat(d.css(e?"top":"bottom"));this.options.fullscreen||(c=c&&c.type===b&&c||this.page||d.closest(".ui-page"),c=this.page?this.page:".ui-page-active",a(c).css("padding-"+(e?"top":"bottom"),d.outerHeight()+f))},_useTransition:function(b){var c=this.window,d=this.element,e=c.scrollTop(),f=d.height(),g=this.page?d.closest(".ui-page").height():a(".ui-page-active").height(),h=a.mobile.getScreenHeight();return!b&&(this.options.transition&&"none"!==this.options.transition&&("header"===this.role&&!this.options.fullscreen&&e>f||"footer"===this.role&&!this.options.fullscreen&&g-f>e+h)||this.options.fullscreen)},show:function(a){var b="ui-fixed-hidden",c=this.element;this._useTransition(a)?c.removeClass("out "+b).addClass("in").animationComplete(function(){c.removeClass("in")}):c.removeClass(b),this._visible=!0},hide:function(a){var b="ui-fixed-hidden",c=this.element,d="out"+("slide"===this.options.transition?" reverse":"");this._useTransition(a)?c.addClass(d).removeClass("in").animationComplete(function(){c.addClass(b).removeClass(d)}):c.addClass(b).removeClass(d),this._visible=!1},toggle:function(){this[this._visible?"hide":"show"]()},_bindToggleHandlers:function(){var b,c,d=this,e=d.options,f=!0,g=this.page?this.page:a(".ui-page");g.bind("vclick",function(b){e.tapToggle&&!a(b.target).closest(e.tapToggleBlacklist).length&&d.toggle()}).bind("focusin focusout",function(g){screen.width<1025&&a(g.target).is(e.hideDuringFocus)&&!a(g.target).closest(".ui-header-fixed, .ui-footer-fixed").length&&("focusout"!==g.type||f?"focusin"===g.type&&f&&(clearTimeout(b),f=!1,c=setTimeout(function(){d.hide()},0)):(f=!0,clearTimeout(c),b=setTimeout(function(){d.show()},0)))})},_setRelative:function(){"fixed"!==this.options.position&&a("[data-"+a.mobile.ns+"role='page']").css({position:"relative"})},_destroy:function(){var b,c,d,e,f,g=this.pagecontainer.pagecontainer("getActivePage");this._super(),"fixed"===this.options.position&&(d=a("body>.ui-"+this.role+"-fixed").add(g.find(".ui-"+this.options.role+"-fixed")).not(this.element).length>0,f=a("body>.ui-"+this.role+"-fixed").add(g.find(".ui-"+this.options.role+"-fullscreen")).not(this.element).length>0,c="ui-header-fixed ui-footer-fixed ui-header-fullscreen in out ui-footer-fullscreen fade slidedown slideup ui-fixed-hidden",this.element.removeClass(c),f||(b="ui-page-"+this.role+"-fullscreen"),d||(e="header"===this.role,b+=" ui-page-"+this.role+"-fixed",g.css("padding-"+(e?"top":"bottom"),"")),g.removeClass(b))
+}})}(a),function(a){a.widget("mobile.toolbar",a.mobile.toolbar,{_makeFixed:function(){this._super(),this._workarounds()},_workarounds:function(){var a=navigator.userAgent,b=navigator.platform,c=a.match(/AppleWebKit\/([0-9]+)/),d=!!c&&c[1],e=null,f=this;if(b.indexOf("iPhone")>-1||b.indexOf("iPad")>-1||b.indexOf("iPod")>-1)e="ios";else{if(!(a.indexOf("Android")>-1))return;e="android"}if("ios"===e)f._bindScrollWorkaround();else{if(!("android"===e&&d&&534>d))return;f._bindScrollWorkaround(),f._bindListThumbWorkaround()}},_viewportOffset:function(){var a=this.element,b=a.hasClass("ui-header"),c=Math.abs(a.offset().top-this.window.scrollTop());return b||(c=Math.round(c-this.window.height()+a.outerHeight())-60),c},_bindScrollWorkaround:function(){var a=this;this._on(this.window,{scrollstop:function(){var b=a._viewportOffset();b>2&&a._visible&&a._triggerRedraw()}})},_bindListThumbWorkaround:function(){this.element.closest(".ui-page").addClass("ui-android-2x-fixed")},_triggerRedraw:function(){var b=parseFloat(a(".ui-page-active").css("padding-bottom"));a(".ui-page-active").css("padding-bottom",b+1+"px"),setTimeout(function(){a(".ui-page-active").css("padding-bottom",b+"px")},0)},destroy:function(){this._super(),this.element.closest(".ui-page-active").removeClass("ui-android-2x-fix")}})}(a),function(a,b){function c(){var a=e.clone(),b=a.eq(0),c=a.eq(1),d=c.children();return{arEls:c.add(b),gd:b,ct:c,ar:d}}var d=a.mobile.browser.oldIE&&a.mobile.browser.oldIE<=8,e=a("<div class='ui-popup-arrow-guide'></div><div class='ui-popup-arrow-container"+(d?" ie":"")+"'><div class='ui-popup-arrow'></div></div>");a.widget("mobile.popup",a.mobile.popup,{options:{arrow:""},_create:function(){var a,b=this._super();return this.options.arrow&&(this._ui.arrow=a=this._addArrow()),b},_addArrow:function(){var a,b=this.options,d=c();return a=this._themeClassFromOption("ui-body-",b.theme),d.ar.addClass(a+(b.shadow?" ui-overlay-shadow":"")),d.arEls.hide().appendTo(this.element),d},_unenhance:function(){var a=this._ui.arrow;return a&&a.arEls.remove(),this._super()},_tryAnArrow:function(a,b,c,d,e){var f,g,h,i={},j={};return d.arFull[a.dimKey]>d.guideDims[a.dimKey]?e:(i[a.fst]=c[a.fst]+(d.arHalf[a.oDimKey]+d.menuHalf[a.oDimKey])*a.offsetFactor-d.contentBox[a.fst]+(d.clampInfo.menuSize[a.oDimKey]-d.contentBox[a.oDimKey])*a.arrowOffsetFactor,i[a.snd]=c[a.snd],f=d.result||this._calculateFinalLocation(i,d.clampInfo),g={x:f.left,y:f.top},j[a.fst]=g[a.fst]+d.contentBox[a.fst]+a.tipOffset,j[a.snd]=Math.max(f[a.prop]+d.guideOffset[a.prop]+d.arHalf[a.dimKey],Math.min(f[a.prop]+d.guideOffset[a.prop]+d.guideDims[a.dimKey]-d.arHalf[a.dimKey],c[a.snd])),h=Math.abs(c.x-j.x)+Math.abs(c.y-j.y),(!e||h<e.diff)&&(j[a.snd]-=d.arHalf[a.dimKey]+f[a.prop]+d.contentBox[a.snd],e={dir:b,diff:h,result:f,posProp:a.prop,posVal:j[a.snd]}),e)},_getPlacementState:function(a){var b,c,d=this._ui.arrow,e={clampInfo:this._clampPopupWidth(!a),arFull:{cx:d.ct.width(),cy:d.ct.height()},guideDims:{cx:d.gd.width(),cy:d.gd.height()},guideOffset:d.gd.offset()};return b=this.element.offset(),d.gd.css({left:0,top:0,right:0,bottom:0}),c=d.gd.offset(),e.contentBox={x:c.left-b.left,y:c.top-b.top,cx:d.gd.width(),cy:d.gd.height()},d.gd.removeAttr("style"),e.guideOffset={left:e.guideOffset.left-b.left,top:e.guideOffset.top-b.top},e.arHalf={cx:e.arFull.cx/2,cy:e.arFull.cy/2},e.menuHalf={cx:e.clampInfo.menuSize.cx/2,cy:e.clampInfo.menuSize.cy/2},e},_placementCoords:function(b){var c,e,f,g,h,i=this.options.arrow,j=this._ui.arrow;return j?(j.arEls.show(),h={},c=this._getPlacementState(!0),f={l:{fst:"x",snd:"y",prop:"top",dimKey:"cy",oDimKey:"cx",offsetFactor:1,tipOffset:-c.arHalf.cx,arrowOffsetFactor:0},r:{fst:"x",snd:"y",prop:"top",dimKey:"cy",oDimKey:"cx",offsetFactor:-1,tipOffset:c.arHalf.cx+c.contentBox.cx,arrowOffsetFactor:1},b:{fst:"y",snd:"x",prop:"left",dimKey:"cx",oDimKey:"cy",offsetFactor:-1,tipOffset:c.arHalf.cy+c.contentBox.cy,arrowOffsetFactor:1},t:{fst:"y",snd:"x",prop:"left",dimKey:"cx",oDimKey:"cy",offsetFactor:1,tipOffset:-c.arHalf.cy,arrowOffsetFactor:0}},a.each((i===!0?"l,t,r,b":i).split(","),a.proxy(function(a,d){e=this._tryAnArrow(f[d],d,b,c,e)},this)),e?(j.ct.removeClass("ui-popup-arrow-l ui-popup-arrow-t ui-popup-arrow-r ui-popup-arrow-b").addClass("ui-popup-arrow-"+e.dir).removeAttr("style").css(e.posProp,e.posVal).show(),d||(g=this.element.offset(),h[f[e.dir].fst]=j.ct.offset(),h[f[e.dir].snd]={left:g.left+c.contentBox.x,top:g.top+c.contentBox.y}),e.result):(j.arEls.hide(),this._super(b))):this._super(b)},_setOptions:function(a){var c,d=this.options.theme,e=this._ui.arrow,f=this._super(a);if(a.arrow!==b){if(!e&&a.arrow)return void(this._ui.arrow=this._addArrow());e&&!a.arrow&&(e.arEls.remove(),this._ui.arrow=null)}return e=this._ui.arrow,e&&(a.theme!==b&&(d=this._themeClassFromOption("ui-body-",d),c=this._themeClassFromOption("ui-body-",a.theme),e.ar.removeClass(d).addClass(c)),a.shadow!==b&&e.ar.toggleClass("ui-overlay-shadow",a.shadow)),f},_destroy:function(){var a=this._ui.arrow;return a&&a.arEls.remove(),this._super()}})}(a),function(a,c){a.widget("mobile.panel",{options:{classes:{panel:"ui-panel",panelOpen:"ui-panel-open",panelClosed:"ui-panel-closed",panelFixed:"ui-panel-fixed",panelInner:"ui-panel-inner",modal:"ui-panel-dismiss",modalOpen:"ui-panel-dismiss-open",pageContainer:"ui-panel-page-container",pageWrapper:"ui-panel-wrapper",pageFixedToolbar:"ui-panel-fixed-toolbar",pageContentPrefix:"ui-panel-page-content",animate:"ui-panel-animate"},animate:!0,theme:null,position:"left",dismissible:!0,display:"reveal",swipeClose:!0,positionFixed:!1},_closeLink:null,_parentPage:null,_page:null,_modal:null,_panelInner:null,_wrapper:null,_fixedToolbars:null,_create:function(){var b=this.element,c=b.closest(".ui-page, :jqmData(role='page')");a.extend(this,{_closeLink:b.find(":jqmData(rel='close')"),_parentPage:c.length>0?c:!1,_openedPage:null,_page:this._getPage,_panelInner:this._getPanelInner(),_fixedToolbars:this._getFixedToolbars}),"overlay"!==this.options.display&&this._getWrapper(),this._addPanelClasses(),a.support.cssTransform3d&&this.options.animate&&this.element.addClass(this.options.classes.animate),this._bindUpdateLayout(),this._bindCloseEvents(),this._bindLinkListeners(),this._bindPageEvents(),this.options.dismissible&&this._createModal(),this._bindSwipeEvents()},_getPanelInner:function(){var a=this.element.find("."+this.options.classes.panelInner);return 0===a.length&&(a=this.element.children().wrapAll("<div class='"+this.options.classes.panelInner+"' />").parent()),a},_createModal:function(){var b=this,c=b._parentPage?b._parentPage.parent():b.element.parent();b._modal=a("<div class='"+b.options.classes.modal+"'></div>").on("mousedown",function(){b.close()}).appendTo(c)},_getPage:function(){var b=this._openedPage||this._parentPage||a("."+a.mobile.activePageClass);return b},_getWrapper:function(){var a=this._page().find("."+this.options.classes.pageWrapper);0===a.length&&(a=this._page().children(".ui-header:not(.ui-header-fixed), .ui-content:not(.ui-popup), .ui-footer:not(.ui-footer-fixed)").wrapAll("<div class='"+this.options.classes.pageWrapper+"'></div>").parent()),this._wrapper=a},_getFixedToolbars:function(){var b=a("body").children(".ui-header-fixed, .ui-footer-fixed"),c=this._page().find(".ui-header-fixed, .ui-footer-fixed"),d=b.add(c).addClass(this.options.classes.pageFixedToolbar);return d},_getPosDisplayClasses:function(a){return a+"-position-"+this.options.position+" "+a+"-display-"+this.options.display},_getPanelClasses:function(){var a=this.options.classes.panel+" "+this._getPosDisplayClasses(this.options.classes.panel)+" "+this.options.classes.panelClosed+" ui-body-"+(this.options.theme?this.options.theme:"inherit");return this.options.positionFixed&&(a+=" "+this.options.classes.panelFixed),a},_addPanelClasses:function(){this.element.addClass(this._getPanelClasses())},_handleCloseClick:function(a){a.isDefaultPrevented()||this.close()},_bindCloseEvents:function(){this._on(this._closeLink,{click:"_handleCloseClick"}),this._on({"click a:jqmData(ajax='false')":"_handleCloseClick"})},_positionPanel:function(b){var c=this,d=c._panelInner.outerHeight(),e=d>a.mobile.getScreenHeight();e||!c.options.positionFixed?(e&&(c._unfixPanel(),a.mobile.resetActivePageHeight(d)),b&&this.window[0].scrollTo(0,a.mobile.defaultHomeScroll)):c._fixPanel()},_bindFixListener:function(){this._on(a(b),{throttledresize:"_positionPanel"})},_unbindFixListener:function(){this._off(a(b),"throttledresize")},_unfixPanel:function(){this.options.positionFixed&&a.support.fixedPosition&&this.element.removeClass(this.options.classes.panelFixed)},_fixPanel:function(){this.options.positionFixed&&a.support.fixedPosition&&this.element.addClass(this.options.classes.panelFixed)},_bindUpdateLayout:function(){var a=this;a.element.on("updatelayout",function(){a._open&&a._positionPanel()})},_bindLinkListeners:function(){this._on("body",{"click a":"_handleClick"})},_handleClick:function(b){var d,e=this.element.attr("id");b.currentTarget.href.split("#")[1]===e&&e!==c&&(b.preventDefault(),d=a(b.target),d.hasClass("ui-btn")&&(d.addClass(a.mobile.activeBtnClass),this.element.one("panelopen panelclose",function(){d.removeClass(a.mobile.activeBtnClass)})),this.toggle())},_bindSwipeEvents:function(){var a=this,b=a._modal?a.element.add(a._modal):a.element;a.options.swipeClose&&("left"===a.options.position?b.on("swipeleft.panel",function(){a.close()}):b.on("swiperight.panel",function(){a.close()}))},_bindPageEvents:function(){var a=this;this.document.on("panelbeforeopen",function(b){a._open&&b.target!==a.element[0]&&a.close()}).on("keyup.panel",function(b){27===b.keyCode&&a._open&&a.close()}),this._parentPage||"overlay"===this.options.display||this._on(this.document,{pageshow:function(){this._openedPage=null,this._getWrapper()}}),a._parentPage?this.document.on("pagehide",":jqmData(role='page')",function(){a._open&&a.close(!0)}):this.document.on("pagebeforehide",function(){a._open&&a.close(!0)})},_open:!1,_pageContentOpenClasses:null,_modalOpenClasses:null,open:function(b){if(!this._open){var c=this,d=c.options,e=function(){c._off(c.document,"panelclose"),c._page().jqmData("panel","open"),a.support.cssTransform3d&&d.animate&&"overlay"!==d.display&&(c._wrapper.addClass(d.classes.animate),c._fixedToolbars().addClass(d.classes.animate)),!b&&a.support.cssTransform3d&&d.animate?(c._wrapper||c.element).animationComplete(f,"transition"):setTimeout(f,0),d.theme&&"overlay"!==d.display&&c._page().parent().addClass(d.classes.pageContainer+"-themed "+d.classes.pageContainer+"-"+d.theme),c.element.removeClass(d.classes.panelClosed).addClass(d.classes.panelOpen),c._positionPanel(!0),c._pageContentOpenClasses=c._getPosDisplayClasses(d.classes.pageContentPrefix),"overlay"!==d.display&&(c._page().parent().addClass(d.classes.pageContainer),c._wrapper.addClass(c._pageContentOpenClasses),c._fixedToolbars().addClass(c._pageContentOpenClasses)),c._modalOpenClasses=c._getPosDisplayClasses(d.classes.modal)+" "+d.classes.modalOpen,c._modal&&c._modal.addClass(c._modalOpenClasses).height(Math.max(c._modal.height(),c.document.height()))},f=function(){c._open&&("overlay"!==d.display&&(c._wrapper.addClass(d.classes.pageContentPrefix+"-open"),c._fixedToolbars().addClass(d.classes.pageContentPrefix+"-open")),c._bindFixListener(),c._trigger("open"),c._openedPage=c._page())};c._trigger("beforeopen"),"open"===c._page().jqmData("panel")?c._on(c.document,{panelclose:e}):e(),c._open=!0}},close:function(b){if(this._open){var c=this,d=this.options,e=function(){c.element.removeClass(d.classes.panelOpen),"overlay"!==d.display&&(c._wrapper.removeClass(c._pageContentOpenClasses),c._fixedToolbars().removeClass(c._pageContentOpenClasses)),!b&&a.support.cssTransform3d&&d.animate?(c._wrapper||c.element).animationComplete(f,"transition"):setTimeout(f,0),c._modal&&c._modal.removeClass(c._modalOpenClasses).height("")},f=function(){d.theme&&"overlay"!==d.display&&c._page().parent().removeClass(d.classes.pageContainer+"-themed "+d.classes.pageContainer+"-"+d.theme),c.element.addClass(d.classes.panelClosed),"overlay"!==d.display&&(c._page().parent().removeClass(d.classes.pageContainer),c._wrapper.removeClass(d.classes.pageContentPrefix+"-open"),c._fixedToolbars().removeClass(d.classes.pageContentPrefix+"-open")),a.support.cssTransform3d&&d.animate&&"overlay"!==d.display&&(c._wrapper.removeClass(d.classes.animate),c._fixedToolbars().removeClass(d.classes.animate)),c._fixPanel(),c._unbindFixListener(),a.mobile.resetActivePageHeight(),c._page().jqmRemoveData("panel"),c._trigger("close"),c._openedPage=null};c._trigger("beforeclose"),e(),c._open=!1}},toggle:function(){this[this._open?"close":"open"]()},_destroy:function(){var b,c=this.options,d=a("body > :mobile-panel").length+a.mobile.activePage.find(":mobile-panel").length>1;"overlay"!==c.display&&(b=a("body > :mobile-panel").add(a.mobile.activePage.find(":mobile-panel")),0===b.not(".ui-panel-display-overlay").not(this.element).length&&this._wrapper.children().unwrap(),this._open&&(this._fixedToolbars().removeClass(c.classes.pageContentPrefix+"-open"),a.support.cssTransform3d&&c.animate&&this._fixedToolbars().removeClass(c.classes.animate),this._page().parent().removeClass(c.classes.pageContainer),c.theme&&this._page().parent().removeClass(c.classes.pageContainer+"-themed "+c.classes.pageContainer+"-"+c.theme))),d||this.document.off("panelopen panelclose"),this._open&&this._page().jqmRemoveData("panel"),this._panelInner.children().unwrap(),this.element.removeClass([this._getPanelClasses(),c.classes.panelOpen,c.classes.animate].join(" ")).off("swipeleft.panel swiperight.panel").off("panelbeforeopen").off("panelhide").off("keyup.panel").off("updatelayout"),this._modal&&this._modal.remove()}})}(a),function(a,b){a.widget("mobile.table",{options:{classes:{table:"ui-table"},enhanced:!1},_create:function(){this.options.enhanced||this.element.addClass(this.options.classes.table),a.extend(this,{headers:b,allHeaders:b}),this._refresh(!0)},_setHeaders:function(){var a=this.element.find("thead tr");this.headers=this.element.find("tr:eq(0)").children(),this.allHeaders=this.headers.add(a.children())},refresh:function(){this._refresh()},rebuild:a.noop,_refresh:function(){var b=this.element,c=b.find("thead tr");this._setHeaders(),c.each(function(){var d=0;a(this).children().each(function(){var e,f=parseInt(this.getAttribute("colspan"),10),g=":nth-child("+(d+1)+")";if(this.setAttribute("data-"+a.mobile.ns+"colstart",d+1),f)for(e=0;f-1>e;e++)d++,g+=", :nth-child("+(d+1)+")";a(this).jqmData("cells",b.find("tr").not(c.eq(0)).not(this).children(g)),d++})})}})}(a),function(a){a.widget("mobile.table",a.mobile.table,{options:{mode:"columntoggle",columnBtnTheme:null,columnPopupTheme:null,columnBtnText:"Columns...",classes:a.extend(a.mobile.table.prototype.options.classes,{popup:"ui-table-columntoggle-popup",columnBtn:"ui-table-columntoggle-btn",priorityPrefix:"ui-table-priority-",columnToggleTable:"ui-table-columntoggle"})},_create:function(){this._super(),"columntoggle"===this.options.mode&&(a.extend(this,{_menu:null}),this.options.enhanced?(this._menu=a(this.document[0].getElementById(this._id()+"-popup")).children().first(),this._addToggles(this._menu,!0)):(this._menu=this._enhanceColToggle(),this.element.addClass(this.options.classes.columnToggleTable)),this._setupEvents(),this._setToggleState())},_id:function(){return this.element.attr("id")||this.widgetName+this.uuid},_setupEvents:function(){this._on(this.window,{throttledresize:"_setToggleState"}),this._on(this._menu,{"change input":"_menuInputChange"})},_addToggles:function(b,c){var d,e=0,f=this.options,g=b.controlgroup("container");c?d=b.find("input"):g.empty(),this.headers.not("td").each(function(){var b,h,i=a(this),j=a.mobile.getAttribute(this,"priority");j&&(h=i.add(i.jqmData("cells")),h.addClass(f.classes.priorityPrefix+j),b=(c?d.eq(e++):a("<label><input type='checkbox' checked />"+(i.children("abbr").first().attr("title")||i.text())+"</label>").appendTo(g).children(0).checkboxradio({theme:f.columnPopupTheme})).jqmData("header",i).jqmData("cells",h),i.jqmData("input",b))}),c||b.controlgroup("refresh")},_menuInputChange:function(b){var c=a(b.target),d=c[0].checked;c.jqmData("cells").toggleClass("ui-table-cell-hidden",!d).toggleClass("ui-table-cell-visible",d)},_unlockCells:function(a){a.removeClass("ui-table-cell-hidden ui-table-cell-visible")},_enhanceColToggle:function(){var b,c,d,e,f=this.element,g=this.options,h=a.mobile.ns,i=this.document[0].createDocumentFragment();return b=this._id()+"-popup",c=a("<a href='#"+b+"' class='"+g.classes.columnBtn+" ui-btn ui-btn-"+(g.columnBtnTheme||"a")+" ui-corner-all ui-shadow ui-mini' data-"+h+"rel='popup'>"+g.columnBtnText+"</a>"),d=a("<div class='"+g.classes.popup+"' id='"+b+"'></div>"),e=a("<fieldset></fieldset>").controlgroup(),this._addToggles(e,!1),e.appendTo(d),i.appendChild(d[0]),i.appendChild(c[0]),f.before(i),d.popup(),e},rebuild:function(){this._super(),"columntoggle"===this.options.mode&&this._refresh(!1)},_refresh:function(b){var c,d,e;if(this._super(b),!b&&"columntoggle"===this.options.mode)for(c=this.headers,d=[],this._menu.find("input").each(function(){var b=a(this),e=b.jqmData("header"),f=c.index(e[0]);f>-1&&!b.prop("checked")&&d.push(f)}),this._unlockCells(this.element.find(".ui-table-cell-hidden, .ui-table-cell-visible")),this._addToggles(this._menu,b),e=d.length-1;e>-1;e--)c.eq(d[e]).jqmData("input").prop("checked",!1).checkboxradio("refresh").trigger("change")},_setToggleState:function(){this._menu.find("input").each(function(){var b=a(this);this.checked="table-cell"===b.jqmData("cells").eq(0).css("display"),b.checkboxradio("refresh")})},_destroy:function(){this._super()}})}(a),function(a){a.widget("mobile.table",a.mobile.table,{options:{mode:"reflow",classes:a.extend(a.mobile.table.prototype.options.classes,{reflowTable:"ui-table-reflow",cellLabels:"ui-table-cell-label"})},_create:function(){this._super(),"reflow"===this.options.mode&&(this.options.enhanced||(this.element.addClass(this.options.classes.reflowTable),this._updateReflow()))},rebuild:function(){this._super(),"reflow"===this.options.mode&&this._refresh(!1)},_refresh:function(a){this._super(a),a||"reflow"!==this.options.mode||this._updateReflow()},_updateReflow:function(){var b=this,c=this.options;a(b.allHeaders.get().reverse()).each(function(){var d,e,f=a(this).jqmData("cells"),g=a.mobile.getAttribute(this,"colstart"),h=f.not(this).filter("thead th").length&&" ui-table-cell-label-top",i=a(this).clone().contents();i.length>0&&(h?(d=parseInt(this.getAttribute("colspan"),10),e="",d&&(e="td:nth-child("+d+"n + "+g+")"),b._addLabels(f.filter(e),c.classes.cellLabels+h,i)):b._addLabels(f,c.classes.cellLabels,i))})},_addLabels:function(b,c,d){1===d.length&&"abbr"===d[0].nodeName.toLowerCase()&&(d=d.eq(0).attr("title")),b.not(":has(b."+c+")").prepend(a("<b class='"+c+"'></b>").append(d))}})}(a),function(a,c){var d=function(b,c){return-1===(""+(a.mobile.getAttribute(this,"filtertext")||a(this).text())).toLowerCase().indexOf(c)};a.widget("mobile.filterable",{initSelector:":jqmData(filter='true')",options:{filterReveal:!1,filterCallback:d,enhanced:!1,input:null,children:"> li, > option, > optgroup option, > tbody tr, > .ui-controlgroup-controls > .ui-btn, > .ui-controlgroup-controls > .ui-checkbox, > .ui-controlgroup-controls > .ui-radio"},_create:function(){var b=this.options;a.extend(this,{_search:null,_timer:0}),this._setInput(b.input),b.enhanced||this._filterItems((this._search&&this._search.val()||"").toLowerCase())},_onKeyUp:function(){var c,d,e=this._search;if(e){if(c=e.val().toLowerCase(),d=a.mobile.getAttribute(e[0],"lastval")+"",d&&d===c)return;this._timer&&(b.clearTimeout(this._timer),this._timer=0),this._timer=this._delay(function(){return this._trigger("beforefilter",null,{input:e})===!1?!1:(e[0].setAttribute("data-"+a.mobile.ns+"lastval",c),this._filterItems(c),void(this._timer=0))},250)}},_getFilterableItems:function(){var b=this.element,c=this.options.children,d=c?a.isFunction(c)?c():c.nodeName?a(c):c.jquery?c:this.element.find(c):{length:0};return 0===d.length&&(d=b.children()),d},_filterItems:function(b){var c,e,f,g,h=[],i=[],j=this.options,k=this._getFilterableItems();if(null!=b)for(e=j.filterCallback||d,f=k.length,c=0;f>c;c++)g=e.call(k[c],c,b)?i:h,g.push(k[c]);0===i.length?k[j.filterReveal&&0===b.length?"addClass":"removeClass"]("ui-screen-hidden"):(a(i).addClass("ui-screen-hidden"),a(h).removeClass("ui-screen-hidden")),this._refreshChildWidget(),this._trigger("filter",null,{items:k})},_refreshChildWidget:function(){var b,c,d=["collapsibleset","selectmenu","controlgroup","listview"];for(c=d.length-1;c>-1;c--)b=d[c],a.mobile[b]&&(b=this.element.data("mobile-"+b),b&&a.isFunction(b.refresh)&&b.refresh())},_setInput:function(c){var d=this._search;this._timer&&(b.clearTimeout(this._timer),this._timer=0),d&&(this._off(d,"keyup change input"),d=null),c&&(d=c.jquery?c:c.nodeName?a(c):this.document.find(c),this._on(d,{keydown:"_onKeyDown",keypress:"_onKeyPress",keyup:"_onKeyUp",change:"_onKeyUp",input:"_onKeyUp"})),this._search=d},_onKeyDown:function(b){b.keyCode===a.ui.keyCode.ENTER&&(b.preventDefault(),this._preventKeyPress=!0)},_onKeyPress:function(a){this._preventKeyPress&&(a.preventDefault(),this._preventKeyPress=!1)},_setOptions:function(a){var b=!(a.filterReveal===c&&a.filterCallback===c&&a.children===c);this._super(a),a.input!==c&&(this._setInput(a.input),b=!0),b&&this.refresh()},_destroy:function(){var a=this.options,b=this._getFilterableItems();a.enhanced?b.toggleClass("ui-screen-hidden",a.filterReveal):b.removeClass("ui-screen-hidden")},refresh:function(){this._timer&&(b.clearTimeout(this._timer),this._timer=0),this._filterItems((this._search&&this._search.val()||"").toLowerCase())}})}(a),function(a,b){var c=function(a,b){return function(c){b.call(this,c),a._syncTextInputOptions(c)}},d=/(^|\s)ui-li-divider(\s|$)/,e=a.mobile.filterable.prototype.options.filterCallback;a.mobile.filterable.prototype.options.filterCallback=function(a,b){return!this.className.match(d)&&e.call(this,a,b)},a.widget("mobile.filterable",a.mobile.filterable,{options:{filterPlaceholder:"Filter items...",filterTheme:null},_create:function(){var b,c,d=this.element,e=["collapsibleset","selectmenu","controlgroup","listview"],f={};for(this._super(),a.extend(this,{_widget:null}),b=e.length-1;b>-1;b--)if(c=e[b],a.mobile[c]){if(this._setWidget(d.data("mobile-"+c)))break;f[c+"create"]="_handleCreate"}this._widget||this._on(d,f)},_handleCreate:function(a){this._setWidget(this.element.data("mobile-"+a.type.substring(0,a.type.length-6)))},_trigger:function(a,b,c){return this._widget&&"mobile-listview"===this._widget.widgetFullName&&"beforefilter"===a&&this._widget._trigger("beforefilter",b,c),this._super(a,b,c)},_setWidget:function(a){return!this._widget&&a&&(this._widget=a,this._widget._setOptions=c(this,this._widget._setOptions)),this._widget&&(this._syncTextInputOptions(this._widget.options),"listview"===this._widget.widgetName&&(this._widget.options.hideDividers=!0,this._widget.element.listview("refresh"))),!!this._widget},_isSearchInternal:function(){return this._search&&this._search.jqmData("ui-filterable-"+this.uuid+"-internal")},_setInput:function(b){var c=this.options,d=!0,e={};if(!b){if(this._isSearchInternal())return;d=!1,b=a("<input data-"+a.mobile.ns+"type='search' placeholder='"+c.filterPlaceholder+"'></input>").jqmData("ui-filterable-"+this.uuid+"-internal",!0),a("<form class='ui-filterable'></form>").append(b).submit(function(a){a.preventDefault(),b.blur()}).insertBefore(this.element),a.mobile.textinput&&(null!=this.options.filterTheme&&(e.theme=c.filterTheme),b.textinput(e))}this._super(b),this._isSearchInternal()&&d&&this._search.attr("placeholder",this.options.filterPlaceholder)},_setOptions:function(c){var d=this._super(c);return c.filterPlaceholder!==b&&this._isSearchInternal()&&this._search.attr("placeholder",c.filterPlaceholder),c.filterTheme!==b&&this._search&&a.mobile.textinput&&this._search.textinput("option","theme",c.filterTheme),d},_refreshChildWidget:function(){this._refreshingChildWidget=!0,this._superApply(arguments),this._refreshingChildWidget=!1},refresh:function(){this._refreshingChildWidget||this._superApply(arguments)},_destroy:function(){this._isSearchInternal()&&this._search.remove(),this._super()},_syncTextInputOptions:function(c){var d,e={};if(this._isSearchInternal()&&a.mobile.textinput){for(d in a.mobile.textinput.prototype.options)c[d]!==b&&(e[d]="theme"===d&&null!=this.options.filterTheme?this.options.filterTheme:c[d]);this._search.textinput("option",e)}}}),a.widget("mobile.listview",a.mobile.listview,{options:{filter:!1},_create:function(){return this.options.filter!==!0||this.element.data("mobile-filterable")||this.element.filterable(),this._super()},refresh:function(){var a;this._superApply(arguments),this.options.filter===!0&&(a=this.element.data("mobile-filterable"),a&&a.refresh())}})}(a),function(a,b){function c(){return++e}function d(a){return a.hash.length>1&&decodeURIComponent(a.href.replace(f,""))===decodeURIComponent(location.href.replace(f,""))}var e=0,f=/#.*$/;a.widget("ui.tabs",{version:"fadf2b312a05040436451c64bbfaf4814bc62c56",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_create:function(){var b=this,c=this.options;this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",c.collapsible).delegate(".ui-tabs-nav > li","mousedown"+this.eventNamespace,function(b){a(this).is(".ui-state-disabled")&&b.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){a(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this._processTabs(),c.active=this._initialActive(),a.isArray(c.disabled)&&(c.disabled=a.unique(c.disabled.concat(a.map(this.tabs.filter(".ui-state-disabled"),function(a){return b.tabs.index(a)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(c.active):a(),this._refresh(),this.active.length&&this.load(c.active)},_initialActive:function(){var b=this.options.active,c=this.options.collapsible,d=location.hash.substring(1);return null===b&&(d&&this.tabs.each(function(c,e){return a(e).attr("aria-controls")===d?(b=c,!1):void 0}),null===b&&(b=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===b||-1===b)&&(b=this.tabs.length?0:!1)),b!==!1&&(b=this.tabs.index(this.tabs.eq(b)),-1===b&&(b=c?!1:0)),!c&&b===!1&&this.anchors.length&&(b=0),b},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):a()}},_tabKeydown:function(b){var c=a(this.document[0].activeElement).closest("li"),d=this.tabs.index(c),e=!0;if(!this._handlePageNav(b)){switch(b.keyCode){case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:d++;break;case a.ui.keyCode.UP:case a.ui.keyCode.LEFT:e=!1,d--;break;case a.ui.keyCode.END:d=this.anchors.length-1;break;case a.ui.keyCode.HOME:d=0;break;case a.ui.keyCode.SPACE:return b.preventDefault(),clearTimeout(this.activating),void this._activate(d);case a.ui.keyCode.ENTER:return b.preventDefault(),clearTimeout(this.activating),void this._activate(d===this.options.active?!1:d);default:return}b.preventDefault(),clearTimeout(this.activating),d=this._focusNextTab(d,e),b.ctrlKey||(c.attr("aria-selected","false"),this.tabs.eq(d).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",d)},this.delay))}},_panelKeydown:function(b){this._handlePageNav(b)||b.ctrlKey&&b.keyCode===a.ui.keyCode.UP&&(b.preventDefault(),this.active.focus())},_handlePageNav:function(b){return b.altKey&&b.keyCode===a.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):b.altKey&&b.keyCode===a.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):void 0},_findNextTab:function(b,c){function d(){return b>e&&(b=0),0>b&&(b=e),b}for(var e=this.tabs.length-1;-1!==a.inArray(d(),this.options.disabled);)b=c?b+1:b-1;return b},_focusNextTab:function(a,b){return a=this._findNextTab(a,b),this.tabs.eq(a).focus(),a},_setOption:function(a,b){return"active"===a?void this._activate(b):"disabled"===a?void this._setupDisabled(b):(this._super(a,b),"collapsible"===a&&(this.element.toggleClass("ui-tabs-collapsible",b),b||this.options.active!==!1||this._activate(0)),"event"===a&&this._setupEvents(b),void("heightStyle"===a&&this._setupHeightStyle(b)))},_tabId:function(a){return a.attr("aria-controls")||"ui-tabs-"+c()},_sanitizeSelector:function(a){return a?a.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var b=this.options,c=this.tablist.children(":has(a[href])");b.disabled=a.map(c.filter(".ui-state-disabled"),function(a){return c.index(a)}),this._processTabs(),b.active!==!1&&this.anchors.length?this.active.length&&!a.contains(this.tablist[0],this.active[0])?this.tabs.length===b.disabled.length?(b.active=!1,this.active=a()):this._activate(this._findNextTab(Math.max(0,b.active-1),!1)):b.active=this.tabs.index(this.active):(b.active=!1,this.active=a()),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-expanded":"false","aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-expanded":"true","aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var b=this;this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist"),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return a("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=a(),this.anchors.each(function(c,e){var f,g,h,i=a(e).uniqueId().attr("id"),j=a(e).closest("li"),k=j.attr("aria-controls");d(e)?(f=e.hash,g=b.element.find(b._sanitizeSelector(f))):(h=b._tabId(j),f="#"+h,g=b.element.find(f),g.length||(g=b._createPanel(h),g.insertAfter(b.panels[c-1]||b.tablist)),g.attr("aria-live","polite")),g.length&&(b.panels=b.panels.add(g)),k&&j.data("ui-tabs-aria-controls",k),j.attr({"aria-controls":f.substring(1),"aria-labelledby":i}),g.attr("aria-labelledby",i)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel")},_getList:function(){return this.element.find("ol,ul").eq(0)},_createPanel:function(b){return a("<div>").attr("id",b).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(b){a.isArray(b)&&(b.length?b.length===this.anchors.length&&(b=!0):b=!1);for(var c,d=0;c=this.tabs[d];d++)b===!0||-1!==a.inArray(d,b)?a(c).addClass("ui-state-disabled").attr("aria-disabled","true"):a(c).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=b},_setupEvents:function(b){var c={click:function(a){a.preventDefault()}};b&&a.each(b.split(" "),function(a,b){c[b]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(this.anchors,c),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(b){var c,d=this.element.parent();"fill"===b?(c=d.height(),c-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var b=a(this),d=b.css("position");"absolute"!==d&&"fixed"!==d&&(c-=b.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){c-=a(this).outerHeight(!0)
+}),this.panels.each(function(){a(this).height(Math.max(0,c-a(this).innerHeight()+a(this).height()))}).css("overflow","auto")):"auto"===b&&(c=0,this.panels.each(function(){c=Math.max(c,a(this).height("").height())}).height(c))},_eventHandler:function(b){var c=this.options,d=this.active,e=a(b.currentTarget),f=e.closest("li"),g=f[0]===d[0],h=g&&c.collapsible,i=h?a():this._getPanelForTab(f),j=d.length?this._getPanelForTab(d):a(),k={oldTab:d,oldPanel:j,newTab:h?a():f,newPanel:i};b.preventDefault(),f.hasClass("ui-state-disabled")||f.hasClass("ui-tabs-loading")||this.running||g&&!c.collapsible||this._trigger("beforeActivate",b,k)===!1||(c.active=h?!1:this.tabs.index(f),this.active=g?a():f,this.xhr&&this.xhr.abort(),j.length||i.length||a.error("jQuery UI Tabs: Mismatching fragment identifier."),i.length&&this.load(this.tabs.index(f),b),this._toggle(b,k))},_toggle:function(b,c){function d(){f.running=!1,f._trigger("activate",b,c)}function e(){c.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),g.length&&f.options.show?f._show(g,f.options.show,d):(g.show(),d())}var f=this,g=c.newPanel,h=c.oldPanel;this.running=!0,h.length&&this.options.hide?this._hide(h,this.options.hide,function(){c.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),e()}):(c.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),h.hide(),e()),h.attr({"aria-expanded":"false","aria-hidden":"true"}),c.oldTab.attr("aria-selected","false"),g.length&&h.length?c.oldTab.attr("tabIndex",-1):g.length&&this.tabs.filter(function(){return 0===a(this).attr("tabIndex")}).attr("tabIndex",-1),g.attr({"aria-expanded":"true","aria-hidden":"false"}),c.newTab.attr({"aria-selected":"true",tabIndex:0})},_activate:function(b){var c,d=this._findActive(b);d[0]!==this.active[0]&&(d.length||(d=this.active),c=d.find(".ui-tabs-anchor")[0],this._eventHandler({target:c,currentTarget:c,preventDefault:a.noop}))},_findActive:function(b){return b===!1?a():this.tabs.eq(b)},_getIndex:function(a){return"string"==typeof a&&(a=this.anchors.index(this.anchors.filter("[href$='"+a+"']"))),a},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){a.data(this,"ui-tabs-destroy")?a(this).remove():a(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var b=a(this),c=b.data("ui-tabs-aria-controls");c?b.attr("aria-controls",c).removeData("ui-tabs-aria-controls"):b.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(c){var d=this.options.disabled;d!==!1&&(c===b?d=!1:(c=this._getIndex(c),d=a.isArray(d)?a.map(d,function(a){return a!==c?a:null}):a.map(this.tabs,function(a,b){return b!==c?b:null})),this._setupDisabled(d))},disable:function(c){var d=this.options.disabled;if(d!==!0){if(c===b)d=!0;else{if(c=this._getIndex(c),-1!==a.inArray(c,d))return;d=a.isArray(d)?a.merge([c],d).sort():[c]}this._setupDisabled(d)}},load:function(b,c){b=this._getIndex(b);var e=this,f=this.tabs.eq(b),g=f.find(".ui-tabs-anchor"),h=this._getPanelForTab(f),i={tab:f,panel:h};d(g[0])||(this.xhr=a.ajax(this._ajaxSettings(g,c,i)),this.xhr&&"canceled"!==this.xhr.statusText&&(f.addClass("ui-tabs-loading"),h.attr("aria-busy","true"),this.xhr.success(function(a){setTimeout(function(){h.html(a),e._trigger("load",c,i)},1)}).complete(function(a,b){setTimeout(function(){"abort"===b&&e.panels.stop(!1,!0),f.removeClass("ui-tabs-loading"),h.removeAttr("aria-busy"),a===e.xhr&&delete e.xhr},1)})))},_ajaxSettings:function(b,c,d){var e=this;return{url:b.attr("href"),beforeSend:function(b,f){return e._trigger("beforeLoad",c,a.extend({jqXHR:b,ajaxSettings:f},d))}}},_getPanelForTab:function(b){var c=a(b).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+c))}})}(a),function(){}(a),function(a,b){function c(a){e=a.originalEvent,i=e.accelerationIncludingGravity,f=Math.abs(i.x),g=Math.abs(i.y),h=Math.abs(i.z),!b.orientation&&(f>7||(h>6&&8>g||8>h&&g>6)&&f>5)?d.enabled&&d.disable():d.enabled||d.enable()}a.mobile.iosorientationfixEnabled=!0;var d,e,f,g,h,i,j=navigator.userAgent;return/iPhone|iPad|iPod/.test(navigator.platform)&&/OS [1-5]_[0-9_]* like Mac OS X/i.test(j)&&j.indexOf("AppleWebKit")>-1?(d=a.mobile.zoom,void a.mobile.document.on("mobileinit",function(){a.mobile.iosorientationfixEnabled&&a.mobile.window.bind("orientationchange.iosorientationfix",d.enable).bind("devicemotion.iosorientationfix",c)})):void(a.mobile.iosorientationfixEnabled=!1)}(a,this),function(a,b,d){function e(){f.removeClass("ui-mobile-rendering")}var f=a("html"),g=a.mobile.window;a(b.document).trigger("mobileinit"),a.mobile.gradeA()&&(a.mobile.ajaxBlacklist&&(a.mobile.ajaxEnabled=!1),f.addClass("ui-mobile ui-mobile-rendering"),setTimeout(e,5e3),a.extend(a.mobile,{initializePage:function(){var b=a.mobile.path,f=a(":jqmData(role='page'), :jqmData(role='dialog')"),h=b.stripHash(b.stripQueryParams(b.parseLocation().hash)),i=a.mobile.path.parseLocation(),j=h?c.getElementById(h):d;f.length||(f=a("body").wrapInner("<div data-"+a.mobile.ns+"role='page'></div>").children(0)),f.each(function(){var c=a(this);c[0].getAttribute("data-"+a.mobile.ns+"url")||c.attr("data-"+a.mobile.ns+"url",c.attr("id")||b.convertUrlToDataUrl(i.pathname+i.search))}),a.mobile.firstPage=f.first(),a.mobile.pageContainer=a.mobile.firstPage.parent().addClass("ui-mobile-viewport").pagecontainer(),a.mobile.navreadyDeferred.resolve(),g.trigger("pagecontainercreate"),a.mobile.loading("show"),e(),a.mobile.hashListeningEnabled&&a.mobile.path.isHashValid(location.hash)&&(a(j).is(":jqmData(role='page')")||a.mobile.path.isPath(h)||h===a.mobile.dialogHashKey)?a.event.special.navigate.isPushStateEnabled()?(a.mobile.navigate.history.stack=[],a.mobile.navigate(a.mobile.path.isPath(location.hash)?location.hash:location.href)):g.trigger("hashchange",[!0]):(a.event.special.navigate.isPushStateEnabled()&&a.mobile.navigate.navigator.squash(b.parseLocation().href),a.mobile.changePage(a.mobile.firstPage,{transition:"none",reverse:!0,changeHash:!1,fromHashChange:!0}))}}),a(function(){a.support.inlineSVG(),a.mobile.hideUrlBar&&b.scrollTo(0,1),a.mobile.defaultHomeScroll=a.support.scrollTop&&1!==a.mobile.window.scrollTop()?1:0,a.mobile.autoInitializePage&&a.mobile.initializePage(),a.mobile.hideUrlBar&&g.load(a.mobile.silentScroll),a.support.cssPointerEvents||a.mobile.document.delegate(".ui-state-disabled,.ui-disabled","vclick",function(a){a.preventDefault(),a.stopImmediatePropagation()})}))}(a,this)});
+//# sourceMappingURL=jquery.mobile-1.4.5.min.map
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/qrcode.min.js b/platforms/android/app/src/main/assets/www/js/lib/qrcode.min.js
new file mode 100755
index 0000000..993e88f
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/qrcode.min.js
@@ -0,0 +1 @@
+var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this.parsedData=[];for(var b=[],d=0,e=this.data.length;e>d;d++){var f=this.data.charCodeAt(d);f>65536?(b[0]=240|(1835008&f)>>>18,b[1]=128|(258048&f)>>>12,b[2]=128|(4032&f)>>>6,b[3]=128|63&f):f>2048?(b[0]=224|(61440&f)>>>12,b[1]=128|(4032&f)>>>6,b[2]=128|63&f):f>128?(b[0]=192|(1984&f)>>>6,b[1]=128|63&f):b[0]=f,this.parsedData=this.parsedData.concat(b)}this.parsedData.length!=this.data.length&&(this.parsedData.unshift(191),this.parsedData.unshift(187),this.parsedData.unshift(239))}function b(a,b){this.typeNumber=a,this.errorCorrectLevel=b,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=[]}function i(a,b){if(void 0==a.length)throw new Error(a.length+"/"+b);for(var c=0;c<a.length&&0==a[c];)c++;this.num=new Array(a.length-c+b);for(var d=0;d<a.length-c;d++)this.num[d]=a[d+c]}function j(a,b){this.totalCount=a,this.dataCount=b}function k(){this.buffer=[],this.length=0}function m(){return"undefined"!=typeof CanvasRenderingContext2D}function n(){var a=!1,b=navigator.userAgent;return/android/i.test(b)&&(a=!0,aMat=b.toString().match(/android ([0-9]\.[0-9])/i),aMat&&aMat[1]&&(a=parseFloat(aMat[1]))),a}function r(a,b){for(var c=1,e=s(a),f=0,g=l.length;g>=f;f++){var h=0;switch(b){case d.L:h=l[f][0];break;case d.M:h=l[f][1];break;case d.Q:h=l[f][2];break;case d.H:h=l[f][3]}if(h>=e)break;c++}if(c>l.length)throw new Error("Too long data");return c}function s(a){var b=encodeURI(a).toString().replace(/\%[0-9a-fA-F]{2}/g,"a");return b.length+(b.length!=a?3:0)}a.prototype={getLength:function(){return this.parsedData.length},write:function(a){for(var b=0,c=this.parsedData.length;c>b;b++)a.put(this.parsedData[b],8)}},b.prototype={addData:function(b){var c=new a(b);this.dataList.push(c),this.dataCache=null},isDark:function(a,b){if(0>a||this.moduleCount<=a||0>b||this.moduleCount<=b)throw new Error(a+","+b);return this.modules[a][b]},getModuleCount:function(){return this.moduleCount},make:function(){this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17,this.modules=new Array(this.moduleCount);for(var d=0;d<this.moduleCount;d++){this.modules[d]=new Array(this.moduleCount);for(var e=0;e<this.moduleCount;e++)this.modules[d][e]=null}this.setupPositionProbePattern(0,0),this.setupPositionProbePattern(this.moduleCount-7,0),this.setupPositionProbePattern(0,this.moduleCount-7),this.setupPositionAdjustPattern(),this.setupTimingPattern(),this.setupTypeInfo(a,c),this.typeNumber>=7&&this.setupTypeNumber(a),null==this.dataCache&&(this.dataCache=b.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,b){for(var c=-1;7>=c;c++)if(!(-1>=a+c||this.moduleCount<=a+c))for(var d=-1;7>=d;d++)-1>=b+d||this.moduleCount<=b+d||(this.modules[a+c][b+d]=c>=0&&6>=c&&(0==d||6==d)||d>=0&&6>=d&&(0==c||6==c)||c>=2&&4>=c&&d>=2&&4>=d?!0:!1)},getBestMaskPattern:function(){for(var a=0,b=0,c=0;8>c;c++){this.makeImpl(!0,c);var d=f.getLostPoint(this);(0==c||a>d)&&(a=d,b=c)}return b},createMovieClip:function(a,b,c){var d=a.createEmptyMovieClip(b,c),e=1;this.make();for(var f=0;f<this.modules.length;f++)for(var g=f*e,h=0;h<this.modules[f].length;h++){var i=h*e,j=this.modules[f][h];j&&(d.beginFill(0,100),d.moveTo(i,g),d.lineTo(i+e,g),d.lineTo(i+e,g+e),d.lineTo(i,g+e),d.endFill())}return d},setupTimingPattern:function(){for(var a=8;a<this.moduleCount-8;a++)null==this.modules[a][6]&&(this.modules[a][6]=0==a%2);for(var b=8;b<this.moduleCount-8;b++)null==this.modules[6][b]&&(this.modules[6][b]=0==b%2)},setupPositionAdjustPattern:function(){for(var a=f.getPatternPosition(this.typeNumber),b=0;b<a.length;b++)for(var c=0;c<a.length;c++){var d=a[b],e=a[c];if(null==this.modules[d][e])for(var g=-2;2>=g;g++)for(var h=-2;2>=h;h++)this.modules[d+g][e+h]=-2==g||2==g||-2==h||2==h||0==g&&0==h?!0:!1}},setupTypeNumber:function(a){for(var b=f.getBCHTypeNumber(this.typeNumber),c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[Math.floor(c/3)][c%3+this.moduleCount-8-3]=d}for(var c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[c%3+this.moduleCount-8-3][Math.floor(c/3)]=d}},setupTypeInfo:function(a,b){for(var c=this.errorCorrectLevel<<3|b,d=f.getBCHTypeInfo(c),e=0;15>e;e++){var g=!a&&1==(1&d>>e);6>e?this.modules[e][8]=g:8>e?this.modules[e+1][8]=g:this.modules[this.moduleCount-15+e][8]=g}for(var e=0;15>e;e++){var g=!a&&1==(1&d>>e);8>e?this.modules[8][this.moduleCount-e-1]=g:9>e?this.modules[8][15-e-1+1]=g:this.modules[8][15-e-1]=g}this.modules[this.moduleCount-8][8]=!a},mapData:function(a,b){for(var c=-1,d=this.moduleCount-1,e=7,g=0,h=this.moduleCount-1;h>0;h-=2)for(6==h&&h--;;){for(var i=0;2>i;i++)if(null==this.modules[d][h-i]){var j=!1;g<a.length&&(j=1==(1&a[g]>>>e));var k=f.getMask(b,d,h-i);k&&(j=!j),this.modules[d][h-i]=j,e--,-1==e&&(g++,e=7)}if(d+=c,0>d||this.moduleCount<=d){d-=c,c=-c;break}}}},b.PAD0=236,b.PAD1=17,b.createData=function(a,c,d){for(var e=j.getRSBlocks(a,c),g=new k,h=0;h<d.length;h++){var i=d[h];g.put(i.mode,4),g.put(i.getLength(),f.getLengthInBits(i.mode,a)),i.write(g)}for(var l=0,h=0;h<e.length;h++)l+=e[h].dataCount;if(g.getLengthInBits()>8*l)throw new Error("code length overflow. ("+g.getLengthInBits()+">"+8*l+")");for(g.getLengthInBits()+4<=8*l&&g.put(0,4);0!=g.getLengthInBits()%8;)g.putBit(!1);for(;;){if(g.getLengthInBits()>=8*l)break;if(g.put(b.PAD0,8),g.getLengthInBits()>=8*l)break;g.put(b.PAD1,8)}return b.createBytes(g,e)},b.createBytes=function(a,b){for(var c=0,d=0,e=0,g=new Array(b.length),h=new Array(b.length),j=0;j<b.length;j++){var k=b[j].dataCount,l=b[j].totalCount-k;d=Math.max(d,k),e=Math.max(e,l),g[j]=new Array(k);for(var m=0;m<g[j].length;m++)g[j][m]=255&a.buffer[m+c];c+=k;var n=f.getErrorCorrectPolynomial(l),o=new i(g[j],n.getLength()-1),p=o.mod(n);h[j]=new Array(n.getLength()-1);for(var m=0;m<h[j].length;m++){var q=m+p.getLength()-h[j].length;h[j][m]=q>=0?p.get(q):0}}for(var r=0,m=0;m<b.length;m++)r+=b[m].totalCount;for(var s=new Array(r),t=0,m=0;d>m;m++)for(var j=0;j<b.length;j++)m<g[j].length&&(s[t++]=g[j][m]);for(var m=0;e>m;m++)for(var j=0;j<b.length;j++)m<h[j].length&&(s[t++]=h[j][m]);return s};for(var c={MODE_NUMBER:1,MODE_ALPHA_NUM:2,MODE_8BIT_BYTE:4,MODE_KANJI:8},d={L:1,M:0,Q:3,H:2},e={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7},f={PATTERN_POSITION_TABLE:[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],G15:1335,G18:7973,G15_MASK:21522,getBCHTypeInfo:function(a){for(var b=a<<10;f.getBCHDigit(b)-f.getBCHDigit(f.G15)>=0;)b^=f.G15<<f.getBCHDigit(b)-f.getBCHDigit(f.G15);return(a<<10|b)^f.G15_MASK},getBCHTypeNumber:function(a){for(var b=a<<12;f.getBCHDigit(b)-f.getBCHDigit(f.G18)>=0;)b^=f.G18<<f.getBCHDigit(b)-f.getBCHDigit(f.G18);return a<<12|b},getBCHDigit:function(a){for(var b=0;0!=a;)b++,a>>>=1;return b},getPatternPosition:function(a){return f.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,b,c){switch(a){case e.PATTERN000:return 0==(b+c)%2;case e.PATTERN001:return 0==b%2;case e.PATTERN010:return 0==c%3;case e.PATTERN011:return 0==(b+c)%3;case e.PATTERN100:return 0==(Math.floor(b/2)+Math.floor(c/3))%2;case e.PATTERN101:return 0==b*c%2+b*c%3;case e.PATTERN110:return 0==(b*c%2+b*c%3)%2;case e.PATTERN111:return 0==(b*c%3+(b+c)%2)%2;default:throw new Error("bad maskPattern:"+a)}},getErrorCorrectPolynomial:function(a){for(var b=new i([1],0),c=0;a>c;c++)b=b.multiply(new i([1,g.gexp(c)],0));return b},getLengthInBits:function(a,b){if(b>=1&&10>b)switch(a){case c.MODE_NUMBER:return 10;case c.MODE_ALPHA_NUM:return 9;case c.MODE_8BIT_BYTE:return 8;case c.MODE_KANJI:return 8;default:throw new Error("mode:"+a)}else if(27>b)switch(a){case c.MODE_NUMBER:return 12;case c.MODE_ALPHA_NUM:return 11;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 10;default:throw new Error("mode:"+a)}else{if(!(41>b))throw new Error("type:"+b);switch(a){case c.MODE_NUMBER:return 14;case c.MODE_ALPHA_NUM:return 13;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 12;default:throw new Error("mode:"+a)}}},getLostPoint:function(a){for(var b=a.getModuleCount(),c=0,d=0;b>d;d++)for(var e=0;b>e;e++){for(var f=0,g=a.isDark(d,e),h=-1;1>=h;h++)if(!(0>d+h||d+h>=b))for(var i=-1;1>=i;i++)0>e+i||e+i>=b||(0!=h||0!=i)&&g==a.isDark(d+h,e+i)&&f++;f>5&&(c+=3+f-5)}for(var d=0;b-1>d;d++)for(var e=0;b-1>e;e++){var j=0;a.isDark(d,e)&&j++,a.isDark(d+1,e)&&j++,a.isDark(d,e+1)&&j++,a.isDark(d+1,e+1)&&j++,(0==j||4==j)&&(c+=3)}for(var d=0;b>d;d++)for(var e=0;b-6>e;e++)a.isDark(d,e)&&!a.isDark(d,e+1)&&a.isDark(d,e+2)&&a.isDark(d,e+3)&&a.isDark(d,e+4)&&!a.isDark(d,e+5)&&a.isDark(d,e+6)&&(c+=40);for(var e=0;b>e;e++)for(var d=0;b-6>d;d++)a.isDark(d,e)&&!a.isDark(d+1,e)&&a.isDark(d+2,e)&&a.isDark(d+3,e)&&a.isDark(d+4,e)&&!a.isDark(d+5,e)&&a.isDark(d+6,e)&&(c+=40);for(var k=0,e=0;b>e;e++)for(var d=0;b>d;d++)a.isDark(d,e)&&k++;var l=Math.abs(100*k/b/b-50)/5;return c+=10*l}},g={glog:function(a){if(1>a)throw new Error("glog("+a+")");return g.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;a>=256;)a-=255;return g.EXP_TABLE[a]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},h=0;8>h;h++)g.EXP_TABLE[h]=1<<h;for(var h=8;256>h;h++)g.EXP_TABLE[h]=g.EXP_TABLE[h-4]^g.EXP_TABLE[h-5]^g.EXP_TABLE[h-6]^g.EXP_TABLE[h-8];for(var h=0;255>h;h++)g.LOG_TABLE[g.EXP_TABLE[h]]=h;i.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var b=new Array(this.getLength()+a.getLength()-1),c=0;c<this.getLength();c++)for(var d=0;d<a.getLength();d++)b[c+d]^=g.gexp(g.glog(this.get(c))+g.glog(a.get(d)));return new i(b,0)},mod:function(a){if(this.getLength()-a.getLength()<0)return this;for(var b=g.glog(this.get(0))-g.glog(a.get(0)),c=new Array(this.getLength()),d=0;d<this.getLength();d++)c[d]=this.get(d);for(var d=0;d<a.getLength();d++)c[d]^=g.gexp(g.glog(a.get(d))+b);return new i(c,0).mod(a)}},j.RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]],j.getRSBlocks=function(a,b){var c=j.getRsBlockTable(a,b);if(void 0==c)throw new Error("bad rs block @ typeNumber:"+a+"/errorCorrectLevel:"+b);for(var d=c.length/3,e=[],f=0;d>f;f++)for(var g=c[3*f+0],h=c[3*f+1],i=c[3*f+2],k=0;g>k;k++)e.push(new j(h,i));return e},j.getRsBlockTable=function(a,b){switch(b){case d.L:return j.RS_BLOCK_TABLE[4*(a-1)+0];case d.M:return j.RS_BLOCK_TABLE[4*(a-1)+1];case d.Q:return j.RS_BLOCK_TABLE[4*(a-1)+2];case d.H:return j.RS_BLOCK_TABLE[4*(a-1)+3];default:return void 0}},k.prototype={get:function(a){var b=Math.floor(a/8);return 1==(1&this.buffer[b]>>>7-a%8)},put:function(a,b){for(var c=0;b>c;c++)this.putBit(1==(1&a>>>b-c-1))},getLengthInBits:function(){return this.length},putBit:function(a){var b=Math.floor(this.length/8);this.buffer.length<=b&&this.buffer.push(0),a&&(this.buffer[b]|=128>>>this.length%8),this.length++}};var l=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]],o=function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){function g(a,b){var c=document.createElementNS("http://www.w3.org/2000/svg",a);for(var d in b)b.hasOwnProperty(d)&&c.setAttribute(d,b[d]);return c}var b=this._htOption,c=this._el,d=a.getModuleCount();Math.floor(b.width/d),Math.floor(b.height/d),this.clear();var h=g("svg",{viewBox:"0 0 "+String(d)+" "+String(d),width:"100%",height:"100%",fill:b.colorLight});h.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xlink","http://www.w3.org/1999/xlink"),c.appendChild(h),h.appendChild(g("rect",{fill:b.colorDark,width:"1",height:"1",id:"template"}));for(var i=0;d>i;i++)for(var j=0;d>j;j++)if(a.isDark(i,j)){var k=g("use",{x:String(i),y:String(j)});k.setAttributeNS("http://www.w3.org/1999/xlink","href","#template"),h.appendChild(k)}},a.prototype.clear=function(){for(;this._el.hasChildNodes();)this._el.removeChild(this._el.lastChild)},a}(),p="svg"===document.documentElement.tagName.toLowerCase(),q=p?o:m()?function(){function a(){this._elImage.src=this._elCanvas.toDataURL("image/png"),this._elImage.style.display="block",this._elCanvas.style.display="none"}function d(a,b){var c=this;if(c._fFail=b,c._fSuccess=a,null===c._bSupportDataURI){var d=document.createElement("img"),e=function(){c._bSupportDataURI=!1,c._fFail&&_fFail.call(c)},f=function(){c._bSupportDataURI=!0,c._fSuccess&&c._fSuccess.call(c)};return d.onabort=e,d.onerror=e,d.onload=f,d.src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",void 0}c._bSupportDataURI===!0&&c._fSuccess?c._fSuccess.call(c):c._bSupportDataURI===!1&&c._fFail&&c._fFail.call(c)}if(this._android&&this._android<=2.1){var b=1/window.devicePixelRatio,c=CanvasRenderingContext2D.prototype.drawImage;CanvasRenderingContext2D.prototype.drawImage=function(a,d,e,f,g,h,i,j){if("nodeName"in a&&/img/i.test(a.nodeName))for(var l=arguments.length-1;l>=1;l--)arguments[l]=arguments[l]*b;else"undefined"==typeof j&&(arguments[1]*=b,arguments[2]*=b,arguments[3]*=b,arguments[4]*=b);c.apply(this,arguments)}}var e=function(a,b){this._bIsPainted=!1,this._android=n(),this._htOption=b,this._elCanvas=document.createElement("canvas"),this._elCanvas.width=b.width,this._elCanvas.height=b.height,a.appendChild(this._elCanvas),this._el=a,this._oContext=this._elCanvas.getContext("2d"),this._bIsPainted=!1,this._elImage=document.createElement("img"),this._elImage.style.display="none",this._el.appendChild(this._elImage),this._bSupportDataURI=null};return e.prototype.draw=function(a){var b=this._elImage,c=this._oContext,d=this._htOption,e=a.getModuleCount(),f=d.width/e,g=d.height/e,h=Math.round(f),i=Math.round(g);b.style.display="none",this.clear();for(var j=0;e>j;j++)for(var k=0;e>k;k++){var l=a.isDark(j,k),m=k*f,n=j*g;c.strokeStyle=l?d.colorDark:d.colorLight,c.lineWidth=1,c.fillStyle=l?d.colorDark:d.colorLight,c.fillRect(m,n,f,g),c.strokeRect(Math.floor(m)+.5,Math.floor(n)+.5,h,i),c.strokeRect(Math.ceil(m)-.5,Math.ceil(n)-.5,h,i)}this._bIsPainted=!0},e.prototype.makeImage=function(){this._bIsPainted&&d.call(this,a)},e.prototype.isPainted=function(){return this._bIsPainted},e.prototype.clear=function(){this._oContext.clearRect(0,0,this._elCanvas.width,this._elCanvas.height),this._bIsPainted=!1},e.prototype.round=function(a){return a?Math.floor(1e3*a)/1e3:a},e}():function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){for(var b=this._htOption,c=this._el,d=a.getModuleCount(),e=Math.floor(b.width/d),f=Math.floor(b.height/d),g=['<table style="border:0;border-collapse:collapse;">'],h=0;d>h;h++){g.push("<tr>");for(var i=0;d>i;i++)g.push('<td style="border:0;border-collapse:collapse;padding:0;margin:0;width:'+e+"px;height:"+f+"px;background-color:"+(a.isDark(h,i)?b.colorDark:b.colorLight)+';"></td>');g.push("</tr>")}g.push("</table>"),c.innerHTML=g.join("");var j=c.childNodes[0],k=(b.width-j.offsetWidth)/2,l=(b.height-j.offsetHeight)/2;k>0&&l>0&&(j.style.margin=l+"px "+k+"px")},a.prototype.clear=function(){this._el.innerHTML=""},a}();QRCode=function(a,b){if(this._htOption={width:256,height:256,typeNumber:4,colorDark:"#000000",colorLight:"#ffffff",correctLevel:d.H},"string"==typeof b&&(b={text:b}),b)for(var c in b)this._htOption[c]=b[c];"string"==typeof a&&(a=document.getElementById(a)),this._android=n(),this._el=a,this._oQRCode=null,this._oDrawing=new q(this._el,this._htOption),this._htOption.text&&this.makeCode(this._htOption.text)},QRCode.prototype.makeCode=function(a){this._oQRCode=new b(r(a,this._htOption.correctLevel),this._htOption.correctLevel),this._oQRCode.addData(a),this._oQRCode.make(),this._el.title=a,this._oDrawing.draw(this._oQRCode),this.makeImage()},QRCode.prototype.makeImage=function(){"function"==typeof this._oDrawing.makeImage&&(!this._android||this._android>=3)&&this._oDrawing.makeImage()},QRCode.prototype.clear=function(){this._oDrawing.clear()},QRCode.CorrectLevel=d}();
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/lib/swiper.js b/platforms/android/app/src/main/assets/www/js/lib/swiper.js
new file mode 100755
index 0000000..a83b981
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/swiper.js
@@ -0,0 +1,4161 @@
+/**
+ * Swiper 3.3.1
+ * Most modern mobile touch slider and framework with hardware accelerated transitions
+ * 
+ * http://www.idangero.us/swiper/
+ * 
+ * Copyright 2016, Vladimir Kharlampidi
+ * The iDangero.us
+ * http://www.idangero.us/
+ * 
+ * Licensed under MIT
+ * 
+ * Released on: February 7, 2016
+ */
+(function () {
+    'use strict';
+    var $;
+    /*===========================
+    Swiper
+    ===========================*/
+    var Swiper = function (container, params) {
+        if (!(this instanceof Swiper)) return new Swiper(container, params);
+
+        var defaults = {
+            direction: 'horizontal',
+            touchEventsTarget: 'container',
+            initialSlide: 0,
+            speed: 300,
+            // autoplay
+            autoplay: false,
+            autoplayDisableOnInteraction: true,
+            autoplayStopOnLast: false,
+            // To support iOS's swipe-to-go-back gesture (when being used in-app, with UIWebView).
+            iOSEdgeSwipeDetection: false,
+            iOSEdgeSwipeThreshold: 20,
+            // Free mode
+            freeMode: false,
+            freeModeMomentum: true,
+            freeModeMomentumRatio: 1,
+            freeModeMomentumBounce: true,
+            freeModeMomentumBounceRatio: 1,
+            freeModeSticky: false,
+            freeModeMinimumVelocity: 0.02,
+            // Autoheight
+            autoHeight: false,
+            // Set wrapper width
+            setWrapperSize: false,
+            // Virtual Translate
+            virtualTranslate: false,
+            // Effects
+            effect: 'slide', // 'slide' or 'fade' or 'cube' or 'coverflow' or 'flip'
+            coverflow: {
+                rotate: 50,
+                stretch: 0,
+                depth: 100,
+                modifier: 1,
+                slideShadows : true
+            },
+            flip: {
+                slideShadows : true,
+                limitRotation: true
+            },
+            cube: {
+                slideShadows: true,
+                shadow: true,
+                shadowOffset: 20,
+                shadowScale: 0.94
+            },
+            fade: {
+                crossFade: false
+            },
+            // Parallax
+            parallax: false,
+            // Scrollbar
+            scrollbar: null,
+            scrollbarHide: true,
+            scrollbarDraggable: false,
+            scrollbarSnapOnRelease: false,
+            // Keyboard Mousewheel
+            keyboardControl: false,
+            mousewheelControl: false,
+            mousewheelReleaseOnEdges: false,
+            mousewheelInvert: false,
+            mousewheelForceToAxis: false,
+            mousewheelSensitivity: 1,
+            // Hash Navigation
+            hashnav: false,
+            // Breakpoints
+            breakpoints: undefined,
+            // Slides grid
+            spaceBetween: 0,
+            slidesPerView: 1,
+            slidesPerColumn: 1,
+            slidesPerColumnFill: 'column',
+            slidesPerGroup: 1,
+            centeredSlides: false,
+            slidesOffsetBefore: 0, // in px
+            slidesOffsetAfter: 0, // in px
+            // Round length
+            roundLengths: false,
+            // Touches
+            touchRatio: 1,
+            touchAngle: 45,
+            simulateTouch: true,
+            shortSwipes: true,
+            longSwipes: true,
+            longSwipesRatio: 0.5,
+            longSwipesMs: 300,
+            followFinger: true,
+            onlyExternal: false,
+            threshold: 0,
+            touchMoveStopPropagation: true,
+            // Unique Navigation Elements
+            uniqueNavElements: true,
+            // Pagination
+            pagination: null,
+            paginationElement: 'span',
+            paginationClickable: false,
+            paginationHide: false,
+            paginationBulletRender: null,
+            paginationProgressRender: null,
+            paginationFractionRender: null,
+            paginationCustomRender: null,
+            paginationType: 'bullets', // 'bullets' or 'progress' or 'fraction' or 'custom'
+            // Resistance
+            resistance: true,
+            resistanceRatio: 0.85,
+            // Next/prev buttons
+            nextButton: null,
+            prevButton: null,
+            // Progress
+            watchSlidesProgress: false,
+            watchSlidesVisibility: false,
+            // Cursor
+            grabCursor: false,
+            // Clicks
+            preventClicks: true,
+            preventClicksPropagation: true,
+            slideToClickedSlide: false,
+            // Lazy Loading
+            lazyLoading: false,
+            lazyLoadingInPrevNext: false,
+            lazyLoadingInPrevNextAmount: 1,
+            lazyLoadingOnTransitionStart: false,
+            // Images
+            preloadImages: true,
+            updateOnImagesReady: true,
+            // loop
+            loop: false,
+            loopAdditionalSlides: 0,
+            loopedSlides: null,
+            // Control
+            control: undefined,
+            controlInverse: false,
+            controlBy: 'slide', //or 'container'
+            // Swiping/no swiping
+            allowSwipeToPrev: true,
+            allowSwipeToNext: true,
+            swipeHandler: null, //'.swipe-handler',
+            noSwiping: true,
+            noSwipingClass: 'swiper-no-swiping',
+            // NS
+            slideClass: 'swiper-slide',
+            slideActiveClass: 'swiper-slide-active',
+            slideVisibleClass: 'swiper-slide-visible',
+            slideDuplicateClass: 'swiper-slide-duplicate',
+            slideNextClass: 'swiper-slide-next',
+            slidePrevClass: 'swiper-slide-prev',
+            wrapperClass: 'swiper-wrapper',
+            bulletClass: 'swiper-pagination-bullet',
+            bulletActiveClass: 'swiper-pagination-bullet-active',
+            buttonDisabledClass: 'swiper-button-disabled',
+            paginationCurrentClass: 'swiper-pagination-current',
+            paginationTotalClass: 'swiper-pagination-total',
+            paginationHiddenClass: 'swiper-pagination-hidden',
+            paginationProgressbarClass: 'swiper-pagination-progressbar',
+            // Observer
+            observer: false,
+            observeParents: false,
+            // Accessibility
+            a11y: false,
+            prevSlideMessage: 'Previous slide',
+            nextSlideMessage: 'Next slide',
+            firstSlideMessage: 'This is the first slide',
+            lastSlideMessage: 'This is the last slide',
+            paginationBulletMessage: 'Go to slide {{index}}',
+            // Callbacks
+            runCallbacksOnInit: true
+            /*
+            Callbacks:
+            onInit: function (swiper)
+            onDestroy: function (swiper)
+            onClick: function (swiper, e)
+            onTap: function (swiper, e)
+            onDoubleTap: function (swiper, e)
+            onSliderMove: function (swiper, e)
+            onSlideChangeStart: function (swiper)
+            onSlideChangeEnd: function (swiper)
+            onTransitionStart: function (swiper)
+            onTransitionEnd: function (swiper)
+            onImagesReady: function (swiper)
+            onProgress: function (swiper, progress)
+            onTouchStart: function (swiper, e)
+            onTouchMove: function (swiper, e)
+            onTouchMoveOpposite: function (swiper, e)
+            onTouchEnd: function (swiper, e)
+            onReachBeginning: function (swiper)
+            onReachEnd: function (swiper)
+            onSetTransition: function (swiper, duration)
+            onSetTranslate: function (swiper, translate)
+            onAutoplayStart: function (swiper)
+            onAutoplayStop: function (swiper),
+            onLazyImageLoad: function (swiper, slide, image)
+            onLazyImageReady: function (swiper, slide, image)
+            */
+        
+        };
+        var initialVirtualTranslate = params && params.virtualTranslate;
+        
+        params = params || {};
+        var originalParams = {};
+        for (var param in params) {
+            if (typeof params[param] === 'object' && params[param] !== null && !(params[param].nodeType || params[param] === window || params[param] === document || (typeof Dom7 !== 'undefined' && params[param] instanceof Dom7) || (typeof jQuery !== 'undefined' && params[param] instanceof jQuery))) {
+                originalParams[param] = {};
+                for (var deepParam in params[param]) {
+                    originalParams[param][deepParam] = params[param][deepParam];
+                }
+            }
+            else {
+                originalParams[param] = params[param];
+            }
+        }
+        for (var def in defaults) {
+            if (typeof params[def] === 'undefined') {
+                params[def] = defaults[def];
+            }
+            else if (typeof params[def] === 'object') {
+                for (var deepDef in defaults[def]) {
+                    if (typeof params[def][deepDef] === 'undefined') {
+                        params[def][deepDef] = defaults[def][deepDef];
+                    }
+                }
+            }
+        }
+        
+        // Swiper
+        var s = this;
+        
+        // Params
+        s.params = params;
+        s.originalParams = originalParams;
+        
+        // Classname
+        s.classNames = [];
+        /*=========================
+          Dom Library and plugins
+          ===========================*/
+        if (typeof $ !== 'undefined' && typeof Dom7 !== 'undefined'){
+            $ = Dom7;
+        }
+        if (typeof $ === 'undefined') {
+            if (typeof Dom7 === 'undefined') {
+                $ = window.Dom7 || window.Zepto || window.jQuery;
+            }
+            else {
+                $ = Dom7;
+            }
+            if (!$) return;
+        }
+        // Export it to Swiper instance
+        s.$ = $;
+        
+        /*=========================
+          Breakpoints
+          ===========================*/
+        s.currentBreakpoint = undefined;
+        s.getActiveBreakpoint = function () {
+            //Get breakpoint for window width
+            if (!s.params.breakpoints) return false;
+            var breakpoint = false;
+            var points = [], point;
+            for ( point in s.params.breakpoints ) {
+                if (s.params.breakpoints.hasOwnProperty(point)) {
+                    points.push(point);
+                }
+            }
+            points.sort(function (a, b) {
+                return parseInt(a, 10) > parseInt(b, 10);
+            });
+            for (var i = 0; i < points.length; i++) {
+                point = points[i];
+                if (point >= window.innerWidth && !breakpoint) {
+                    breakpoint = point;
+                }
+            }
+            return breakpoint || 'max';
+        };
+        s.setBreakpoint = function () {
+            //Set breakpoint for window width and update parameters
+            var breakpoint = s.getActiveBreakpoint();
+            if (breakpoint && s.currentBreakpoint !== breakpoint) {
+                var breakPointsParams = breakpoint in s.params.breakpoints ? s.params.breakpoints[breakpoint] : s.originalParams;
+                var needsReLoop = s.params.loop && (breakPointsParams.slidesPerView !== s.params.slidesPerView);
+                for ( var param in breakPointsParams ) {
+                    s.params[param] = breakPointsParams[param];
+                }
+                s.currentBreakpoint = breakpoint;
+                if(needsReLoop && s.destroyLoop) {
+                    s.reLoop(true);
+                }
+            }
+        };
+        // Set breakpoint on load
+        if (s.params.breakpoints) {
+            s.setBreakpoint();
+        }
+        
+        /*=========================
+          Preparation - Define Container, Wrapper and Pagination
+          ===========================*/
+        s.container = $(container);
+        if (s.container.length === 0) return;
+        if (s.container.length > 1) {
+            var swipers = [];
+            s.container.each(function () {
+                var container = this;
+                swipers.push(new Swiper(this, params));
+            });
+            return swipers;
+        }
+        
+        // Save instance in container HTML Element and in data
+        s.container[0].swiper = s;
+        s.container.data('swiper', s);
+        
+        s.classNames.push('swiper-container-' + s.params.direction);
+        
+        if (s.params.freeMode) {
+            s.classNames.push('swiper-container-free-mode');
+        }
+        if (!s.support.flexbox) {
+            s.classNames.push('swiper-container-no-flexbox');
+            s.params.slidesPerColumn = 1;
+        }
+        if (s.params.autoHeight) {
+            s.classNames.push('swiper-container-autoheight');
+        }
+        // Enable slides progress when required
+        if (s.params.parallax || s.params.watchSlidesVisibility) {
+            s.params.watchSlidesProgress = true;
+        }
+        // Coverflow / 3D
+        if (['cube', 'coverflow', 'flip'].indexOf(s.params.effect) >= 0) {
+            if (s.support.transforms3d) {
+                s.params.watchSlidesProgress = true;
+                s.classNames.push('swiper-container-3d');
+            }
+            else {
+                s.params.effect = 'slide';
+            }
+        }
+        if (s.params.effect !== 'slide') {
+            s.classNames.push('swiper-container-' + s.params.effect);
+        }
+        if (s.params.effect === 'cube') {
+            s.params.resistanceRatio = 0;
+            s.params.slidesPerView = 1;
+            s.params.slidesPerColumn = 1;
+            s.params.slidesPerGroup = 1;
+            s.params.centeredSlides = false;
+            s.params.spaceBetween = 0;
+            s.params.virtualTranslate = true;
+            s.params.setWrapperSize = false;
+        }
+        if (s.params.effect === 'fade' || s.params.effect === 'flip') {
+            s.params.slidesPerView = 1;
+            s.params.slidesPerColumn = 1;
+            s.params.slidesPerGroup = 1;
+            s.params.watchSlidesProgress = true;
+            s.params.spaceBetween = 0;
+            s.params.setWrapperSize = false;
+            if (typeof initialVirtualTranslate === 'undefined') {
+                s.params.virtualTranslate = true;
+            }
+        }
+        
+        // Grab Cursor
+        if (s.params.grabCursor && s.support.touch) {
+            s.params.grabCursor = false;
+        }
+        
+        // Wrapper
+        s.wrapper = s.container.children('.' + s.params.wrapperClass);
+        
+        // Pagination
+        if (s.params.pagination) {
+            s.paginationContainer = $(s.params.pagination);
+            if (s.params.uniqueNavElements && typeof s.params.pagination === 'string' && s.paginationContainer.length > 1 && s.container.find(s.params.pagination).length === 1) {
+                s.paginationContainer = s.container.find(s.params.pagination);
+            }
+        
+            if (s.params.paginationType === 'bullets' && s.params.paginationClickable) {
+                s.paginationContainer.addClass('swiper-pagination-clickable');
+            }
+            else {
+                s.params.paginationClickable = false;
+            }
+            s.paginationContainer.addClass('swiper-pagination-' + s.params.paginationType);
+        }
+        // Next/Prev Buttons
+        if (s.params.nextButton || s.params.prevButton) {
+            if (s.params.nextButton) {
+                s.nextButton = $(s.params.nextButton);
+                if (s.params.uniqueNavElements && typeof s.params.nextButton === 'string' && s.nextButton.length > 1 && s.container.find(s.params.nextButton).length === 1) {
+                    s.nextButton = s.container.find(s.params.nextButton);
+                }
+            }
+            if (s.params.prevButton) {
+                s.prevButton = $(s.params.prevButton);
+                if (s.params.uniqueNavElements && typeof s.params.prevButton === 'string' && s.prevButton.length > 1 && s.container.find(s.params.prevButton).length === 1) {
+                    s.prevButton = s.container.find(s.params.prevButton);
+                }
+            }
+        }
+        
+        // Is Horizontal
+        s.isHorizontal = function () {
+            return s.params.direction === 'horizontal';
+        };
+        // s.isH = isH;
+        
+        // RTL
+        s.rtl = s.isHorizontal() && (s.container[0].dir.toLowerCase() === 'rtl' || s.container.css('direction') === 'rtl');
+        if (s.rtl) {
+            s.classNames.push('swiper-container-rtl');
+        }
+        
+        // Wrong RTL support
+        if (s.rtl) {
+            s.wrongRTL = s.wrapper.css('display') === '-webkit-box';
+        }
+        
+        // Columns
+        if (s.params.slidesPerColumn > 1) {
+            s.classNames.push('swiper-container-multirow');
+        }
+        
+        // Check for Android
+        if (s.device.android) {
+            s.classNames.push('swiper-container-android');
+        }
+        
+        // Add classes
+        s.container.addClass(s.classNames.join(' '));
+        
+        // Translate
+        s.translate = 0;
+        
+        // Progress
+        s.progress = 0;
+        
+        // Velocity
+        s.velocity = 0;
+        
+        /*=========================
+          Locks, unlocks
+          ===========================*/
+        s.lockSwipeToNext = function () {
+            s.params.allowSwipeToNext = false;
+        };
+        s.lockSwipeToPrev = function () {
+            s.params.allowSwipeToPrev = false;
+        };
+        s.lockSwipes = function () {
+            s.params.allowSwipeToNext = s.params.allowSwipeToPrev = false;
+        };
+        s.unlockSwipeToNext = function () {
+            s.params.allowSwipeToNext = true;
+        };
+        s.unlockSwipeToPrev = function () {
+            s.params.allowSwipeToPrev = true;
+        };
+        s.unlockSwipes = function () {
+            s.params.allowSwipeToNext = s.params.allowSwipeToPrev = true;
+        };
+        
+        /*=========================
+          Round helper
+          ===========================*/
+        function round(a) {
+            return Math.floor(a);
+        }
+        /*=========================
+          Set grab cursor
+          ===========================*/
+        if (s.params.grabCursor) {
+            s.container[0].style.cursor = 'move';
+            s.container[0].style.cursor = '-webkit-grab';
+            s.container[0].style.cursor = '-moz-grab';
+            s.container[0].style.cursor = 'grab';
+        }
+        /*=========================
+          Update on Images Ready
+          ===========================*/
+        s.imagesToLoad = [];
+        s.imagesLoaded = 0;
+        
+        s.loadImage = function (imgElement, src, srcset, checkForComplete, callback) {
+            var image;
+            function onReady () {
+                if (callback) callback();
+            }
+            if (!imgElement.complete || !checkForComplete) {
+                if (src) {
+                    image = new window.Image();
+                    image.onload = onReady;
+                    image.onerror = onReady;
+                    if (srcset) {
+                        image.srcset = srcset;
+                    }
+                    if (src) {
+                        image.src = src;
+                    }
+                } else {
+                    onReady();
+                }
+        
+            } else {//image already loaded...
+                onReady();
+            }
+        };
+        s.preloadImages = function () {
+            s.imagesToLoad = s.container.find('img');
+            function _onReady() {
+                if (typeof s === 'undefined' || s === null) return;
+                if (s.imagesLoaded !== undefined) s.imagesLoaded++;
+                if (s.imagesLoaded === s.imagesToLoad.length) {
+                    if (s.params.updateOnImagesReady) s.update();
+                    s.emit('onImagesReady', s);
+                }
+            }
+            for (var i = 0; i < s.imagesToLoad.length; i++) {
+                s.loadImage(s.imagesToLoad[i], (s.imagesToLoad[i].currentSrc || s.imagesToLoad[i].getAttribute('src')), (s.imagesToLoad[i].srcset || s.imagesToLoad[i].getAttribute('srcset')), true, _onReady);
+            }
+        };
+        
+        /*=========================
+          Autoplay
+          ===========================*/
+        s.autoplayTimeoutId = undefined;
+        s.autoplaying = false;
+        s.autoplayPaused = false;
+        function autoplay() {
+            s.autoplayTimeoutId = setTimeout(function () {
+                if (s.params.loop) {
+                    s.fixLoop();
+                    s._slideNext();
+                    s.emit('onAutoplay', s);
+                }
+                else {
+                    if (!s.isEnd) {
+                        s._slideNext();
+                        s.emit('onAutoplay', s);
+                    }
+                    else {
+                        if (!params.autoplayStopOnLast) {
+                            s._slideTo(0);
+                            s.emit('onAutoplay', s);
+                        }
+                        else {
+                            s.stopAutoplay();
+                        }
+                    }
+                }
+            }, s.params.autoplay);
+        }
+        s.startAutoplay = function () {
+            if (typeof s.autoplayTimeoutId !== 'undefined') return false;
+            if (!s.params.autoplay) return false;
+            if (s.autoplaying) return false;
+            s.autoplaying = true;
+            s.emit('onAutoplayStart', s);
+            autoplay();
+        };
+        s.stopAutoplay = function (internal) {
+            if (!s.autoplayTimeoutId) return;
+            if (s.autoplayTimeoutId) clearTimeout(s.autoplayTimeoutId);
+            s.autoplaying = false;
+            s.autoplayTimeoutId = undefined;
+            s.emit('onAutoplayStop', s);
+        };
+        s.pauseAutoplay = function (speed) {
+            if (s.autoplayPaused) return;
+            if (s.autoplayTimeoutId) clearTimeout(s.autoplayTimeoutId);
+            s.autoplayPaused = true;
+            if (speed === 0) {
+                s.autoplayPaused = false;
+                autoplay();
+            }
+            else {
+                s.wrapper.transitionEnd(function () {
+                    if (!s) return;
+                    s.autoplayPaused = false;
+                    if (!s.autoplaying) {
+                        s.stopAutoplay();
+                    }
+                    else {
+                        autoplay();
+                    }
+                });
+            }
+        };
+        /*=========================
+          Min/Max Translate
+          ===========================*/
+        s.minTranslate = function () {
+            return (-s.snapGrid[0]);
+        };
+        s.maxTranslate = function () {
+            return (-s.snapGrid[s.snapGrid.length - 1]);
+        };
+        /*=========================
+          Slider/slides sizes
+          ===========================*/
+        s.updateAutoHeight = function () {
+            // Update Height
+            var slide = s.slides.eq(s.activeIndex)[0];
+            if (typeof slide !== 'undefined') {
+                var newHeight = slide.offsetHeight;
+                if (newHeight) s.wrapper.css('height', newHeight + 'px');
+            }
+        };
+        s.updateContainerSize = function () {
+            var width, height;
+            if (typeof s.params.width !== 'undefined') {
+                width = s.params.width;
+            }
+            else {
+                width = s.container[0].clientWidth;
+            }
+            if (typeof s.params.height !== 'undefined') {
+                height = s.params.height;
+            }
+            else {
+                height = s.container[0].clientHeight;
+            }
+            if (width === 0 && s.isHorizontal() || height === 0 && !s.isHorizontal()) {
+                return;
+            }
+        
+            //Subtract paddings
+            width = width - parseInt(s.container.css('padding-left'), 10) - parseInt(s.container.css('padding-right'), 10);
+            height = height - parseInt(s.container.css('padding-top'), 10) - parseInt(s.container.css('padding-bottom'), 10);
+        
+            // Store values
+            s.width = width;
+            s.height = height;
+            s.size = s.isHorizontal() ? s.width : s.height;
+        };
+        
+        s.updateSlidesSize = function () {
+            s.slides = s.wrapper.children('.' + s.params.slideClass);
+            s.snapGrid = [];
+            s.slidesGrid = [];
+            s.slidesSizesGrid = [];
+        
+            var spaceBetween = s.params.spaceBetween,
+                slidePosition = -s.params.slidesOffsetBefore,
+                i,
+                prevSlideSize = 0,
+                index = 0;
+            if (typeof s.size === 'undefined') return;
+            if (typeof spaceBetween === 'string' && spaceBetween.indexOf('%') >= 0) {
+                spaceBetween = parseFloat(spaceBetween.replace('%', '')) / 100 * s.size;
+            }
+        
+            s.virtualSize = -spaceBetween;
+            // reset margins
+            if (s.rtl) s.slides.css({marginLeft: '', marginTop: ''});
+            else s.slides.css({marginRight: '', marginBottom: ''});
+        
+            var slidesNumberEvenToRows;
+            if (s.params.slidesPerColumn > 1) {
+                if (Math.floor(s.slides.length / s.params.slidesPerColumn) === s.slides.length / s.params.slidesPerColumn) {
+                    slidesNumberEvenToRows = s.slides.length;
+                }
+                else {
+                    slidesNumberEvenToRows = Math.ceil(s.slides.length / s.params.slidesPerColumn) * s.params.slidesPerColumn;
+                }
+                if (s.params.slidesPerView !== 'auto' && s.params.slidesPerColumnFill === 'row') {
+                    slidesNumberEvenToRows = Math.max(slidesNumberEvenToRows, s.params.slidesPerView * s.params.slidesPerColumn);
+                }
+            }
+        
+            // Calc slides
+            var slideSize;
+            var slidesPerColumn = s.params.slidesPerColumn;
+            var slidesPerRow = slidesNumberEvenToRows / slidesPerColumn;
+            var numFullColumns = slidesPerRow - (s.params.slidesPerColumn * slidesPerRow - s.slides.length);
+            for (i = 0; i < s.slides.length; i++) {
+                slideSize = 0;
+                var slide = s.slides.eq(i);
+                if (s.params.slidesPerColumn > 1) {
+                    // Set slides order
+                    var newSlideOrderIndex;
+                    var column, row;
+                    if (s.params.slidesPerColumnFill === 'column') {
+                        column = Math.floor(i / slidesPerColumn);
+                        row = i - column * slidesPerColumn;
+                        if (column > numFullColumns || (column === numFullColumns && row === slidesPerColumn-1)) {
+                            if (++row >= slidesPerColumn) {
+                                row = 0;
+                                column++;
+                            }
+                        }
+                        newSlideOrderIndex = column + row * slidesNumberEvenToRows / slidesPerColumn;
+                        slide
+                            .css({
+                                '-webkit-box-ordinal-group': newSlideOrderIndex,
+                                '-moz-box-ordinal-group': newSlideOrderIndex,
+                                '-ms-flex-order': newSlideOrderIndex,
+                                '-webkit-order': newSlideOrderIndex,
+                                'order': newSlideOrderIndex
+                            });
+                    }
+                    else {
+                        row = Math.floor(i / slidesPerRow);
+                        column = i - row * slidesPerRow;
+                    }
+                    slide
+                        .css({
+                            'margin-top': (row !== 0 && s.params.spaceBetween) && (s.params.spaceBetween + 'px')
+                        })
+                        .attr('data-swiper-column', column)
+                        .attr('data-swiper-row', row);
+        
+                }
+                if (slide.css('display') === 'none') continue;
+                if (s.params.slidesPerView === 'auto') {
+                    slideSize = s.isHorizontal() ? slide.outerWidth(true) : slide.outerHeight(true);
+                    if (s.params.roundLengths) slideSize = round(slideSize);
+                }
+                else {
+                    slideSize = (s.size - (s.params.slidesPerView - 1) * spaceBetween) / s.params.slidesPerView;
+                    if (s.params.roundLengths) slideSize = round(slideSize);
+        
+                    if (s.isHorizontal()) {
+                        s.slides[i].style.width = slideSize + 'px';
+                    }
+                    else {
+                        s.slides[i].style.height = slideSize + 'px';
+                    }
+                }
+                s.slides[i].swiperSlideSize = slideSize;
+                s.slidesSizesGrid.push(slideSize);
+        
+        
+                if (s.params.centeredSlides) {
+                    slidePosition = slidePosition + slideSize / 2 + prevSlideSize / 2 + spaceBetween;
+                    if (i === 0) slidePosition = slidePosition - s.size / 2 - spaceBetween;
+                    if (Math.abs(slidePosition) < 1 / 1000) slidePosition = 0;
+                    if ((index) % s.params.slidesPerGroup === 0) s.snapGrid.push(slidePosition);
+                    s.slidesGrid.push(slidePosition);
+                }
+                else {
+                    if ((index) % s.params.slidesPerGroup === 0) s.snapGrid.push(slidePosition);
+                    s.slidesGrid.push(slidePosition);
+                    slidePosition = slidePosition + slideSize + spaceBetween;
+                }
+        
+                s.virtualSize += slideSize + spaceBetween;
+        
+                prevSlideSize = slideSize;
+        
+                index ++;
+            }
+            s.virtualSize = Math.max(s.virtualSize, s.size) + s.params.slidesOffsetAfter;
+            var newSlidesGrid;
+        
+            if (
+                s.rtl && s.wrongRTL && (s.params.effect === 'slide' || s.params.effect === 'coverflow')) {
+                s.wrapper.css({width: s.virtualSize + s.params.spaceBetween + 'px'});
+            }
+            if (!s.support.flexbox || s.params.setWrapperSize) {
+                if (s.isHorizontal()) s.wrapper.css({width: s.virtualSize + s.params.spaceBetween + 'px'});
+                else s.wrapper.css({height: s.virtualSize + s.params.spaceBetween + 'px'});
+            }
+        
+            if (s.params.slidesPerColumn > 1) {
+                s.virtualSize = (slideSize + s.params.spaceBetween) * slidesNumberEvenToRows;
+                s.virtualSize = Math.ceil(s.virtualSize / s.params.slidesPerColumn) - s.params.spaceBetween;
+                s.wrapper.css({width: s.virtualSize + s.params.spaceBetween + 'px'});
+                if (s.params.centeredSlides) {
+                    newSlidesGrid = [];
+                    for (i = 0; i < s.snapGrid.length; i++) {
+                        if (s.snapGrid[i] < s.virtualSize + s.snapGrid[0]) newSlidesGrid.push(s.snapGrid[i]);
+                    }
+                    s.snapGrid = newSlidesGrid;
+                }
+            }
+        
+            // Remove last grid elements depending on width
+            if (!s.params.centeredSlides) {
+                newSlidesGrid = [];
+                for (i = 0; i < s.snapGrid.length; i++) {
+                    if (s.snapGrid[i] <= s.virtualSize - s.size) {
+                        newSlidesGrid.push(s.snapGrid[i]);
+                    }
+                }
+                s.snapGrid = newSlidesGrid;
+                if (Math.floor(s.virtualSize - s.size) - Math.floor(s.snapGrid[s.snapGrid.length - 1]) > 1) {
+                    s.snapGrid.push(s.virtualSize - s.size);
+                }
+            }
+            if (s.snapGrid.length === 0) s.snapGrid = [0];
+        
+            if (s.params.spaceBetween !== 0) {
+                if (s.isHorizontal()) {
+                    if (s.rtl) s.slides.css({marginLeft: spaceBetween + 'px'});
+                    else s.slides.css({marginRight: spaceBetween + 'px'});
+                }
+                else s.slides.css({marginBottom: spaceBetween + 'px'});
+            }
+            if (s.params.watchSlidesProgress) {
+                s.updateSlidesOffset();
+            }
+        };
+        s.updateSlidesOffset = function () {
+            for (var i = 0; i < s.slides.length; i++) {
+                s.slides[i].swiperSlideOffset = s.isHorizontal() ? s.slides[i].offsetLeft : s.slides[i].offsetTop;
+            }
+        };
+        
+        /*=========================
+          Slider/slides progress
+          ===========================*/
+        s.updateSlidesProgress = function (translate) {
+            if (typeof translate === 'undefined') {
+                translate = s.translate || 0;
+            }
+            if (s.slides.length === 0) return;
+            if (typeof s.slides[0].swiperSlideOffset === 'undefined') s.updateSlidesOffset();
+        
+            var offsetCenter = -translate;
+            if (s.rtl) offsetCenter = translate;
+        
+            // Visible Slides
+            s.slides.removeClass(s.params.slideVisibleClass);
+            for (var i = 0; i < s.slides.length; i++) {
+                var slide = s.slides[i];
+                var slideProgress = (offsetCenter - slide.swiperSlideOffset) / (slide.swiperSlideSize + s.params.spaceBetween);
+                if (s.params.watchSlidesVisibility) {
+                    var slideBefore = -(offsetCenter - slide.swiperSlideOffset);
+                    var slideAfter = slideBefore + s.slidesSizesGrid[i];
+                    var isVisible =
+                        (slideBefore >= 0 && slideBefore < s.size) ||
+                        (slideAfter > 0 && slideAfter <= s.size) ||
+                        (slideBefore <= 0 && slideAfter >= s.size);
+                    if (isVisible) {
+                        s.slides.eq(i).addClass(s.params.slideVisibleClass);
+                    }
+                }
+                slide.progress = s.rtl ? -slideProgress : slideProgress;
+            }
+        };
+        s.updateProgress = function (translate) {
+            if (typeof translate === 'undefined') {
+                translate = s.translate || 0;
+            }
+            var translatesDiff = s.maxTranslate() - s.minTranslate();
+            var wasBeginning = s.isBeginning;
+            var wasEnd = s.isEnd;
+            if (translatesDiff === 0) {
+                s.progress = 0;
+                s.isBeginning = s.isEnd = true;
+            }
+            else {
+                s.progress = (translate - s.minTranslate()) / (translatesDiff);
+                s.isBeginning = s.progress <= 0;
+                s.isEnd = s.progress >= 1;
+            }
+            if (s.isBeginning && !wasBeginning) s.emit('onReachBeginning', s);
+            if (s.isEnd && !wasEnd) s.emit('onReachEnd', s);
+        
+            if (s.params.watchSlidesProgress) s.updateSlidesProgress(translate);
+            s.emit('onProgress', s, s.progress);
+        };
+        s.updateActiveIndex = function () {
+            var translate = s.rtl ? s.translate : -s.translate;
+            var newActiveIndex, i, snapIndex;
+            for (i = 0; i < s.slidesGrid.length; i ++) {
+                if (typeof s.slidesGrid[i + 1] !== 'undefined') {
+                    if (translate >= s.slidesGrid[i] && translate < s.slidesGrid[i + 1] - (s.slidesGrid[i + 1] - s.slidesGrid[i]) / 2) {
+                        newActiveIndex = i;
+                    }
+                    else if (translate >= s.slidesGrid[i] && translate < s.slidesGrid[i + 1]) {
+                        newActiveIndex = i + 1;
+                    }
+                }
+                else {
+                    if (translate >= s.slidesGrid[i]) {
+                        newActiveIndex = i;
+                    }
+                }
+            }
+            // Normalize slideIndex
+            if (newActiveIndex < 0 || typeof newActiveIndex === 'undefined') newActiveIndex = 0;
+            // for (i = 0; i < s.slidesGrid.length; i++) {
+                // if (- translate >= s.slidesGrid[i]) {
+                    // newActiveIndex = i;
+                // }
+            // }
+            snapIndex = Math.floor(newActiveIndex / s.params.slidesPerGroup);
+            if (snapIndex >= s.snapGrid.length) snapIndex = s.snapGrid.length - 1;
+        
+            if (newActiveIndex === s.activeIndex) {
+                return;
+            }
+            s.snapIndex = snapIndex;
+            s.previousIndex = s.activeIndex;
+            s.activeIndex = newActiveIndex;
+            s.updateClasses();
+        };
+        
+        /*=========================
+          Classes
+          ===========================*/
+        s.updateClasses = function () {
+            s.slides.removeClass(s.params.slideActiveClass + ' ' + s.params.slideNextClass + ' ' + s.params.slidePrevClass);
+            var activeSlide = s.slides.eq(s.activeIndex);
+            // Active classes
+            activeSlide.addClass(s.params.slideActiveClass);
+            // Next Slide
+            var nextSlide = activeSlide.next('.' + s.params.slideClass).addClass(s.params.slideNextClass);
+            if (s.params.loop && nextSlide.length === 0) {
+                s.slides.eq(0).addClass(s.params.slideNextClass);
+            }
+            // Prev Slide
+            var prevSlide = activeSlide.prev('.' + s.params.slideClass).addClass(s.params.slidePrevClass);
+            if (s.params.loop && prevSlide.length === 0) {
+                s.slides.eq(-1).addClass(s.params.slidePrevClass);
+            }
+        
+            // Pagination
+            if (s.paginationContainer && s.paginationContainer.length > 0) {
+                // Current/Total
+                var current,
+                    total = s.params.loop ? Math.ceil((s.slides.length - s.loopedSlides * 2) / s.params.slidesPerGroup) : s.snapGrid.length;
+                if (s.params.loop) {
+                    current = Math.ceil((s.activeIndex - s.loopedSlides)/s.params.slidesPerGroup);
+                    if (current > s.slides.length - 1 - s.loopedSlides * 2) {
+                        current = current - (s.slides.length - s.loopedSlides * 2);
+                    }
+                    if (current > total - 1) current = current - total;
+                    if (current < 0 && s.params.paginationType !== 'bullets') current = total + current;
+                }
+                else {
+                    if (typeof s.snapIndex !== 'undefined') {
+                        current = s.snapIndex;
+                    }
+                    else {
+                        current = s.activeIndex || 0;
+                    }
+                }
+                // Types
+                if (s.params.paginationType === 'bullets' && s.bullets && s.bullets.length > 0) {
+                    s.bullets.removeClass(s.params.bulletActiveClass);
+                    if (s.paginationContainer.length > 1) {
+                        s.bullets.each(function () {
+                            if ($(this).index() === current) $(this).addClass(s.params.bulletActiveClass);
+                        });
+                    }
+                    else {
+                        s.bullets.eq(current).addClass(s.params.bulletActiveClass);
+                    }
+                }
+                if (s.params.paginationType === 'fraction') {
+                    s.paginationContainer.find('.' + s.params.paginationCurrentClass).text(current + 1);
+                    s.paginationContainer.find('.' + s.params.paginationTotalClass).text(total);
+                }
+                if (s.params.paginationType === 'progress') {
+                    var scale = (current + 1) / total,
+                        scaleX = scale,
+                        scaleY = 1;
+                    if (!s.isHorizontal()) {
+                        scaleY = scale;
+                        scaleX = 1;
+                    }
+                    s.paginationContainer.find('.' + s.params.paginationProgressbarClass).transform('translate3d(0,0,0) scaleX(' + scaleX + ') scaleY(' + scaleY + ')').transition(s.params.speed);
+                }
+                if (s.params.paginationType === 'custom' && s.params.paginationCustomRender) {
+                    s.paginationContainer.html(s.params.paginationCustomRender(s, current + 1, total));
+                    s.emit('onPaginationRendered', s, s.paginationContainer[0]);
+                }
+            }
+        
+            // Next/active buttons
+            if (!s.params.loop) {
+                if (s.params.prevButton && s.prevButton && s.prevButton.length > 0) {
+                    if (s.isBeginning) {
+                        s.prevButton.addClass(s.params.buttonDisabledClass);
+                        if (s.params.a11y && s.a11y) s.a11y.disable(s.prevButton);
+                    }
+                    else {
+                        s.prevButton.removeClass(s.params.buttonDisabledClass);
+                        if (s.params.a11y && s.a11y) s.a11y.enable(s.prevButton);
+                    }
+                }
+                if (s.params.nextButton && s.nextButton && s.nextButton.length > 0) {
+                    if (s.isEnd) {
+                        s.nextButton.addClass(s.params.buttonDisabledClass);
+                        if (s.params.a11y && s.a11y) s.a11y.disable(s.nextButton);
+                    }
+                    else {
+                        s.nextButton.removeClass(s.params.buttonDisabledClass);
+                        if (s.params.a11y && s.a11y) s.a11y.enable(s.nextButton);
+                    }
+                }
+            }
+        };
+        
+        /*=========================
+          Pagination
+          ===========================*/
+        s.updatePagination = function () {
+            if (!s.params.pagination) return;
+            if (s.paginationContainer && s.paginationContainer.length > 0) {
+                var paginationHTML = '';
+                if (s.params.paginationType === 'bullets') {
+                    var numberOfBullets = s.params.loop ? Math.ceil((s.slides.length - s.loopedSlides * 2) / s.params.slidesPerGroup) : s.snapGrid.length;
+                    for (var i = 0; i < numberOfBullets; i++) {
+                        if (s.params.paginationBulletRender) {
+                            paginationHTML += s.params.paginationBulletRender(i, s.params.bulletClass);
+                        }
+                        else {
+                            paginationHTML += '<' + s.params.paginationElement+' class="' + s.params.bulletClass + '"></' + s.params.paginationElement + '>';
+                        }
+                    }
+                    s.paginationContainer.html(paginationHTML);
+                    s.bullets = s.paginationContainer.find('.' + s.params.bulletClass);
+                    if (s.params.paginationClickable && s.params.a11y && s.a11y) {
+                        s.a11y.initPagination();
+                    }
+                }
+                if (s.params.paginationType === 'fraction') {
+                    if (s.params.paginationFractionRender) {
+                        paginationHTML = s.params.paginationFractionRender(s, s.params.paginationCurrentClass, s.params.paginationTotalClass);
+                    }
+                    else {
+                        paginationHTML =
+                            '<span class="' + s.params.paginationCurrentClass + '"></span>' +
+                            ' / ' +
+                            '<span class="' + s.params.paginationTotalClass+'"></span>';
+                    }
+                    s.paginationContainer.html(paginationHTML);
+                }
+                if (s.params.paginationType === 'progress') {
+                    if (s.params.paginationProgressRender) {
+                        paginationHTML = s.params.paginationProgressRender(s, s.params.paginationProgressbarClass);
+                    }
+                    else {
+                        paginationHTML = '<span class="' + s.params.paginationProgressbarClass + '"></span>';
+                    }
+                    s.paginationContainer.html(paginationHTML);
+                }
+                if (s.params.paginationType !== 'custom') {
+                    s.emit('onPaginationRendered', s, s.paginationContainer[0]);
+                }
+            }
+        };
+        /*=========================
+          Common update method
+          ===========================*/
+        s.update = function (updateTranslate) {
+            s.updateContainerSize();
+            s.updateSlidesSize();
+            s.updateProgress();
+            s.updatePagination();
+            s.updateClasses();
+            if (s.params.scrollbar && s.scrollbar) {
+                s.scrollbar.set();
+            }
+            function forceSetTranslate() {
+                newTranslate = Math.min(Math.max(s.translate, s.maxTranslate()), s.minTranslate());
+                s.setWrapperTranslate(newTranslate);
+                s.updateActiveIndex();
+                s.updateClasses();
+            }
+            if (updateTranslate) {
+                var translated, newTranslate;
+                if (s.controller && s.controller.spline) {
+                    s.controller.spline = undefined;
+                }
+                if (s.params.freeMode) {
+                    forceSetTranslate();
+                    if (s.params.autoHeight) {
+                        s.updateAutoHeight();
+                    }
+                }
+                else {
+                    if ((s.params.slidesPerView === 'auto' || s.params.slidesPerView > 1) && s.isEnd && !s.params.centeredSlides) {
+                        translated = s.slideTo(s.slides.length - 1, 0, false, true);
+                    }
+                    else {
+                        translated = s.slideTo(s.activeIndex, 0, false, true);
+                    }
+                    if (!translated) {
+                        forceSetTranslate();
+                    }
+                }
+            }
+            else if (s.params.autoHeight) {
+                s.updateAutoHeight();
+            }
+        };
+        
+        /*=========================
+          Resize Handler
+          ===========================*/
+        s.onResize = function (forceUpdatePagination) {
+            //Breakpoints
+            if (s.params.breakpoints) {
+                s.setBreakpoint();
+            }
+        
+            // Disable locks on resize
+            var allowSwipeToPrev = s.params.allowSwipeToPrev;
+            var allowSwipeToNext = s.params.allowSwipeToNext;
+            s.params.allowSwipeToPrev = s.params.allowSwipeToNext = true;
+        
+            s.updateContainerSize();
+            s.updateSlidesSize();
+            if (s.params.slidesPerView === 'auto' || s.params.freeMode || forceUpdatePagination) s.updatePagination();
+            if (s.params.scrollbar && s.scrollbar) {
+                s.scrollbar.set();
+            }
+            if (s.controller && s.controller.spline) {
+                s.controller.spline = undefined;
+            }
+            var slideChangedBySlideTo = false;
+            if (s.params.freeMode) {
+                var newTranslate = Math.min(Math.max(s.translate, s.maxTranslate()), s.minTranslate());
+                s.setWrapperTranslate(newTranslate);
+                s.updateActiveIndex();
+                s.updateClasses();
+        
+                if (s.params.autoHeight) {
+                    s.updateAutoHeight();
+                }
+            }
+            else {
+                s.updateClasses();
+                if ((s.params.slidesPerView === 'auto' || s.params.slidesPerView > 1) && s.isEnd && !s.params.centeredSlides) {
+                    slideChangedBySlideTo = s.slideTo(s.slides.length - 1, 0, false, true);
+                }
+                else {
+                    slideChangedBySlideTo = s.slideTo(s.activeIndex, 0, false, true);
+                }
+            }
+            if (s.params.lazyLoading && !slideChangedBySlideTo && s.lazy) {
+                s.lazy.load();
+            }
+            // Return locks after resize
+            s.params.allowSwipeToPrev = allowSwipeToPrev;
+            s.params.allowSwipeToNext = allowSwipeToNext;
+        };
+        
+        /*=========================
+          Events
+          ===========================*/
+        
+        //Define Touch Events
+        var desktopEvents = ['mousedown', 'mousemove', 'mouseup'];
+        if (window.navigator.pointerEnabled) desktopEvents = ['pointerdown', 'pointermove', 'pointerup'];
+        else if (window.navigator.msPointerEnabled) desktopEvents = ['MSPointerDown', 'MSPointerMove', 'MSPointerUp'];
+        s.touchEvents = {
+            start : s.support.touch || !s.params.simulateTouch  ? 'touchstart' : desktopEvents[0],
+            move : s.support.touch || !s.params.simulateTouch ? 'touchmove' : desktopEvents[1],
+            end : s.support.touch || !s.params.simulateTouch ? 'touchend' : desktopEvents[2]
+        };
+        
+        
+        // WP8 Touch Events Fix
+        if (window.navigator.pointerEnabled || window.navigator.msPointerEnabled) {
+            (s.params.touchEventsTarget === 'container' ? s.container : s.wrapper).addClass('swiper-wp8-' + s.params.direction);
+        }
+        
+        // Attach/detach events
+        s.initEvents = function (detach) {
+            var actionDom = detach ? 'off' : 'on';
+            var action = detach ? 'removeEventListener' : 'addEventListener';
+            var touchEventsTarget = s.params.touchEventsTarget === 'container' ? s.container[0] : s.wrapper[0];
+            var target = s.support.touch ? touchEventsTarget : document;
+        
+            var moveCapture = s.params.nested ? true : false;
+        
+            //Touch Events
+            if (s.browser.ie) {
+                touchEventsTarget[action](s.touchEvents.start, s.onTouchStart, false);
+                target[action](s.touchEvents.move, s.onTouchMove, moveCapture);
+                target[action](s.touchEvents.end, s.onTouchEnd, false);
+            }
+            else {
+                if (s.support.touch) {
+                    touchEventsTarget[action](s.touchEvents.start, s.onTouchStart, false);
+                    touchEventsTarget[action](s.touchEvents.move, s.onTouchMove, moveCapture);
+                    touchEventsTarget[action](s.touchEvents.end, s.onTouchEnd, false);
+                }
+                if (params.simulateTouch && !s.device.ios && !s.device.android) {
+                    touchEventsTarget[action]('mousedown', s.onTouchStart, false);
+                    document[action]('mousemove', s.onTouchMove, moveCapture);
+                    document[action]('mouseup', s.onTouchEnd, false);
+                }
+            }
+            window[action]('resize', s.onResize);
+        
+            // Next, Prev, Index
+            if (s.params.nextButton && s.nextButton && s.nextButton.length > 0) {
+                s.nextButton[actionDom]('click', s.onClickNext);
+                if (s.params.a11y && s.a11y) s.nextButton[actionDom]('keydown', s.a11y.onEnterKey);
+            }
+            if (s.params.prevButton && s.prevButton && s.prevButton.length > 0) {
+                s.prevButton[actionDom]('click', s.onClickPrev);
+                if (s.params.a11y && s.a11y) s.prevButton[actionDom]('keydown', s.a11y.onEnterKey);
+            }
+            if (s.params.pagination && s.params.paginationClickable) {
+                s.paginationContainer[actionDom]('click', '.' + s.params.bulletClass, s.onClickIndex);
+                if (s.params.a11y && s.a11y) s.paginationContainer[actionDom]('keydown', '.' + s.params.bulletClass, s.a11y.onEnterKey);
+            }
+        
+            // Prevent Links Clicks
+            if (s.params.preventClicks || s.params.preventClicksPropagation) touchEventsTarget[action]('click', s.preventClicks, true);
+        };
+        s.attachEvents = function () {
+            s.initEvents();
+        };
+        s.detachEvents = function () {
+            s.initEvents(true);
+        };
+        
+        /*=========================
+          Handle Clicks
+          ===========================*/
+        // Prevent Clicks
+        s.allowClick = true;
+        s.preventClicks = function (e) {
+            if (!s.allowClick) {
+                if (s.params.preventClicks) e.preventDefault();
+                if (s.params.preventClicksPropagation && s.animating) {
+                    e.stopPropagation();
+                    e.stopImmediatePropagation();
+                }
+            }
+        };
+        // Clicks
+        s.onClickNext = function (e) {
+            e.preventDefault();
+            if (s.isEnd && !s.params.loop) return;
+            s.slideNext();
+        };
+        s.onClickPrev = function (e) {
+            e.preventDefault();
+            if (s.isBeginning && !s.params.loop) return;
+            s.slidePrev();
+        };
+        s.onClickIndex = function (e) {
+            e.preventDefault();
+            var index = $(this).index() * s.params.slidesPerGroup;
+            if (s.params.loop) index = index + s.loopedSlides;
+            s.slideTo(index);
+        };
+        
+        /*=========================
+          Handle Touches
+          ===========================*/
+        function findElementInEvent(e, selector) {
+            var el = $(e.target);
+            if (!el.is(selector)) {
+                if (typeof selector === 'string') {
+                    el = el.parents(selector);
+                }
+                else if (selector.nodeType) {
+                    var found;
+                    el.parents().each(function (index, _el) {
+                        if (_el === selector) found = selector;
+                    });
+                    if (!found) return undefined;
+                    else return selector;
+                }
+            }
+            if (el.length === 0) {
+                return undefined;
+            }
+            return el[0];
+        }
+        s.updateClickedSlide = function (e) {
+            var slide = findElementInEvent(e, '.' + s.params.slideClass);
+            var slideFound = false;
+            if (slide) {
+                for (var i = 0; i < s.slides.length; i++) {
+                    if (s.slides[i] === slide) slideFound = true;
+                }
+            }
+        
+            if (slide && slideFound) {
+                s.clickedSlide = slide;
+                s.clickedIndex = $(slide).index();
+            }
+            else {
+                s.clickedSlide = undefined;
+                s.clickedIndex = undefined;
+                return;
+            }
+            if (s.params.slideToClickedSlide && s.clickedIndex !== undefined && s.clickedIndex !== s.activeIndex) {
+                var slideToIndex = s.clickedIndex,
+                    realIndex,
+                    duplicatedSlides;
+                if (s.params.loop) {
+                    if (s.animating) return;
+                    realIndex = $(s.clickedSlide).attr('data-swiper-slide-index');
+                    if (s.params.centeredSlides) {
+                        if ((slideToIndex < s.loopedSlides - s.params.slidesPerView/2) || (slideToIndex > s.slides.length - s.loopedSlides + s.params.slidesPerView/2)) {
+                            s.fixLoop();
+                            slideToIndex = s.wrapper.children('.' + s.params.slideClass + '[data-swiper-slide-index="' + realIndex + '"]:not(.swiper-slide-duplicate)').eq(0).index();
+                            setTimeout(function () {
+                                s.slideTo(slideToIndex);
+                            }, 0);
+                        }
+                        else {
+                            s.slideTo(slideToIndex);
+                        }
+                    }
+                    else {
+                        if (slideToIndex > s.slides.length - s.params.slidesPerView) {
+                            s.fixLoop();
+                            slideToIndex = s.wrapper.children('.' + s.params.slideClass + '[data-swiper-slide-index="' + realIndex + '"]:not(.swiper-slide-duplicate)').eq(0).index();
+                            setTimeout(function () {
+                                s.slideTo(slideToIndex);
+                            }, 0);
+                        }
+                        else {
+                            s.slideTo(slideToIndex);
+                        }
+                    }
+                }
+                else {
+                    s.slideTo(slideToIndex);
+                }
+            }
+        };
+        
+        var isTouched,
+            isMoved,
+            allowTouchCallbacks,
+            touchStartTime,
+            isScrolling,
+            currentTranslate,
+            startTranslate,
+            allowThresholdMove,
+            // Form elements to match
+            formElements = 'input, select, textarea, button',
+            // Last click time
+            lastClickTime = Date.now(), clickTimeout,
+            //Velocities
+            velocities = [],
+            allowMomentumBounce;
+        
+        // Animating Flag
+        s.animating = false;
+        
+        // Touches information
+        s.touches = {
+            startX: 0,
+            startY: 0,
+            currentX: 0,
+            currentY: 0,
+            diff: 0
+        };
+        
+        // Touch handlers
+        var isTouchEvent, startMoving;
+        s.onTouchStart = function (e) {
+            if (e.originalEvent) e = e.originalEvent;
+            isTouchEvent = e.type === 'touchstart';
+            if (!isTouchEvent && 'which' in e && e.which === 3) return;
+            if (s.params.noSwiping && findElementInEvent(e, '.' + s.params.noSwipingClass)) {
+                s.allowClick = true;
+                return;
+            }
+            if (s.params.swipeHandler) {
+                if (!findElementInEvent(e, s.params.swipeHandler)) return;
+            }
+        
+            var startX = s.touches.currentX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
+            var startY = s.touches.currentY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
+        
+            // Do NOT start if iOS edge swipe is detected. Otherwise iOS app (UIWebView) cannot swipe-to-go-back anymore
+            if(s.device.ios && s.params.iOSEdgeSwipeDetection && startX <= s.params.iOSEdgeSwipeThreshold) {
+                return;
+            }
+        
+            isTouched = true;
+            isMoved = false;
+            allowTouchCallbacks = true;
+            isScrolling = undefined;
+            startMoving = undefined;
+            s.touches.startX = startX;
+            s.touches.startY = startY;
+            touchStartTime = Date.now();
+            s.allowClick = true;
+            s.updateContainerSize();
+            s.swipeDirection = undefined;
+            if (s.params.threshold > 0) allowThresholdMove = false;
+            if (e.type !== 'touchstart') {
+                var preventDefault = true;
+                if ($(e.target).is(formElements)) preventDefault = false;
+                if (document.activeElement && $(document.activeElement).is(formElements)) {
+                    document.activeElement.blur();
+                }
+                if (preventDefault) {
+                    e.preventDefault();
+                }
+            }
+            s.emit('onTouchStart', s, e);
+        };
+        
+        s.onTouchMove = function (e) {
+            if (e.originalEvent) e = e.originalEvent;
+            if (isTouchEvent && e.type === 'mousemove') return;
+            if (e.preventedByNestedSwiper) {
+                s.touches.startX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
+                s.touches.startY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
+                return;
+            }
+            if (s.params.onlyExternal) {
+                // isMoved = true;
+                s.allowClick = false;
+                if (isTouched) {
+                    s.touches.startX = s.touches.currentX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
+                    s.touches.startY = s.touches.currentY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
+                    touchStartTime = Date.now();
+                }
+                return;
+            }
+            if (isTouchEvent && document.activeElement) {
+                if (e.target === document.activeElement && $(e.target).is(formElements)) {
+                    isMoved = true;
+                    s.allowClick = false;
+                    return;
+                }
+            }
+            if (allowTouchCallbacks) {
+                s.emit('onTouchMove', s, e);
+            }
+            if (e.targetTouches && e.targetTouches.length > 1) return;
+        
+            s.touches.currentX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
+            s.touches.currentY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
+        
+            if (typeof isScrolling === 'undefined') {
+                var touchAngle = Math.atan2(Math.abs(s.touches.currentY - s.touches.startY), Math.abs(s.touches.currentX - s.touches.startX)) * 180 / Math.PI;
+                isScrolling = s.isHorizontal() ? touchAngle > s.params.touchAngle : (90 - touchAngle > s.params.touchAngle);
+            }
+            if (isScrolling) {
+                s.emit('onTouchMoveOpposite', s, e);
+            }
+            if (typeof startMoving === 'undefined' && s.browser.ieTouch) {
+                if (s.touches.currentX !== s.touches.startX || s.touches.currentY !== s.touches.startY) {
+                    startMoving = true;
+                }
+            }
+            if (!isTouched) return;
+            if (isScrolling)  {
+                isTouched = false;
+                return;
+            }
+            if (!startMoving && s.browser.ieTouch) {
+                return;
+            }
+            s.allowClick = false;
+            s.emit('onSliderMove', s, e);
+            e.preventDefault();
+            if (s.params.touchMoveStopPropagation && !s.params.nested) {
+                e.stopPropagation();
+            }
+        
+            if (!isMoved) {
+                if (params.loop) {
+                    s.fixLoop();
+                }
+                startTranslate = s.getWrapperTranslate();
+                s.setWrapperTransition(0);
+                if (s.animating) {
+                    s.wrapper.trigger('webkitTransitionEnd transitionend oTransitionEnd MSTransitionEnd msTransitionEnd');
+                }
+                if (s.params.autoplay && s.autoplaying) {
+                    if (s.params.autoplayDisableOnInteraction) {
+                        s.stopAutoplay();
+                    }
+                    else {
+                        s.pauseAutoplay();
+                    }
+                }
+                allowMomentumBounce = false;
+                //Grab Cursor
+                if (s.params.grabCursor) {
+                    s.container[0].style.cursor = 'move';
+                    s.container[0].style.cursor = '-webkit-grabbing';
+                    s.container[0].style.cursor = '-moz-grabbin';
+                    s.container[0].style.cursor = 'grabbing';
+                }
+            }
+            isMoved = true;
+        
+            var diff = s.touches.diff = s.isHorizontal() ? s.touches.currentX - s.touches.startX : s.touches.currentY - s.touches.startY;
+        
+            diff = diff * s.params.touchRatio;
+            if (s.rtl) diff = -diff;
+        
+            s.swipeDirection = diff > 0 ? 'prev' : 'next';
+            currentTranslate = diff + startTranslate;
+        
+            var disableParentSwiper = true;
+            if ((diff > 0 && currentTranslate > s.minTranslate())) {
+                disableParentSwiper = false;
+                if (s.params.resistance) currentTranslate = s.minTranslate() - 1 + Math.pow(-s.minTranslate() + startTranslate + diff, s.params.resistanceRatio);
+            }
+            else if (diff < 0 && currentTranslate < s.maxTranslate()) {
+                disableParentSwiper = false;
+                if (s.params.resistance) currentTranslate = s.maxTranslate() + 1 - Math.pow(s.maxTranslate() - startTranslate - diff, s.params.resistanceRatio);
+            }
+        
+            if (disableParentSwiper) {
+                e.preventedByNestedSwiper = true;
+            }
+        
+            // Directions locks
+            if (!s.params.allowSwipeToNext && s.swipeDirection === 'next' && currentTranslate < startTranslate) {
+                currentTranslate = startTranslate;
+            }
+            if (!s.params.allowSwipeToPrev && s.swipeDirection === 'prev' && currentTranslate > startTranslate) {
+                currentTranslate = startTranslate;
+            }
+        
+            if (!s.params.followFinger) return;
+        
+            // Threshold
+            if (s.params.threshold > 0) {
+                if (Math.abs(diff) > s.params.threshold || allowThresholdMove) {
+                    if (!allowThresholdMove) {
+                        allowThresholdMove = true;
+                        s.touches.startX = s.touches.currentX;
+                        s.touches.startY = s.touches.currentY;
+                        currentTranslate = startTranslate;
+                        s.touches.diff = s.isHorizontal() ? s.touches.currentX - s.touches.startX : s.touches.currentY - s.touches.startY;
+                        return;
+                    }
+                }
+                else {
+                    currentTranslate = startTranslate;
+                    return;
+                }
+            }
+            // Update active index in free mode
+            if (s.params.freeMode || s.params.watchSlidesProgress) {
+                s.updateActiveIndex();
+            }
+            if (s.params.freeMode) {
+                //Velocity
+                if (velocities.length === 0) {
+                    velocities.push({
+                        position: s.touches[s.isHorizontal() ? 'startX' : 'startY'],
+                        time: touchStartTime
+                    });
+                }
+                velocities.push({
+                    position: s.touches[s.isHorizontal() ? 'currentX' : 'currentY'],
+                    time: (new window.Date()).getTime()
+                });
+            }
+            // Update progress
+            s.updateProgress(currentTranslate);
+            // Update translate
+            s.setWrapperTranslate(currentTranslate);
+        };
+        s.onTouchEnd = function (e) {
+            if (e.originalEvent) e = e.originalEvent;
+            if (allowTouchCallbacks) {
+                s.emit('onTouchEnd', s, e);
+            }
+            allowTouchCallbacks = false;
+            if (!isTouched) return;
+            //Return Grab Cursor
+            if (s.params.grabCursor && isMoved && isTouched) {
+                s.container[0].style.cursor = 'move';
+                s.container[0].style.cursor = '-webkit-grab';
+                s.container[0].style.cursor = '-moz-grab';
+                s.container[0].style.cursor = 'grab';
+            }
+        
+            // Time diff
+            var touchEndTime = Date.now();
+            var timeDiff = touchEndTime - touchStartTime;
+        
+            // Tap, doubleTap, Click
+            if (s.allowClick) {
+                s.updateClickedSlide(e);
+                s.emit('onTap', s, e);
+                if (timeDiff < 300 && (touchEndTime - lastClickTime) > 300) {
+                    if (clickTimeout) clearTimeout(clickTimeout);
+                    clickTimeout = setTimeout(function () {
+                        if (!s) return;
+                        if (s.params.paginationHide && s.paginationContainer.length > 0 && !$(e.target).hasClass(s.params.bulletClass)) {
+                            s.paginationContainer.toggleClass(s.params.paginationHiddenClass);
+                        }
+                        s.emit('onClick', s, e);
+                    }, 300);
+        
+                }
+                if (timeDiff < 300 && (touchEndTime - lastClickTime) < 300) {
+                    if (clickTimeout) clearTimeout(clickTimeout);
+                    s.emit('onDoubleTap', s, e);
+                }
+            }
+        
+            lastClickTime = Date.now();
+            setTimeout(function () {
+                if (s) s.allowClick = true;
+            }, 0);
+        
+            if (!isTouched || !isMoved || !s.swipeDirection || s.touches.diff === 0 || currentTranslate === startTranslate) {
+                isTouched = isMoved = false;
+                return;
+            }
+            isTouched = isMoved = false;
+        
+            var currentPos;
+            if (s.params.followFinger) {
+                currentPos = s.rtl ? s.translate : -s.translate;
+            }
+            else {
+                currentPos = -currentTranslate;
+            }
+            if (s.params.freeMode) {
+                if (currentPos < -s.minTranslate()) {
+                    s.slideTo(s.activeIndex);
+                    return;
+                }
+                else if (currentPos > -s.maxTranslate()) {
+                    if (s.slides.length < s.snapGrid.length) {
+                        s.slideTo(s.snapGrid.length - 1);
+                    }
+                    else {
+                        s.slideTo(s.slides.length - 1);
+                    }
+                    return;
+                }
+        
+                if (s.params.freeModeMomentum) {
+                    if (velocities.length > 1) {
+                        var lastMoveEvent = velocities.pop(), velocityEvent = velocities.pop();
+        
+                        var distance = lastMoveEvent.position - velocityEvent.position;
+                        var time = lastMoveEvent.time - velocityEvent.time;
+                        s.velocity = distance / time;
+                        s.velocity = s.velocity / 2;
+                        if (Math.abs(s.velocity) < s.params.freeModeMinimumVelocity) {
+                            s.velocity = 0;
+                        }
+                        // this implies that the user stopped moving a finger then released.
+                        // There would be no events with distance zero, so the last event is stale.
+                        if (time > 150 || (new window.Date().getTime() - lastMoveEvent.time) > 300) {
+                            s.velocity = 0;
+                        }
+                    } else {
+                        s.velocity = 0;
+                    }
+        
+                    velocities.length = 0;
+                    var momentumDuration = 1000 * s.params.freeModeMomentumRatio;
+                    var momentumDistance = s.velocity * momentumDuration;
+        
+                    var newPosition = s.translate + momentumDistance;
+                    if (s.rtl) newPosition = - newPosition;
+                    var doBounce = false;
+                    var afterBouncePosition;
+                    var bounceAmount = Math.abs(s.velocity) * 20 * s.params.freeModeMomentumBounceRatio;
+                    if (newPosition < s.maxTranslate()) {
+                        if (s.params.freeModeMomentumBounce) {
+                            if (newPosition + s.maxTranslate() < -bounceAmount) {
+                                newPosition = s.maxTranslate() - bounceAmount;
+                            }
+                            afterBouncePosition = s.maxTranslate();
+                            doBounce = true;
+                            allowMomentumBounce = true;
+                        }
+                        else {
+                            newPosition = s.maxTranslate();
+                        }
+                    }
+                    else if (newPosition > s.minTranslate()) {
+                        if (s.params.freeModeMomentumBounce) {
+                            if (newPosition - s.minTranslate() > bounceAmount) {
+                                newPosition = s.minTranslate() + bounceAmount;
+                            }
+                            afterBouncePosition = s.minTranslate();
+                            doBounce = true;
+                            allowMomentumBounce = true;
+                        }
+                        else {
+                            newPosition = s.minTranslate();
+                        }
+                    }
+                    else if (s.params.freeModeSticky) {
+                        var j = 0,
+                            nextSlide;
+                        for (j = 0; j < s.snapGrid.length; j += 1) {
+                            if (s.snapGrid[j] > -newPosition) {
+                                nextSlide = j;
+                                break;
+                            }
+        
+                        }
+                        if (Math.abs(s.snapGrid[nextSlide] - newPosition) < Math.abs(s.snapGrid[nextSlide - 1] - newPosition) || s.swipeDirection === 'next') {
+                            newPosition = s.snapGrid[nextSlide];
+                        } else {
+                            newPosition = s.snapGrid[nextSlide - 1];
+                        }
+                        if (!s.rtl) newPosition = - newPosition;
+                    }
+                    //Fix duration
+                    if (s.velocity !== 0) {
+                        if (s.rtl) {
+                            momentumDuration = Math.abs((-newPosition - s.translate) / s.velocity);
+                        }
+                        else {
+                            momentumDuration = Math.abs((newPosition - s.translate) / s.velocity);
+                        }
+                    }
+                    else if (s.params.freeModeSticky) {
+                        s.slideReset();
+                        return;
+                    }
+        
+                    if (s.params.freeModeMomentumBounce && doBounce) {
+                        s.updateProgress(afterBouncePosition);
+                        s.setWrapperTransition(momentumDuration);
+                        s.setWrapperTranslate(newPosition);
+                        s.onTransitionStart();
+                        s.animating = true;
+                        s.wrapper.transitionEnd(function () {
+                            if (!s || !allowMomentumBounce) return;
+                            s.emit('onMomentumBounce', s);
+        
+                            s.setWrapperTransition(s.params.speed);
+                            s.setWrapperTranslate(afterBouncePosition);
+                            s.wrapper.transitionEnd(function () {
+                                if (!s) return;
+                                s.onTransitionEnd();
+                            });
+                        });
+                    } else if (s.velocity) {
+                        s.updateProgress(newPosition);
+                        s.setWrapperTransition(momentumDuration);
+                        s.setWrapperTranslate(newPosition);
+                        s.onTransitionStart();
+                        if (!s.animating) {
+                            s.animating = true;
+                            s.wrapper.transitionEnd(function () {
+                                if (!s) return;
+                                s.onTransitionEnd();
+                            });
+                        }
+        
+                    } else {
+                        s.updateProgress(newPosition);
+                    }
+        
+                    s.updateActiveIndex();
+                }
+                if (!s.params.freeModeMomentum || timeDiff >= s.params.longSwipesMs) {
+                    s.updateProgress();
+                    s.updateActiveIndex();
+                }
+                return;
+            }
+        
+            // Find current slide
+            var i, stopIndex = 0, groupSize = s.slidesSizesGrid[0];
+            for (i = 0; i < s.slidesGrid.length; i += s.params.slidesPerGroup) {
+                if (typeof s.slidesGrid[i + s.params.slidesPerGroup] !== 'undefined') {
+                    if (currentPos >= s.slidesGrid[i] && currentPos < s.slidesGrid[i + s.params.slidesPerGroup]) {
+                        stopIndex = i;
+                        groupSize = s.slidesGrid[i + s.params.slidesPerGroup] - s.slidesGrid[i];
+                    }
+                }
+                else {
+                    if (currentPos >= s.slidesGrid[i]) {
+                        stopIndex = i;
+                        groupSize = s.slidesGrid[s.slidesGrid.length - 1] - s.slidesGrid[s.slidesGrid.length - 2];
+                    }
+                }
+            }
+        
+            // Find current slide size
+            var ratio = (currentPos - s.slidesGrid[stopIndex]) / groupSize;
+        
+            if (timeDiff > s.params.longSwipesMs) {
+                // Long touches
+                if (!s.params.longSwipes) {
+                    s.slideTo(s.activeIndex);
+                    return;
+                }
+                if (s.swipeDirection === 'next') {
+                    if (ratio >= s.params.longSwipesRatio) s.slideTo(stopIndex + s.params.slidesPerGroup);
+                    else s.slideTo(stopIndex);
+        
+                }
+                if (s.swipeDirection === 'prev') {
+                    if (ratio > (1 - s.params.longSwipesRatio)) s.slideTo(stopIndex + s.params.slidesPerGroup);
+                    else s.slideTo(stopIndex);
+                }
+            }
+            else {
+                // Short swipes
+                if (!s.params.shortSwipes) {
+                    s.slideTo(s.activeIndex);
+                    return;
+                }
+                if (s.swipeDirection === 'next') {
+                    s.slideTo(stopIndex + s.params.slidesPerGroup);
+        
+                }
+                if (s.swipeDirection === 'prev') {
+                    s.slideTo(stopIndex);
+                }
+            }
+        };
+        /*=========================
+          Transitions
+          ===========================*/
+        s._slideTo = function (slideIndex, speed) {
+            return s.slideTo(slideIndex, speed, true, true);
+        };
+        s.slideTo = function (slideIndex, speed, runCallbacks, internal) {
+            if (typeof runCallbacks === 'undefined') runCallbacks = true;
+            if (typeof slideIndex === 'undefined') slideIndex = 0;
+            if (slideIndex < 0) slideIndex = 0;
+            s.snapIndex = Math.floor(slideIndex / s.params.slidesPerGroup);
+            if (s.snapIndex >= s.snapGrid.length) s.snapIndex = s.snapGrid.length - 1;
+        
+            var translate = - s.snapGrid[s.snapIndex];
+            // Stop autoplay
+            if (s.params.autoplay && s.autoplaying) {
+                if (internal || !s.params.autoplayDisableOnInteraction) {
+                    s.pauseAutoplay(speed);
+                }
+                else {
+                    s.stopAutoplay();
+                }
+            }
+            // Update progress
+            s.updateProgress(translate);
+        
+            // Normalize slideIndex
+            for (var i = 0; i < s.slidesGrid.length; i++) {
+                if (- Math.floor(translate * 100) >= Math.floor(s.slidesGrid[i] * 100)) {
+                    slideIndex = i;
+                }
+            }
+        
+            // Directions locks
+            if (!s.params.allowSwipeToNext && translate < s.translate && translate < s.minTranslate()) {
+                return false;
+            }
+            if (!s.params.allowSwipeToPrev && translate > s.translate && translate > s.maxTranslate()) {
+                if ((s.activeIndex || 0) !== slideIndex ) return false;
+            }
+        
+            // Update Index
+            if (typeof speed === 'undefined') speed = s.params.speed;
+            s.previousIndex = s.activeIndex || 0;
+            s.activeIndex = slideIndex;
+        
+            if ((s.rtl && -translate === s.translate) || (!s.rtl && translate === s.translate)) {
+                // Update Height
+                if (s.params.autoHeight) {
+                    s.updateAutoHeight();
+                }
+                s.updateClasses();
+                if (s.params.effect !== 'slide') {
+                    s.setWrapperTranslate(translate);
+                }
+                return false;
+            }
+            s.updateClasses();
+            s.onTransitionStart(runCallbacks);
+        
+            if (speed === 0) {
+                s.setWrapperTranslate(translate);
+                s.setWrapperTransition(0);
+                s.onTransitionEnd(runCallbacks);
+            }
+            else {
+                s.setWrapperTranslate(translate);
+                s.setWrapperTransition(speed);
+                if (!s.animating) {
+                    s.animating = true;
+                    s.wrapper.transitionEnd(function () {
+                        if (!s) return;
+                        s.onTransitionEnd(runCallbacks);
+                    });
+                }
+        
+            }
+        
+            return true;
+        };
+        
+        s.onTransitionStart = function (runCallbacks) {
+            if (typeof runCallbacks === 'undefined') runCallbacks = true;
+            if (s.params.autoHeight) {
+                s.updateAutoHeight();
+            }
+            if (s.lazy) s.lazy.onTransitionStart();
+            if (runCallbacks) {
+                s.emit('onTransitionStart', s);
+                if (s.activeIndex !== s.previousIndex) {
+                    s.emit('onSlideChangeStart', s);
+                    if (s.activeIndex > s.previousIndex) {
+                        s.emit('onSlideNextStart', s);
+                    }
+                    else {
+                        s.emit('onSlidePrevStart', s);
+                    }
+                }
+        
+            }
+        };
+        s.onTransitionEnd = function (runCallbacks) {
+            s.animating = false;
+            s.setWrapperTransition(0);
+            if (typeof runCallbacks === 'undefined') runCallbacks = true;
+            if (s.lazy) s.lazy.onTransitionEnd();
+            if (runCallbacks) {
+                s.emit('onTransitionEnd', s);
+                if (s.activeIndex !== s.previousIndex) {
+                    s.emit('onSlideChangeEnd', s);
+                    if (s.activeIndex > s.previousIndex) {
+                        s.emit('onSlideNextEnd', s);
+                    }
+                    else {
+                        s.emit('onSlidePrevEnd', s);
+                    }
+                }
+            }
+            if (s.params.hashnav && s.hashnav) {
+                s.hashnav.setHash();
+            }
+        
+        };
+        s.slideNext = function (runCallbacks, speed, internal) {
+            if (s.params.loop) {
+                if (s.animating) return false;
+                s.fixLoop();
+                var clientLeft = s.container[0].clientLeft;
+                return s.slideTo(s.activeIndex + s.params.slidesPerGroup, speed, runCallbacks, internal);
+            }
+            else return s.slideTo(s.activeIndex + s.params.slidesPerGroup, speed, runCallbacks, internal);
+        };
+        s._slideNext = function (speed) {
+            return s.slideNext(true, speed, true);
+        };
+        s.slidePrev = function (runCallbacks, speed, internal) {
+            if (s.params.loop) {
+                if (s.animating) return false;
+                s.fixLoop();
+                var clientLeft = s.container[0].clientLeft;
+                return s.slideTo(s.activeIndex - 1, speed, runCallbacks, internal);
+            }
+            else return s.slideTo(s.activeIndex - 1, speed, runCallbacks, internal);
+        };
+        s._slidePrev = function (speed) {
+            return s.slidePrev(true, speed, true);
+        };
+        s.slideReset = function (runCallbacks, speed, internal) {
+            return s.slideTo(s.activeIndex, speed, runCallbacks);
+        };
+        
+        /*=========================
+          Translate/transition helpers
+          ===========================*/
+        s.setWrapperTransition = function (duration, byController) {
+            s.wrapper.transition(duration);
+            if (s.params.effect !== 'slide' && s.effects[s.params.effect]) {
+                s.effects[s.params.effect].setTransition(duration);
+            }
+            if (s.params.parallax && s.parallax) {
+                s.parallax.setTransition(duration);
+            }
+            if (s.params.scrollbar && s.scrollbar) {
+                s.scrollbar.setTransition(duration);
+            }
+            if (s.params.control && s.controller) {
+                s.controller.setTransition(duration, byController);
+            }
+            s.emit('onSetTransition', s, duration);
+        };
+        s.setWrapperTranslate = function (translate, updateActiveIndex, byController) {
+            var x = 0, y = 0, z = 0;
+            if (s.isHorizontal()) {
+                x = s.rtl ? -translate : translate;
+            }
+            else {
+                y = translate;
+            }
+        
+            if (s.params.roundLengths) {
+                x = round(x);
+                y = round(y);
+            }
+        
+            if (!s.params.virtualTranslate) {
+                if (s.support.transforms3d) s.wrapper.transform('translate3d(' + x + 'px, ' + y + 'px, ' + z + 'px)');
+                else s.wrapper.transform('translate(' + x + 'px, ' + y + 'px)');
+            }
+        
+            s.translate = s.isHorizontal() ? x : y;
+        
+            // Check if we need to update progress
+            var progress;
+            var translatesDiff = s.maxTranslate() - s.minTranslate();
+            if (translatesDiff === 0) {
+                progress = 0;
+            }
+            else {
+                progress = (translate - s.minTranslate()) / (translatesDiff);
+            }
+            if (progress !== s.progress) {
+                s.updateProgress(translate);
+            }
+        
+            if (updateActiveIndex) s.updateActiveIndex();
+            if (s.params.effect !== 'slide' && s.effects[s.params.effect]) {
+                s.effects[s.params.effect].setTranslate(s.translate);
+            }
+            if (s.params.parallax && s.parallax) {
+                s.parallax.setTranslate(s.translate);
+            }
+            if (s.params.scrollbar && s.scrollbar) {
+                s.scrollbar.setTranslate(s.translate);
+            }
+            if (s.params.control && s.controller) {
+                s.controller.setTranslate(s.translate, byController);
+            }
+            s.emit('onSetTranslate', s, s.translate);
+        };
+        
+        s.getTranslate = function (el, axis) {
+            var matrix, curTransform, curStyle, transformMatrix;
+        
+            // automatic axis detection
+            if (typeof axis === 'undefined') {
+                axis = 'x';
+            }
+        
+            if (s.params.virtualTranslate) {
+                return s.rtl ? -s.translate : s.translate;
+            }
+        
+            curStyle = window.getComputedStyle(el, null);
+            if (window.WebKitCSSMatrix) {
+                curTransform = curStyle.transform || curStyle.webkitTransform;
+                if (curTransform.split(',').length > 6) {
+                    curTransform = curTransform.split(', ').map(function(a){
+                        return a.replace(',','.');
+                    }).join(', ');
+                }
+                // Some old versions of Webkit choke when 'none' is passed; pass
+                // empty string instead in this case
+                transformMatrix = new window.WebKitCSSMatrix(curTransform === 'none' ? '' : curTransform);
+            }
+            else {
+                transformMatrix = curStyle.MozTransform || curStyle.OTransform || curStyle.MsTransform || curStyle.msTransform  || curStyle.transform || curStyle.getPropertyValue('transform').replace('translate(', 'matrix(1, 0, 0, 1,');
+                matrix = transformMatrix.toString().split(',');
+            }
+        
+            if (axis === 'x') {
+                //Latest Chrome and webkits Fix
+                if (window.WebKitCSSMatrix)
+                    curTransform = transformMatrix.m41;
+                //Crazy IE10 Matrix
+                else if (matrix.length === 16)
+                    curTransform = parseFloat(matrix[12]);
+                //Normal Browsers
+                else
+                    curTransform = parseFloat(matrix[4]);
+            }
+            if (axis === 'y') {
+                //Latest Chrome and webkits Fix
+                if (window.WebKitCSSMatrix)
+                    curTransform = transformMatrix.m42;
+                //Crazy IE10 Matrix
+                else if (matrix.length === 16)
+                    curTransform = parseFloat(matrix[13]);
+                //Normal Browsers
+                else
+                    curTransform = parseFloat(matrix[5]);
+            }
+            if (s.rtl && curTransform) curTransform = -curTransform;
+            return curTransform || 0;
+        };
+        s.getWrapperTranslate = function (axis) {
+            if (typeof axis === 'undefined') {
+                axis = s.isHorizontal() ? 'x' : 'y';
+            }
+            return s.getTranslate(s.wrapper[0], axis);
+        };
+        
+        /*=========================
+          Observer
+          ===========================*/
+        s.observers = [];
+        function initObserver(target, options) {
+            options = options || {};
+            // create an observer instance
+            var ObserverFunc = window.MutationObserver || window.WebkitMutationObserver;
+            var observer = new ObserverFunc(function (mutations) {
+                mutations.forEach(function (mutation) {
+                    s.onResize(true);
+                    s.emit('onObserverUpdate', s, mutation);
+                });
+            });
+        
+            observer.observe(target, {
+                attributes: typeof options.attributes === 'undefined' ? true : options.attributes,
+                childList: typeof options.childList === 'undefined' ? true : options.childList,
+                characterData: typeof options.characterData === 'undefined' ? true : options.characterData
+            });
+        
+            s.observers.push(observer);
+        }
+        s.initObservers = function () {
+            if (s.params.observeParents) {
+                var containerParents = s.container.parents();
+                for (var i = 0; i < containerParents.length; i++) {
+                    initObserver(containerParents[i]);
+                }
+            }
+        
+            // Observe container
+            initObserver(s.container[0], {childList: false});
+        
+            // Observe wrapper
+            initObserver(s.wrapper[0], {attributes: false});
+        };
+        s.disconnectObservers = function () {
+            for (var i = 0; i < s.observers.length; i++) {
+                s.observers[i].disconnect();
+            }
+            s.observers = [];
+        };
+        /*=========================
+          Loop
+          ===========================*/
+        // Create looped slides
+        s.createLoop = function () {
+            // Remove duplicated slides
+            s.wrapper.children('.' + s.params.slideClass + '.' + s.params.slideDuplicateClass).remove();
+        
+            var slides = s.wrapper.children('.' + s.params.slideClass);
+        
+            if(s.params.slidesPerView === 'auto' && !s.params.loopedSlides) s.params.loopedSlides = slides.length;
+        
+            s.loopedSlides = parseInt(s.params.loopedSlides || s.params.slidesPerView, 10);
+            s.loopedSlides = s.loopedSlides + s.params.loopAdditionalSlides;
+            if (s.loopedSlides > slides.length) {
+                s.loopedSlides = slides.length;
+            }
+        
+            var prependSlides = [], appendSlides = [], i;
+            slides.each(function (index, el) {
+                var slide = $(this);
+                if (index < s.loopedSlides) appendSlides.push(el);
+                if (index < slides.length && index >= slides.length - s.loopedSlides) prependSlides.push(el);
+                slide.attr('data-swiper-slide-index', index);
+            });
+            for (i = 0; i < appendSlides.length; i++) {
+                s.wrapper.append($(appendSlides[i].cloneNode(true)).addClass(s.params.slideDuplicateClass));
+            }
+            for (i = prependSlides.length - 1; i >= 0; i--) {
+                s.wrapper.prepend($(prependSlides[i].cloneNode(true)).addClass(s.params.slideDuplicateClass));
+            }
+        };
+        s.destroyLoop = function () {
+            s.wrapper.children('.' + s.params.slideClass + '.' + s.params.slideDuplicateClass).remove();
+            s.slides.removeAttr('data-swiper-slide-index');
+        };
+        s.reLoop = function (updatePosition) {
+            var oldIndex = s.activeIndex - s.loopedSlides;
+            s.destroyLoop();
+            s.createLoop();
+            s.updateSlidesSize();
+            if (updatePosition) {
+                s.slideTo(oldIndex + s.loopedSlides, 0, false);
+            }
+        
+        };
+        s.fixLoop = function () {
+            var newIndex;
+            //Fix For Negative Oversliding
+            if (s.activeIndex < s.loopedSlides) {
+                newIndex = s.slides.length - s.loopedSlides * 3 + s.activeIndex;
+                newIndex = newIndex + s.loopedSlides;
+                s.slideTo(newIndex, 0, false, true);
+            }
+            //Fix For Positive Oversliding
+            else if ((s.params.slidesPerView === 'auto' && s.activeIndex >= s.loopedSlides * 2) || (s.activeIndex > s.slides.length - s.params.slidesPerView * 2)) {
+                newIndex = -s.slides.length + s.activeIndex + s.loopedSlides;
+                newIndex = newIndex + s.loopedSlides;
+                s.slideTo(newIndex, 0, false, true);
+            }
+        };
+        /*=========================
+          Append/Prepend/Remove Slides
+          ===========================*/
+        s.appendSlide = function (slides) {
+            if (s.params.loop) {
+                s.destroyLoop();
+            }
+            if (typeof slides === 'object' && slides.length) {
+                for (var i = 0; i < slides.length; i++) {
+                    if (slides[i]) s.wrapper.append(slides[i]);
+                }
+            }
+            else {
+                s.wrapper.append(slides);
+            }
+            if (s.params.loop) {
+                s.createLoop();
+            }
+            if (!(s.params.observer && s.support.observer)) {
+                s.update(true);
+            }
+        };
+        s.prependSlide = function (slides) {
+            if (s.params.loop) {
+                s.destroyLoop();
+            }
+            var newActiveIndex = s.activeIndex + 1;
+            if (typeof slides === 'object' && slides.length) {
+                for (var i = 0; i < slides.length; i++) {
+                    if (slides[i]) s.wrapper.prepend(slides[i]);
+                }
+                newActiveIndex = s.activeIndex + slides.length;
+            }
+            else {
+                s.wrapper.prepend(slides);
+            }
+            if (s.params.loop) {
+                s.createLoop();
+            }
+            if (!(s.params.observer && s.support.observer)) {
+                s.update(true);
+            }
+            s.slideTo(newActiveIndex, 0, false);
+        };
+        s.removeSlide = function (slidesIndexes) {
+            if (s.params.loop) {
+                s.destroyLoop();
+                s.slides = s.wrapper.children('.' + s.params.slideClass);
+            }
+            var newActiveIndex = s.activeIndex,
+                indexToRemove;
+            if (typeof slidesIndexes === 'object' && slidesIndexes.length) {
+                for (var i = 0; i < slidesIndexes.length; i++) {
+                    indexToRemove = slidesIndexes[i];
+                    if (s.slides[indexToRemove]) s.slides.eq(indexToRemove).remove();
+                    if (indexToRemove < newActiveIndex) newActiveIndex--;
+                }
+                newActiveIndex = Math.max(newActiveIndex, 0);
+            }
+            else {
+                indexToRemove = slidesIndexes;
+                if (s.slides[indexToRemove]) s.slides.eq(indexToRemove).remove();
+                if (indexToRemove < newActiveIndex) newActiveIndex--;
+                newActiveIndex = Math.max(newActiveIndex, 0);
+            }
+        
+            if (s.params.loop) {
+                s.createLoop();
+            }
+        
+            if (!(s.params.observer && s.support.observer)) {
+                s.update(true);
+            }
+            if (s.params.loop) {
+                s.slideTo(newActiveIndex + s.loopedSlides, 0, false);
+            }
+            else {
+                s.slideTo(newActiveIndex, 0, false);
+            }
+        
+        };
+        s.removeAllSlides = function () {
+            var slidesIndexes = [];
+            for (var i = 0; i < s.slides.length; i++) {
+                slidesIndexes.push(i);
+            }
+            s.removeSlide(slidesIndexes);
+        };
+        
+
+        /*=========================
+          Effects
+          ===========================*/
+        s.effects = {
+            fade: {
+                setTranslate: function () {
+                    for (var i = 0; i < s.slides.length; i++) {
+                        var slide = s.slides.eq(i);
+                        var offset = slide[0].swiperSlideOffset;
+                        var tx = -offset;
+                        if (!s.params.virtualTranslate) tx = tx - s.translate;
+                        var ty = 0;
+                        if (!s.isHorizontal()) {
+                            ty = tx;
+                            tx = 0;
+                        }
+                        var slideOpacity = s.params.fade.crossFade ?
+                                Math.max(1 - Math.abs(slide[0].progress), 0) :
+                                1 + Math.min(Math.max(slide[0].progress, -1), 0);
+                        slide
+                            .css({
+                                opacity: slideOpacity
+                            })
+                            .transform('translate3d(' + tx + 'px, ' + ty + 'px, 0px)');
+        
+                    }
+        
+                },
+                setTransition: function (duration) {
+                    s.slides.transition(duration);
+                    if (s.params.virtualTranslate && duration !== 0) {
+                        var eventTriggered = false;
+                        s.slides.transitionEnd(function () {
+                            if (eventTriggered) return;
+                            if (!s) return;
+                            eventTriggered = true;
+                            s.animating = false;
+                            var triggerEvents = ['webkitTransitionEnd', 'transitionend', 'oTransitionEnd', 'MSTransitionEnd', 'msTransitionEnd'];
+                            for (var i = 0; i < triggerEvents.length; i++) {
+                                s.wrapper.trigger(triggerEvents[i]);
+                            }
+                        });
+                    }
+                }
+            },
+            flip: {
+                setTranslate: function () {
+                    for (var i = 0; i < s.slides.length; i++) {
+                        var slide = s.slides.eq(i);
+                        var progress = slide[0].progress;
+                        if (s.params.flip.limitRotation) {
+                            progress = Math.max(Math.min(slide[0].progress, 1), -1);
+                        }
+                        var offset = slide[0].swiperSlideOffset;
+                        var rotate = -180 * progress,
+                            rotateY = rotate,
+                            rotateX = 0,
+                            tx = -offset,
+                            ty = 0;
+                        if (!s.isHorizontal()) {
+                            ty = tx;
+                            tx = 0;
+                            rotateX = -rotateY;
+                            rotateY = 0;
+                        }
+                        else if (s.rtl) {
+                            rotateY = -rotateY;
+                        }
+        
+                        slide[0].style.zIndex = -Math.abs(Math.round(progress)) + s.slides.length;
+        
+                        if (s.params.flip.slideShadows) {
+                            //Set shadows
+                            var shadowBefore = s.isHorizontal() ? slide.find('.swiper-slide-shadow-left') : slide.find('.swiper-slide-shadow-top');
+                            var shadowAfter = s.isHorizontal() ? slide.find('.swiper-slide-shadow-right') : slide.find('.swiper-slide-shadow-bottom');
+                            if (shadowBefore.length === 0) {
+                                shadowBefore = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'left' : 'top') + '"></div>');
+                                slide.append(shadowBefore);
+                            }
+                            if (shadowAfter.length === 0) {
+                                shadowAfter = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'right' : 'bottom') + '"></div>');
+                                slide.append(shadowAfter);
+                            }
+                            if (shadowBefore.length) shadowBefore[0].style.opacity = Math.max(-progress, 0);
+                            if (shadowAfter.length) shadowAfter[0].style.opacity = Math.max(progress, 0);
+                        }
+        
+                        slide
+                            .transform('translate3d(' + tx + 'px, ' + ty + 'px, 0px) rotateX(' + rotateX + 'deg) rotateY(' + rotateY + 'deg)');
+                    }
+                },
+                setTransition: function (duration) {
+                    s.slides.transition(duration).find('.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left').transition(duration);
+                    if (s.params.virtualTranslate && duration !== 0) {
+                        var eventTriggered = false;
+                        s.slides.eq(s.activeIndex).transitionEnd(function () {
+                            if (eventTriggered) return;
+                            if (!s) return;
+                            if (!$(this).hasClass(s.params.slideActiveClass)) return;
+                            eventTriggered = true;
+                            s.animating = false;
+                            var triggerEvents = ['webkitTransitionEnd', 'transitionend', 'oTransitionEnd', 'MSTransitionEnd', 'msTransitionEnd'];
+                            for (var i = 0; i < triggerEvents.length; i++) {
+                                s.wrapper.trigger(triggerEvents[i]);
+                            }
+                        });
+                    }
+                }
+            },
+            cube: {
+                setTranslate: function () {
+                    var wrapperRotate = 0, cubeShadow;
+                    if (s.params.cube.shadow) {
+                        if (s.isHorizontal()) {
+                            cubeShadow = s.wrapper.find('.swiper-cube-shadow');
+                            if (cubeShadow.length === 0) {
+                                cubeShadow = $('<div class="swiper-cube-shadow"></div>');
+                                s.wrapper.append(cubeShadow);
+                            }
+                            cubeShadow.css({height: s.width + 'px'});
+                        }
+                        else {
+                            cubeShadow = s.container.find('.swiper-cube-shadow');
+                            if (cubeShadow.length === 0) {
+                                cubeShadow = $('<div class="swiper-cube-shadow"></div>');
+                                s.container.append(cubeShadow);
+                            }
+                        }
+                    }
+                    for (var i = 0; i < s.slides.length; i++) {
+                        var slide = s.slides.eq(i);
+                        var slideAngle = i * 90;
+                        var round = Math.floor(slideAngle / 360);
+                        if (s.rtl) {
+                            slideAngle = -slideAngle;
+                            round = Math.floor(-slideAngle / 360);
+                        }
+                        var progress = Math.max(Math.min(slide[0].progress, 1), -1);
+                        var tx = 0, ty = 0, tz = 0;
+                        if (i % 4 === 0) {
+                            tx = - round * 4 * s.size;
+                            tz = 0;
+                        }
+                        else if ((i - 1) % 4 === 0) {
+                            tx = 0;
+                            tz = - round * 4 * s.size;
+                        }
+                        else if ((i - 2) % 4 === 0) {
+                            tx = s.size + round * 4 * s.size;
+                            tz = s.size;
+                        }
+                        else if ((i - 3) % 4 === 0) {
+                            tx = - s.size;
+                            tz = 3 * s.size + s.size * 4 * round;
+                        }
+                        if (s.rtl) {
+                            tx = -tx;
+                        }
+        
+                        if (!s.isHorizontal()) {
+                            ty = tx;
+                            tx = 0;
+                        }
+        
+                        var transform = 'rotateX(' + (s.isHorizontal() ? 0 : -slideAngle) + 'deg) rotateY(' + (s.isHorizontal() ? slideAngle : 0) + 'deg) translate3d(' + tx + 'px, ' + ty + 'px, ' + tz + 'px)';
+                        if (progress <= 1 && progress > -1) {
+                            wrapperRotate = i * 90 + progress * 90;
+                            if (s.rtl) wrapperRotate = -i * 90 - progress * 90;
+                        }
+                        slide.transform(transform);
+                        if (s.params.cube.slideShadows) {
+                            //Set shadows
+                            var shadowBefore = s.isHorizontal() ? slide.find('.swiper-slide-shadow-left') : slide.find('.swiper-slide-shadow-top');
+                            var shadowAfter = s.isHorizontal() ? slide.find('.swiper-slide-shadow-right') : slide.find('.swiper-slide-shadow-bottom');
+                            if (shadowBefore.length === 0) {
+                                shadowBefore = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'left' : 'top') + '"></div>');
+                                slide.append(shadowBefore);
+                            }
+                            if (shadowAfter.length === 0) {
+                                shadowAfter = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'right' : 'bottom') + '"></div>');
+                                slide.append(shadowAfter);
+                            }
+                            if (shadowBefore.length) shadowBefore[0].style.opacity = Math.max(-progress, 0);
+                            if (shadowAfter.length) shadowAfter[0].style.opacity = Math.max(progress, 0);
+                        }
+                    }
+                    s.wrapper.css({
+                        '-webkit-transform-origin': '50% 50% -' + (s.size / 2) + 'px',
+                        '-moz-transform-origin': '50% 50% -' + (s.size / 2) + 'px',
+                        '-ms-transform-origin': '50% 50% -' + (s.size / 2) + 'px',
+                        'transform-origin': '50% 50% -' + (s.size / 2) + 'px'
+                    });
+        
+                    if (s.params.cube.shadow) {
+                        if (s.isHorizontal()) {
+                            cubeShadow.transform('translate3d(0px, ' + (s.width / 2 + s.params.cube.shadowOffset) + 'px, ' + (-s.width / 2) + 'px) rotateX(90deg) rotateZ(0deg) scale(' + (s.params.cube.shadowScale) + ')');
+                        }
+                        else {
+                            var shadowAngle = Math.abs(wrapperRotate) - Math.floor(Math.abs(wrapperRotate) / 90) * 90;
+                            var multiplier = 1.5 - (Math.sin(shadowAngle * 2 * Math.PI / 360) / 2 + Math.cos(shadowAngle * 2 * Math.PI / 360) / 2);
+                            var scale1 = s.params.cube.shadowScale,
+                                scale2 = s.params.cube.shadowScale / multiplier,
+                                offset = s.params.cube.shadowOffset;
+                            cubeShadow.transform('scale3d(' + scale1 + ', 1, ' + scale2 + ') translate3d(0px, ' + (s.height / 2 + offset) + 'px, ' + (-s.height / 2 / scale2) + 'px) rotateX(-90deg)');
+                        }
+                    }
+                    var zFactor = (s.isSafari || s.isUiWebView) ? (-s.size / 2) : 0;
+                    s.wrapper.transform('translate3d(0px,0,' + zFactor + 'px) rotateX(' + (s.isHorizontal() ? 0 : wrapperRotate) + 'deg) rotateY(' + (s.isHorizontal() ? -wrapperRotate : 0) + 'deg)');
+                },
+                setTransition: function (duration) {
+                    s.slides.transition(duration).find('.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left').transition(duration);
+                    if (s.params.cube.shadow && !s.isHorizontal()) {
+                        s.container.find('.swiper-cube-shadow').transition(duration);
+                    }
+                }
+            },
+            coverflow: {
+                setTranslate: function () {
+                    var transform = s.translate;
+                    var center = s.isHorizontal() ? -transform + s.width / 2 : -transform + s.height / 2;
+                    var rotate = s.isHorizontal() ? s.params.coverflow.rotate: -s.params.coverflow.rotate;
+                    var translate = s.params.coverflow.depth;
+                    //Each slide offset from center
+                    for (var i = 0, length = s.slides.length; i < length; i++) {
+                        var slide = s.slides.eq(i);
+                        var slideSize = s.slidesSizesGrid[i];
+                        var slideOffset = slide[0].swiperSlideOffset;
+                        var offsetMultiplier = (center - slideOffset - slideSize / 2) / slideSize * s.params.coverflow.modifier;
+        
+                        var rotateY = s.isHorizontal() ? rotate * offsetMultiplier : 0;
+                        var rotateX = s.isHorizontal() ? 0 : rotate * offsetMultiplier;
+                        // var rotateZ = 0
+                        var translateZ = -translate * Math.abs(offsetMultiplier);
+        
+                        var translateY = s.isHorizontal() ? 0 : s.params.coverflow.stretch * (offsetMultiplier);
+                        var translateX = s.isHorizontal() ? s.params.coverflow.stretch * (offsetMultiplier) : 0;
+        
+                        //Fix for ultra small values
+                        if (Math.abs(translateX) < 0.001) translateX = 0;
+                        if (Math.abs(translateY) < 0.001) translateY = 0;
+                        if (Math.abs(translateZ) < 0.001) translateZ = 0;
+                        if (Math.abs(rotateY) < 0.001) rotateY = 0;
+                        if (Math.abs(rotateX) < 0.001) rotateX = 0;
+        
+                        var slideTransform = 'translate3d(' + translateX + 'px,' + translateY + 'px,' + translateZ + 'px)  rotateX(' + rotateX + 'deg) rotateY(' + rotateY + 'deg)';
+        
+                        slide.transform(slideTransform);
+                        slide[0].style.zIndex = -Math.abs(Math.round(offsetMultiplier)) + 1;
+                        if (s.params.coverflow.slideShadows) {
+                            //Set shadows
+                            var shadowBefore = s.isHorizontal() ? slide.find('.swiper-slide-shadow-left') : slide.find('.swiper-slide-shadow-top');
+                            var shadowAfter = s.isHorizontal() ? slide.find('.swiper-slide-shadow-right') : slide.find('.swiper-slide-shadow-bottom');
+                            if (shadowBefore.length === 0) {
+                                shadowBefore = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'left' : 'top') + '"></div>');
+                                slide.append(shadowBefore);
+                            }
+                            if (shadowAfter.length === 0) {
+                                shadowAfter = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'right' : 'bottom') + '"></div>');
+                                slide.append(shadowAfter);
+                            }
+                            if (shadowBefore.length) shadowBefore[0].style.opacity = offsetMultiplier > 0 ? offsetMultiplier : 0;
+                            if (shadowAfter.length) shadowAfter[0].style.opacity = (-offsetMultiplier) > 0 ? -offsetMultiplier : 0;
+                        }
+                    }
+        
+                    //Set correct perspective for IE10
+                    if (s.browser.ie) {
+                        var ws = s.wrapper[0].style;
+                        ws.perspectiveOrigin = center + 'px 50%';
+                    }
+                },
+                setTransition: function (duration) {
+                    s.slides.transition(duration).find('.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left').transition(duration);
+                }
+            }
+        };
+
+        /*=========================
+          Images Lazy Loading
+          ===========================*/
+        s.lazy = {
+            initialImageLoaded: false,
+            loadImageInSlide: function (index, loadInDuplicate) {
+                if (typeof index === 'undefined') return;
+                if (typeof loadInDuplicate === 'undefined') loadInDuplicate = true;
+                if (s.slides.length === 0) return;
+        
+                var slide = s.slides.eq(index);
+                var img = slide.find('.swiper-lazy:not(.swiper-lazy-loaded):not(.swiper-lazy-loading)');
+                if (slide.hasClass('swiper-lazy') && !slide.hasClass('swiper-lazy-loaded') && !slide.hasClass('swiper-lazy-loading')) {
+                    img = img.add(slide[0]);
+                }
+                if (img.length === 0) return;
+        
+                img.each(function () {
+                    var _img = $(this);
+                    _img.addClass('swiper-lazy-loading');
+                    var background = _img.attr('data-background');
+                    var src = _img.attr('data-src'),
+                        srcset = _img.attr('data-srcset');
+                    s.loadImage(_img[0], (src || background), srcset, false, function () {
+                        if (background) {
+                            _img.css('background-image', 'url("' + background + '")');
+                            _img.removeAttr('data-background');
+                        }
+                        else {
+                            if (srcset) {
+                                _img.attr('srcset', srcset);
+                                _img.removeAttr('data-srcset');
+                            }
+                            if (src) {
+                                _img.attr('src', src);
+                                _img.removeAttr('data-src');
+                            }
+        
+                        }
+        
+                        _img.addClass('swiper-lazy-loaded').removeClass('swiper-lazy-loading');
+                        slide.find('.swiper-lazy-preloader, .preloader').remove();
+                        if (s.params.loop && loadInDuplicate) {
+                            var slideOriginalIndex = slide.attr('data-swiper-slide-index');
+                            if (slide.hasClass(s.params.slideDuplicateClass)) {
+                                var originalSlide = s.wrapper.children('[data-swiper-slide-index="' + slideOriginalIndex + '"]:not(.' + s.params.slideDuplicateClass + ')');
+                                s.lazy.loadImageInSlide(originalSlide.index(), false);
+                            }
+                            else {
+                                var duplicatedSlide = s.wrapper.children('.' + s.params.slideDuplicateClass + '[data-swiper-slide-index="' + slideOriginalIndex + '"]');
+                                s.lazy.loadImageInSlide(duplicatedSlide.index(), false);
+                            }
+                        }
+                        s.emit('onLazyImageReady', s, slide[0], _img[0]);
+                    });
+        
+                    s.emit('onLazyImageLoad', s, slide[0], _img[0]);
+                });
+        
+            },
+            load: function () {
+                var i;
+                if (s.params.watchSlidesVisibility) {
+                    s.wrapper.children('.' + s.params.slideVisibleClass).each(function () {
+                        s.lazy.loadImageInSlide($(this).index());
+                    });
+                }
+                else {
+                    if (s.params.slidesPerView > 1) {
+                        for (i = s.activeIndex; i < s.activeIndex + s.params.slidesPerView ; i++) {
+                            if (s.slides[i]) s.lazy.loadImageInSlide(i);
+                        }
+                    }
+                    else {
+                        s.lazy.loadImageInSlide(s.activeIndex);
+                    }
+                }
+                if (s.params.lazyLoadingInPrevNext) {
+                    if (s.params.slidesPerView > 1 || (s.params.lazyLoadingInPrevNextAmount && s.params.lazyLoadingInPrevNextAmount > 1)) {
+                        var amount = s.params.lazyLoadingInPrevNextAmount;
+                        var spv = s.params.slidesPerView;
+                        var maxIndex = Math.min(s.activeIndex + spv + Math.max(amount, spv), s.slides.length);
+                        var minIndex = Math.max(s.activeIndex - Math.max(spv, amount), 0);
+                        // Next Slides
+                        for (i = s.activeIndex + s.params.slidesPerView; i < maxIndex; i++) {
+                            if (s.slides[i]) s.lazy.loadImageInSlide(i);
+                        }
+                        // Prev Slides
+                        for (i = minIndex; i < s.activeIndex ; i++) {
+                            if (s.slides[i]) s.lazy.loadImageInSlide(i);
+                        }
+                    }
+                    else {
+                        var nextSlide = s.wrapper.children('.' + s.params.slideNextClass);
+                        if (nextSlide.length > 0) s.lazy.loadImageInSlide(nextSlide.index());
+        
+                        var prevSlide = s.wrapper.children('.' + s.params.slidePrevClass);
+                        if (prevSlide.length > 0) s.lazy.loadImageInSlide(prevSlide.index());
+                    }
+                }
+            },
+            onTransitionStart: function () {
+                if (s.params.lazyLoading) {
+                    if (s.params.lazyLoadingOnTransitionStart || (!s.params.lazyLoadingOnTransitionStart && !s.lazy.initialImageLoaded)) {
+                        s.lazy.load();
+                    }
+                }
+            },
+            onTransitionEnd: function () {
+                if (s.params.lazyLoading && !s.params.lazyLoadingOnTransitionStart) {
+                    s.lazy.load();
+                }
+            }
+        };
+        
+
+        /*=========================
+          Scrollbar
+          ===========================*/
+        s.scrollbar = {
+            isTouched: false,
+            setDragPosition: function (e) {
+                var sb = s.scrollbar;
+                var x = 0, y = 0;
+                var translate;
+                var pointerPosition = s.isHorizontal() ?
+                    ((e.type === 'touchstart' || e.type === 'touchmove') ? e.targetTouches[0].pageX : e.pageX || e.clientX) :
+                    ((e.type === 'touchstart' || e.type === 'touchmove') ? e.targetTouches[0].pageY : e.pageY || e.clientY) ;
+                var position = (pointerPosition) - sb.track.offset()[s.isHorizontal() ? 'left' : 'top'] - sb.dragSize / 2;
+                var positionMin = -s.minTranslate() * sb.moveDivider;
+                var positionMax = -s.maxTranslate() * sb.moveDivider;
+                if (position < positionMin) {
+                    position = positionMin;
+                }
+                else if (position > positionMax) {
+                    position = positionMax;
+                }
+                position = -position / sb.moveDivider;
+                s.updateProgress(position);
+                s.setWrapperTranslate(position, true);
+            },
+            dragStart: function (e) {
+                var sb = s.scrollbar;
+                sb.isTouched = true;
+                e.preventDefault();
+                e.stopPropagation();
+        
+                sb.setDragPosition(e);
+                clearTimeout(sb.dragTimeout);
+        
+                sb.track.transition(0);
+                if (s.params.scrollbarHide) {
+                    sb.track.css('opacity', 1);
+                }
+                s.wrapper.transition(100);
+                sb.drag.transition(100);
+                s.emit('onScrollbarDragStart', s);
+            },
+            dragMove: function (e) {
+                var sb = s.scrollbar;
+                if (!sb.isTouched) return;
+                if (e.preventDefault) e.preventDefault();
+                else e.returnValue = false;
+                sb.setDragPosition(e);
+                s.wrapper.transition(0);
+                sb.track.transition(0);
+                sb.drag.transition(0);
+                s.emit('onScrollbarDragMove', s);
+            },
+            dragEnd: function (e) {
+                var sb = s.scrollbar;
+                if (!sb.isTouched) return;
+                sb.isTouched = false;
+                if (s.params.scrollbarHide) {
+                    clearTimeout(sb.dragTimeout);
+                    sb.dragTimeout = setTimeout(function () {
+                        sb.track.css('opacity', 0);
+                        sb.track.transition(400);
+                    }, 1000);
+        
+                }
+                s.emit('onScrollbarDragEnd', s);
+                if (s.params.scrollbarSnapOnRelease) {
+                    s.slideReset();
+                }
+            },
+            enableDraggable: function () {
+                var sb = s.scrollbar;
+                var target = s.support.touch ? sb.track : document;
+                $(sb.track).on(s.touchEvents.start, sb.dragStart);
+                $(target).on(s.touchEvents.move, sb.dragMove);
+                $(target).on(s.touchEvents.end, sb.dragEnd);
+            },
+            disableDraggable: function () {
+                var sb = s.scrollbar;
+                var target = s.support.touch ? sb.track : document;
+                $(sb.track).off(s.touchEvents.start, sb.dragStart);
+                $(target).off(s.touchEvents.move, sb.dragMove);
+                $(target).off(s.touchEvents.end, sb.dragEnd);
+            },
+            set: function () {
+                if (!s.params.scrollbar) return;
+                var sb = s.scrollbar;
+                sb.track = $(s.params.scrollbar);
+                if (s.params.uniqueNavElements && typeof s.params.scrollbar === 'string' && sb.track.length > 1 && s.container.find(s.params.scrollbar).length === 1) {
+                    sb.track = s.container.find(s.params.scrollbar);
+                }
+                sb.drag = sb.track.find('.swiper-scrollbar-drag');
+                if (sb.drag.length === 0) {
+                    sb.drag = $('<div class="swiper-scrollbar-drag"></div>');
+                    sb.track.append(sb.drag);
+                }
+                sb.drag[0].style.width = '';
+                sb.drag[0].style.height = '';
+                sb.trackSize = s.isHorizontal() ? sb.track[0].offsetWidth : sb.track[0].offsetHeight;
+        
+                sb.divider = s.size / s.virtualSize;
+                sb.moveDivider = sb.divider * (sb.trackSize / s.size);
+                sb.dragSize = sb.trackSize * sb.divider;
+        
+                if (s.isHorizontal()) {
+                    sb.drag[0].style.width = sb.dragSize + 'px';
+                }
+                else {
+                    sb.drag[0].style.height = sb.dragSize + 'px';
+                }
+        
+                if (sb.divider >= 1) {
+                    sb.track[0].style.display = 'none';
+                }
+                else {
+                    sb.track[0].style.display = '';
+                }
+                if (s.params.scrollbarHide) {
+                    sb.track[0].style.opacity = 0;
+                }
+            },
+            setTranslate: function () {
+                if (!s.params.scrollbar) return;
+                var diff;
+                var sb = s.scrollbar;
+                var translate = s.translate || 0;
+                var newPos;
+        
+                var newSize = sb.dragSize;
+                newPos = (sb.trackSize - sb.dragSize) * s.progress;
+                if (s.rtl && s.isHorizontal()) {
+                    newPos = -newPos;
+                    if (newPos > 0) {
+                        newSize = sb.dragSize - newPos;
+                        newPos = 0;
+                    }
+                    else if (-newPos + sb.dragSize > sb.trackSize) {
+                        newSize = sb.trackSize + newPos;
+                    }
+                }
+                else {
+                    if (newPos < 0) {
+                        newSize = sb.dragSize + newPos;
+                        newPos = 0;
+                    }
+                    else if (newPos + sb.dragSize > sb.trackSize) {
+                        newSize = sb.trackSize - newPos;
+                    }
+                }
+                if (s.isHorizontal()) {
+                    if (s.support.transforms3d) {
+                        sb.drag.transform('translate3d(' + (newPos) + 'px, 0, 0)');
+                    }
+                    else {
+                        sb.drag.transform('translateX(' + (newPos) + 'px)');
+                    }
+                    sb.drag[0].style.width = newSize + 'px';
+                }
+                else {
+                    if (s.support.transforms3d) {
+                        sb.drag.transform('translate3d(0px, ' + (newPos) + 'px, 0)');
+                    }
+                    else {
+                        sb.drag.transform('translateY(' + (newPos) + 'px)');
+                    }
+                    sb.drag[0].style.height = newSize + 'px';
+                }
+                if (s.params.scrollbarHide) {
+                    clearTimeout(sb.timeout);
+                    sb.track[0].style.opacity = 1;
+                    sb.timeout = setTimeout(function () {
+                        sb.track[0].style.opacity = 0;
+                        sb.track.transition(400);
+                    }, 1000);
+                }
+            },
+            setTransition: function (duration) {
+                if (!s.params.scrollbar) return;
+                s.scrollbar.drag.transition(duration);
+            }
+        };
+
+        /*=========================
+          Controller
+          ===========================*/
+        s.controller = {
+            LinearSpline: function (x, y) {
+                this.x = x;
+                this.y = y;
+                this.lastIndex = x.length - 1;
+                // Given an x value (x2), return the expected y2 value:
+                // (x1,y1) is the known point before given value,
+                // (x3,y3) is the known point after given value.
+                var i1, i3;
+                var l = this.x.length;
+        
+                this.interpolate = function (x2) {
+                    if (!x2) return 0;
+        
+                    // Get the indexes of x1 and x3 (the array indexes before and after given x2):
+                    i3 = binarySearch(this.x, x2);
+                    i1 = i3 - 1;
+        
+                    // We have our indexes i1 & i3, so we can calculate already:
+                    // y2 := ((x2−x1) × (y3−y1)) ÷ (x3−x1) + y1
+                    return ((x2 - this.x[i1]) * (this.y[i3] - this.y[i1])) / (this.x[i3] - this.x[i1]) + this.y[i1];
+                };
+        
+                var binarySearch = (function() {
+                    var maxIndex, minIndex, guess;
+                    return function(array, val) {
+                        minIndex = -1;
+                        maxIndex = array.length;
+                        while (maxIndex - minIndex > 1)
+                            if (array[guess = maxIndex + minIndex >> 1] <= val) {
+                                minIndex = guess;
+                            } else {
+                                maxIndex = guess;
+                            }
+                        return maxIndex;
+                    };
+                })();
+            },
+            //xxx: for now i will just save one spline function to to
+            getInterpolateFunction: function(c){
+                if(!s.controller.spline) s.controller.spline = s.params.loop ?
+                    new s.controller.LinearSpline(s.slidesGrid, c.slidesGrid) :
+                    new s.controller.LinearSpline(s.snapGrid, c.snapGrid);
+            },
+            setTranslate: function (translate, byController) {
+               var controlled = s.params.control;
+               var multiplier, controlledTranslate;
+               function setControlledTranslate(c) {
+                    // this will create an Interpolate function based on the snapGrids
+                    // x is the Grid of the scrolled scroller and y will be the controlled scroller
+                    // it makes sense to create this only once and recall it for the interpolation
+                    // the function does a lot of value caching for performance
+                    translate = c.rtl && c.params.direction === 'horizontal' ? -s.translate : s.translate;
+                    if (s.params.controlBy === 'slide') {
+                        s.controller.getInterpolateFunction(c);
+                        // i am not sure why the values have to be multiplicated this way, tried to invert the snapGrid
+                        // but it did not work out
+                        controlledTranslate = -s.controller.spline.interpolate(-translate);
+                    }
+        
+                    if(!controlledTranslate || s.params.controlBy === 'container'){
+                        multiplier = (c.maxTranslate() - c.minTranslate()) / (s.maxTranslate() - s.minTranslate());
+                        controlledTranslate = (translate - s.minTranslate()) * multiplier + c.minTranslate();
+                    }
+        
+                    if (s.params.controlInverse) {
+                        controlledTranslate = c.maxTranslate() - controlledTranslate;
+                    }
+                    c.updateProgress(controlledTranslate);
+                    c.setWrapperTranslate(controlledTranslate, false, s);
+                    c.updateActiveIndex();
+               }
+               if (s.isArray(controlled)) {
+                   for (var i = 0; i < controlled.length; i++) {
+                       if (controlled[i] !== byController && controlled[i] instanceof Swiper) {
+                           setControlledTranslate(controlled[i]);
+                       }
+                   }
+               }
+               else if (controlled instanceof Swiper && byController !== controlled) {
+        
+                   setControlledTranslate(controlled);
+               }
+            },
+            setTransition: function (duration, byController) {
+                var controlled = s.params.control;
+                var i;
+                function setControlledTransition(c) {
+                    c.setWrapperTransition(duration, s);
+                    if (duration !== 0) {
+                        c.onTransitionStart();
+                        c.wrapper.transitionEnd(function(){
+                            if (!controlled) return;
+                            if (c.params.loop && s.params.controlBy === 'slide') {
+                                c.fixLoop();
+                            }
+                            c.onTransitionEnd();
+        
+                        });
+                    }
+                }
+                if (s.isArray(controlled)) {
+                    for (i = 0; i < controlled.length; i++) {
+                        if (controlled[i] !== byController && controlled[i] instanceof Swiper) {
+                            setControlledTransition(controlled[i]);
+                        }
+                    }
+                }
+                else if (controlled instanceof Swiper && byController !== controlled) {
+                    setControlledTransition(controlled);
+                }
+            }
+        };
+
+        /*=========================
+          Hash Navigation
+          ===========================*/
+        s.hashnav = {
+            init: function () {
+                if (!s.params.hashnav) return;
+                s.hashnav.initialized = true;
+                var hash = document.location.hash.replace('#', '');
+                if (!hash) return;
+                var speed = 0;
+                for (var i = 0, length = s.slides.length; i < length; i++) {
+                    var slide = s.slides.eq(i);
+                    var slideHash = slide.attr('data-hash');
+                    if (slideHash === hash && !slide.hasClass(s.params.slideDuplicateClass)) {
+                        var index = slide.index();
+                        s.slideTo(index, speed, s.params.runCallbacksOnInit, true);
+                    }
+                }
+            },
+            setHash: function () {
+                if (!s.hashnav.initialized || !s.params.hashnav) return;
+                document.location.hash = s.slides.eq(s.activeIndex).attr('data-hash') || '';
+            }
+        };
+
+        /*=========================
+          Keyboard Control
+          ===========================*/
+        function handleKeyboard(e) {
+            if (e.originalEvent) e = e.originalEvent; //jquery fix
+            var kc = e.keyCode || e.charCode;
+            // Directions locks
+            if (!s.params.allowSwipeToNext && (s.isHorizontal() && kc === 39 || !s.isHorizontal() && kc === 40)) {
+                return false;
+            }
+            if (!s.params.allowSwipeToPrev && (s.isHorizontal() && kc === 37 || !s.isHorizontal() && kc === 38)) {
+                return false;
+            }
+            if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey) {
+                return;
+            }
+            if (document.activeElement && document.activeElement.nodeName && (document.activeElement.nodeName.toLowerCase() === 'input' || document.activeElement.nodeName.toLowerCase() === 'textarea')) {
+                return;
+            }
+            if (kc === 37 || kc === 39 || kc === 38 || kc === 40) {
+                var inView = false;
+                //Check that swiper should be inside of visible area of window
+                if (s.container.parents('.swiper-slide').length > 0 && s.container.parents('.swiper-slide-active').length === 0) {
+                    return;
+                }
+                var windowScroll = {
+                    left: window.pageXOffset,
+                    top: window.pageYOffset
+                };
+                var windowWidth = window.innerWidth;
+                var windowHeight = window.innerHeight;
+                var swiperOffset = s.container.offset();
+                if (s.rtl) swiperOffset.left = swiperOffset.left - s.container[0].scrollLeft;
+                var swiperCoord = [
+                    [swiperOffset.left, swiperOffset.top],
+                    [swiperOffset.left + s.width, swiperOffset.top],
+                    [swiperOffset.left, swiperOffset.top + s.height],
+                    [swiperOffset.left + s.width, swiperOffset.top + s.height]
+                ];
+                for (var i = 0; i < swiperCoord.length; i++) {
+                    var point = swiperCoord[i];
+                    if (
+                        point[0] >= windowScroll.left && point[0] <= windowScroll.left + windowWidth &&
+                        point[1] >= windowScroll.top && point[1] <= windowScroll.top + windowHeight
+                    ) {
+                        inView = true;
+                    }
+        
+                }
+                if (!inView) return;
+            }
+            if (s.isHorizontal()) {
+                if (kc === 37 || kc === 39) {
+                    if (e.preventDefault) e.preventDefault();
+                    else e.returnValue = false;
+                }
+                if ((kc === 39 && !s.rtl) || (kc === 37 && s.rtl)) s.slideNext();
+                if ((kc === 37 && !s.rtl) || (kc === 39 && s.rtl)) s.slidePrev();
+            }
+            else {
+                if (kc === 38 || kc === 40) {
+                    if (e.preventDefault) e.preventDefault();
+                    else e.returnValue = false;
+                }
+                if (kc === 40) s.slideNext();
+                if (kc === 38) s.slidePrev();
+            }
+        }
+        s.disableKeyboardControl = function () {
+            s.params.keyboardControl = false;
+            $(document).off('keydown', handleKeyboard);
+        };
+        s.enableKeyboardControl = function () {
+            s.params.keyboardControl = true;
+            $(document).on('keydown', handleKeyboard);
+        };
+        
+
+        /*=========================
+          Mousewheel Control
+          ===========================*/
+        s.mousewheel = {
+            event: false,
+            lastScrollTime: (new window.Date()).getTime()
+        };
+        if (s.params.mousewheelControl) {
+            try {
+                new window.WheelEvent('wheel');
+                s.mousewheel.event = 'wheel';
+            } catch (e) {
+                if (window.WheelEvent || (s.container[0] && 'wheel' in s.container[0])) {
+                    s.mousewheel.event = 'wheel';
+                }
+            }
+            if (!s.mousewheel.event && window.WheelEvent) {
+        
+            }
+            if (!s.mousewheel.event && document.onmousewheel !== undefined) {
+                s.mousewheel.event = 'mousewheel';
+            }
+            if (!s.mousewheel.event) {
+                s.mousewheel.event = 'DOMMouseScroll';
+            }
+        }
+        function handleMousewheel(e) {
+            if (e.originalEvent) e = e.originalEvent; //jquery fix
+            var we = s.mousewheel.event;
+            var delta = 0;
+            var rtlFactor = s.rtl ? -1 : 1;
+        
+            //WebKits
+            if (we === 'mousewheel') {
+                if (s.params.mousewheelForceToAxis) {
+                    if (s.isHorizontal()) {
+                        if (Math.abs(e.wheelDeltaX) > Math.abs(e.wheelDeltaY)) delta = e.wheelDeltaX * rtlFactor;
+                        else return;
+                    }
+                    else {
+                        if (Math.abs(e.wheelDeltaY) > Math.abs(e.wheelDeltaX)) delta = e.wheelDeltaY;
+                        else return;
+                    }
+                }
+                else {
+                    delta = Math.abs(e.wheelDeltaX) > Math.abs(e.wheelDeltaY) ? - e.wheelDeltaX * rtlFactor : - e.wheelDeltaY;
+                }
+            }
+            //Old FireFox
+            else if (we === 'DOMMouseScroll') delta = -e.detail;
+            //New FireFox
+            else if (we === 'wheel') {
+                if (s.params.mousewheelForceToAxis) {
+                    if (s.isHorizontal()) {
+                        if (Math.abs(e.deltaX) > Math.abs(e.deltaY)) delta = -e.deltaX * rtlFactor;
+                        else return;
+                    }
+                    else {
+                        if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) delta = -e.deltaY;
+                        else return;
+                    }
+                }
+                else {
+                    delta = Math.abs(e.deltaX) > Math.abs(e.deltaY) ? - e.deltaX * rtlFactor : - e.deltaY;
+                }
+            }
+            if (delta === 0) return;
+        
+            if (s.params.mousewheelInvert) delta = -delta;
+        
+            if (!s.params.freeMode) {
+                if ((new window.Date()).getTime() - s.mousewheel.lastScrollTime > 60) {
+                    if (delta < 0) {
+                        if ((!s.isEnd || s.params.loop) && !s.animating) s.slideNext();
+                        else if (s.params.mousewheelReleaseOnEdges) return true;
+                    }
+                    else {
+                        if ((!s.isBeginning || s.params.loop) && !s.animating) s.slidePrev();
+                        else if (s.params.mousewheelReleaseOnEdges) return true;
+                    }
+                }
+                s.mousewheel.lastScrollTime = (new window.Date()).getTime();
+        
+            }
+            else {
+                //Freemode or scrollContainer:
+                var position = s.getWrapperTranslate() + delta * s.params.mousewheelSensitivity;
+                var wasBeginning = s.isBeginning,
+                    wasEnd = s.isEnd;
+        
+                if (position >= s.minTranslate()) position = s.minTranslate();
+                if (position <= s.maxTranslate()) position = s.maxTranslate();
+        
+                s.setWrapperTransition(0);
+                s.setWrapperTranslate(position);
+                s.updateProgress();
+                s.updateActiveIndex();
+        
+                if (!wasBeginning && s.isBeginning || !wasEnd && s.isEnd) {
+                    s.updateClasses();
+                }
+        
+                if (s.params.freeModeSticky) {
+                    clearTimeout(s.mousewheel.timeout);
+                    s.mousewheel.timeout = setTimeout(function () {
+                        s.slideReset();
+                    }, 300);
+                }
+                else {
+                    if (s.params.lazyLoading && s.lazy) {
+                        s.lazy.load();
+                    }
+                }
+        
+                // Return page scroll on edge positions
+                if (position === 0 || position === s.maxTranslate()) return;
+            }
+            if (s.params.autoplay) s.stopAutoplay();
+        
+            if (e.preventDefault) e.preventDefault();
+            else e.returnValue = false;
+            return false;
+        }
+        s.disableMousewheelControl = function () {
+            if (!s.mousewheel.event) return false;
+            s.container.off(s.mousewheel.event, handleMousewheel);
+            return true;
+        };
+        
+        s.enableMousewheelControl = function () {
+            if (!s.mousewheel.event) return false;
+            s.container.on(s.mousewheel.event, handleMousewheel);
+            return true;
+        };
+        
+
+        /*=========================
+          Parallax
+          ===========================*/
+        function setParallaxTransform(el, progress) {
+            el = $(el);
+            var p, pX, pY;
+            var rtlFactor = s.rtl ? -1 : 1;
+        
+            p = el.attr('data-swiper-parallax') || '0';
+            pX = el.attr('data-swiper-parallax-x');
+            pY = el.attr('data-swiper-parallax-y');
+            if (pX || pY) {
+                pX = pX || '0';
+                pY = pY || '0';
+            }
+            else {
+                if (s.isHorizontal()) {
+                    pX = p;
+                    pY = '0';
+                }
+                else {
+                    pY = p;
+                    pX = '0';
+                }
+            }
+        
+            if ((pX).indexOf('%') >= 0) {
+                pX = parseInt(pX, 10) * progress * rtlFactor + '%';
+            }
+            else {
+                pX = pX * progress * rtlFactor + 'px' ;
+            }
+            if ((pY).indexOf('%') >= 0) {
+                pY = parseInt(pY, 10) * progress + '%';
+            }
+            else {
+                pY = pY * progress + 'px' ;
+            }
+        
+            el.transform('translate3d(' + pX + ', ' + pY + ',0px)');
+        }
+        s.parallax = {
+            setTranslate: function () {
+                s.container.children('[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]').each(function(){
+                    setParallaxTransform(this, s.progress);
+        
+                });
+                s.slides.each(function () {
+                    var slide = $(this);
+                    slide.find('[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]').each(function () {
+                        var progress = Math.min(Math.max(slide[0].progress, -1), 1);
+                        setParallaxTransform(this, progress);
+                    });
+                });
+            },
+            setTransition: function (duration) {
+                if (typeof duration === 'undefined') duration = s.params.speed;
+                s.container.find('[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]').each(function(){
+                    var el = $(this);
+                    var parallaxDuration = parseInt(el.attr('data-swiper-parallax-duration'), 10) || duration;
+                    if (duration === 0) parallaxDuration = 0;
+                    el.transition(parallaxDuration);
+                });
+            }
+        };
+        
+
+        /*=========================
+          Plugins API. Collect all and init all plugins
+          ===========================*/
+        s._plugins = [];
+        for (var plugin in s.plugins) {
+            var p = s.plugins[plugin](s, s.params[plugin]);
+            if (p) s._plugins.push(p);
+        }
+        // Method to call all plugins event/method
+        s.callPlugins = function (eventName) {
+            for (var i = 0; i < s._plugins.length; i++) {
+                if (eventName in s._plugins[i]) {
+                    s._plugins[i][eventName](arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
+                }
+            }
+        };
+
+        /*=========================
+          Events/Callbacks/Plugins Emitter
+          ===========================*/
+        function normalizeEventName (eventName) {
+            if (eventName.indexOf('on') !== 0) {
+                if (eventName[0] !== eventName[0].toUpperCase()) {
+                    eventName = 'on' + eventName[0].toUpperCase() + eventName.substring(1);
+                }
+                else {
+                    eventName = 'on' + eventName;
+                }
+            }
+            return eventName;
+        }
+        s.emitterEventListeners = {
+        
+        };
+        s.emit = function (eventName) {
+            // Trigger callbacks
+            if (s.params[eventName]) {
+                s.params[eventName](arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
+            }
+            var i;
+            // Trigger events
+            if (s.emitterEventListeners[eventName]) {
+                for (i = 0; i < s.emitterEventListeners[eventName].length; i++) {
+                    s.emitterEventListeners[eventName][i](arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
+                }
+            }
+            // Trigger plugins
+            if (s.callPlugins) s.callPlugins(eventName, arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
+        };
+        s.on = function (eventName, handler) {
+            eventName = normalizeEventName(eventName);
+            if (!s.emitterEventListeners[eventName]) s.emitterEventListeners[eventName] = [];
+            s.emitterEventListeners[eventName].push(handler);
+            return s;
+        };
+        s.off = function (eventName, handler) {
+            var i;
+            eventName = normalizeEventName(eventName);
+            if (typeof handler === 'undefined') {
+                // Remove all handlers for such event
+                s.emitterEventListeners[eventName] = [];
+                return s;
+            }
+            if (!s.emitterEventListeners[eventName] || s.emitterEventListeners[eventName].length === 0) return;
+            for (i = 0; i < s.emitterEventListeners[eventName].length; i++) {
+                if(s.emitterEventListeners[eventName][i] === handler) s.emitterEventListeners[eventName].splice(i, 1);
+            }
+            return s;
+        };
+        s.once = function (eventName, handler) {
+            eventName = normalizeEventName(eventName);
+            var _handler = function () {
+                handler(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);
+                s.off(eventName, _handler);
+            };
+            s.on(eventName, _handler);
+            return s;
+        };
+
+        // Accessibility tools
+        s.a11y = {
+            makeFocusable: function ($el) {
+                $el.attr('tabIndex', '0');
+                return $el;
+            },
+            addRole: function ($el, role) {
+                $el.attr('role', role);
+                return $el;
+            },
+        
+            addLabel: function ($el, label) {
+                $el.attr('aria-label', label);
+                return $el;
+            },
+        
+            disable: function ($el) {
+                $el.attr('aria-disabled', true);
+                return $el;
+            },
+        
+            enable: function ($el) {
+                $el.attr('aria-disabled', false);
+                return $el;
+            },
+        
+            onEnterKey: function (event) {
+                if (event.keyCode !== 13) return;
+                if ($(event.target).is(s.params.nextButton)) {
+                    s.onClickNext(event);
+                    if (s.isEnd) {
+                        s.a11y.notify(s.params.lastSlideMessage);
+                    }
+                    else {
+                        s.a11y.notify(s.params.nextSlideMessage);
+                    }
+                }
+                else if ($(event.target).is(s.params.prevButton)) {
+                    s.onClickPrev(event);
+                    if (s.isBeginning) {
+                        s.a11y.notify(s.params.firstSlideMessage);
+                    }
+                    else {
+                        s.a11y.notify(s.params.prevSlideMessage);
+                    }
+                }
+                if ($(event.target).is('.' + s.params.bulletClass)) {
+                    $(event.target)[0].click();
+                }
+            },
+        
+            liveRegion: $('<span class="swiper-notification" aria-live="assertive" aria-atomic="true"></span>'),
+        
+            notify: function (message) {
+                var notification = s.a11y.liveRegion;
+                if (notification.length === 0) return;
+                notification.html('');
+                notification.html(message);
+            },
+            init: function () {
+                // Setup accessibility
+                if (s.params.nextButton && s.nextButton && s.nextButton.length > 0) {
+                    s.a11y.makeFocusable(s.nextButton);
+                    s.a11y.addRole(s.nextButton, 'button');
+                    s.a11y.addLabel(s.nextButton, s.params.nextSlideMessage);
+                }
+                if (s.params.prevButton && s.prevButton && s.prevButton.length > 0) {
+                    s.a11y.makeFocusable(s.prevButton);
+                    s.a11y.addRole(s.prevButton, 'button');
+                    s.a11y.addLabel(s.prevButton, s.params.prevSlideMessage);
+                }
+        
+                $(s.container).append(s.a11y.liveRegion);
+            },
+            initPagination: function () {
+                if (s.params.pagination && s.params.paginationClickable && s.bullets && s.bullets.length) {
+                    s.bullets.each(function () {
+                        var bullet = $(this);
+                        s.a11y.makeFocusable(bullet);
+                        s.a11y.addRole(bullet, 'button');
+                        s.a11y.addLabel(bullet, s.params.paginationBulletMessage.replace(/{{index}}/, bullet.index() + 1));
+                    });
+                }
+            },
+            destroy: function () {
+                if (s.a11y.liveRegion && s.a11y.liveRegion.length > 0) s.a11y.liveRegion.remove();
+            }
+        };
+        
+
+        /*=========================
+          Init/Destroy
+          ===========================*/
+        s.init = function () {
+            if (s.params.loop) s.createLoop();
+            s.updateContainerSize();
+            s.updateSlidesSize();
+            s.updatePagination();
+            if (s.params.scrollbar && s.scrollbar) {
+                s.scrollbar.set();
+                if (s.params.scrollbarDraggable) {
+                    s.scrollbar.enableDraggable();
+                }
+            }
+            if (s.params.effect !== 'slide' && s.effects[s.params.effect]) {
+                if (!s.params.loop) s.updateProgress();
+                s.effects[s.params.effect].setTranslate();
+            }
+            if (s.params.loop) {
+                s.slideTo(s.params.initialSlide + s.loopedSlides, 0, s.params.runCallbacksOnInit);
+            }
+            else {
+                s.slideTo(s.params.initialSlide, 0, s.params.runCallbacksOnInit);
+                if (s.params.initialSlide === 0) {
+                    if (s.parallax && s.params.parallax) s.parallax.setTranslate();
+                    if (s.lazy && s.params.lazyLoading) {
+                        s.lazy.load();
+                        s.lazy.initialImageLoaded = true;
+                    }
+                }
+            }
+            s.attachEvents();
+            if (s.params.observer && s.support.observer) {
+                s.initObservers();
+            }
+            if (s.params.preloadImages && !s.params.lazyLoading) {
+                s.preloadImages();
+            }
+            if (s.params.autoplay) {
+                s.startAutoplay();
+            }
+            if (s.params.keyboardControl) {
+                if (s.enableKeyboardControl) s.enableKeyboardControl();
+            }
+            if (s.params.mousewheelControl) {
+                if (s.enableMousewheelControl) s.enableMousewheelControl();
+            }
+            if (s.params.hashnav) {
+                if (s.hashnav) s.hashnav.init();
+            }
+            if (s.params.a11y && s.a11y) s.a11y.init();
+            s.emit('onInit', s);
+        };
+        
+        // Cleanup dynamic styles
+        s.cleanupStyles = function () {
+            // Container
+            s.container.removeClass(s.classNames.join(' ')).removeAttr('style');
+        
+            // Wrapper
+            s.wrapper.removeAttr('style');
+        
+            // Slides
+            if (s.slides && s.slides.length) {
+                s.slides
+                    .removeClass([
+                      s.params.slideVisibleClass,
+                      s.params.slideActiveClass,
+                      s.params.slideNextClass,
+                      s.params.slidePrevClass
+                    ].join(' '))
+                    .removeAttr('style')
+                    .removeAttr('data-swiper-column')
+                    .removeAttr('data-swiper-row');
+            }
+        
+            // Pagination/Bullets
+            if (s.paginationContainer && s.paginationContainer.length) {
+                s.paginationContainer.removeClass(s.params.paginationHiddenClass);
+            }
+            if (s.bullets && s.bullets.length) {
+                s.bullets.removeClass(s.params.bulletActiveClass);
+            }
+        
+            // Buttons
+            if (s.params.prevButton) $(s.params.prevButton).removeClass(s.params.buttonDisabledClass);
+            if (s.params.nextButton) $(s.params.nextButton).removeClass(s.params.buttonDisabledClass);
+        
+            // Scrollbar
+            if (s.params.scrollbar && s.scrollbar) {
+                if (s.scrollbar.track && s.scrollbar.track.length) s.scrollbar.track.removeAttr('style');
+                if (s.scrollbar.drag && s.scrollbar.drag.length) s.scrollbar.drag.removeAttr('style');
+            }
+        };
+        
+        // Destroy
+        s.destroy = function (deleteInstance, cleanupStyles) {
+            // Detach evebts
+            s.detachEvents();
+            // Stop autoplay
+            s.stopAutoplay();
+            // Disable draggable
+            if (s.params.scrollbar && s.scrollbar) {
+                if (s.params.scrollbarDraggable) {
+                    s.scrollbar.disableDraggable();
+                }
+            }
+            // Destroy loop
+            if (s.params.loop) {
+                s.destroyLoop();
+            }
+            // Cleanup styles
+            if (cleanupStyles) {
+                s.cleanupStyles();
+            }
+            // Disconnect observer
+            s.disconnectObservers();
+            // Disable keyboard/mousewheel
+            if (s.params.keyboardControl) {
+                if (s.disableKeyboardControl) s.disableKeyboardControl();
+            }
+            if (s.params.mousewheelControl) {
+                if (s.disableMousewheelControl) s.disableMousewheelControl();
+            }
+            // Disable a11y
+            if (s.params.a11y && s.a11y) s.a11y.destroy();
+            // Destroy callback
+            s.emit('onDestroy');
+            // Delete instance
+            if (deleteInstance !== false) s = null;
+        };
+        
+        s.init();
+        
+
+    
+        // Return swiper instance
+        return s;
+    };
+    
+
+    /*==================================================
+        Prototype
+    ====================================================*/
+    Swiper.prototype = {
+        isSafari: (function () {
+            var ua = navigator.userAgent.toLowerCase();
+            return (ua.indexOf('safari') >= 0 && ua.indexOf('chrome') < 0 && ua.indexOf('android') < 0);
+        })(),
+        isUiWebView: /(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(navigator.userAgent),
+        isArray: function (arr) {
+            return Object.prototype.toString.apply(arr) === '[object Array]';
+        },
+        /*==================================================
+        Browser
+        ====================================================*/
+        browser: {
+            ie: window.navigator.pointerEnabled || window.navigator.msPointerEnabled,
+            ieTouch: (window.navigator.msPointerEnabled && window.navigator.msMaxTouchPoints > 1) || (window.navigator.pointerEnabled && window.navigator.maxTouchPoints > 1)
+        },
+        /*==================================================
+        Devices
+        ====================================================*/
+        device: (function () {
+            var ua = navigator.userAgent;
+            var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/);
+            var ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
+            var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/);
+            var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/);
+            return {
+                ios: ipad || iphone || ipod,
+                android: android
+            };
+        })(),
+        /*==================================================
+        Feature Detection
+        ====================================================*/
+        support: {
+            touch : (window.Modernizr && Modernizr.touch === true) || (function () {
+                return !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch);
+            })(),
+    
+            transforms3d : (window.Modernizr && Modernizr.csstransforms3d === true) || (function () {
+                var div = document.createElement('div').style;
+                return ('webkitPerspective' in div || 'MozPerspective' in div || 'OPerspective' in div || 'MsPerspective' in div || 'perspective' in div);
+            })(),
+    
+            flexbox: (function () {
+                var div = document.createElement('div').style;
+                var styles = ('alignItems webkitAlignItems webkitBoxAlign msFlexAlign mozBoxAlign webkitFlexDirection msFlexDirection mozBoxDirection mozBoxOrient webkitBoxDirection webkitBoxOrient').split(' ');
+                for (var i = 0; i < styles.length; i++) {
+                    if (styles[i] in div) return true;
+                }
+            })(),
+    
+            observer: (function () {
+                return ('MutationObserver' in window || 'WebkitMutationObserver' in window);
+            })()
+        },
+        /*==================================================
+        Plugins
+        ====================================================*/
+        plugins: {}
+    };
+    
+
+    /*===========================
+     Get Dom libraries
+     ===========================*/
+    var swiperDomPlugins = ['jQuery', 'Zepto', 'Dom7'];
+    for (var i = 0; i < swiperDomPlugins.length; i++) {
+    	if (window[swiperDomPlugins[i]]) {
+    		addLibraryPlugin(window[swiperDomPlugins[i]]);
+    	}
+    }
+    // Required DOM Plugins
+    var domLib;
+    if (typeof Dom7 === 'undefined') {
+    	domLib = window.Dom7 || window.Zepto || window.jQuery;
+    }
+    else {
+    	domLib = Dom7;
+    }
+
+    /*===========================
+    Add .swiper plugin from Dom libraries
+    ===========================*/
+    function addLibraryPlugin(lib) {
+        lib.fn.swiper = function (params) {
+            var firstInstance;
+            lib(this).each(function () {
+                var s = new Swiper(this, params);
+                if (!firstInstance) firstInstance = s;
+            });
+            return firstInstance;
+        };
+    }
+    
+    if (domLib) {
+        if (!('transitionEnd' in domLib.fn)) {
+            domLib.fn.transitionEnd = function (callback) {
+                var events = ['webkitTransitionEnd', 'transitionend', 'oTransitionEnd', 'MSTransitionEnd', 'msTransitionEnd'],
+                    i, j, dom = this;
+                function fireCallBack(e) {
+                    /*jshint validthis:true */
+                    if (e.target !== this) return;
+                    callback.call(this, e);
+                    for (i = 0; i < events.length; i++) {
+                        dom.off(events[i], fireCallBack);
+                    }
+                }
+                if (callback) {
+                    for (i = 0; i < events.length; i++) {
+                        dom.on(events[i], fireCallBack);
+                    }
+                }
+                return this;
+            };
+        }
+        if (!('transform' in domLib.fn)) {
+            domLib.fn.transform = function (transform) {
+                for (var i = 0; i < this.length; i++) {
+                    var elStyle = this[i].style;
+                    elStyle.webkitTransform = elStyle.MsTransform = elStyle.msTransform = elStyle.MozTransform = elStyle.OTransform = elStyle.transform = transform;
+                }
+                return this;
+            };
+        }
+        if (!('transition' in domLib.fn)) {
+            domLib.fn.transition = function (duration) {
+                if (typeof duration !== 'string') {
+                    duration = duration + 'ms';
+                }
+                for (var i = 0; i < this.length; i++) {
+                    var elStyle = this[i].style;
+                    elStyle.webkitTransitionDuration = elStyle.MsTransitionDuration = elStyle.msTransitionDuration = elStyle.MozTransitionDuration = elStyle.OTransitionDuration = elStyle.transitionDuration = duration;
+                }
+                return this;
+            };
+        }
+    }
+
+    window.Swiper = Swiper;
+})();
+/*===========================
+Swiper AMD Export
+===========================*/
+if (typeof(module) !== 'undefined')
+{
+    module.exports = window.Swiper;
+}
+else if (typeof define === 'function' && define.amd) {
+    define([], function () {
+        'use strict';
+        return window.Swiper;
+    });
+}
+//# sourceMappingURL=maps/swiper.jquery.js.map
+
+/* ===============================================================================
+************ Swiper ************
+=============================================================================== */
+/* global $:true */
+
++function ($) {
+  "use strict";
+
+  var defaults;
+
+  $.fn.swiper = function(params) {
+    return this.each(function() {
+      if(!this) return;
+      var $this = $(this);
+      var swiper = $this.data("swiper");
+      if(!swiper) $this.data("swiper", new Swiper(this, $.extend({}, defaults, params))); 
+      return swiper;
+    });
+  }
+
+  defaults = $.fn.swiper.prototype.defaults = {
+    pagination: ".swiper-pagination"
+  };
+
+}($);
+
+/* global $:true */
++ function($) {
+
+  var defaults;
+
+  var Photos = function(config) {
+    this.initConfig(config);
+    this.index = 0;
+  }
+
+  Photos.prototype = {
+    initConfig: function (config) {
+      this.config = $.extend({}, defaults, config);
+      this.activeIndex = this.lastActiveIndex = this.config.initIndex;
+
+      this.config.items = this.config.items.map(function(d, i) {
+        if(typeof d === typeof 'a') {
+          return {
+            image: d,
+            caption: ''
+          }
+        }
+        return d;
+      });
+
+      this.tpl = $.t7.compile(this.config.tpl);
+      if(this.config.autoOpen) this.open();
+    },
+
+    open: function (index) {
+      if (this._open) return false;
+      if (!this.modal) {
+        this.modal = $(this.tpl(this.config)).appendTo(document.body);
+        this.container = this.modal.find('.swiper-container');
+        this.wrapper = this.modal.find('.swiper-wrapper');
+
+        var hammer = new Hammer(this.container[0]);
+        hammer.get('pinch').set({ enable: true });
+        hammer.on('pinchstart', $.proxy(this.onGestureStart, this));
+        hammer.on('pinchmove', $.proxy(this.onGestureChange, this));
+        hammer.on('pinchend', $.proxy(this.onGestureEnd, this));
+        this.modal.on($.touchEvents.start, $.proxy(this.onTouchStart, this));
+        this.modal.on($.touchEvents.move, $.proxy(this.onTouchMove, this));
+        this.modal.on($.touchEvents.end, $.proxy(this.onTouchEnd, this));
+
+        //init index
+        this.wrapper.transition(0);
+        this.wrapper.transform('translate3d(-' + $(window).width()*this.config.initIndex + 'px,0,0)');
+        this.container.find('.caption-item').eq(this.config.initIndex).addClass('active');
+        this.container.find('.swiper-pagination-bullet').eq(this.config.initIndex).addClass('swiper-pagination-bullet-active');
+      }
+
+      var self = this;
+      this.modal.show().height();
+      this.modal.addClass('weui-photo-browser-modal-visible');
+      this.container.addClass('swiper-container-visible').transitionEnd(function() {
+        self.initParams();
+        if(index !== undefined) {
+          self.slideTo(index);
+        }
+        if(self.config.onOpen) {
+          self.config.onOpen.call(self);
+        }
+      });
+
+      this._open = true;
+    },
+
+    close: function() {
+      this.container.transitionEnd($.proxy(function() {
+        this.modal.hide();
+        this._open = false;
+        if(this.config.onClose) this.config.onClose.call(this);
+      }, this));
+      this.container.removeClass('swiper-container-visible');
+      this.modal.removeClass('weui-photo-browser-modal-visible');
+    },
+
+    initParams: function () {
+      if(this.containerHeight) return false;
+
+      this.windowWidth = $(window).width();
+      this.containerHeight = this.container.height();
+      this.containerWidth = this.container.width();
+
+      this.touchStart = {};
+
+      this.wrapperTransform = 0;
+      this.wrapperLastTransform = - $(window).width()*this.config.initIndex;
+      this.wrapperDiff = 0;
+
+      this.lastScale = 1;
+      this.currentScale = 1;
+
+      this.imageLastTransform = { x: 0, y: 0 };
+      this.imageTransform = { x: 0, y: 0 };
+      this.imageDiff = { x: 0, y: 0 };
+      this.imageLastDiff = { x: 0, y: 0 };
+    },
+
+    onTouchStart: function (e) {
+      if(this.scaling) return false;
+      this.touching = true;
+      this.touchStart = $.getTouchPosition(e);
+      this.touchMove = null;
+      this.touchStartTime = + new Date;
+      this.wrapperDiff = 0;
+      this.breakpointPosition = null;
+    },
+
+    onTouchMove: function (e) {
+      if(!this.touching || this.scaling) return false;
+
+      e.preventDefault();
+
+      if(this.gestureImage) {
+        var rect = this.gestureImage[0].getBoundingClientRect();
+        if (rect.left >= 0 || rect.right <= this.windowWidth) {
+          this.overflow = true;
+        } else {
+          this.overflow = false;
+        }
+      } else {
+        this.oveflow = false;
+      }
+      var p = this.touchMove = $.getTouchPosition(e);
+      if(this.currentScale === 1 || this.overflow) {
+        if(this.breakpointPosition) {
+          this.wrapperDiff = p.x - this.breakpointPosition.x;
+        } else {
+          this.wrapperDiff = p.x - this.touchStart.x;
+        }
+        if(this.activeIndex === 0 && this.wrapperDiff > 0) this.wrapperDiff = Math.pow(this.wrapperDiff, .8);
+        if(this.activeIndex === this.config.items.length - 1 && this.wrapperDiff < 0) this.wrapperDiff = - Math.pow(-this.wrapperDiff, .8);
+        this.wrapperTransform = this.wrapperLastTransform + this.wrapperDiff;
+        this.doWrapperTransform();
+      } else {
+        var img = this.gestureImage;
+        this.imageDiff = {
+          x: p.x - this.touchStart.x,
+          y: p.y - this.touchStart.y
+        }
+
+        this.imageTransform = {
+          x: this.imageDiff.x + this.imageLastTransform.x,
+          y: this.imageDiff.y + this.imageLastTransform.y
+        };
+        this.doImageTransform();
+
+        this.breakpointPosition = p;
+
+        this.imageLastDiff = this.imageDiff;
+      }
+    },
+
+    onTouchEnd: function (e) {
+      if(!this.touching) return false;
+      this.touching = false;
+      if(this.scaling) return false;
+      var duration = (+ new Date) - this.touchStartTime;
+
+      if(duration < 200 && (!this.touchMove || Math.abs(this.touchStart.x - this.touchMove.x) <= 2 && Math.abs(this.touchStart.y - this.touchMove.y) <= 2)) {
+        this.onClick();
+        return;
+      }
+      if(this.wrapperDiff > 0) {
+        if(this.wrapperDiff > this.containerWidth/2 || (this.wrapperDiff > 20 && duration < 300)) {
+          this.slidePrev();
+        } else {
+          this.slideTo(this.activeIndex, 200);
+        }
+      } else {
+        if(- this.wrapperDiff > this.containerWidth/2 || (-this.wrapperDiff > 20 && duration < 300)) {
+          this.slideNext();
+        } else {
+          this.slideTo(this.activeIndex, 200);
+        }
+      }
+
+      this.imageLastTransform = this.imageTransform;
+
+      this.adjust();
+    },
+
+    onClick: function () {
+      var self = this;
+      if (this._lastClickTime && ( + new Date - this._lastClickTime < 300)) {
+        this.onDoubleClick();
+        clearTimeout(this._clickTimeout);
+      } else {
+        this._clickTimeout = setTimeout(function () {
+          self.close();
+        }, 300);
+      }
+      this._lastClickTime = + new Date;
+    },
+
+    onDoubleClick: function () {
+      this.gestureImage = this.container.find('.swiper-slide').eq(this.activeIndex).find('img');
+      this.currentScale = this.currentScale > 1 ? 1 : 2;
+      this.doImageTransform(200); 
+      this.adjust();
+    },
+
+    onGestureStart: function (e) {
+      this.scaling = true;
+      this.gestureImage = this.container.find('.swiper-slide').eq(this.activeIndex).find('img');
+    },
+
+    onGestureChange: function (e) {
+      var s = this.lastScale * e.scale;
+      if (s > this.config.maxScale) {
+        s = this.config.maxScale + Math.pow((s - this.config.maxScale), 0.5);
+      } else if (s < 1) {
+        s = Math.pow(s, .5);
+      }
+      this.currentScale = s;
+      this.doImageTransform();
+    },
+
+    onGestureEnd: function (e) {
+      if (this.currentScale > this.config.maxScale) {
+        this.currentScale = this.config.maxScale;
+        this.doImageTransform(200);
+      } else if (this.currentScale < 1) {
+        this.currentScale = 1;
+        this.doImageTransform(200);
+      }
+      this.lastScale = this.currentScale;
+      this.scaling = false;
+      this.adjust();
+    },
+
+    doWrapperTransform: function(duration, callback) {
+      if (duration === 0) {
+        var origin = this.wrapper.css('transition-property')
+        this.wrapper.css('transition-property', 'none').transform('translate3d(' + this.wrapperTransform + 'px, 0, 0)');
+        this.wrapper.css('transition-property', origin);
+        callback()
+      } else {
+        this.wrapper.transitionEnd(function() {
+          callback && callback();
+        });
+        this.wrapper.transition(duration || defaults.duration).transform('translate3d(' + this.wrapperTransform + 'px, 0, 0)');
+      }
+    },
+
+    doImageTransform: function(duration, callback) {
+      if(!this.gestureImage) return;
+      this.gestureImage.transition(duration || 0).transform('translate3d(' + this.imageTransform.x + 'px,' + this.imageTransform.y + 'px, 0) scale(' + this.currentScale + ')');
+      this._needAdjust = true;
+    },
+
+    adjust: function() {
+      if(!this._needAdjust) return false;
+      var img = this.gestureImage;
+      if(!img) return false;
+      if(this.currentScale === 1) {
+        this.imageTransform = this.imageLastDiff =  {x:0,y:0};
+        this.doImageTransform(200);
+        return;
+      }
+
+      var rect = img[0].getBoundingClientRect();
+
+      //调整上下
+      if(rect.height < this.containerHeight) {  // 如果高度没容器高,则自动居中
+        this.imageTransform.y = this.imageLastTransform.y = 0;
+      } else {  //如果比容器高,那么要保证上下不能有空隙
+        if(rect.top > 0) this.imageTransform.y = this.imageTransform.y - rect.top;
+        else if(rect.bottom < this.containerHeight) this.imageTransform.y = this.imageTransform.y + this.containerHeight - rect.bottom;
+      }
+
+      this.doImageTransform(200);
+      this._needAdjust = false; // must at last line, because doImageTransform will set this._needAdjust true
+    },
+
+    slideTo: function(index, duration) {
+      if(index < 0) index = 0;
+      if(index > this.config.items.length-1) index = this.config.items.length - 1;
+      this.lastActiveIndex = this.activeIndex;
+      this.activeIndex = index;
+      this.wrapperTransform = - (index * this.containerWidth);
+      this.wrapperLastTransform = this.wrapperTransform;
+      this.doWrapperTransform(duration, $.proxy(function() {
+        if(this.lastActiveIndex === this.activeIndex) return false; // active index not change
+        this.container.find('.caption-item.active').removeClass('active');
+        this.container.find('.swiper-slide-active').removeClass('swiper-slide-active');
+        this.container.find('.swiper-pagination-bullet-active').removeClass('swiper-pagination-bullet-active');
+        this.container.find('.caption-item').eq(this.activeIndex).addClass('active');
+        this.container.find('.swiper-slide').eq(this.activeIndex).addClass('swiper-slide-active');
+        this.container.find('.swiper-pagination-bullet').eq(this.activeIndex).addClass('swiper-pagination-bullet-active');
+
+        //reset image transform
+        this.container.find('.swiper-slide img[style]').transition(0).transform('translate3d(0,0,0) scale(1)');
+
+        this.lastScale = 1;
+        this.currentScale = 1;
+
+        this.imageLastTransform = { x: 0, y: 0 };
+        this.imageTransform = { x: 0, y: 0 };
+        this.imageDiff = { x: 0, y: 0 };
+        this.imageLastDiff = { x: 0, y: 0 };
+
+        if(this.config.onSlideChange) {
+          this.config.onSlideChange.call(this, this.activeIndex);
+        }
+
+      }, this));
+    },
+    slideNext: function() {
+      return this.slideTo(this.activeIndex+1, 200);
+    },
+    slidePrev: function() {
+      return this.slideTo(this.activeIndex-1, 200);
+    }
+  }
+
+  defaults = Photos.prototype.defaults = {
+    items: [],
+    autoOpen: false, //初始化完成之后立刻打开
+    onOpen: undefined,
+    onClose: undefined,
+    initIndex: 0, //打开时默认显示第几张
+    maxScale: 3,
+    onSlideChange: undefined,
+    duration: 200, // 默认动画时间,如果没有在调用函数的时候指定,则使用这个值
+    tpl: '<div class="weui-photo-browser-modal">\
+            <div class="swiper-container">\
+              <div class="swiper-wrapper">\
+                {{#items}}\
+                <div class="swiper-slide">\
+                  <div class="photo-container">\
+                    <img src="{{image}}" />\
+                  </div>\
+                </div>\
+                {{/items}}\
+              </div>\
+              <div class="caption">\
+                {{#items}}\
+                <div class="caption-item caption-item-{{@index}}">{{caption}}</div>\
+                {{/items}}\
+              </div>\
+              <div class="swiper-pagination swiper-pagination-bullets">\
+                {{#items}}\
+                <span class="swiper-pagination-bullet"></span>\
+                {{/items}}\
+              </div>\
+            </div>\
+          </div>'
+  }
+
+  $.photoBrowser = function(params) {
+    return new Photos(params);
+  }
+}($);
diff --git a/platforms/android/app/src/main/assets/www/js/lib/swiper.min.js b/platforms/android/app/src/main/assets/www/js/lib/swiper.min.js
new file mode 100755
index 0000000..69f968b
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/lib/swiper.min.js
@@ -0,0 +1,17 @@
+/**
+ * Swiper 3.3.1
+ * Most modern mobile touch slider and framework with hardware accelerated transitions
+ * 
+ * http://www.idangero.us/swiper/
+ * 
+ * Copyright 2016, Vladimir Kharlampidi
+ * The iDangero.us
+ * http://www.idangero.us/
+ * 
+ * Licensed under MIT
+ * 
+ * Released on: February 7, 2016
+ */
+!function(){"use strict";function e(e){e.fn.swiper=function(a){var i;return e(this).each(function(){var e=new t(this,a);i||(i=e)}),i}}var a,t=function(e,i){function s(e){return Math.floor(e)}function r(){y.autoplayTimeoutId=setTimeout(function(){y.params.loop?(y.fixLoop(),y._slideNext(),y.emit("onAutoplay",y)):y.isEnd?i.autoplayStopOnLast?y.stopAutoplay():(y._slideTo(0),y.emit("onAutoplay",y)):(y._slideNext(),y.emit("onAutoplay",y))},y.params.autoplay)}function n(e,t){var i=a(e.target);if(!i.is(t))if("string"==typeof t)i=i.parents(t);else if(t.nodeType){var s;return i.parents().each(function(e,a){a===t&&(s=t)}),s?t:void 0}if(0!==i.length)return i[0]}function o(e,a){a=a||{};var t=window.MutationObserver||window.WebkitMutationObserver,i=new t(function(e){e.forEach(function(e){y.onResize(!0),y.emit("onObserverUpdate",y,e)})});i.observe(e,{attributes:"undefined"==typeof a.attributes||a.attributes,childList:"undefined"==typeof a.childList||a.childList,characterData:"undefined"==typeof a.characterData||a.characterData}),y.observers.push(i)}function l(e){e.originalEvent&&(e=e.originalEvent);var a=e.keyCode||e.charCode;if(!y.params.allowSwipeToNext&&(y.isHorizontal()&&39===a||!y.isHorizontal()&&40===a))return!1;if(!y.params.allowSwipeToPrev&&(y.isHorizontal()&&37===a||!y.isHorizontal()&&38===a))return!1;if(!(e.shiftKey||e.altKey||e.ctrlKey||e.metaKey||document.activeElement&&document.activeElement.nodeName&&("input"===document.activeElement.nodeName.toLowerCase()||"textarea"===document.activeElement.nodeName.toLowerCase()))){if(37===a||39===a||38===a||40===a){var t=!1;if(y.container.parents(".swiper-slide").length>0&&0===y.container.parents(".swiper-slide-active").length)return;var i={left:window.pageXOffset,top:window.pageYOffset},s=window.innerWidth,r=window.innerHeight,n=y.container.offset();y.rtl&&(n.left=n.left-y.container[0].scrollLeft);for(var o=[[n.left,n.top],[n.left+y.width,n.top],[n.left,n.top+y.height],[n.left+y.width,n.top+y.height]],l=0;l<o.length;l++){var p=o[l];p[0]>=i.left&&p[0]<=i.left+s&&p[1]>=i.top&&p[1]<=i.top+r&&(t=!0)}if(!t)return}y.isHorizontal()?(37!==a&&39!==a||(e.preventDefault?e.preventDefault():e.returnValue=!1),(39===a&&!y.rtl||37===a&&y.rtl)&&y.slideNext(),(37===a&&!y.rtl||39===a&&y.rtl)&&y.slidePrev()):(38!==a&&40!==a||(e.preventDefault?e.preventDefault():e.returnValue=!1),40===a&&y.slideNext(),38===a&&y.slidePrev())}}function p(e){e.originalEvent&&(e=e.originalEvent);var a=y.mousewheel.event,t=0,i=y.rtl?-1:1;if("mousewheel"===a)if(y.params.mousewheelForceToAxis)if(y.isHorizontal()){if(!(Math.abs(e.wheelDeltaX)>Math.abs(e.wheelDeltaY)))return;t=e.wheelDeltaX*i}else{if(!(Math.abs(e.wheelDeltaY)>Math.abs(e.wheelDeltaX)))return;t=e.wheelDeltaY}else t=Math.abs(e.wheelDeltaX)>Math.abs(e.wheelDeltaY)?-e.wheelDeltaX*i:-e.wheelDeltaY;else if("DOMMouseScroll"===a)t=-e.detail;else if("wheel"===a)if(y.params.mousewheelForceToAxis)if(y.isHorizontal()){if(!(Math.abs(e.deltaX)>Math.abs(e.deltaY)))return;t=-e.deltaX*i}else{if(!(Math.abs(e.deltaY)>Math.abs(e.deltaX)))return;t=-e.deltaY}else t=Math.abs(e.deltaX)>Math.abs(e.deltaY)?-e.deltaX*i:-e.deltaY;if(0!==t){if(y.params.mousewheelInvert&&(t=-t),y.params.freeMode){var s=y.getWrapperTranslate()+t*y.params.mousewheelSensitivity,r=y.isBeginning,n=y.isEnd;if(s>=y.minTranslate()&&(s=y.minTranslate()),s<=y.maxTranslate()&&(s=y.maxTranslate()),y.setWrapperTransition(0),y.setWrapperTranslate(s),y.updateProgress(),y.updateActiveIndex(),(!r&&y.isBeginning||!n&&y.isEnd)&&y.updateClasses(),y.params.freeModeSticky?(clearTimeout(y.mousewheel.timeout),y.mousewheel.timeout=setTimeout(function(){y.slideReset()},300)):y.params.lazyLoading&&y.lazy&&y.lazy.load(),0===s||s===y.maxTranslate())return}else{if((new window.Date).getTime()-y.mousewheel.lastScrollTime>60)if(t<0)if(y.isEnd&&!y.params.loop||y.animating){if(y.params.mousewheelReleaseOnEdges)return!0}else y.slideNext();else if(y.isBeginning&&!y.params.loop||y.animating){if(y.params.mousewheelReleaseOnEdges)return!0}else y.slidePrev();y.mousewheel.lastScrollTime=(new window.Date).getTime()}return y.params.autoplay&&y.stopAutoplay(),e.preventDefault?e.preventDefault():e.returnValue=!1,!1}}function d(e,t){e=a(e);var i,s,r,n=y.rtl?-1:1;i=e.attr("data-swiper-parallax")||"0",s=e.attr("data-swiper-parallax-x"),r=e.attr("data-swiper-parallax-y"),s||r?(s=s||"0",r=r||"0"):y.isHorizontal()?(s=i,r="0"):(r=i,s="0"),s=s.indexOf("%")>=0?parseInt(s,10)*t*n+"%":s*t*n+"px",r=r.indexOf("%")>=0?parseInt(r,10)*t+"%":r*t+"px",e.transform("translate3d("+s+", "+r+",0px)")}function c(e){return 0!==e.indexOf("on")&&(e=e[0]!==e[0].toUpperCase()?"on"+e[0].toUpperCase()+e.substring(1):"on"+e),e}if(!(this instanceof t))return new t(e,i);var u={direction:"horizontal",touchEventsTarget:"container",initialSlide:0,speed:300,autoplay:!1,autoplayDisableOnInteraction:!0,autoplayStopOnLast:!1,iOSEdgeSwipeDetection:!1,iOSEdgeSwipeThreshold:20,freeMode:!1,freeModeMomentum:!0,freeModeMomentumRatio:1,freeModeMomentumBounce:!0,freeModeMomentumBounceRatio:1,freeModeSticky:!1,freeModeMinimumVelocity:.02,autoHeight:!1,setWrapperSize:!1,virtualTranslate:!1,effect:"slide",coverflow:{rotate:50,stretch:0,depth:100,modifier:1,slideShadows:!0},flip:{slideShadows:!0,limitRotation:!0},cube:{slideShadows:!0,shadow:!0,shadowOffset:20,shadowScale:.94},fade:{crossFade:!1},parallax:!1,scrollbar:null,scrollbarHide:!0,scrollbarDraggable:!1,scrollbarSnapOnRelease:!1,keyboardControl:!1,mousewheelControl:!1,mousewheelReleaseOnEdges:!1,mousewheelInvert:!1,mousewheelForceToAxis:!1,mousewheelSensitivity:1,hashnav:!1,breakpoints:void 0,spaceBetween:0,slidesPerView:1,slidesPerColumn:1,slidesPerColumnFill:"column",slidesPerGroup:1,centeredSlides:!1,slidesOffsetBefore:0,slidesOffsetAfter:0,roundLengths:!1,touchRatio:1,touchAngle:45,simulateTouch:!0,shortSwipes:!0,longSwipes:!0,longSwipesRatio:.5,longSwipesMs:300,followFinger:!0,onlyExternal:!1,threshold:0,touchMoveStopPropagation:!0,uniqueNavElements:!0,pagination:null,paginationElement:"span",paginationClickable:!1,paginationHide:!1,paginationBulletRender:null,paginationProgressRender:null,paginationFractionRender:null,paginationCustomRender:null,paginationType:"bullets",resistance:!0,resistanceRatio:.85,nextButton:null,prevButton:null,watchSlidesProgress:!1,watchSlidesVisibility:!1,grabCursor:!1,preventClicks:!0,preventClicksPropagation:!0,slideToClickedSlide:!1,lazyLoading:!1,lazyLoadingInPrevNext:!1,lazyLoadingInPrevNextAmount:1,lazyLoadingOnTransitionStart:!1,preloadImages:!0,updateOnImagesReady:!0,loop:!1,loopAdditionalSlides:0,loopedSlides:null,control:void 0,controlInverse:!1,controlBy:"slide",allowSwipeToPrev:!0,allowSwipeToNext:!0,swipeHandler:null,noSwiping:!0,noSwipingClass:"swiper-no-swiping",slideClass:"swiper-slide",slideActiveClass:"swiper-slide-active",slideVisibleClass:"swiper-slide-visible",slideDuplicateClass:"swiper-slide-duplicate",slideNextClass:"swiper-slide-next",slidePrevClass:"swiper-slide-prev",wrapperClass:"swiper-wrapper",bulletClass:"swiper-pagination-bullet",bulletActiveClass:"swiper-pagination-bullet-active",buttonDisabledClass:"swiper-button-disabled",paginationCurrentClass:"swiper-pagination-current",paginationTotalClass:"swiper-pagination-total",paginationHiddenClass:"swiper-pagination-hidden",paginationProgressbarClass:"swiper-pagination-progressbar",observer:!1,observeParents:!1,a11y:!1,prevSlideMessage:"Previous slide",nextSlideMessage:"Next slide",firstSlideMessage:"This is the first slide",lastSlideMessage:"This is the last slide",paginationBulletMessage:"Go to slide {{index}}",runCallbacksOnInit:!0},m=i&&i.virtualTranslate;i=i||{};var h={};for(var f in i)if("object"!=typeof i[f]||null===i[f]||(i[f].nodeType||i[f]===window||i[f]===document||"undefined"!=typeof Dom7&&i[f]instanceof Dom7||"undefined"!=typeof jQuery&&i[f]instanceof jQuery))h[f]=i[f];else{h[f]={};for(var g in i[f])h[f][g]=i[f][g]}for(var v in u)if("undefined"==typeof i[v])i[v]=u[v];else if("object"==typeof i[v])for(var w in u[v])"undefined"==typeof i[v][w]&&(i[v][w]=u[v][w]);var y=this;if(y.params=i,y.originalParams=h,y.classNames=[],"undefined"!=typeof a&&"undefined"!=typeof Dom7&&(a=Dom7),("undefined"!=typeof a||(a="undefined"==typeof Dom7?window.Dom7||window.Zepto||window.jQuery:Dom7))&&(y.$=a,y.currentBreakpoint=void 0,y.getActiveBreakpoint=function(){if(!y.params.breakpoints)return!1;var e,a=!1,t=[];for(e in y.params.breakpoints)y.params.breakpoints.hasOwnProperty(e)&&t.push(e);t.sort(function(e,a){return parseInt(e,10)>parseInt(a,10)});for(var i=0;i<t.length;i++)e=t[i],e>=window.innerWidth&&!a&&(a=e);return a||"max"},y.setBreakpoint=function(){var e=y.getActiveBreakpoint();if(e&&y.currentBreakpoint!==e){var a=e in y.params.breakpoints?y.params.breakpoints[e]:y.originalParams,t=y.params.loop&&a.slidesPerView!==y.params.slidesPerView;for(var i in a)y.params[i]=a[i];y.currentBreakpoint=e,t&&y.destroyLoop&&y.reLoop(!0)}},y.params.breakpoints&&y.setBreakpoint(),y.container=a(e),0!==y.container.length)){if(y.container.length>1){var x=[];return y.container.each(function(){x.push(new t(this,i))}),x}y.container[0].swiper=y,y.container.data("swiper",y),y.classNames.push("swiper-container-"+y.params.direction),y.params.freeMode&&y.classNames.push("swiper-container-free-mode"),y.support.flexbox||(y.classNames.push("swiper-container-no-flexbox"),y.params.slidesPerColumn=1),y.params.autoHeight&&y.classNames.push("swiper-container-autoheight"),(y.params.parallax||y.params.watchSlidesVisibility)&&(y.params.watchSlidesProgress=!0),["cube","coverflow","flip"].indexOf(y.params.effect)>=0&&(y.support.transforms3d?(y.params.watchSlidesProgress=!0,y.classNames.push("swiper-container-3d")):y.params.effect="slide"),"slide"!==y.params.effect&&y.classNames.push("swiper-container-"+y.params.effect),"cube"===y.params.effect&&(y.params.resistanceRatio=0,y.params.slidesPerView=1,y.params.slidesPerColumn=1,y.params.slidesPerGroup=1,y.params.centeredSlides=!1,y.params.spaceBetween=0,y.params.virtualTranslate=!0,y.params.setWrapperSize=!1),"fade"!==y.params.effect&&"flip"!==y.params.effect||(y.params.slidesPerView=1,y.params.slidesPerColumn=1,y.params.slidesPerGroup=1,y.params.watchSlidesProgress=!0,y.params.spaceBetween=0,y.params.setWrapperSize=!1,"undefined"==typeof m&&(y.params.virtualTranslate=!0)),y.params.grabCursor&&y.support.touch&&(y.params.grabCursor=!1),y.wrapper=y.container.children("."+y.params.wrapperClass),y.params.pagination&&(y.paginationContainer=a(y.params.pagination),y.params.uniqueNavElements&&"string"==typeof y.params.pagination&&y.paginationContainer.length>1&&1===y.container.find(y.params.pagination).length&&(y.paginationContainer=y.container.find(y.params.pagination)),"bullets"===y.params.paginationType&&y.params.paginationClickable?y.paginationContainer.addClass("swiper-pagination-clickable"):y.params.paginationClickable=!1,y.paginationContainer.addClass("swiper-pagination-"+y.params.paginationType)),(y.params.nextButton||y.params.prevButton)&&(y.params.nextButton&&(y.nextButton=a(y.params.nextButton),y.params.uniqueNavElements&&"string"==typeof y.params.nextButton&&y.nextButton.length>1&&1===y.container.find(y.params.nextButton).length&&(y.nextButton=y.container.find(y.params.nextButton))),y.params.prevButton&&(y.prevButton=a(y.params.prevButton),y.params.uniqueNavElements&&"string"==typeof y.params.prevButton&&y.prevButton.length>1&&1===y.container.find(y.params.prevButton).length&&(y.prevButton=y.container.find(y.params.prevButton)))),y.isHorizontal=function(){return"horizontal"===y.params.direction},y.rtl=y.isHorizontal()&&("rtl"===y.container[0].dir.toLowerCase()||"rtl"===y.container.css("direction")),y.rtl&&y.classNames.push("swiper-container-rtl"),y.rtl&&(y.wrongRTL="-webkit-box"===y.wrapper.css("display")),y.params.slidesPerColumn>1&&y.classNames.push("swiper-container-multirow"),y.device.android&&y.classNames.push("swiper-container-android"),y.container.addClass(y.classNames.join(" ")),y.translate=0,y.progress=0,y.velocity=0,y.lockSwipeToNext=function(){y.params.allowSwipeToNext=!1},y.lockSwipeToPrev=function(){y.params.allowSwipeToPrev=!1},y.lockSwipes=function(){y.params.allowSwipeToNext=y.params.allowSwipeToPrev=!1},y.unlockSwipeToNext=function(){y.params.allowSwipeToNext=!0},y.unlockSwipeToPrev=function(){y.params.allowSwipeToPrev=!0},y.unlockSwipes=function(){y.params.allowSwipeToNext=y.params.allowSwipeToPrev=!0},y.params.grabCursor&&(y.container[0].style.cursor="move",y.container[0].style.cursor="-webkit-grab",y.container[0].style.cursor="-moz-grab",y.container[0].style.cursor="grab"),y.imagesToLoad=[],y.imagesLoaded=0,y.loadImage=function(e,a,t,i,s){function r(){s&&s()}var n;e.complete&&i?r():a?(n=new window.Image,n.onload=r,n.onerror=r,t&&(n.srcset=t),a&&(n.src=a)):r()},y.preloadImages=function(){function e(){"undefined"!=typeof y&&null!==y&&(void 0!==y.imagesLoaded&&y.imagesLoaded++,y.imagesLoaded===y.imagesToLoad.length&&(y.params.updateOnImagesReady&&y.update(),y.emit("onImagesReady",y)))}y.imagesToLoad=y.container.find("img");for(var a=0;a<y.imagesToLoad.length;a++)y.loadImage(y.imagesToLoad[a],y.imagesToLoad[a].currentSrc||y.imagesToLoad[a].getAttribute("src"),y.imagesToLoad[a].srcset||y.imagesToLoad[a].getAttribute("srcset"),!0,e)},y.autoplayTimeoutId=void 0,y.autoplaying=!1,y.autoplayPaused=!1,y.startAutoplay=function(){return"undefined"==typeof y.autoplayTimeoutId&&(!!y.params.autoplay&&(!y.autoplaying&&(y.autoplaying=!0,y.emit("onAutoplayStart",y),void r())))},y.stopAutoplay=function(e){y.autoplayTimeoutId&&(y.autoplayTimeoutId&&clearTimeout(y.autoplayTimeoutId),y.autoplaying=!1,y.autoplayTimeoutId=void 0,y.emit("onAutoplayStop",y))},y.pauseAutoplay=function(e){y.autoplayPaused||(y.autoplayTimeoutId&&clearTimeout(y.autoplayTimeoutId),y.autoplayPaused=!0,0===e?(y.autoplayPaused=!1,r()):y.wrapper.transitionEnd(function(){y&&(y.autoplayPaused=!1,y.autoplaying?r():y.stopAutoplay())}))},y.minTranslate=function(){return-y.snapGrid[0]},y.maxTranslate=function(){return-y.snapGrid[y.snapGrid.length-1]},y.updateAutoHeight=function(){var e=y.slides.eq(y.activeIndex)[0];if("undefined"!=typeof e){var a=e.offsetHeight;a&&y.wrapper.css("height",a+"px")}},y.updateContainerSize=function(){var e,a;e="undefined"!=typeof y.params.width?y.params.width:y.container[0].clientWidth,a="undefined"!=typeof y.params.height?y.params.height:y.container[0].clientHeight,0===e&&y.isHorizontal()||0===a&&!y.isHorizontal()||(e=e-parseInt(y.container.css("padding-left"),10)-parseInt(y.container.css("padding-right"),10),a=a-parseInt(y.container.css("padding-top"),10)-parseInt(y.container.css("padding-bottom"),10),y.width=e,y.height=a,y.size=y.isHorizontal()?y.width:y.height)},y.updateSlidesSize=function(){y.slides=y.wrapper.children("."+y.params.slideClass),y.snapGrid=[],y.slidesGrid=[],y.slidesSizesGrid=[];var e,a=y.params.spaceBetween,t=-y.params.slidesOffsetBefore,i=0,r=0;if("undefined"!=typeof y.size){"string"==typeof a&&a.indexOf("%")>=0&&(a=parseFloat(a.replace("%",""))/100*y.size),y.virtualSize=-a,y.rtl?y.slides.css({marginLeft:"",marginTop:""}):y.slides.css({marginRight:"",marginBottom:""});var n;y.params.slidesPerColumn>1&&(n=Math.floor(y.slides.length/y.params.slidesPerColumn)===y.slides.length/y.params.slidesPerColumn?y.slides.length:Math.ceil(y.slides.length/y.params.slidesPerColumn)*y.params.slidesPerColumn,"auto"!==y.params.slidesPerView&&"row"===y.params.slidesPerColumnFill&&(n=Math.max(n,y.params.slidesPerView*y.params.slidesPerColumn)));var o,l=y.params.slidesPerColumn,p=n/l,d=p-(y.params.slidesPerColumn*p-y.slides.length);for(e=0;e<y.slides.length;e++){o=0;var c=y.slides.eq(e);if(y.params.slidesPerColumn>1){var u,m,h;"column"===y.params.slidesPerColumnFill?(m=Math.floor(e/l),h=e-m*l,(m>d||m===d&&h===l-1)&&++h>=l&&(h=0,m++),u=m+h*n/l,c.css({"-webkit-box-ordinal-group":u,"-moz-box-ordinal-group":u,"-ms-flex-order":u,"-webkit-order":u,order:u})):(h=Math.floor(e/p),m=e-h*p),c.css({"margin-top":0!==h&&y.params.spaceBetween&&y.params.spaceBetween+"px"}).attr("data-swiper-column",m).attr("data-swiper-row",h)}"none"!==c.css("display")&&("auto"===y.params.slidesPerView?(o=y.isHorizontal()?c.outerWidth(!0):c.outerHeight(!0),y.params.roundLengths&&(o=s(o))):(o=(y.size-(y.params.slidesPerView-1)*a)/y.params.slidesPerView,y.params.roundLengths&&(o=s(o)),y.isHorizontal()?y.slides[e].style.width=o+"px":y.slides[e].style.height=o+"px"),y.slides[e].swiperSlideSize=o,y.slidesSizesGrid.push(o),y.params.centeredSlides?(t=t+o/2+i/2+a,0===e&&(t=t-y.size/2-a),Math.abs(t)<.001&&(t=0),r%y.params.slidesPerGroup===0&&y.snapGrid.push(t),y.slidesGrid.push(t)):(r%y.params.slidesPerGroup===0&&y.snapGrid.push(t),y.slidesGrid.push(t),t=t+o+a),y.virtualSize+=o+a,i=o,r++)}y.virtualSize=Math.max(y.virtualSize,y.size)+y.params.slidesOffsetAfter;var f;if(y.rtl&&y.wrongRTL&&("slide"===y.params.effect||"coverflow"===y.params.effect)&&y.wrapper.css({width:y.virtualSize+y.params.spaceBetween+"px"}),y.support.flexbox&&!y.params.setWrapperSize||(y.isHorizontal()?y.wrapper.css({width:y.virtualSize+y.params.spaceBetween+"px"}):y.wrapper.css({height:y.virtualSize+y.params.spaceBetween+"px"})),y.params.slidesPerColumn>1&&(y.virtualSize=(o+y.params.spaceBetween)*n,y.virtualSize=Math.ceil(y.virtualSize/y.params.slidesPerColumn)-y.params.spaceBetween,y.wrapper.css({width:y.virtualSize+y.params.spaceBetween+"px"}),y.params.centeredSlides)){for(f=[],e=0;e<y.snapGrid.length;e++)y.snapGrid[e]<y.virtualSize+y.snapGrid[0]&&f.push(y.snapGrid[e]);y.snapGrid=f}if(!y.params.centeredSlides){for(f=[],e=0;e<y.snapGrid.length;e++)y.snapGrid[e]<=y.virtualSize-y.size&&f.push(y.snapGrid[e]);y.snapGrid=f,Math.floor(y.virtualSize-y.size)-Math.floor(y.snapGrid[y.snapGrid.length-1])>1&&y.snapGrid.push(y.virtualSize-y.size)}0===y.snapGrid.length&&(y.snapGrid=[0]),0!==y.params.spaceBetween&&(y.isHorizontal()?y.rtl?y.slides.css({marginLeft:a+"px"}):y.slides.css({marginRight:a+"px"}):y.slides.css({marginBottom:a+"px"})),y.params.watchSlidesProgress&&y.updateSlidesOffset()}},y.updateSlidesOffset=function(){for(var e=0;e<y.slides.length;e++)y.slides[e].swiperSlideOffset=y.isHorizontal()?y.slides[e].offsetLeft:y.slides[e].offsetTop},y.updateSlidesProgress=function(e){if("undefined"==typeof e&&(e=y.translate||0),0!==y.slides.length){"undefined"==typeof y.slides[0].swiperSlideOffset&&y.updateSlidesOffset();var a=-e;y.rtl&&(a=e),y.slides.removeClass(y.params.slideVisibleClass);for(var t=0;t<y.slides.length;t++){var i=y.slides[t],s=(a-i.swiperSlideOffset)/(i.swiperSlideSize+y.params.spaceBetween);if(y.params.watchSlidesVisibility){var r=-(a-i.swiperSlideOffset),n=r+y.slidesSizesGrid[t],o=r>=0&&r<y.size||n>0&&n<=y.size||r<=0&&n>=y.size;o&&y.slides.eq(t).addClass(y.params.slideVisibleClass)}i.progress=y.rtl?-s:s}}},y.updateProgress=function(e){"undefined"==typeof e&&(e=y.translate||0);var a=y.maxTranslate()-y.minTranslate(),t=y.isBeginning,i=y.isEnd;0===a?(y.progress=0,y.isBeginning=y.isEnd=!0):(y.progress=(e-y.minTranslate())/a,y.isBeginning=y.progress<=0,y.isEnd=y.progress>=1),y.isBeginning&&!t&&y.emit("onReachBeginning",y),y.isEnd&&!i&&y.emit("onReachEnd",y),y.params.watchSlidesProgress&&y.updateSlidesProgress(e),y.emit("onProgress",y,y.progress)},y.updateActiveIndex=function(){var e,a,t,i=y.rtl?y.translate:-y.translate;for(a=0;a<y.slidesGrid.length;a++)"undefined"!=typeof y.slidesGrid[a+1]?i>=y.slidesGrid[a]&&i<y.slidesGrid[a+1]-(y.slidesGrid[a+1]-y.slidesGrid[a])/2?e=a:i>=y.slidesGrid[a]&&i<y.slidesGrid[a+1]&&(e=a+1):i>=y.slidesGrid[a]&&(e=a);(e<0||"undefined"==typeof e)&&(e=0),t=Math.floor(e/y.params.slidesPerGroup),t>=y.snapGrid.length&&(t=y.snapGrid.length-1),e!==y.activeIndex&&(y.snapIndex=t,y.previousIndex=y.activeIndex,y.activeIndex=e,y.updateClasses())},y.updateClasses=function(){y.slides.removeClass(y.params.slideActiveClass+" "+y.params.slideNextClass+" "+y.params.slidePrevClass);var e=y.slides.eq(y.activeIndex);e.addClass(y.params.slideActiveClass);var t=e.next("."+y.params.slideClass).addClass(y.params.slideNextClass);y.params.loop&&0===t.length&&y.slides.eq(0).addClass(y.params.slideNextClass);var i=e.prev("."+y.params.slideClass).addClass(y.params.slidePrevClass);if(y.params.loop&&0===i.length&&y.slides.eq(-1).addClass(y.params.slidePrevClass),y.paginationContainer&&y.paginationContainer.length>0){var s,r=y.params.loop?Math.ceil((y.slides.length-2*y.loopedSlides)/y.params.slidesPerGroup):y.snapGrid.length;if(y.params.loop?(s=Math.ceil((y.activeIndex-y.loopedSlides)/y.params.slidesPerGroup),s>y.slides.length-1-2*y.loopedSlides&&(s-=y.slides.length-2*y.loopedSlides),s>r-1&&(s-=r),s<0&&"bullets"!==y.params.paginationType&&(s=r+s)):s="undefined"!=typeof y.snapIndex?y.snapIndex:y.activeIndex||0,"bullets"===y.params.paginationType&&y.bullets&&y.bullets.length>0&&(y.bullets.removeClass(y.params.bulletActiveClass),y.paginationContainer.length>1?y.bullets.each(function(){a(this).index()===s&&a(this).addClass(y.params.bulletActiveClass)}):y.bullets.eq(s).addClass(y.params.bulletActiveClass)),"fraction"===y.params.paginationType&&(y.paginationContainer.find("."+y.params.paginationCurrentClass).text(s+1),y.paginationContainer.find("."+y.params.paginationTotalClass).text(r)),"progress"===y.params.paginationType){var n=(s+1)/r,o=n,l=1;y.isHorizontal()||(l=n,o=1),y.paginationContainer.find("."+y.params.paginationProgressbarClass).transform("translate3d(0,0,0) scaleX("+o+") scaleY("+l+")").transition(y.params.speed)}"custom"===y.params.paginationType&&y.params.paginationCustomRender&&(y.paginationContainer.html(y.params.paginationCustomRender(y,s+1,r)),y.emit("onPaginationRendered",y,y.paginationContainer[0]))}y.params.loop||(y.params.prevButton&&y.prevButton&&y.prevButton.length>0&&(y.isBeginning?(y.prevButton.addClass(y.params.buttonDisabledClass),y.params.a11y&&y.a11y&&y.a11y.disable(y.prevButton)):(y.prevButton.removeClass(y.params.buttonDisabledClass),y.params.a11y&&y.a11y&&y.a11y.enable(y.prevButton))),y.params.nextButton&&y.nextButton&&y.nextButton.length>0&&(y.isEnd?(y.nextButton.addClass(y.params.buttonDisabledClass),y.params.a11y&&y.a11y&&y.a11y.disable(y.nextButton)):(y.nextButton.removeClass(y.params.buttonDisabledClass),y.params.a11y&&y.a11y&&y.a11y.enable(y.nextButton))))},y.updatePagination=function(){if(y.params.pagination&&y.paginationContainer&&y.paginationContainer.length>0){var e="";if("bullets"===y.params.paginationType){for(var a=y.params.loop?Math.ceil((y.slides.length-2*y.loopedSlides)/y.params.slidesPerGroup):y.snapGrid.length,t=0;t<a;t++)e+=y.params.paginationBulletRender?y.params.paginationBulletRender(t,y.params.bulletClass):"<"+y.params.paginationElement+' class="'+y.params.bulletClass+'"></'+y.params.paginationElement+">";y.paginationContainer.html(e),y.bullets=y.paginationContainer.find("."+y.params.bulletClass),y.params.paginationClickable&&y.params.a11y&&y.a11y&&y.a11y.initPagination()}"fraction"===y.params.paginationType&&(e=y.params.paginationFractionRender?y.params.paginationFractionRender(y,y.params.paginationCurrentClass,y.params.paginationTotalClass):'<span class="'+y.params.paginationCurrentClass+'"></span> / <span class="'+y.params.paginationTotalClass+'"></span>',y.paginationContainer.html(e)),"progress"===y.params.paginationType&&(e=y.params.paginationProgressRender?y.params.paginationProgressRender(y,y.params.paginationProgressbarClass):'<span class="'+y.params.paginationProgressbarClass+'"></span>',y.paginationContainer.html(e)),"custom"!==y.params.paginationType&&y.emit("onPaginationRendered",y,y.paginationContainer[0])}},y.update=function(e){function a(){i=Math.min(Math.max(y.translate,y.maxTranslate()),y.minTranslate()),y.setWrapperTranslate(i),y.updateActiveIndex(),y.updateClasses()}if(y.updateContainerSize(),y.updateSlidesSize(),y.updateProgress(),y.updatePagination(),y.updateClasses(),y.params.scrollbar&&y.scrollbar&&y.scrollbar.set(),e){var t,i;y.controller&&y.controller.spline&&(y.controller.spline=void 0),y.params.freeMode?(a(),y.params.autoHeight&&y.updateAutoHeight()):(t=("auto"===y.params.slidesPerView||y.params.slidesPerView>1)&&y.isEnd&&!y.params.centeredSlides?y.slideTo(y.slides.length-1,0,!1,!0):y.slideTo(y.activeIndex,0,!1,!0),t||a())}else y.params.autoHeight&&y.updateAutoHeight()},y.onResize=function(e){y.params.breakpoints&&y.setBreakpoint();var a=y.params.allowSwipeToPrev,t=y.params.allowSwipeToNext;y.params.allowSwipeToPrev=y.params.allowSwipeToNext=!0,y.updateContainerSize(),y.updateSlidesSize(),("auto"===y.params.slidesPerView||y.params.freeMode||e)&&y.updatePagination(),y.params.scrollbar&&y.scrollbar&&y.scrollbar.set(),y.controller&&y.controller.spline&&(y.controller.spline=void 0);var i=!1;if(y.params.freeMode){var s=Math.min(Math.max(y.translate,y.maxTranslate()),y.minTranslate());y.setWrapperTranslate(s),y.updateActiveIndex(),y.updateClasses(),y.params.autoHeight&&y.updateAutoHeight()}else y.updateClasses(),i=("auto"===y.params.slidesPerView||y.params.slidesPerView>1)&&y.isEnd&&!y.params.centeredSlides?y.slideTo(y.slides.length-1,0,!1,!0):y.slideTo(y.activeIndex,0,!1,!0);y.params.lazyLoading&&!i&&y.lazy&&y.lazy.load(),y.params.allowSwipeToPrev=a,y.params.allowSwipeToNext=t};var T=["mousedown","mousemove","mouseup"];window.navigator.pointerEnabled?T=["pointerdown","pointermove","pointerup"]:window.navigator.msPointerEnabled&&(T=["MSPointerDown","MSPointerMove","MSPointerUp"]),y.touchEvents={start:y.support.touch||!y.params.simulateTouch?"touchstart":T[0],move:y.support.touch||!y.params.simulateTouch?"touchmove":T[1],end:y.support.touch||!y.params.simulateTouch?"touchend":T[2]},(window.navigator.pointerEnabled||window.navigator.msPointerEnabled)&&("container"===y.params.touchEventsTarget?y.container:y.wrapper).addClass("swiper-wp8-"+y.params.direction),y.initEvents=function(e){var a=e?"off":"on",t=e?"removeEventListener":"addEventListener",s="container"===y.params.touchEventsTarget?y.container[0]:y.wrapper[0],r=y.support.touch?s:document,n=!!y.params.nested;y.browser.ie?(s[t](y.touchEvents.start,y.onTouchStart,!1),r[t](y.touchEvents.move,y.onTouchMove,n),r[t](y.touchEvents.end,y.onTouchEnd,!1)):(y.support.touch&&(s[t](y.touchEvents.start,y.onTouchStart,!1),s[t](y.touchEvents.move,y.onTouchMove,n),s[t](y.touchEvents.end,y.onTouchEnd,!1)),!i.simulateTouch||y.device.ios||y.device.android||(s[t]("mousedown",y.onTouchStart,!1),document[t]("mousemove",y.onTouchMove,n),document[t]("mouseup",y.onTouchEnd,!1))),window[t]("resize",y.onResize),y.params.nextButton&&y.nextButton&&y.nextButton.length>0&&(y.nextButton[a]("click",y.onClickNext),y.params.a11y&&y.a11y&&y.nextButton[a]("keydown",y.a11y.onEnterKey)),y.params.prevButton&&y.prevButton&&y.prevButton.length>0&&(y.prevButton[a]("click",y.onClickPrev),y.params.a11y&&y.a11y&&y.prevButton[a]("keydown",y.a11y.onEnterKey)),y.params.pagination&&y.params.paginationClickable&&(y.paginationContainer[a]("click","."+y.params.bulletClass,y.onClickIndex),y.params.a11y&&y.a11y&&y.paginationContainer[a]("keydown","."+y.params.bulletClass,y.a11y.onEnterKey)),(y.params.preventClicks||y.params.preventClicksPropagation)&&s[t]("click",y.preventClicks,!0)},y.attachEvents=function(){y.initEvents()},y.detachEvents=function(){y.initEvents(!0)},y.allowClick=!0,y.preventClicks=function(e){y.allowClick||(y.params.preventClicks&&e.preventDefault(),y.params.preventClicksPropagation&&y.animating&&(e.stopPropagation(),e.stopImmediatePropagation()))},y.onClickNext=function(e){e.preventDefault(),y.isEnd&&!y.params.loop||y.slideNext()},y.onClickPrev=function(e){e.preventDefault(),y.isBeginning&&!y.params.loop||y.slidePrev()},y.onClickIndex=function(e){e.preventDefault();var t=a(this).index()*y.params.slidesPerGroup;y.params.loop&&(t+=y.loopedSlides),y.slideTo(t)},y.updateClickedSlide=function(e){var t=n(e,"."+y.params.slideClass),i=!1;if(t)for(var s=0;s<y.slides.length;s++)y.slides[s]===t&&(i=!0);if(!t||!i)return y.clickedSlide=void 0,void(y.clickedIndex=void 0);if(y.clickedSlide=t,y.clickedIndex=a(t).index(),y.params.slideToClickedSlide&&void 0!==y.clickedIndex&&y.clickedIndex!==y.activeIndex){var r,o=y.clickedIndex;if(y.params.loop){if(y.animating)return;r=a(y.clickedSlide).attr("data-swiper-slide-index"),y.params.centeredSlides?o<y.loopedSlides-y.params.slidesPerView/2||o>y.slides.length-y.loopedSlides+y.params.slidesPerView/2?(y.fixLoop(),o=y.wrapper.children("."+y.params.slideClass+'[data-swiper-slide-index="'+r+'"]:not(.swiper-slide-duplicate)').eq(0).index(),setTimeout(function(){y.slideTo(o)},0)):y.slideTo(o):o>y.slides.length-y.params.slidesPerView?(y.fixLoop(),o=y.wrapper.children("."+y.params.slideClass+'[data-swiper-slide-index="'+r+'"]:not(.swiper-slide-duplicate)').eq(0).index(),setTimeout(function(){y.slideTo(o)},0)):y.slideTo(o)}else y.slideTo(o)}};var b,S,C,z,M,P,I,k,E,D,B="input, select, textarea, button",L=Date.now(),H=[];y.animating=!1,y.touches={startX:0,startY:0,currentX:0,currentY:0,diff:0};var G,A;if(y.onTouchStart=function(e){if(e.originalEvent&&(e=e.originalEvent),G="touchstart"===e.type,G||!("which"in e)||3!==e.which){if(y.params.noSwiping&&n(e,"."+y.params.noSwipingClass))return void(y.allowClick=!0);if(!y.params.swipeHandler||n(e,y.params.swipeHandler)){var t=y.touches.currentX="touchstart"===e.type?e.targetTouches[0].pageX:e.pageX,i=y.touches.currentY="touchstart"===e.type?e.targetTouches[0].pageY:e.pageY;if(!(y.device.ios&&y.params.iOSEdgeSwipeDetection&&t<=y.params.iOSEdgeSwipeThreshold)){if(b=!0,S=!1,C=!0,M=void 0,A=void 0,y.touches.startX=t,y.touches.startY=i,z=Date.now(),y.allowClick=!0,y.updateContainerSize(),y.swipeDirection=void 0,y.params.threshold>0&&(k=!1),"touchstart"!==e.type){var s=!0;a(e.target).is(B)&&(s=!1),document.activeElement&&a(document.activeElement).is(B)&&document.activeElement.blur(),s&&e.preventDefault()}y.emit("onTouchStart",y,e)}}}},y.onTouchMove=function(e){if(e.originalEvent&&(e=e.originalEvent),!G||"mousemove"!==e.type){if(e.preventedByNestedSwiper)return y.touches.startX="touchmove"===e.type?e.targetTouches[0].pageX:e.pageX,void(y.touches.startY="touchmove"===e.type?e.targetTouches[0].pageY:e.pageY);if(y.params.onlyExternal)return y.allowClick=!1,void(b&&(y.touches.startX=y.touches.currentX="touchmove"===e.type?e.targetTouches[0].pageX:e.pageX,y.touches.startY=y.touches.currentY="touchmove"===e.type?e.targetTouches[0].pageY:e.pageY,z=Date.now()));if(G&&document.activeElement&&e.target===document.activeElement&&a(e.target).is(B))return S=!0,void(y.allowClick=!1);if(C&&y.emit("onTouchMove",y,e),!(e.targetTouches&&e.targetTouches.length>1)){if(y.touches.currentX="touchmove"===e.type?e.targetTouches[0].pageX:e.pageX,y.touches.currentY="touchmove"===e.type?e.targetTouches[0].pageY:e.pageY,"undefined"==typeof M){var t=180*Math.atan2(Math.abs(y.touches.currentY-y.touches.startY),Math.abs(y.touches.currentX-y.touches.startX))/Math.PI;M=y.isHorizontal()?t>y.params.touchAngle:90-t>y.params.touchAngle}if(M&&y.emit("onTouchMoveOpposite",y,e),"undefined"==typeof A&&y.browser.ieTouch&&(y.touches.currentX===y.touches.startX&&y.touches.currentY===y.touches.startY||(A=!0)),b){if(M)return void(b=!1);if(A||!y.browser.ieTouch){y.allowClick=!1,y.emit("onSliderMove",y,e),e.preventDefault(),y.params.touchMoveStopPropagation&&!y.params.nested&&e.stopPropagation(),S||(i.loop&&y.fixLoop(),I=y.getWrapperTranslate(),y.setWrapperTransition(0),y.animating&&y.wrapper.trigger("webkitTransitionEnd transitionend oTransitionEnd MSTransitionEnd msTransitionEnd"),y.params.autoplay&&y.autoplaying&&(y.params.autoplayDisableOnInteraction?y.stopAutoplay():y.pauseAutoplay()),D=!1,y.params.grabCursor&&(y.container[0].style.cursor="move",y.container[0].style.cursor="-webkit-grabbing",y.container[0].style.cursor="-moz-grabbin",y.container[0].style.cursor="grabbing")),S=!0;var s=y.touches.diff=y.isHorizontal()?y.touches.currentX-y.touches.startX:y.touches.currentY-y.touches.startY;s*=y.params.touchRatio,y.rtl&&(s=-s),y.swipeDirection=s>0?"prev":"next",P=s+I;var r=!0;if(s>0&&P>y.minTranslate()?(r=!1,y.params.resistance&&(P=y.minTranslate()-1+Math.pow(-y.minTranslate()+I+s,y.params.resistanceRatio))):s<0&&P<y.maxTranslate()&&(r=!1,y.params.resistance&&(P=y.maxTranslate()+1-Math.pow(y.maxTranslate()-I-s,y.params.resistanceRatio))),
+r&&(e.preventedByNestedSwiper=!0),!y.params.allowSwipeToNext&&"next"===y.swipeDirection&&P<I&&(P=I),!y.params.allowSwipeToPrev&&"prev"===y.swipeDirection&&P>I&&(P=I),y.params.followFinger){if(y.params.threshold>0){if(!(Math.abs(s)>y.params.threshold||k))return void(P=I);if(!k)return k=!0,y.touches.startX=y.touches.currentX,y.touches.startY=y.touches.currentY,P=I,void(y.touches.diff=y.isHorizontal()?y.touches.currentX-y.touches.startX:y.touches.currentY-y.touches.startY)}(y.params.freeMode||y.params.watchSlidesProgress)&&y.updateActiveIndex(),y.params.freeMode&&(0===H.length&&H.push({position:y.touches[y.isHorizontal()?"startX":"startY"],time:z}),H.push({position:y.touches[y.isHorizontal()?"currentX":"currentY"],time:(new window.Date).getTime()})),y.updateProgress(P),y.setWrapperTranslate(P)}}}}}},y.onTouchEnd=function(e){if(e.originalEvent&&(e=e.originalEvent),C&&y.emit("onTouchEnd",y,e),C=!1,b){y.params.grabCursor&&S&&b&&(y.container[0].style.cursor="move",y.container[0].style.cursor="-webkit-grab",y.container[0].style.cursor="-moz-grab",y.container[0].style.cursor="grab");var t=Date.now(),i=t-z;if(y.allowClick&&(y.updateClickedSlide(e),y.emit("onTap",y,e),i<300&&t-L>300&&(E&&clearTimeout(E),E=setTimeout(function(){y&&(y.params.paginationHide&&y.paginationContainer.length>0&&!a(e.target).hasClass(y.params.bulletClass)&&y.paginationContainer.toggleClass(y.params.paginationHiddenClass),y.emit("onClick",y,e))},300)),i<300&&t-L<300&&(E&&clearTimeout(E),y.emit("onDoubleTap",y,e))),L=Date.now(),setTimeout(function(){y&&(y.allowClick=!0)},0),!b||!S||!y.swipeDirection||0===y.touches.diff||P===I)return void(b=S=!1);b=S=!1;var s;if(s=y.params.followFinger?y.rtl?y.translate:-y.translate:-P,y.params.freeMode){if(s<-y.minTranslate())return void y.slideTo(y.activeIndex);if(s>-y.maxTranslate())return void(y.slides.length<y.snapGrid.length?y.slideTo(y.snapGrid.length-1):y.slideTo(y.slides.length-1));if(y.params.freeModeMomentum){if(H.length>1){var r=H.pop(),n=H.pop(),o=r.position-n.position,l=r.time-n.time;y.velocity=o/l,y.velocity=y.velocity/2,Math.abs(y.velocity)<y.params.freeModeMinimumVelocity&&(y.velocity=0),(l>150||(new window.Date).getTime()-r.time>300)&&(y.velocity=0)}else y.velocity=0;H.length=0;var p=1e3*y.params.freeModeMomentumRatio,d=y.velocity*p,c=y.translate+d;y.rtl&&(c=-c);var u,m=!1,h=20*Math.abs(y.velocity)*y.params.freeModeMomentumBounceRatio;if(c<y.maxTranslate())y.params.freeModeMomentumBounce?(c+y.maxTranslate()<-h&&(c=y.maxTranslate()-h),u=y.maxTranslate(),m=!0,D=!0):c=y.maxTranslate();else if(c>y.minTranslate())y.params.freeModeMomentumBounce?(c-y.minTranslate()>h&&(c=y.minTranslate()+h),u=y.minTranslate(),m=!0,D=!0):c=y.minTranslate();else if(y.params.freeModeSticky){var f,g=0;for(g=0;g<y.snapGrid.length;g+=1)if(y.snapGrid[g]>-c){f=g;break}c=Math.abs(y.snapGrid[f]-c)<Math.abs(y.snapGrid[f-1]-c)||"next"===y.swipeDirection?y.snapGrid[f]:y.snapGrid[f-1],y.rtl||(c=-c)}if(0!==y.velocity)p=y.rtl?Math.abs((-c-y.translate)/y.velocity):Math.abs((c-y.translate)/y.velocity);else if(y.params.freeModeSticky)return void y.slideReset();y.params.freeModeMomentumBounce&&m?(y.updateProgress(u),y.setWrapperTransition(p),y.setWrapperTranslate(c),y.onTransitionStart(),y.animating=!0,y.wrapper.transitionEnd(function(){y&&D&&(y.emit("onMomentumBounce",y),y.setWrapperTransition(y.params.speed),y.setWrapperTranslate(u),y.wrapper.transitionEnd(function(){y&&y.onTransitionEnd()}))})):y.velocity?(y.updateProgress(c),y.setWrapperTransition(p),y.setWrapperTranslate(c),y.onTransitionStart(),y.animating||(y.animating=!0,y.wrapper.transitionEnd(function(){y&&y.onTransitionEnd()}))):y.updateProgress(c),y.updateActiveIndex()}return void((!y.params.freeModeMomentum||i>=y.params.longSwipesMs)&&(y.updateProgress(),y.updateActiveIndex()))}var v,w=0,x=y.slidesSizesGrid[0];for(v=0;v<y.slidesGrid.length;v+=y.params.slidesPerGroup)"undefined"!=typeof y.slidesGrid[v+y.params.slidesPerGroup]?s>=y.slidesGrid[v]&&s<y.slidesGrid[v+y.params.slidesPerGroup]&&(w=v,x=y.slidesGrid[v+y.params.slidesPerGroup]-y.slidesGrid[v]):s>=y.slidesGrid[v]&&(w=v,x=y.slidesGrid[y.slidesGrid.length-1]-y.slidesGrid[y.slidesGrid.length-2]);var T=(s-y.slidesGrid[w])/x;if(i>y.params.longSwipesMs){if(!y.params.longSwipes)return void y.slideTo(y.activeIndex);"next"===y.swipeDirection&&(T>=y.params.longSwipesRatio?y.slideTo(w+y.params.slidesPerGroup):y.slideTo(w)),"prev"===y.swipeDirection&&(T>1-y.params.longSwipesRatio?y.slideTo(w+y.params.slidesPerGroup):y.slideTo(w))}else{if(!y.params.shortSwipes)return void y.slideTo(y.activeIndex);"next"===y.swipeDirection&&y.slideTo(w+y.params.slidesPerGroup),"prev"===y.swipeDirection&&y.slideTo(w)}}},y._slideTo=function(e,a){return y.slideTo(e,a,!0,!0)},y.slideTo=function(e,a,t,i){"undefined"==typeof t&&(t=!0),"undefined"==typeof e&&(e=0),e<0&&(e=0),y.snapIndex=Math.floor(e/y.params.slidesPerGroup),y.snapIndex>=y.snapGrid.length&&(y.snapIndex=y.snapGrid.length-1);var s=-y.snapGrid[y.snapIndex];y.params.autoplay&&y.autoplaying&&(i||!y.params.autoplayDisableOnInteraction?y.pauseAutoplay(a):y.stopAutoplay()),y.updateProgress(s);for(var r=0;r<y.slidesGrid.length;r++)-Math.floor(100*s)>=Math.floor(100*y.slidesGrid[r])&&(e=r);return!(!y.params.allowSwipeToNext&&s<y.translate&&s<y.minTranslate())&&(!(!y.params.allowSwipeToPrev&&s>y.translate&&s>y.maxTranslate()&&(y.activeIndex||0)!==e)&&("undefined"==typeof a&&(a=y.params.speed),y.previousIndex=y.activeIndex||0,y.activeIndex=e,y.rtl&&-s===y.translate||!y.rtl&&s===y.translate?(y.params.autoHeight&&y.updateAutoHeight(),y.updateClasses(),"slide"!==y.params.effect&&y.setWrapperTranslate(s),!1):(y.updateClasses(),y.onTransitionStart(t),0===a?(y.setWrapperTranslate(s),y.setWrapperTransition(0),y.onTransitionEnd(t)):(y.setWrapperTranslate(s),y.setWrapperTransition(a),y.animating||(y.animating=!0,y.wrapper.transitionEnd(function(){y&&y.onTransitionEnd(t)}))),!0)))},y.onTransitionStart=function(e){"undefined"==typeof e&&(e=!0),y.params.autoHeight&&y.updateAutoHeight(),y.lazy&&y.lazy.onTransitionStart(),e&&(y.emit("onTransitionStart",y),y.activeIndex!==y.previousIndex&&(y.emit("onSlideChangeStart",y),y.activeIndex>y.previousIndex?y.emit("onSlideNextStart",y):y.emit("onSlidePrevStart",y)))},y.onTransitionEnd=function(e){y.animating=!1,y.setWrapperTransition(0),"undefined"==typeof e&&(e=!0),y.lazy&&y.lazy.onTransitionEnd(),e&&(y.emit("onTransitionEnd",y),y.activeIndex!==y.previousIndex&&(y.emit("onSlideChangeEnd",y),y.activeIndex>y.previousIndex?y.emit("onSlideNextEnd",y):y.emit("onSlidePrevEnd",y))),y.params.hashnav&&y.hashnav&&y.hashnav.setHash()},y.slideNext=function(e,a,t){if(y.params.loop){if(y.animating)return!1;y.fixLoop();y.container[0].clientLeft;return y.slideTo(y.activeIndex+y.params.slidesPerGroup,a,e,t)}return y.slideTo(y.activeIndex+y.params.slidesPerGroup,a,e,t)},y._slideNext=function(e){return y.slideNext(!0,e,!0)},y.slidePrev=function(e,a,t){if(y.params.loop){if(y.animating)return!1;y.fixLoop();y.container[0].clientLeft;return y.slideTo(y.activeIndex-1,a,e,t)}return y.slideTo(y.activeIndex-1,a,e,t)},y._slidePrev=function(e){return y.slidePrev(!0,e,!0)},y.slideReset=function(e,a,t){return y.slideTo(y.activeIndex,a,e)},y.setWrapperTransition=function(e,a){y.wrapper.transition(e),"slide"!==y.params.effect&&y.effects[y.params.effect]&&y.effects[y.params.effect].setTransition(e),y.params.parallax&&y.parallax&&y.parallax.setTransition(e),y.params.scrollbar&&y.scrollbar&&y.scrollbar.setTransition(e),y.params.control&&y.controller&&y.controller.setTransition(e,a),y.emit("onSetTransition",y,e)},y.setWrapperTranslate=function(e,a,t){var i=0,r=0,n=0;y.isHorizontal()?i=y.rtl?-e:e:r=e,y.params.roundLengths&&(i=s(i),r=s(r)),y.params.virtualTranslate||(y.support.transforms3d?y.wrapper.transform("translate3d("+i+"px, "+r+"px, "+n+"px)"):y.wrapper.transform("translate("+i+"px, "+r+"px)")),y.translate=y.isHorizontal()?i:r;var o,l=y.maxTranslate()-y.minTranslate();o=0===l?0:(e-y.minTranslate())/l,o!==y.progress&&y.updateProgress(e),a&&y.updateActiveIndex(),"slide"!==y.params.effect&&y.effects[y.params.effect]&&y.effects[y.params.effect].setTranslate(y.translate),y.params.parallax&&y.parallax&&y.parallax.setTranslate(y.translate),y.params.scrollbar&&y.scrollbar&&y.scrollbar.setTranslate(y.translate),y.params.control&&y.controller&&y.controller.setTranslate(y.translate,t),y.emit("onSetTranslate",y,y.translate)},y.getTranslate=function(e,a){var t,i,s,r;return"undefined"==typeof a&&(a="x"),y.params.virtualTranslate?y.rtl?-y.translate:y.translate:(s=window.getComputedStyle(e,null),window.WebKitCSSMatrix?(i=s.transform||s.webkitTransform,i.split(",").length>6&&(i=i.split(", ").map(function(e){return e.replace(",",".")}).join(", ")),r=new window.WebKitCSSMatrix("none"===i?"":i)):(r=s.MozTransform||s.OTransform||s.MsTransform||s.msTransform||s.transform||s.getPropertyValue("transform").replace("translate(","matrix(1, 0, 0, 1,"),t=r.toString().split(",")),"x"===a&&(i=window.WebKitCSSMatrix?r.m41:16===t.length?parseFloat(t[12]):parseFloat(t[4])),"y"===a&&(i=window.WebKitCSSMatrix?r.m42:16===t.length?parseFloat(t[13]):parseFloat(t[5])),y.rtl&&i&&(i=-i),i||0)},y.getWrapperTranslate=function(e){return"undefined"==typeof e&&(e=y.isHorizontal()?"x":"y"),y.getTranslate(y.wrapper[0],e)},y.observers=[],y.initObservers=function(){if(y.params.observeParents)for(var e=y.container.parents(),a=0;a<e.length;a++)o(e[a]);o(y.container[0],{childList:!1}),o(y.wrapper[0],{attributes:!1})},y.disconnectObservers=function(){for(var e=0;e<y.observers.length;e++)y.observers[e].disconnect();y.observers=[]},y.createLoop=function(){y.wrapper.children("."+y.params.slideClass+"."+y.params.slideDuplicateClass).remove();var e=y.wrapper.children("."+y.params.slideClass);"auto"!==y.params.slidesPerView||y.params.loopedSlides||(y.params.loopedSlides=e.length),y.loopedSlides=parseInt(y.params.loopedSlides||y.params.slidesPerView,10),y.loopedSlides=y.loopedSlides+y.params.loopAdditionalSlides,y.loopedSlides>e.length&&(y.loopedSlides=e.length);var t,i=[],s=[];for(e.each(function(t,r){var n=a(this);t<y.loopedSlides&&s.push(r),t<e.length&&t>=e.length-y.loopedSlides&&i.push(r),n.attr("data-swiper-slide-index",t)}),t=0;t<s.length;t++)y.wrapper.append(a(s[t].cloneNode(!0)).addClass(y.params.slideDuplicateClass));for(t=i.length-1;t>=0;t--)y.wrapper.prepend(a(i[t].cloneNode(!0)).addClass(y.params.slideDuplicateClass))},y.destroyLoop=function(){y.wrapper.children("."+y.params.slideClass+"."+y.params.slideDuplicateClass).remove(),y.slides.removeAttr("data-swiper-slide-index")},y.reLoop=function(e){var a=y.activeIndex-y.loopedSlides;y.destroyLoop(),y.createLoop(),y.updateSlidesSize(),e&&y.slideTo(a+y.loopedSlides,0,!1)},y.fixLoop=function(){var e;y.activeIndex<y.loopedSlides?(e=y.slides.length-3*y.loopedSlides+y.activeIndex,e+=y.loopedSlides,y.slideTo(e,0,!1,!0)):("auto"===y.params.slidesPerView&&y.activeIndex>=2*y.loopedSlides||y.activeIndex>y.slides.length-2*y.params.slidesPerView)&&(e=-y.slides.length+y.activeIndex+y.loopedSlides,e+=y.loopedSlides,y.slideTo(e,0,!1,!0))},y.appendSlide=function(e){if(y.params.loop&&y.destroyLoop(),"object"==typeof e&&e.length)for(var a=0;a<e.length;a++)e[a]&&y.wrapper.append(e[a]);else y.wrapper.append(e);y.params.loop&&y.createLoop(),y.params.observer&&y.support.observer||y.update(!0)},y.prependSlide=function(e){y.params.loop&&y.destroyLoop();var a=y.activeIndex+1;if("object"==typeof e&&e.length){for(var t=0;t<e.length;t++)e[t]&&y.wrapper.prepend(e[t]);a=y.activeIndex+e.length}else y.wrapper.prepend(e);y.params.loop&&y.createLoop(),y.params.observer&&y.support.observer||y.update(!0),y.slideTo(a,0,!1)},y.removeSlide=function(e){y.params.loop&&(y.destroyLoop(),y.slides=y.wrapper.children("."+y.params.slideClass));var a,t=y.activeIndex;if("object"==typeof e&&e.length){for(var i=0;i<e.length;i++)a=e[i],y.slides[a]&&y.slides.eq(a).remove(),a<t&&t--;t=Math.max(t,0)}else a=e,y.slides[a]&&y.slides.eq(a).remove(),a<t&&t--,t=Math.max(t,0);y.params.loop&&y.createLoop(),y.params.observer&&y.support.observer||y.update(!0),y.params.loop?y.slideTo(t+y.loopedSlides,0,!1):y.slideTo(t,0,!1)},y.removeAllSlides=function(){for(var e=[],a=0;a<y.slides.length;a++)e.push(a);y.removeSlide(e)},y.effects={fade:{setTranslate:function(){for(var e=0;e<y.slides.length;e++){var a=y.slides.eq(e),t=a[0].swiperSlideOffset,i=-t;y.params.virtualTranslate||(i-=y.translate);var s=0;y.isHorizontal()||(s=i,i=0);var r=y.params.fade.crossFade?Math.max(1-Math.abs(a[0].progress),0):1+Math.min(Math.max(a[0].progress,-1),0);a.css({opacity:r}).transform("translate3d("+i+"px, "+s+"px, 0px)")}},setTransition:function(e){if(y.slides.transition(e),y.params.virtualTranslate&&0!==e){var a=!1;y.slides.transitionEnd(function(){if(!a&&y){a=!0,y.animating=!1;for(var e=["webkitTransitionEnd","transitionend","oTransitionEnd","MSTransitionEnd","msTransitionEnd"],t=0;t<e.length;t++)y.wrapper.trigger(e[t])}})}}},flip:{setTranslate:function(){for(var e=0;e<y.slides.length;e++){var t=y.slides.eq(e),i=t[0].progress;y.params.flip.limitRotation&&(i=Math.max(Math.min(t[0].progress,1),-1));var s=t[0].swiperSlideOffset,r=-180*i,n=r,o=0,l=-s,p=0;if(y.isHorizontal()?y.rtl&&(n=-n):(p=l,l=0,o=-n,n=0),t[0].style.zIndex=-Math.abs(Math.round(i))+y.slides.length,y.params.flip.slideShadows){var d=y.isHorizontal()?t.find(".swiper-slide-shadow-left"):t.find(".swiper-slide-shadow-top"),c=y.isHorizontal()?t.find(".swiper-slide-shadow-right"):t.find(".swiper-slide-shadow-bottom");0===d.length&&(d=a('<div class="swiper-slide-shadow-'+(y.isHorizontal()?"left":"top")+'"></div>'),t.append(d)),0===c.length&&(c=a('<div class="swiper-slide-shadow-'+(y.isHorizontal()?"right":"bottom")+'"></div>'),t.append(c)),d.length&&(d[0].style.opacity=Math.max(-i,0)),c.length&&(c[0].style.opacity=Math.max(i,0))}t.transform("translate3d("+l+"px, "+p+"px, 0px) rotateX("+o+"deg) rotateY("+n+"deg)")}},setTransition:function(e){if(y.slides.transition(e).find(".swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left").transition(e),y.params.virtualTranslate&&0!==e){var t=!1;y.slides.eq(y.activeIndex).transitionEnd(function(){if(!t&&y&&a(this).hasClass(y.params.slideActiveClass)){t=!0,y.animating=!1;for(var e=["webkitTransitionEnd","transitionend","oTransitionEnd","MSTransitionEnd","msTransitionEnd"],i=0;i<e.length;i++)y.wrapper.trigger(e[i])}})}}},cube:{setTranslate:function(){var e,t=0;y.params.cube.shadow&&(y.isHorizontal()?(e=y.wrapper.find(".swiper-cube-shadow"),0===e.length&&(e=a('<div class="swiper-cube-shadow"></div>'),y.wrapper.append(e)),e.css({height:y.width+"px"})):(e=y.container.find(".swiper-cube-shadow"),0===e.length&&(e=a('<div class="swiper-cube-shadow"></div>'),y.container.append(e))));for(var i=0;i<y.slides.length;i++){var s=y.slides.eq(i),r=90*i,n=Math.floor(r/360);y.rtl&&(r=-r,n=Math.floor(-r/360));var o=Math.max(Math.min(s[0].progress,1),-1),l=0,p=0,d=0;i%4===0?(l=4*-n*y.size,d=0):(i-1)%4===0?(l=0,d=4*-n*y.size):(i-2)%4===0?(l=y.size+4*n*y.size,d=y.size):(i-3)%4===0&&(l=-y.size,d=3*y.size+4*y.size*n),y.rtl&&(l=-l),y.isHorizontal()||(p=l,l=0);var c="rotateX("+(y.isHorizontal()?0:-r)+"deg) rotateY("+(y.isHorizontal()?r:0)+"deg) translate3d("+l+"px, "+p+"px, "+d+"px)";if(o<=1&&o>-1&&(t=90*i+90*o,y.rtl&&(t=90*-i-90*o)),s.transform(c),y.params.cube.slideShadows){var u=y.isHorizontal()?s.find(".swiper-slide-shadow-left"):s.find(".swiper-slide-shadow-top"),m=y.isHorizontal()?s.find(".swiper-slide-shadow-right"):s.find(".swiper-slide-shadow-bottom");0===u.length&&(u=a('<div class="swiper-slide-shadow-'+(y.isHorizontal()?"left":"top")+'"></div>'),s.append(u)),0===m.length&&(m=a('<div class="swiper-slide-shadow-'+(y.isHorizontal()?"right":"bottom")+'"></div>'),s.append(m)),u.length&&(u[0].style.opacity=Math.max(-o,0)),m.length&&(m[0].style.opacity=Math.max(o,0))}}if(y.wrapper.css({"-webkit-transform-origin":"50% 50% -"+y.size/2+"px","-moz-transform-origin":"50% 50% -"+y.size/2+"px","-ms-transform-origin":"50% 50% -"+y.size/2+"px","transform-origin":"50% 50% -"+y.size/2+"px"}),y.params.cube.shadow)if(y.isHorizontal())e.transform("translate3d(0px, "+(y.width/2+y.params.cube.shadowOffset)+"px, "+-y.width/2+"px) rotateX(90deg) rotateZ(0deg) scale("+y.params.cube.shadowScale+")");else{var h=Math.abs(t)-90*Math.floor(Math.abs(t)/90),f=1.5-(Math.sin(2*h*Math.PI/360)/2+Math.cos(2*h*Math.PI/360)/2),g=y.params.cube.shadowScale,v=y.params.cube.shadowScale/f,w=y.params.cube.shadowOffset;e.transform("scale3d("+g+", 1, "+v+") translate3d(0px, "+(y.height/2+w)+"px, "+-y.height/2/v+"px) rotateX(-90deg)")}var x=y.isSafari||y.isUiWebView?-y.size/2:0;y.wrapper.transform("translate3d(0px,0,"+x+"px) rotateX("+(y.isHorizontal()?0:t)+"deg) rotateY("+(y.isHorizontal()?-t:0)+"deg)")},setTransition:function(e){y.slides.transition(e).find(".swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left").transition(e),y.params.cube.shadow&&!y.isHorizontal()&&y.container.find(".swiper-cube-shadow").transition(e)}},coverflow:{setTranslate:function(){for(var e=y.translate,t=y.isHorizontal()?-e+y.width/2:-e+y.height/2,i=y.isHorizontal()?y.params.coverflow.rotate:-y.params.coverflow.rotate,s=y.params.coverflow.depth,r=0,n=y.slides.length;r<n;r++){var o=y.slides.eq(r),l=y.slidesSizesGrid[r],p=o[0].swiperSlideOffset,d=(t-p-l/2)/l*y.params.coverflow.modifier,c=y.isHorizontal()?i*d:0,u=y.isHorizontal()?0:i*d,m=-s*Math.abs(d),h=y.isHorizontal()?0:y.params.coverflow.stretch*d,f=y.isHorizontal()?y.params.coverflow.stretch*d:0;Math.abs(f)<.001&&(f=0),Math.abs(h)<.001&&(h=0),Math.abs(m)<.001&&(m=0),Math.abs(c)<.001&&(c=0),Math.abs(u)<.001&&(u=0);var g="translate3d("+f+"px,"+h+"px,"+m+"px)  rotateX("+u+"deg) rotateY("+c+"deg)";if(o.transform(g),o[0].style.zIndex=-Math.abs(Math.round(d))+1,y.params.coverflow.slideShadows){var v=y.isHorizontal()?o.find(".swiper-slide-shadow-left"):o.find(".swiper-slide-shadow-top"),w=y.isHorizontal()?o.find(".swiper-slide-shadow-right"):o.find(".swiper-slide-shadow-bottom");0===v.length&&(v=a('<div class="swiper-slide-shadow-'+(y.isHorizontal()?"left":"top")+'"></div>'),o.append(v)),0===w.length&&(w=a('<div class="swiper-slide-shadow-'+(y.isHorizontal()?"right":"bottom")+'"></div>'),o.append(w)),v.length&&(v[0].style.opacity=d>0?d:0),w.length&&(w[0].style.opacity=-d>0?-d:0)}}if(y.browser.ie){var x=y.wrapper[0].style;x.perspectiveOrigin=t+"px 50%"}},setTransition:function(e){y.slides.transition(e).find(".swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left").transition(e)}}},y.lazy={initialImageLoaded:!1,loadImageInSlide:function(e,t){if("undefined"!=typeof e&&("undefined"==typeof t&&(t=!0),0!==y.slides.length)){var i=y.slides.eq(e),s=i.find(".swiper-lazy:not(.swiper-lazy-loaded):not(.swiper-lazy-loading)");!i.hasClass("swiper-lazy")||i.hasClass("swiper-lazy-loaded")||i.hasClass("swiper-lazy-loading")||(s=s.add(i[0])),0!==s.length&&s.each(function(){var e=a(this);e.addClass("swiper-lazy-loading");var s=e.attr("data-background"),r=e.attr("data-src"),n=e.attr("data-srcset");y.loadImage(e[0],r||s,n,!1,function(){if(s?(e.css("background-image",'url("'+s+'")'),e.removeAttr("data-background")):(n&&(e.attr("srcset",n),e.removeAttr("data-srcset")),r&&(e.attr("src",r),e.removeAttr("data-src"))),e.addClass("swiper-lazy-loaded").removeClass("swiper-lazy-loading"),i.find(".swiper-lazy-preloader, .preloader").remove(),y.params.loop&&t){var a=i.attr("data-swiper-slide-index");if(i.hasClass(y.params.slideDuplicateClass)){var o=y.wrapper.children('[data-swiper-slide-index="'+a+'"]:not(.'+y.params.slideDuplicateClass+")");y.lazy.loadImageInSlide(o.index(),!1)}else{var l=y.wrapper.children("."+y.params.slideDuplicateClass+'[data-swiper-slide-index="'+a+'"]');y.lazy.loadImageInSlide(l.index(),!1)}}y.emit("onLazyImageReady",y,i[0],e[0])}),y.emit("onLazyImageLoad",y,i[0],e[0])})}},load:function(){var e;if(y.params.watchSlidesVisibility)y.wrapper.children("."+y.params.slideVisibleClass).each(function(){y.lazy.loadImageInSlide(a(this).index())});else if(y.params.slidesPerView>1)for(e=y.activeIndex;e<y.activeIndex+y.params.slidesPerView;e++)y.slides[e]&&y.lazy.loadImageInSlide(e);else y.lazy.loadImageInSlide(y.activeIndex);if(y.params.lazyLoadingInPrevNext)if(y.params.slidesPerView>1||y.params.lazyLoadingInPrevNextAmount&&y.params.lazyLoadingInPrevNextAmount>1){var t=y.params.lazyLoadingInPrevNextAmount,i=y.params.slidesPerView,s=Math.min(y.activeIndex+i+Math.max(t,i),y.slides.length),r=Math.max(y.activeIndex-Math.max(i,t),0);for(e=y.activeIndex+y.params.slidesPerView;e<s;e++)y.slides[e]&&y.lazy.loadImageInSlide(e);for(e=r;e<y.activeIndex;e++)y.slides[e]&&y.lazy.loadImageInSlide(e)}else{var n=y.wrapper.children("."+y.params.slideNextClass);n.length>0&&y.lazy.loadImageInSlide(n.index());var o=y.wrapper.children("."+y.params.slidePrevClass);o.length>0&&y.lazy.loadImageInSlide(o.index())}},onTransitionStart:function(){y.params.lazyLoading&&(y.params.lazyLoadingOnTransitionStart||!y.params.lazyLoadingOnTransitionStart&&!y.lazy.initialImageLoaded)&&y.lazy.load()},onTransitionEnd:function(){y.params.lazyLoading&&!y.params.lazyLoadingOnTransitionStart&&y.lazy.load()}},y.scrollbar={isTouched:!1,setDragPosition:function(e){var a=y.scrollbar,t=y.isHorizontal()?"touchstart"===e.type||"touchmove"===e.type?e.targetTouches[0].pageX:e.pageX||e.clientX:"touchstart"===e.type||"touchmove"===e.type?e.targetTouches[0].pageY:e.pageY||e.clientY,i=t-a.track.offset()[y.isHorizontal()?"left":"top"]-a.dragSize/2,s=-y.minTranslate()*a.moveDivider,r=-y.maxTranslate()*a.moveDivider;i<s?i=s:i>r&&(i=r),i=-i/a.moveDivider,y.updateProgress(i),y.setWrapperTranslate(i,!0)},dragStart:function(e){var a=y.scrollbar;a.isTouched=!0,e.preventDefault(),e.stopPropagation(),a.setDragPosition(e),clearTimeout(a.dragTimeout),a.track.transition(0),y.params.scrollbarHide&&a.track.css("opacity",1),y.wrapper.transition(100),a.drag.transition(100),y.emit("onScrollbarDragStart",y)},dragMove:function(e){var a=y.scrollbar;a.isTouched&&(e.preventDefault?e.preventDefault():e.returnValue=!1,a.setDragPosition(e),y.wrapper.transition(0),a.track.transition(0),a.drag.transition(0),y.emit("onScrollbarDragMove",y))},dragEnd:function(e){var a=y.scrollbar;a.isTouched&&(a.isTouched=!1,y.params.scrollbarHide&&(clearTimeout(a.dragTimeout),a.dragTimeout=setTimeout(function(){a.track.css("opacity",0),a.track.transition(400)},1e3)),y.emit("onScrollbarDragEnd",y),y.params.scrollbarSnapOnRelease&&y.slideReset())},enableDraggable:function(){var e=y.scrollbar,t=y.support.touch?e.track:document;a(e.track).on(y.touchEvents.start,e.dragStart),a(t).on(y.touchEvents.move,e.dragMove),a(t).on(y.touchEvents.end,e.dragEnd)},disableDraggable:function(){var e=y.scrollbar,t=y.support.touch?e.track:document;a(e.track).off(y.touchEvents.start,e.dragStart),a(t).off(y.touchEvents.move,e.dragMove),a(t).off(y.touchEvents.end,e.dragEnd)},set:function(){if(y.params.scrollbar){var e=y.scrollbar;e.track=a(y.params.scrollbar),y.params.uniqueNavElements&&"string"==typeof y.params.scrollbar&&e.track.length>1&&1===y.container.find(y.params.scrollbar).length&&(e.track=y.container.find(y.params.scrollbar)),e.drag=e.track.find(".swiper-scrollbar-drag"),0===e.drag.length&&(e.drag=a('<div class="swiper-scrollbar-drag"></div>'),e.track.append(e.drag)),e.drag[0].style.width="",e.drag[0].style.height="",e.trackSize=y.isHorizontal()?e.track[0].offsetWidth:e.track[0].offsetHeight,e.divider=y.size/y.virtualSize,e.moveDivider=e.divider*(e.trackSize/y.size),e.dragSize=e.trackSize*e.divider,y.isHorizontal()?e.drag[0].style.width=e.dragSize+"px":e.drag[0].style.height=e.dragSize+"px",e.divider>=1?e.track[0].style.display="none":e.track[0].style.display="",y.params.scrollbarHide&&(e.track[0].style.opacity=0)}},setTranslate:function(){if(y.params.scrollbar){var e,a=y.scrollbar,t=(y.translate||0,a.dragSize);e=(a.trackSize-a.dragSize)*y.progress,y.rtl&&y.isHorizontal()?(e=-e,e>0?(t=a.dragSize-e,e=0):-e+a.dragSize>a.trackSize&&(t=a.trackSize+e)):e<0?(t=a.dragSize+e,e=0):e+a.dragSize>a.trackSize&&(t=a.trackSize-e),y.isHorizontal()?(y.support.transforms3d?a.drag.transform("translate3d("+e+"px, 0, 0)"):a.drag.transform("translateX("+e+"px)"),a.drag[0].style.width=t+"px"):(y.support.transforms3d?a.drag.transform("translate3d(0px, "+e+"px, 0)"):a.drag.transform("translateY("+e+"px)"),a.drag[0].style.height=t+"px"),y.params.scrollbarHide&&(clearTimeout(a.timeout),a.track[0].style.opacity=1,a.timeout=setTimeout(function(){a.track[0].style.opacity=0,a.track.transition(400)},1e3))}},setTransition:function(e){y.params.scrollbar&&y.scrollbar.drag.transition(e)}},y.controller={LinearSpline:function(e,a){this.x=e,this.y=a,this.lastIndex=e.length-1;var t,i;this.x.length;this.interpolate=function(e){return e?(i=s(this.x,e),t=i-1,(e-this.x[t])*(this.y[i]-this.y[t])/(this.x[i]-this.x[t])+this.y[t]):0};var s=function(){var e,a,t;return function(i,s){for(a=-1,e=i.length;e-a>1;)i[t=e+a>>1]<=s?a=t:e=t;return e}}()},getInterpolateFunction:function(e){y.controller.spline||(y.controller.spline=y.params.loop?new y.controller.LinearSpline(y.slidesGrid,e.slidesGrid):new y.controller.LinearSpline(y.snapGrid,e.snapGrid))},setTranslate:function(e,a){function i(a){e=a.rtl&&"horizontal"===a.params.direction?-y.translate:y.translate,"slide"===y.params.controlBy&&(y.controller.getInterpolateFunction(a),r=-y.controller.spline.interpolate(-e)),r&&"container"!==y.params.controlBy||(s=(a.maxTranslate()-a.minTranslate())/(y.maxTranslate()-y.minTranslate()),r=(e-y.minTranslate())*s+a.minTranslate()),y.params.controlInverse&&(r=a.maxTranslate()-r),a.updateProgress(r),a.setWrapperTranslate(r,!1,y),a.updateActiveIndex()}var s,r,n=y.params.control;if(y.isArray(n))for(var o=0;o<n.length;o++)n[o]!==a&&n[o]instanceof t&&i(n[o]);else n instanceof t&&a!==n&&i(n)},setTransition:function(e,a){function i(a){a.setWrapperTransition(e,y),0!==e&&(a.onTransitionStart(),a.wrapper.transitionEnd(function(){r&&(a.params.loop&&"slide"===y.params.controlBy&&a.fixLoop(),a.onTransitionEnd())}))}var s,r=y.params.control;if(y.isArray(r))for(s=0;s<r.length;s++)r[s]!==a&&r[s]instanceof t&&i(r[s]);else r instanceof t&&a!==r&&i(r)}},y.hashnav={init:function(){if(y.params.hashnav){y.hashnav.initialized=!0;var e=document.location.hash.replace("#","");if(e)for(var a=0,t=0,i=y.slides.length;t<i;t++){var s=y.slides.eq(t),r=s.attr("data-hash");if(r===e&&!s.hasClass(y.params.slideDuplicateClass)){var n=s.index();y.slideTo(n,a,y.params.runCallbacksOnInit,!0)}}}},setHash:function(){y.hashnav.initialized&&y.params.hashnav&&(document.location.hash=y.slides.eq(y.activeIndex).attr("data-hash")||"")}},y.disableKeyboardControl=function(){y.params.keyboardControl=!1,a(document).off("keydown",l)},y.enableKeyboardControl=function(){y.params.keyboardControl=!0,a(document).on("keydown",l)},y.mousewheel={event:!1,lastScrollTime:(new window.Date).getTime()},y.params.mousewheelControl){try{new window.WheelEvent("wheel"),y.mousewheel.event="wheel"}catch(O){(window.WheelEvent||y.container[0]&&"wheel"in y.container[0])&&(y.mousewheel.event="wheel")}!y.mousewheel.event&&window.WheelEvent,y.mousewheel.event||void 0===document.onmousewheel||(y.mousewheel.event="mousewheel"),y.mousewheel.event||(y.mousewheel.event="DOMMouseScroll")}y.disableMousewheelControl=function(){return!!y.mousewheel.event&&(y.container.off(y.mousewheel.event,p),!0)},y.enableMousewheelControl=function(){return!!y.mousewheel.event&&(y.container.on(y.mousewheel.event,p),!0)},y.parallax={setTranslate:function(){y.container.children("[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]").each(function(){d(this,y.progress)}),y.slides.each(function(){var e=a(this);e.find("[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]").each(function(){var a=Math.min(Math.max(e[0].progress,-1),1);d(this,a)})})},setTransition:function(e){"undefined"==typeof e&&(e=y.params.speed),y.container.find("[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]").each(function(){var t=a(this),i=parseInt(t.attr("data-swiper-parallax-duration"),10)||e;0===e&&(i=0),t.transition(i)})}},y._plugins=[];for(var N in y.plugins){var R=y.plugins[N](y,y.params[N]);R&&y._plugins.push(R)}return y.callPlugins=function(e){for(var a=0;a<y._plugins.length;a++)e in y._plugins[a]&&y._plugins[a][e](arguments[1],arguments[2],arguments[3],arguments[4],arguments[5])},y.emitterEventListeners={},y.emit=function(e){y.params[e]&&y.params[e](arguments[1],arguments[2],arguments[3],arguments[4],arguments[5]);var a;if(y.emitterEventListeners[e])for(a=0;a<y.emitterEventListeners[e].length;a++)y.emitterEventListeners[e][a](arguments[1],arguments[2],arguments[3],arguments[4],arguments[5]);y.callPlugins&&y.callPlugins(e,arguments[1],arguments[2],arguments[3],arguments[4],arguments[5])},y.on=function(e,a){return e=c(e),y.emitterEventListeners[e]||(y.emitterEventListeners[e]=[]),y.emitterEventListeners[e].push(a),y},y.off=function(e,a){var t;if(e=c(e),"undefined"==typeof a)return y.emitterEventListeners[e]=[],y;if(y.emitterEventListeners[e]&&0!==y.emitterEventListeners[e].length){for(t=0;t<y.emitterEventListeners[e].length;t++)y.emitterEventListeners[e][t]===a&&y.emitterEventListeners[e].splice(t,1);return y}},y.once=function(e,a){e=c(e);var t=function(){a(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4]),y.off(e,t)};return y.on(e,t),y},y.a11y={makeFocusable:function(e){return e.attr("tabIndex","0"),e},addRole:function(e,a){return e.attr("role",a),e},addLabel:function(e,a){return e.attr("aria-label",a),e},disable:function(e){return e.attr("aria-disabled",!0),e},enable:function(e){return e.attr("aria-disabled",!1),e},onEnterKey:function(e){13===e.keyCode&&(a(e.target).is(y.params.nextButton)?(y.onClickNext(e),y.isEnd?y.a11y.notify(y.params.lastSlideMessage):y.a11y.notify(y.params.nextSlideMessage)):a(e.target).is(y.params.prevButton)&&(y.onClickPrev(e),y.isBeginning?y.a11y.notify(y.params.firstSlideMessage):y.a11y.notify(y.params.prevSlideMessage)),a(e.target).is("."+y.params.bulletClass)&&a(e.target)[0].click())},liveRegion:a('<span class="swiper-notification" aria-live="assertive" aria-atomic="true"></span>'),notify:function(e){var a=y.a11y.liveRegion;0!==a.length&&(a.html(""),a.html(e))},init:function(){y.params.nextButton&&y.nextButton&&y.nextButton.length>0&&(y.a11y.makeFocusable(y.nextButton),y.a11y.addRole(y.nextButton,"button"),y.a11y.addLabel(y.nextButton,y.params.nextSlideMessage)),y.params.prevButton&&y.prevButton&&y.prevButton.length>0&&(y.a11y.makeFocusable(y.prevButton),y.a11y.addRole(y.prevButton,"button"),y.a11y.addLabel(y.prevButton,y.params.prevSlideMessage)),a(y.container).append(y.a11y.liveRegion)},initPagination:function(){y.params.pagination&&y.params.paginationClickable&&y.bullets&&y.bullets.length&&y.bullets.each(function(){var e=a(this);y.a11y.makeFocusable(e),y.a11y.addRole(e,"button"),y.a11y.addLabel(e,y.params.paginationBulletMessage.replace(/{{index}}/,e.index()+1))})},destroy:function(){y.a11y.liveRegion&&y.a11y.liveRegion.length>0&&y.a11y.liveRegion.remove()}},y.init=function(){y.params.loop&&y.createLoop(),y.updateContainerSize(),y.updateSlidesSize(),y.updatePagination(),y.params.scrollbar&&y.scrollbar&&(y.scrollbar.set(),y.params.scrollbarDraggable&&y.scrollbar.enableDraggable()),"slide"!==y.params.effect&&y.effects[y.params.effect]&&(y.params.loop||y.updateProgress(),y.effects[y.params.effect].setTranslate()),y.params.loop?y.slideTo(y.params.initialSlide+y.loopedSlides,0,y.params.runCallbacksOnInit):(y.slideTo(y.params.initialSlide,0,y.params.runCallbacksOnInit),0===y.params.initialSlide&&(y.parallax&&y.params.parallax&&y.parallax.setTranslate(),y.lazy&&y.params.lazyLoading&&(y.lazy.load(),y.lazy.initialImageLoaded=!0))),y.attachEvents(),y.params.observer&&y.support.observer&&y.initObservers(),y.params.preloadImages&&!y.params.lazyLoading&&y.preloadImages(),y.params.autoplay&&y.startAutoplay(),y.params.keyboardControl&&y.enableKeyboardControl&&y.enableKeyboardControl(),y.params.mousewheelControl&&y.enableMousewheelControl&&y.enableMousewheelControl(),
+y.params.hashnav&&y.hashnav&&y.hashnav.init(),y.params.a11y&&y.a11y&&y.a11y.init(),y.emit("onInit",y)},y.cleanupStyles=function(){y.container.removeClass(y.classNames.join(" ")).removeAttr("style"),y.wrapper.removeAttr("style"),y.slides&&y.slides.length&&y.slides.removeClass([y.params.slideVisibleClass,y.params.slideActiveClass,y.params.slideNextClass,y.params.slidePrevClass].join(" ")).removeAttr("style").removeAttr("data-swiper-column").removeAttr("data-swiper-row"),y.paginationContainer&&y.paginationContainer.length&&y.paginationContainer.removeClass(y.params.paginationHiddenClass),y.bullets&&y.bullets.length&&y.bullets.removeClass(y.params.bulletActiveClass),y.params.prevButton&&a(y.params.prevButton).removeClass(y.params.buttonDisabledClass),y.params.nextButton&&a(y.params.nextButton).removeClass(y.params.buttonDisabledClass),y.params.scrollbar&&y.scrollbar&&(y.scrollbar.track&&y.scrollbar.track.length&&y.scrollbar.track.removeAttr("style"),y.scrollbar.drag&&y.scrollbar.drag.length&&y.scrollbar.drag.removeAttr("style"))},y.destroy=function(e,a){y.detachEvents(),y.stopAutoplay(),y.params.scrollbar&&y.scrollbar&&y.params.scrollbarDraggable&&y.scrollbar.disableDraggable(),y.params.loop&&y.destroyLoop(),a&&y.cleanupStyles(),y.disconnectObservers(),y.params.keyboardControl&&y.disableKeyboardControl&&y.disableKeyboardControl(),y.params.mousewheelControl&&y.disableMousewheelControl&&y.disableMousewheelControl(),y.params.a11y&&y.a11y&&y.a11y.destroy(),y.emit("onDestroy"),e!==!1&&(y=null)},y.init(),y}};t.prototype={isSafari:function(){var e=navigator.userAgent.toLowerCase();return e.indexOf("safari")>=0&&e.indexOf("chrome")<0&&e.indexOf("android")<0}(),isUiWebView:/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(navigator.userAgent),isArray:function(e){return"[object Array]"===Object.prototype.toString.apply(e)},browser:{ie:window.navigator.pointerEnabled||window.navigator.msPointerEnabled,ieTouch:window.navigator.msPointerEnabled&&window.navigator.msMaxTouchPoints>1||window.navigator.pointerEnabled&&window.navigator.maxTouchPoints>1},device:function(){var e=navigator.userAgent,a=e.match(/(Android);?[\s\/]+([\d.]+)?/),t=e.match(/(iPad).*OS\s([\d_]+)/),i=e.match(/(iPod)(.*OS\s([\d_]+))?/),s=!t&&e.match(/(iPhone\sOS)\s([\d_]+)/);return{ios:t||s||i,android:a}}(),support:{touch:window.Modernizr&&Modernizr.touch===!0||function(){return!!("ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch)}(),transforms3d:window.Modernizr&&Modernizr.csstransforms3d===!0||function(){var e=document.createElement("div").style;return"webkitPerspective"in e||"MozPerspective"in e||"OPerspective"in e||"MsPerspective"in e||"perspective"in e}(),flexbox:function(){for(var e=document.createElement("div").style,a="alignItems webkitAlignItems webkitBoxAlign msFlexAlign mozBoxAlign webkitFlexDirection msFlexDirection mozBoxDirection mozBoxOrient webkitBoxDirection webkitBoxOrient".split(" "),t=0;t<a.length;t++)if(a[t]in e)return!0}(),observer:function(){return"MutationObserver"in window||"WebkitMutationObserver"in window}()},plugins:{}};for(var i=["jQuery","Zepto","Dom7"],s=0;s<i.length;s++)window[i[s]]&&e(window[i[s]]);var r;r="undefined"==typeof Dom7?window.Dom7||window.Zepto||window.jQuery:Dom7,r&&("transitionEnd"in r.fn||(r.fn.transitionEnd=function(e){function a(r){if(r.target===this)for(e.call(this,r),t=0;t<i.length;t++)s.off(i[t],a)}var t,i=["webkitTransitionEnd","transitionend","oTransitionEnd","MSTransitionEnd","msTransitionEnd"],s=this;if(e)for(t=0;t<i.length;t++)s.on(i[t],a);return this}),"transform"in r.fn||(r.fn.transform=function(e){for(var a=0;a<this.length;a++){var t=this[a].style;t.webkitTransform=t.MsTransform=t.msTransform=t.MozTransform=t.OTransform=t.transform=e}return this}),"transition"in r.fn||(r.fn.transition=function(e){"string"!=typeof e&&(e+="ms");for(var a=0;a<this.length;a++){var t=this[a].style;t.webkitTransitionDuration=t.MsTransitionDuration=t.msTransitionDuration=t.MozTransitionDuration=t.OTransitionDuration=t.transitionDuration=e}return this})),window.Swiper=t}(),"undefined"!=typeof module?module.exports=window.Swiper:"function"==typeof define&&define.amd&&define([],function(){"use strict";return window.Swiper}),+function(e){"use strict";var a;e.fn.swiper=function(t){return this.each(function(){if(this){var i=e(this),s=i.data("swiper");return s||i.data("swiper",new Swiper(this,e.extend({},a,t))),s}})},a=e.fn.swiper.prototype.defaults={pagination:".swiper-pagination"}}($),+function(e){var a,t=function(e){this.initConfig(e),this.index=0};t.prototype={initConfig:function(t){this.config=e.extend({},a,t),this.activeIndex=this.lastActiveIndex=this.config.initIndex,this.config.items=this.config.items.map(function(e,a){return"string"==typeof e?{image:e,caption:""}:e}),this.tpl=e.t7.compile(this.config.tpl),this.config.autoOpen&&this.open()},open:function(a){if(this._open)return!1;if(!this.modal){this.modal=e(this.tpl(this.config)).appendTo(document.body),this.container=this.modal.find(".swiper-container"),this.wrapper=this.modal.find(".swiper-wrapper");var t=new Hammer(this.container[0]);t.get("pinch").set({enable:!0}),t.on("pinchstart",e.proxy(this.onGestureStart,this)),t.on("pinchmove",e.proxy(this.onGestureChange,this)),t.on("pinchend",e.proxy(this.onGestureEnd,this)),this.modal.on(e.touchEvents.start,e.proxy(this.onTouchStart,this)),this.modal.on(e.touchEvents.move,e.proxy(this.onTouchMove,this)),this.modal.on(e.touchEvents.end,e.proxy(this.onTouchEnd,this)),this.wrapper.transition(0),this.wrapper.transform("translate3d(-"+e(window).width()*this.config.initIndex+"px,0,0)"),this.container.find(".caption-item").eq(this.config.initIndex).addClass("active"),this.container.find(".swiper-pagination-bullet").eq(this.config.initIndex).addClass("swiper-pagination-bullet-active")}var i=this;this.modal.show().height(),this.modal.addClass("weui-photo-browser-modal-visible"),this.container.addClass("swiper-container-visible").transitionEnd(function(){i.initParams(),void 0!==a&&i.slideTo(a),i.config.onOpen&&i.config.onOpen.call(i)}),this._open=!0},close:function(){this.container.transitionEnd(e.proxy(function(){this.modal.hide(),this._open=!1,this.config.onClose&&this.config.onClose.call(this)},this)),this.container.removeClass("swiper-container-visible"),this.modal.removeClass("weui-photo-browser-modal-visible")},initParams:function(){return!this.containerHeight&&(this.windowWidth=e(window).width(),this.containerHeight=this.container.height(),this.containerWidth=this.container.width(),this.touchStart={},this.wrapperTransform=0,this.wrapperLastTransform=-e(window).width()*this.config.initIndex,this.wrapperDiff=0,this.lastScale=1,this.currentScale=1,this.imageLastTransform={x:0,y:0},this.imageTransform={x:0,y:0},this.imageDiff={x:0,y:0},void(this.imageLastDiff={x:0,y:0}))},onTouchStart:function(a){return!this.scaling&&(this.touching=!0,this.touchStart=e.getTouchPosition(a),this.touchMove=null,this.touchStartTime=+new Date,this.wrapperDiff=0,void(this.breakpointPosition=null))},onTouchMove:function(a){if(!this.touching||this.scaling)return!1;if(a.preventDefault(),this.gestureImage){var t=this.gestureImage[0].getBoundingClientRect();t.left>=0||t.right<=this.windowWidth?this.overflow=!0:this.overflow=!1}else this.oveflow=!1;var i=this.touchMove=e.getTouchPosition(a);if(1===this.currentScale||this.overflow)this.breakpointPosition?this.wrapperDiff=i.x-this.breakpointPosition.x:this.wrapperDiff=i.x-this.touchStart.x,0===this.activeIndex&&this.wrapperDiff>0&&(this.wrapperDiff=Math.pow(this.wrapperDiff,.8)),this.activeIndex===this.config.items.length-1&&this.wrapperDiff<0&&(this.wrapperDiff=-Math.pow(-this.wrapperDiff,.8)),this.wrapperTransform=this.wrapperLastTransform+this.wrapperDiff,this.doWrapperTransform();else{this.gestureImage;this.imageDiff={x:i.x-this.touchStart.x,y:i.y-this.touchStart.y},this.imageTransform={x:this.imageDiff.x+this.imageLastTransform.x,y:this.imageDiff.y+this.imageLastTransform.y},this.doImageTransform(),this.breakpointPosition=i,this.imageLastDiff=this.imageDiff}},onTouchEnd:function(e){if(!this.touching)return!1;if(this.touching=!1,this.scaling)return!1;var a=+new Date-this.touchStartTime;return a<200&&(!this.touchMove||Math.abs(this.touchStart.x-this.touchMove.x)<=2&&Math.abs(this.touchStart.y-this.touchMove.y)<=2)?void this.onClick():(this.wrapperDiff>0?this.wrapperDiff>this.containerWidth/2||this.wrapperDiff>20&&a<300?this.slidePrev():this.slideTo(this.activeIndex,200):-this.wrapperDiff>this.containerWidth/2||-this.wrapperDiff>20&&a<300?this.slideNext():this.slideTo(this.activeIndex,200),this.imageLastTransform=this.imageTransform,void this.adjust())},onClick:function(){var e=this;this._lastClickTime&&+new Date-this._lastClickTime<300?(this.onDoubleClick(),clearTimeout(this._clickTimeout)):this._clickTimeout=setTimeout(function(){e.close()},300),this._lastClickTime=+new Date},onDoubleClick:function(){this.gestureImage=this.container.find(".swiper-slide").eq(this.activeIndex).find("img"),this.currentScale=this.currentScale>1?1:2,this.doImageTransform(200),this.adjust()},onGestureStart:function(e){this.scaling=!0,this.gestureImage=this.container.find(".swiper-slide").eq(this.activeIndex).find("img")},onGestureChange:function(e){var a=this.lastScale*e.scale;a>this.config.maxScale?a=this.config.maxScale+Math.pow(a-this.config.maxScale,.5):a<1&&(a=Math.pow(a,.5)),this.currentScale=a,this.doImageTransform()},onGestureEnd:function(e){this.currentScale>this.config.maxScale?(this.currentScale=this.config.maxScale,this.doImageTransform(200)):this.currentScale<1&&(this.currentScale=1,this.doImageTransform(200)),this.lastScale=this.currentScale,this.scaling=!1,this.adjust()},doWrapperTransform:function(e,t){if(0===e){var i=this.wrapper.css("transition-property");this.wrapper.css("transition-property","none").transform("translate3d("+this.wrapperTransform+"px, 0, 0)"),this.wrapper.css("transition-property",i),t()}else this.wrapper.transitionEnd(function(){t&&t()}),this.wrapper.transition(e||a.duration).transform("translate3d("+this.wrapperTransform+"px, 0, 0)")},doImageTransform:function(e,a){this.gestureImage&&(this.gestureImage.transition(e||0).transform("translate3d("+this.imageTransform.x+"px,"+this.imageTransform.y+"px, 0) scale("+this.currentScale+")"),this._needAdjust=!0)},adjust:function(){if(!this._needAdjust)return!1;var e=this.gestureImage;if(!e)return!1;if(1===this.currentScale)return this.imageTransform=this.imageLastDiff={x:0,y:0},void this.doImageTransform(200);var a=e[0].getBoundingClientRect();a.height<this.containerHeight?this.imageTransform.y=this.imageLastTransform.y=0:a.top>0?this.imageTransform.y=this.imageTransform.y-a.top:a.bottom<this.containerHeight&&(this.imageTransform.y=this.imageTransform.y+this.containerHeight-a.bottom),this.doImageTransform(200),this._needAdjust=!1},slideTo:function(a,t){a<0&&(a=0),a>this.config.items.length-1&&(a=this.config.items.length-1),this.lastActiveIndex=this.activeIndex,this.activeIndex=a,this.wrapperTransform=-(a*this.containerWidth),this.wrapperLastTransform=this.wrapperTransform,this.doWrapperTransform(t,e.proxy(function(){return this.lastActiveIndex!==this.activeIndex&&(this.container.find(".caption-item.active").removeClass("active"),this.container.find(".swiper-slide-active").removeClass("swiper-slide-active"),this.container.find(".swiper-pagination-bullet-active").removeClass("swiper-pagination-bullet-active"),this.container.find(".caption-item").eq(this.activeIndex).addClass("active"),this.container.find(".swiper-slide").eq(this.activeIndex).addClass("swiper-slide-active"),this.container.find(".swiper-pagination-bullet").eq(this.activeIndex).addClass("swiper-pagination-bullet-active"),this.container.find(".swiper-slide img[style]").transition(0).transform("translate3d(0,0,0) scale(1)"),this.lastScale=1,this.currentScale=1,this.imageLastTransform={x:0,y:0},this.imageTransform={x:0,y:0},this.imageDiff={x:0,y:0},this.imageLastDiff={x:0,y:0},void(this.config.onSlideChange&&this.config.onSlideChange.call(this,this.activeIndex)))},this))},slideNext:function(){return this.slideTo(this.activeIndex+1,200)},slidePrev:function(){return this.slideTo(this.activeIndex-1,200)}},a=t.prototype.defaults={items:[],autoOpen:!1,onOpen:void 0,onClose:void 0,initIndex:0,maxScale:3,onSlideChange:void 0,duration:200,tpl:'<div class="weui-photo-browser-modal">            <div class="swiper-container">              <div class="swiper-wrapper">                {{#items}}                <div class="swiper-slide">                  <div class="photo-container">                    <img src="{{image}}" />                  </div>                </div>                {{/items}}              </div>              <div class="caption">                {{#items}}                <div class="caption-item caption-item-{{@index}}">{{caption}}</div>                {{/items}}              </div>              <div class="swiper-pagination swiper-pagination-bullets">                {{#items}}                <span class="swiper-pagination-bullet"></span>                {{/items}}              </div>            </div>          </div>'},e.photoBrowser=function(e){return new t(e)}}($);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/login.js b/platforms/android/app/src/main/assets/www/js/login.js
new file mode 100644
index 0000000..77b8b2a
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/login.js
@@ -0,0 +1,69 @@
+var app = {
+
+    // Application Constructor
+    initialize: function() {
+        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
+    },
+  
+    onDeviceReady: function() {
+        this.receivedEvent('deviceready');
+    },
+
+    // Update DOM on a Received Event
+    receivedEvent: function(id) {
+        var phone =  window.localStorage.getItem("phone");
+        if(!isEmpty(phone)){
+            $("#phone").val(phone)
+        }
+    },
+    toRegister :function(){
+        window.location = "register.html";
+    },
+    toForget :function(){
+        window.location = "findpwd.html";
+    },
+    login: function(){
+        //loading("正在处理");
+        var phone = $("#phone").val()
+        var pwd = $("#pwd").val()
+        if(isEmpty(phone)||isEmpty(pwd)){
+            return;
+        }
+        //loadingElement('loginBtn', '登录中...')
+        $.showLoading("登录中");
+        var param={
+            "username":phone,
+            "password":pwd
+        }
+        Login(param,function(ok,ret){
+            console.log(ret)
+            if(ok){
+               if(ret.code!=200){
+                 $.alert(ret.msg, "错误");
+                 //closeLoading('loginBtn')
+                 //showOk(ret.msg)
+                 $.hideLoading();
+               }else{
+                 window.localStorage.setItem("phone",phone); 
+                 window.localStorage.setItem("phoneX",ret.phone);
+                 window.localStorage.setItem("token",ret.token); 
+                 window.localStorage.setItem("tenantid",ret.tenantid); 
+                 window.localStorage.setItem("tokenexpire",ret.expire); 
+                 window.localStorage.setItem("tokentime",ret.now); 
+                 window.localStorage.setItem("userid",ret.userid);
+                 window.localStorage.setItem("signed",ret.signed); 
+                 window.localStorage.setItem("paypwdset",ret.paypwdset); 
+                 window.localStorage.setItem("name",ret.name);  
+                 window.location = "main.html";  
+               }     
+            }else{
+               //$.alert("请求失败了"+ret.status+",请稍后再试", "错误");
+               //closeLoading('loginBtn')
+               //showOk("请求失败了"+ret.status+",请稍后再试")
+               $.alert("请求失败了"+ret.status+",请稍后再试", "错误");
+               $.hideLoading();
+            }
+        })
+    }
+};
+app.initialize();
diff --git a/platforms/android/app/src/main/assets/www/js/main.js b/platforms/android/app/src/main/assets/www/js/main.js
new file mode 100644
index 0000000..a5b788d
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/main.js
@@ -0,0 +1,204 @@
+var app = {
+
+    // Application Constructor
+    initialize: function() {
+        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
+    },
+
+    onDeviceReady: function() {
+        var uid = window.localStorage.getItem("token");
+        $('#scanBtn').click(function() {
+             window.location = "scan.html";
+            /*app.checkBefore(function() {
+                app.checkOther(function() {
+                    window.location = "scan.html";
+                })
+            })*/
+        });
+        $('#qrcodeBtn').click(function() {
+            app.checkBefore(function() {
+                app.checkOther(function() {
+                    window.location = "qrcode.html";
+                })
+            })
+        });
+        $('#cardBtn').click(function() {
+            app.checkBefore(function() {
+                app.checkOther(function() {
+                    window.location = "card.html";
+                })
+            })
+        });
+        $('#billBtn').click(function() {
+            app.checkBefore(function() {
+                window.location = "bill.html";
+            })
+        });
+        $('#moreBtn').click(function() {
+            app.checkBefore(function() {
+                window.location = "bill.html";
+            })
+        });
+        $('#secBtn').click(function() {
+            app.checkBefore(function() {
+                window.location = "security.html";
+            })
+        });
+        $('#usersec').click(function() {
+            app.checkBefore(function() {
+                window.location = "security.html";
+            })
+        });
+        this.initData();
+    },
+    initData: function() {
+        this.loadBill()
+        this.initView();
+    },
+    loadBill:function(){
+        $("#loaddata").show()
+        $("#nodata").hide();
+        var param={
+            "pageno":1
+        }
+        V1Bills(param,function(ok,ret){
+            if(ok){
+                console.log(ret)
+                if(ret.code==200){
+                    $("#maingt").text(ret.t+"!")
+                    $("#user-amount").text(ret.amount)
+                    $("#user-point").text(ret.point)
+                    if(ret.page&&ret.page.count>0){
+                        GLOBAL_TODAY = ret.today;
+                        GLOBAL_YESTERDAY = ret.yesterday;
+                        app.initBillView(ret.page)
+                    }else{
+                        $("#loaddata").hide()
+                        $("#nodatahint").text("暂无数据")
+                        $("#nodata").show(); 
+                    }    
+                }else{
+                    $("#loaddata").hide()
+                    $("#nodatahint").text("数据加载异常")
+                    $("#nodata").show(); 
+                }
+            }else{
+                $("#loaddata").hide()
+                $("#nodatahint").text("请求数据失败")
+                $("#nodata").show();
+            }            
+        })
+    },
+
+    initBillView:function(page){
+        var html ='';
+        for(var i=0;i<page.data.length;i++){
+            var bean=page.data[i]
+            html +='<div class="aui-card-list-header aui-card-list-user" onclick="app.toBillDetail(\''+bean.refno+'\')">';
+            html +='<div class="aui-card-list-user-avatar"><img src="img/icon_meal.png" class="aui-margin-r-10 aui-img-round" />';
+            html +='</div><div class="aui-card-list-user-name">';
+            html +='<div>'+bean.transdesc+'</div>';
+            if(bean.tradeflag=='in'){
+                html +='<div class="aui-list-item-right">+'+bean.amount+'</div>';
+            }else{
+                html +='<div class="aui-list-item-right">'+bean.amount+'</div>';
+            }
+            html +='</div><div class="aui-card-list-user-info">'+formatDateNoYear(bean.transdate,bean.transtime)+'</div></div>';
+        }
+        $("#billcontent").html(html);
+        $("#loaddata").hide()
+        $("#nodata").hide(); 
+        $("#billcontent").show(); 
+    },
+    initView: function() {
+        var userid = window.localStorage.getItem("userid");
+        var signed = window.localStorage.getItem("signed");
+        if (isEmpty(userid)) {
+            $("#userbank").text("未绑定");
+            $("#userbank").css("color", "red")
+        } else {
+            $("#userbank").text("已绑定");
+            $("userbank").css("color", "#757575");
+        }
+        if (isEmpty(signed) || signed != 'yes') {
+            $("#usersign").text("未签约");
+            $("#usersign").css("color", "red")
+        } else {
+            $("#usersign").text("已签约");
+            $("usersign").css("color", "#757575");
+        }
+        var phone =  window.localStorage.getItem("phoneX");
+        if(!isEmpty(phone)){
+            $("#userphone").text(phone)
+        }
+        var name =  window.localStorage.getItem("name");
+        if(isEmpty(name)){
+            $("#username").text("匿名")
+        }else{
+            $("#username").text(name)
+            $("#homename").text(name)
+        }
+    },
+    checkBefore: function(callback) {
+        var uid = window.localStorage.getItem("token");
+        if (isEmpty(uid)) {
+            window.location = "login.html";
+        } else {
+            var userid = window.localStorage.getItem("userid");
+            if (isEmpty(userid)) {
+                var cum = new auiDialog({});
+                var confirm = cum.alert({
+                    title: "提示",
+                    msg: '为了不影响您正常使用相关功能,请先绑定银行卡',
+                    buttons: ['取消', '去绑卡']
+                }, function(ret) {
+                    if (ret.buttonIndex == 2) {
+                        window.location = 'bindcard.html'
+                    }
+                })
+            } else {
+                if (callback) {
+                    callback()
+                }
+            }
+        }
+    },
+    checkOther: function(callback) {
+        var payseted = window.localStorage.getItem("paypwdset");
+        var signed = window.localStorage.getItem("signed");
+        var cum = new auiDialog({});
+        console.log(payseted, signed)
+        if (isEmpty(payseted) || !payseted || payseted != 'true') {
+            var confirm = cum.alert({
+                title: "提示",
+                msg: '您还没有设置支付密码,无法使用该功能',
+                buttons: ['取消', '去设置']
+            }, function(ret) {
+                if (ret.buttonIndex == 2) {
+                    window.location = 'paypwdset.html'
+                }
+            })
+        } else {
+            if (isEmpty(signed) || signed != 'yes') {
+                var confirm = cum.alert({
+                    title: "提示",
+                    msg: '您尚未签约代扣免密付协议,无法使用该功能',
+                    buttons: ['取消', '去签约']
+                }, function(ret) {
+                    if (ret.buttonIndex == 2) {
+                        window.location = 'signxy.html'
+                    }
+                })
+            } else {
+                if (callback) {
+                    callback()
+                }
+            }
+        }
+    },
+    toBillDetail: function(refno) {
+        window.localStorage.setItem("currentrefno",refno);
+        window.location='billdetail.html';
+    }
+};
+app.initialize();
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/mobile.js b/platforms/android/app/src/main/assets/www/js/mobile.js
new file mode 100644
index 0000000..e5abfb7
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/mobile.js
@@ -0,0 +1,19 @@
+var app = {
+
+    // Application Constructor
+    initialize: function() {
+        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
+    },
+  
+    onDeviceReady: function() {
+        this.receivedEvent('deviceready');
+        var uid = window.localStorage.getItem("uid");
+        
+    },
+
+    // Update DOM on a Received Event
+    receivedEvent: function(id) {
+        
+    }
+};
+app.initialize();
diff --git a/platforms/android/app/src/main/assets/www/js/paypwdset.js b/platforms/android/app/src/main/assets/www/js/paypwdset.js
new file mode 100644
index 0000000..0fc1c95
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/paypwdset.js
@@ -0,0 +1,63 @@
+var app = {
+
+    // Application Constructor
+    initialize: function() {
+        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
+    },
+  
+    onDeviceReady: function() {
+        var uid = window.localStorage.getItem("uid");
+        
+    },
+    doNext: function() {
+        var pwd =  $("#pwd").val();
+        var repwd =  $("#repwd").val();
+        if(isEmpty(pwd)||isEmpty(repwd)){
+            return;
+        }
+        if(pwd.length!=6){
+            $.alert("支付密码为6位数字", "提示");
+            return;
+        }
+        if(pwd!=repwd){
+            $.alert("两次密码不一致,请确认", "提示");
+            return;
+        }
+        var paypwdtype = window.localStorage.getItem("paypwdtype"); 
+        if(isEmpty(paypwdtype)){
+            paypwdtype = "new"
+        }
+        var randomcode = window.localStorage.getItem("randomcode"); 
+        if(isEmpty(randomcode)){
+            randomcode = ""
+        }
+        $.showLoading("正在保存");
+        var param={
+            "pwd":pwd,
+            "repwd":repwd,
+            "type":paypwdtype,
+            "randcode":randomcode
+        }
+        V1Paypwd(param,function(ok,ret){
+            if(ok){
+                $.hideLoading();
+                if(ret.code==200){
+                     window.localStorage.removeItem("randomcode"); 
+                     var signed = window.localStorage.getItem("signed"); 
+                     window.localStorage.setItem("paypwdset",ret.paypwdset); 
+                     if(isEmpty(signed)||signed!='yes'){
+                        window.location='signxy.html'   
+                     }else{
+                        window.location='main.html'   
+                     }
+                }else{
+                    $.alert(ret.msg, "错误");
+                } 
+            }else{
+                $.hideLoading();
+                $.alert("请求失败了"+ret.status+",请稍后再试", "错误");
+            }
+        })
+    }
+};
+app.initialize();
diff --git a/platforms/android/app/src/main/assets/www/js/pwdset.js b/platforms/android/app/src/main/assets/www/js/pwdset.js
new file mode 100644
index 0000000..e8086a5
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/pwdset.js
@@ -0,0 +1,62 @@
+var app = {
+
+    // Application Constructor
+    initialize: function() {
+        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
+    },
+  
+    onDeviceReady: function() {
+        var uid = window.localStorage.getItem("uid");
+        
+    },
+    doRegister: function() {
+        var pwd =  $("#pwd").val();
+        var repwd =  $("#repwd").val();
+        if(isEmpty(pwd)||isEmpty(repwd)){
+            return;
+        }
+        if(pwd.length<6){
+            $.alert("密码至少6位以上字符", "提示");
+            return;
+        }
+        if(pwd!=repwd){
+            $.alert("两次密码不一致,请确认", "提示");
+            return;
+        }
+        var uid = window.localStorage.getItem("uid"); 
+        var code = window.localStorage.getItem("code"); 
+        $.showLoading("正在保存");
+        var param={
+            "pwd":pwd,
+            "repwd":repwd,
+            "id":uid,
+            "random":code
+        }
+        console.log(param)
+        IRegister(param,function(ok,ret){
+            if(ok){
+                $.hideLoading();
+                if(ret.code==200){
+                     window.localStorage.removeItem("code"); 
+                     window.localStorage.setItem("phoneX",ret.phone);
+                     window.localStorage.setItem("token",ret.token); 
+                     window.localStorage.setItem("userid",ret.userid); 
+                     window.localStorage.setItem("tenantid",ret.tenantid); 
+                     window.localStorage.setItem("tokenexpire",ret.expire); 
+                     window.localStorage.setItem("tokentime",ret.now);   
+                     window.localStorage.setItem("signed",ret.signed); 
+                     window.localStorage.setItem("paypwdset",ret.paypwdset); 
+                     $.alert("密码设置成功,您可以登录系统了", "提示", function() {
+                         window.location = "main.html"; 
+                      });
+                }else{
+                    $.alert(ret.msg, "错误");
+                } 
+            }else{
+                $.hideLoading();
+                $.alert("请求失败了"+ret.status+",请稍后再试", "错误");
+            }
+        })
+    }
+};
+app.initialize();
diff --git a/platforms/android/app/src/main/assets/www/js/qrcode.js b/platforms/android/app/src/main/assets/www/js/qrcode.js
new file mode 100644
index 0000000..35fe7a3
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/qrcode.js
@@ -0,0 +1,23 @@
+var app = {
+
+    // Application Constructor
+    initialize: function() {
+        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
+    },
+
+    onDeviceReady: function() {
+        var uid = window.localStorage.getItem("token");
+        var qrcode = new QRCode(document.getElementById("qrcode"), {
+          text: uid,
+          width: 150,
+          height: 150,
+          colorDark : "#000000",
+          colorLight : "#ffffff",
+          correctLevel : QRCode.CorrectLevel.L
+      });
+    },
+    toBillDetail :function(refno){
+        
+    }
+};
+app.initialize();
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/register.js b/platforms/android/app/src/main/assets/www/js/register.js
new file mode 100644
index 0000000..e0214ab
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/register.js
@@ -0,0 +1,77 @@
+var app = {
+
+    // Application Constructor
+    initialize: function() {
+        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
+    },
+  
+    onDeviceReady: function() {
+        var uid = window.localStorage.getItem("uid");
+        
+    },
+    doRegister: function() {
+        var phone =  $("#phone").val();
+        var code =  $("#code").val();
+        if(isEmpty(phone)||isEmpty(code)){
+            return;
+        }
+        var agree = $("input[type=checkbox]:checked").val();
+        if(isEmpty(agree)){
+            $.alert("请同意用户协议与隐私条款", "提示");
+            return;
+        }
+        $.showLoading("正在处理");
+        var param={
+            "phone":phone,
+            "code":code,
+            "platform":device.name+","+device.platform+","+device.version,
+            "uuid":device.uuid
+        }
+        console.log(param)
+        ICheckCode(param,function(ok,ret){
+            if(ok){
+                $.hideLoading();
+                console.log(ret)
+                if(ret.code==200){
+                     
+                     window.localStorage.setItem("phone",phone); 
+                     window.localStorage.setItem("uid",ret.uid); 
+                     window.localStorage.setItem("code",ret.randcode); 
+                     window.localStorage.removeItem("name"); 
+                     window.location="pwdset.html";
+                }else{
+                     $.alert(ret.msg, "错误");
+                } 
+            }else{
+                $.hideLoading();
+                $.alert("请求失败了"+ret.status+",请稍后再试", "错误");
+            }
+        })
+    },
+    getCode :function(){
+        var phone =  $("#phone").val();
+        if(isEmpty(phone)){
+            return;            
+        }
+        $.showLoading("请求中");
+        var param={
+            "phone":phone
+        }
+        IGetCode(param,function(ok,ret){
+            if(ok){
+                $.hideLoading();
+                if(ret.code==200){
+                    $("#codebtn").attr("disabled","disabled")
+                    $("#codebtn").addClass("vcodedisabled")
+                    btnTime('codebtn');
+                }else{
+                    $.alert(ret.msg, "错误");
+                } 
+            }else{
+                $.hideLoading();
+                $.alert("请求失败了"+ret.status+",请稍后再试", "错误");
+            }
+        })
+    }
+};
+app.initialize();
diff --git a/platforms/android/app/src/main/assets/www/js/scan.js b/platforms/android/app/src/main/assets/www/js/scan.js
new file mode 100644
index 0000000..07a89fc
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/scan.js
@@ -0,0 +1,159 @@
+var app = {
+
+    // Application Constructor
+    initialize: function() {
+        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
+    },
+
+    onDeviceReady: function() {
+        console.log(2);
+        if (typeof(QRScanner) != 'undefined') {
+            //初始化检测,申请摄像头等权限
+            console.log(1);
+            QRScanner.destroy();
+            QRScanner.prepare(onDone); // show the prompt
+        } else {
+            $.alert('插件加载失败');
+        }
+        function onDone(err, status) {
+            if (err) {
+                console.log(err);
+                $.alert('启动扫描出错:' + JSON.stringify(err), '提示');
+            }
+            if (status.authorized) {
+                //绑定扫描监听
+                // `QRScanner.cancelScan()` is called.
+                QRScanner.scan(displayContents);
+                function displayContents(err, text) {
+                    if (err) {
+                        // an error occurred, or the scan was canceled (error code `6`)
+                        $.alert('扫描出错,请稍后再试:' + JSON.stringify(err), '提示');
+                    } else {
+                        // The scan completed, display the contents of the QR code:
+                        //$.alert(text, '提示');
+                        showRet(text)
+                    }
+                }
+                //开始扫描,需要将页面的背景设置成透明
+                QRScanner.show();
+                console.log("QRScanner.scan");   
+            } else if (status.denied) {
+                // The video preview will remain black, and scanning is disabled. We can
+                // try to ask the user to change their mind, but we'll have to send them
+                // to their device settings with `QRScanner.openSettings()`.
+               $.alert('无法请求道相机权限,请在设置中开启', '提示');
+            } else {
+                // we didn't get permission, but we didn't get permanently denied. (On
+                // Android, a denial isn't permanent unless the user checks the "Don't
+                // ask again" box.) We can ask again at the next relevant opportunity.
+                $.alert('无法请求道相机权限,请在设置中开启', '提示');
+            }
+        }
+        this.receivedEvent()
+    },
+    receivedEvent: function() {
+        var light = false;
+        $('#lightBtn').click(function () {
+            if (light) {
+                QRScanner.enableLight();
+            } else {
+                QRScanner.disableLight();
+            }
+            light = !light;
+        });
+    },
+    goPage:function(){
+        QRScanner.destroy();
+        window.location="main.html"
+    }
+};
+app.initialize();
+var inAppBrowserRef;
+
+function showRet(url) {
+
+    var target = "_blank";
+
+    var options = "location=yes,hidden=yes,beforeload=yes";
+
+    inAppBrowserRef = cordova.InAppBrowser.open(url, target, options);
+
+    inAppBrowserRef.addEventListener('loadstart', loadStartCallBack);
+
+    inAppBrowserRef.addEventListener('loadstop', loadStopCallBack);
+
+    inAppBrowserRef.addEventListener('loaderror', loadErrorCallBack);
+
+    inAppBrowserRef.addEventListener('beforeload', beforeloadCallBack);
+
+    inAppBrowserRef.addEventListener('message', messageCallBack);
+}
+function loadStartCallBack() {
+
+    $('#status-message').text("loading please wait ...");
+
+}
+
+function loadStopCallBack() {
+
+    if (inAppBrowserRef != undefined) {
+
+        inAppBrowserRef.insertCSS({ code: "body{font-size: 25px;" });
+
+        inAppBrowserRef.executeScript({ code: "\
+            var message = 'this is the message';\
+            var messageObj = {my_message: message};\
+            var stringifiedMessageObj = JSON.stringify(messageObj);\
+            webkit.messageHandlers.cordova_iab.postMessage(stringifiedMessageObj);"
+        });
+
+        $('#status-message').text("");
+
+        inAppBrowserRef.show();
+    }
+
+}
+
+function loadErrorCallBack(params) {
+
+    $('#status-message').text("");
+
+    var scriptErrorMesssage =
+       "alert('Sorry we cannot open that page. Message from the server is : "
+       + params.message + "');"
+
+    inAppBrowserRef.executeScript({ code: scriptErrorMesssage }, executeScriptCallBack);
+
+    inAppBrowserRef.close();
+
+    inAppBrowserRef = undefined;
+
+}
+
+function executeScriptCallBack(params) {
+
+    if (params[0] == null) {
+
+        $('#status-message').text(
+           "Sorry we couldn't open that page. Message from the server is : '"
+           + params.message + "'");
+    }
+
+}
+
+function beforeloadCallBack(params, callback) {
+
+    if (params.url.startsWith("http://www.example.com/")) {
+
+        // Load this URL in the inAppBrowser.
+        callback(params.url);
+    } else {
+
+        // The callback is not invoked, so the page will not be loaded.
+        $('#status-message').text("This browser only opens pages on http://www.example.com/");
+    }
+}
+
+function messageCallBack(params){
+    $('#status-message').text("message received: "+params.data.my_message);
+}
diff --git a/platforms/android/app/src/main/assets/www/js/security.js b/platforms/android/app/src/main/assets/www/js/security.js
new file mode 100644
index 0000000..441d577
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/security.js
@@ -0,0 +1,17 @@
+var app = {
+
+    // Application Constructor
+    initialize: function() {
+        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
+    },
+  
+    onDeviceReady: function() {
+        var uid = window.localStorage.getItem("uid");
+        var phone =  window.localStorage.getItem("phoneX");
+        
+    },
+    doNext: function() {
+       
+    }
+};
+app.initialize();
diff --git a/platforms/android/app/src/main/assets/www/js/server.js b/platforms/android/app/src/main/assets/www/js/server.js
new file mode 100644
index 0000000..96d5023
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/server.js
@@ -0,0 +1,290 @@
+var dev = true;
+var SERVER = "";
+var GLOBAL_TODAY="";
+var GLOBAL_YESTERDAY="";
+if (dev) {
+    SERVER = "http://172.28.43.3:8099/payapi/mobileapi";
+}
+
+function V1Billdetail(param,callback) {
+    ajaxPost("/v1/billdetail", param, callback)
+}
+
+function V1Bills(param,callback) {
+    ajaxPost("/v1/bills", param, callback)
+}
+
+function V1CardLost(param,callback) {
+    ajaxPost("/v1/cardlost", param, callback)
+}
+
+function V1Signbxy(param,callback) {
+    ajaxPost("/v1/signbxy", param, callback)
+}
+
+function V1Bxy(callback) {
+    ajaxPost("/v1/bxy", {}, callback)
+}
+
+function V1Paypwd(param,callback) {
+    ajaxPost("/v1/paypwd", param, callback)
+}
+function V1Code(callback) {
+    ajaxPost("/v1/code", {}, callback)
+}
+function V1Checkcode(param,callback) {
+    ajaxPost("/v1/checkcode", param, callback)
+}
+
+function V1Bindcard(param,callback) {
+    ajaxPost("/v1/bindcard", param, callback)
+}
+
+function V1Infor(callback) {
+    ajaxPost("/v1/infor", {}, callback)
+}
+
+function IRegister(param,callback) {
+    ajaxPost("/i/register", param, callback)
+}
+
+function ICheckCode(param,callback) {
+    ajaxPost("/i/checkcode", param, callback)
+}
+
+function IGetPage(callback) {
+    ajaxPost("/i/uxy", {}, callback)
+}
+
+function IGetCode(param,callback) {
+    ajaxPost("/i/code", param, callback)
+}
+
+
+function IServeTime(callback) {
+    ajaxPost("/i/time", {}, callback)
+}
+
+function Login(param, callback) {
+    ajaxPost("/login", param, callback)
+}
+
+function ajaxGet(url, callback) {
+    var token = window.localStorage.getItem("token");
+    var tenantid = window.localStorage.getItem("tenantid");
+    $.ajax({
+        url: SERVER + url,
+        type: "GET",
+        dataType: "json",
+        headers: hd,
+        crossDomain: true,
+        success: function(result) {
+            if (callback) {
+                callback(true, result)
+            }
+        },
+        error: function(status, err) {
+            if (callback) {
+                callback(false, status)
+            }
+        }
+    });
+}
+
+function ajaxPost(url, param, callback) {
+    var token = window.localStorage.getItem("token");
+    var tenantid = window.localStorage.getItem("tenantid");
+    var hd = {};
+    hd["Authorization"] = "Bearer " + token;
+    hd["X-TENANT-ID"] = tenantid;
+    console.log(param)
+    $.ajax({
+        url: SERVER + url,
+        type: "POST",
+        contentType: "application/x-www-form-urlencoded",
+        dataType: "json",
+        data: param,
+        crossDomain: true,
+        timeout: 5000,
+        headers: hd,
+        success: function(result) {
+            if (callback) {
+                callback(true, result)
+            }
+        },
+        error: function(status, err) {
+            console.log(status,err)
+            if (status && status.status == 401) {
+                window.location = "login.html";
+            } else {
+                if (callback) {
+                    callback(false, status, err)
+                }
+            }
+        }
+    });
+}
+
+
+function formatDateShort(date) {
+    if (!date || date.length == 0) {
+        return date;
+    }
+    if (date.length < 6) {
+        return date;
+    }
+    if (date.length < 8) {
+        return date.substring(0, 4) + "-" + date.substring(4, 6);
+    }
+    return date.substring(0, 4) + "-" + date.substring(4, 6) + "-" + date.substring(6, 8);
+}
+
+function formatDate(date, flag) {
+    if (!date || date.length == 0) {
+        return date;
+    }
+    if (date.length < 6) {
+        return date;
+    }
+    if (date.length < 8) {
+        return date.substring(0, 4) + "-" + date.substring(4, 6);
+    }
+    if (date.length < 12) {
+        return date.substring(0, 4) + "-" + date.substring(4, 6) + "-" + date.substring(6, 8);
+    }
+    if (flag || date.length < 14) {
+        return date.substring(0, 4) + "-" + date.substring(4, 6) + "-" + date.substring(6, 8) + " " + date.substring(8, 10) + ":" + date.substring(10, 12);
+    }
+    return date.substring(0, 4) + "-" + date.substring(4, 6) + "-" + date.substring(6, 8) + " " + date.substring(8, 10) + ":" + date.substring(10, 12) + ":" + date.substring(12, 14);
+}
+function formatDateNoYear(date,time) {
+    if (isEmpty(date)) {
+        return date;
+    }
+    if(isEmpty(time)){
+        return date;
+    }
+    if (date.length < 8||time.length<4) {
+        return date;
+    }
+    if(!isEmpty(GLOBAL_TODAY)){
+        if(date==GLOBAL_TODAY){
+            return "今天 "+time.substring(0,2)+":"+time.substring(2,4)
+        }
+    }else if(!isEmpty(GLOBAL_YESTERDAY)){
+        if(date==GLOBAL_YESTERDAY){
+            return "昨天 "+time.substring(0,2)+":"+time.substring(2,4)
+        }
+    }
+    return date.substring(4, 6) + "-" + date.substring(6, 8) + " " +time.substring(0,2)+":"+time.substring(2,4)
+}
+
+function formateDateZH(date) {
+    if (!date || date.length == 0) {
+        return date;
+    }
+    if (date.length < 6) {
+        return date;
+    }
+    if (date.length < 8) {
+        return date.substring(0, 4) + "年" + date.substring(4, 6) + "月";
+    }
+    if (date.length < 12) {
+        return date.substring(0, 4) + "年" + date.substring(4, 6) + "月" + date.substring(6, 8) + "日";
+    }
+    if (date.length < 14) {
+        return date.substring(0, 4) + "-" + date.substring(4, 6) + "-" + date.substring(6, 8) + " " + date.substring(8, 10) + ":" + date.substring(10, 12);
+    }
+    return date.substring(0, 4) + "-" + date.substring(4, 6) + "-" + date.substring(6, 8) + " " + date.substring(8, 10) + ":" + date.substring(10, 12) + ":" + date.substring(12, 14);
+}
+
+function isNull(data) {
+    return (data == "" || data == undefined || data == null) ? true : false;
+}
+
+function checkMobile(sMobile) {
+    if (!(/^1[3|4|5|7|8|9][0-9]{9}$/.test(sMobile))) {
+        return false;
+    }
+    return true;
+}
+
+function isEmpty(str) {
+    if (!str || str == 'undefined' || str == null || str == '') {
+        return true;
+    }
+    return false;
+}
+
+function timeText(stime, t) {
+    var temp = parseInt((stime - t) / 1000);
+    if (temp <= 30) {
+        return '刚刚';
+    }
+    if (temp < 60) {
+        return temp + '秒钟前';
+    }
+    temp = parseInt(temp / 60);
+    if (temp < 60) {
+        return temp + '分钟前';
+    }
+    temp = parseInt(temp / 60);
+    if (temp < 24) {
+        return temp + '小时前';
+    }
+    temp = parseInt(temp / 24);
+    if (temp < 30) {
+        return temp + '天前';
+    }
+    temp = parseInt(temp / 30);
+    if (temp < 12) {
+        return temp + '个月前';
+    }
+    temp = parseInt(temp / 12);
+    return temp + '年前';
+}
+
+function trimTxt(str) {
+    if (isEmpty(str)) {
+        return '';
+    }
+    return str;
+}
+var wait=60;
+function btnTime(id) {
+    if (wait == 0) {
+        $("#"+id).removeAttr("disabled");      
+        $("#"+id).removeClass("vcodedisabled")    
+        $("#"+id).text("获取验证码");
+        wait = 60;
+    } else {
+        $("#"+id).attr("disabled", "disabled");
+        $("#"+id).text(wait + "s");
+        wait--;
+        setTimeout(function() {
+            btnTime(id)
+        },
+        1000)
+    }
+}
+var dialog;
+function showOk(m,callback){
+    if(!dialog||dialog==null){
+        dialog = new auiDialog({});
+    }
+    dialog.alert({
+        title:"提示",
+        msg:m,
+        buttons:['确定']
+    },function(ret){
+        if(callback){
+            callback(ret)
+        }
+    })
+}
+function alertError(msg){
+    $.alert(msg, "错误");
+}
+function alertOk(msg){
+    $.alert(msg, "提示");
+}
diff --git a/platforms/android/app/src/main/assets/www/js/signxy.js b/platforms/android/app/src/main/assets/www/js/signxy.js
new file mode 100644
index 0000000..b259a5b
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/signxy.js
@@ -0,0 +1,52 @@
+var db = null;
+var app = {
+
+    // Application Constructor
+    initialize: function() {
+        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
+    },
+
+    onDeviceReady: function() {
+        $.showLoading("加载中");
+        V1Bxy(function(ok, ret, err) {
+            if (ok) {
+                $.hideLoading(); 
+                if(ret.code==200){
+                    $("#content").html(ret.page);
+                    $("#btn").show();  
+                }else{
+                    $.alert(ret.msg, "错误");
+                }
+            } else {
+                $.hideLoading();
+                $.alert("加载失败了:" + ret.status, "错误");
+            }
+        })
+    },
+    agreeXY:function(){
+        var agree = $("input[type=checkbox]:checked").val();
+        if(isEmpty(agree)){
+            $.alert("请同意签约代扣协议", "提示");
+            return;
+        }
+        $.showLoading("正在请求");
+        var param={
+            "agree":agree
+        }
+        V1Signbxy(param,function(ok, ret, err) {
+            if (ok) {
+                $.hideLoading(); 
+                if(ret.code==200){
+                    window.localStorage.setItem("signed",ret.signed); 
+                    window.location="main.html";
+                }else{
+                    $.alert(ret.msg, "错误");
+                }
+            } else {
+                $.hideLoading();
+                $.alert("请求失败了:" + ret.status+"请稍后再试", "错误");
+            }
+        })
+    }
+};
+app.initialize();
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/js/uxy.js b/platforms/android/app/src/main/assets/www/js/uxy.js
new file mode 100644
index 0000000..094b649
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/js/uxy.js
@@ -0,0 +1,30 @@
+var db = null;
+var app = {
+
+    // Application Constructor
+    initialize: function() {
+        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
+    },
+
+    onDeviceReady: function() {
+        //$.showLoading("加载中");
+        IGetPage(function(ok, ret, err) {
+            if (ok) {
+                $.hideLoading(); 
+                if(ret.code==200){
+                    $("#content").html(ret.page)   
+                }else{
+                    /*$.alert(ret.msg, "错误", function() {
+                        window.location = "register.html";
+                    });*/
+                }
+            } else {
+                //$.hideLoading();
+                /*$.alert("加载失败了:" + ret.status, "错误", function() {
+                    window.location = "register.html";
+                });*/
+            }
+        })
+    }
+};
+app.initialize();
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/login.html b/platforms/android/app/src/main/assets/www/login.html
new file mode 100644
index 0000000..60827f3
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/login.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0"/>
+    <meta name="format-detection" content="telephone=no,email=no,date=no,address=no">
+    <title>登录</title>
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css" />
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css" />
+    <link rel="stylesheet" type="text/css" href="css/aui.css" />
+    <link rel="stylesheet" type="text/css" href="css/index.css" />
+</head>
+<body>
+    <div class="login-top">
+        大理市民卡
+    </div>
+    <section class="aui-content" >
+       <ul class="aui-list aui-form-list">
+            <li class="aui-list-item" >
+                <div class="aui-list-item-inner" >
+                    <div class="aui-list-item-label-icon">
+                        <i class="aui-iconfont aui-icon-mobile" ></i>
+                    </div>
+                    <div class="aui-list-item-input">
+                        <input type="tel" pattern="[0-9]*" placeholder="请输入手机号" id="phone" maxlength="11">
+                    </div>
+                </div>
+            </li>
+            <li class="aui-list-item">
+                <div class="aui-list-item-inner" >
+                    <div class="aui-list-item-label-icon">
+                        <i class="aui-iconfont aui-icon-lock"></i>
+                    </div>
+                    <div class="aui-list-item-input">
+                        <input type="password"  placeholder="请输入登录密码"  id="pwd" >
+                    </div>
+                </div>
+            </li>
+        </ul>
+    </section>
+    <section class="aui-content-padded" style="margin-top: 30px;">
+        <div class="aui-btn aui-btn-block aui-btn-info" tapmode onclick="app.login()">登录</div>
+    </section>
+    <section class="aui-content-padded" style="margin-top: 30px;">
+        <a class="aui-pull-left" href="findpwd.html" style="color: #666;">
+            忘记密码?
+        </a>
+        <a class="aui-pull-right" href="register.html" style="color: #666;">
+            新用户注册
+        </a>
+    </section>
+</body>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/lib/jquery-weui.js"></script>
+<script type="text/javascript" src="js/lib/aui-dialog.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
+<script type="text/javascript" src="js/login.js"></script>
+
+</html>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/login1.html b/platforms/android/app/src/main/assets/www/login1.html
new file mode 100644
index 0000000..9f92162
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/login1.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="viewport-fit=cover, initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <title>登录</title>
+</head>
+<body class="cover vertical-align-center align-center blend-soft-light" style="background: #49bce9;">
+    <div class="space"></div>
+    <div class="space"></div>
+    <div class="space"></div>
+    <h1 class="text-white" style="font-size: 35px;">大理市民卡</h1>
+    <div class="space"></div>
+    <div class="space"></div>
+    <div class="row">
+        <div class="col-90 col-center">
+            <div class="list no-border opacity-60 ">
+                <div class="item icon ion-android-phone-portrait border-white border-bottom text-white" style="display: flex;">
+                    <input class="placeholder-white text-white" type="number" style="font-size: 18px;" placeholder="请输入手机号" id="phone" maxlength="11">
+                </div>
+                <div class="item icon ion-android-lock border-white border-bottom text-white" style="display: flex;margin-top: 10px;">
+                    <input class="placeholder-white text-white" type="password" style="font-size: 18px;" placeholder="请输入密码" id="pwd">
+                </div>
+            </div>
+            <div class="space"></div>
+            <div class="space"></div>
+            <button class="border-white text-white full radius" onclick="app.login()" id="loginBtn" style="font-size: 18px;">登录</button>
+            <div class="left" style="margin-top: 20px;font-size: 16px;" onclick="app.toForget()">忘记密码?</div>
+            <div class="right"  style="margin-top: 20px;font-size: 16px;" onclick="app.toRegister()"> 新用户注册</div>
+        </div>
+    </div>
+</body>
+
+</html>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
+<script type="text/javascript" src="js/lib/jquery-weui.js"></script>
+<script type="text/javascript" src="js/login.js"></script>
+<script type="text/javascript">
+
+</script>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/main.html b/platforms/android/app/src/main/assets/www/main.html
new file mode 100644
index 0000000..2cb4444
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/main.html
@@ -0,0 +1,276 @@
+<!doctype html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0" />
+    <meta name="format-detection" content="telephone=no,email=no,date=no,address=no">
+    <link rel="stylesheet" type="text/css" href="css/aui.css" />
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/index.css" />
+</head>
+
+<body>
+    <div id="main1">
+        <div id="maintop">
+            <section class="aui-content " style="background-color: #03a9f4 !important;">
+                <h1 class="text-white align-left" style="font-size: 26px;color: #fff;padding: 30px 20px 0 20px;"><span id="maingt">您好!</span><span id="homename"></span></h1>
+                <div class="aui-grid aui-bg-info">
+                    <div class="aui-row" id="classify">
+                        <div class="aui-col-xs-6 top-btn" id="scanBtn">
+                            <div class="center-in"><img src="img/icon_scan.png" style="width:56px;"></div>
+                            <div class="aui-grid-label top-title">扫一扫</div>
+                        </div>
+                        <div class="aui-col-xs-6 top-btn" id="qrcodeBtn">
+                            <div class="center-in"><img src="img/icon_qrcode.png" style="width:56px;"></div>
+                            <div class="aui-grid-label top-title">付款码</div>
+                        </div>
+                    </div>
+                </div>
+            </section>
+            <section class="aui-content aui-margin-b-10">
+                <div class="aui-grid">
+                    <div class="aui-row">
+                        <div class="aui-col-xs-4" id="cardBtn">
+                            <div class="center-in"><img src="img/icon_card.png" style="width:28px;height: 28px"></div>
+                            <div class="aui-grid-label" style="margin-top:10px;">市民卡挂失</div>
+                        </div>
+                        <div class="aui-col-xs-4" id="billBtn">
+                            <div class="center-in"><img src="img/icon_bill.png" style="width:28px;height: 28px"></div>
+                            <div class="aui-grid-label" style="margin-top:10px;">账单查询</div>
+                        </div>
+                        <div class="aui-col-xs-4" id="secBtn">
+                            <div class="center-in"><img src="img/icon_securty.png" style="width:28px;height: 28px"></div>
+                            <div class="aui-grid-label" style="margin-top:10px;">账户安全</div>
+                        </div>
+                    </div>
+                </div>
+            </section>
+            <div class="aui-card-list">
+                <div class="aui-card-list-header" style="border-bottom: 1px solid #f2f2f2">
+                    <div class="aui-font-size-14">近期交易</div>
+                    <div class="aui-list-item-right" style="font-size: 16px;color:#49bce9" id="moreBtn">更多></div>
+                </div>
+            </div>
+        </div>
+        <div style="position: absolute;top:320px;bottom:52px;width: 100%;overflow: auto;" id="maincontent">
+            <section class="aui-content">
+                <div class="weui-loadmore" id="loaddata">
+                    <i class="weui-loading"></i>
+                    <span class="weui-loadmore__tips">正在加载</span>
+                </div>
+                <div class="weui-loadmore weui-loadmore_line" id="nodata" style="display: none" onclick="app.loadBill()">
+                    <span class="weui-loadmore__tips" style="background: transparent;" id="nodatahint">暂无数据</span>
+                </div>
+                <div class="aui-card-list" id="billcontent" style="display: none">
+                    <div class="aui-card-list-header aui-card-list-user" onclick="app.toBillDetail()">
+                        <div class="aui-card-list-user-avatar">
+                            <img src="img/icon_meal.png" class="aui-margin-r-10 aui-img-round" />
+                        </div>
+                        <div class="aui-card-list-user-name">
+                            <div>食堂就餐</div>
+                            <div class="aui-list-item-right">+100</div>
+                        </div>
+                        <div class="aui-card-list-user-info">2019-08-09 11:05</div>
+                    </div>
+                    <div class="aui-card-list-header aui-card-list-user">
+                        <div class="aui-card-list-user-avatar">
+                            <img src="img/icon_water.png" class="aui-margin-r-10 aui-img-round" />
+                        </div>
+                        <div class="aui-card-list-user-name">
+                            <div>生活用水</div>
+                            <div class="aui-list-item-right">+100</div>
+                        </div>
+                        <div class="aui-card-list-user-info">今天 11:05</div>
+                    </div>
+                    <div class="aui-card-list-header aui-card-list-user">
+                        <div class="aui-card-list-user-avatar">
+                            <img src="img/icon_car.png" class="aui-margin-r-10 aui-img-round" />
+                        </div>
+                        <div class="aui-card-list-user-name">
+                            <div>交通出行</div>
+                            <div class="aui-list-item-right">+100</div>
+                        </div>
+                        <div class="aui-card-list-user-info">今天 11:05</div>
+                    </div>
+                    <div class="aui-card-list-header aui-card-list-user" onclick="app.toBillDetail()">
+                        <div class="aui-card-list-user-avatar">
+                            <img src="img/icon_meal.png" class="aui-margin-r-10 aui-img-round" />
+                        </div>
+                        <div class="aui-card-list-user-name">
+                            <div>食堂就餐</div>
+                            <div class="aui-list-item-right">+100</div>
+                        </div>
+                        <div class="aui-card-list-user-info">2019-08-09 11:05</div>
+                    </div>
+                    <div class="aui-card-list-header aui-card-list-user">
+                        <div class="aui-card-list-user-avatar">
+                            <img src="img/icon_water.png" class="aui-margin-r-10 aui-img-round" />
+                        </div>
+                        <div class="aui-card-list-user-name">
+                            <div>生活用水</div>
+                            <div class="aui-list-item-right">+100</div>
+                        </div>
+                        <div class="aui-card-list-user-info">今天 11:05</div>
+                    </div>
+                    <div class="aui-card-list-header aui-card-list-user">
+                        <div class="aui-card-list-user-avatar">
+                            <img src="img/icon_car.png" class="aui-margin-r-10 aui-img-round" />
+                        </div>
+                        <div class="aui-card-list-user-name">
+                            <div>交通出行</div>
+                            <div class="aui-list-item-right">+100</div>
+                        </div>
+                        <div class="aui-card-list-user-info">今天 11:05</div>
+                    </div>
+                    <div class="aui-card-list-header aui-card-list-user" onclick="app.toBillDetail()">
+                        <div class="aui-card-list-user-avatar">
+                            <img src="img/icon_meal.png" class="aui-margin-r-10 aui-img-round" />
+                        </div>
+                        <div class="aui-card-list-user-name">
+                            <div>食堂就餐</div>
+                            <div class="aui-list-item-right">+100</div>
+                        </div>
+                        <div class="aui-card-list-user-info">2019-08-09 11:05</div>
+                    </div>
+                    <div class="aui-card-list-header aui-card-list-user">
+                        <div class="aui-card-list-user-avatar">
+                            <img src="img/icon_water.png" class="aui-margin-r-10 aui-img-round" />
+                        </div>
+                        <div class="aui-card-list-user-name">
+                            <div>生活用水</div>
+                            <div class="aui-list-item-right">+100</div>
+                        </div>
+                        <div class="aui-card-list-user-info">今天 11:05</div>
+                    </div>
+                    <div class="aui-card-list-header aui-card-list-user">
+                        <div class="aui-card-list-user-avatar">
+                            <img src="img/icon_car.png" class="aui-margin-r-10 aui-img-round" />
+                        </div>
+                        <div class="aui-card-list-user-name">
+                            <div>交通出行</div>
+                            <div class="aui-list-item-right">+100</div>
+                        </div>
+                        <div class="aui-card-list-user-info">今天 11:05</div>
+                    </div>
+                    <div class="aui-card-list-header aui-card-list-user">
+                        <div class="aui-card-list-user-avatar">
+                            <img src="img/icon_car.png" class="aui-margin-r-10 aui-img-round" />
+                        </div>
+                        <div class="aui-card-list-user-name">
+                            <div>交通出行</div>
+                            <div class="aui-list-item-right">+100</div>
+                        </div>
+                        <div class="aui-card-list-user-info">今天 11:05</div>
+                    </div>
+                   
+                </div>
+            </section>
+        </div>
+    </div>
+    <div id="main2" style="display: none;">
+        <header class="aui-bar aui-bar-nav" style="padding-top:25px;font-size: 22px">
+            我的
+        </header>
+        <section class="aui-content bg-white aui-margin-b-15" style=" margin-top: -2px;">
+            <div class="aui-list aui-media-list aui-list-noborder aui-bg-info user-info">
+                <div class="aui-list-item aui-list-item-middle top-btn">
+                    <div class="aui-media-list-item-inner ">
+                        <div class="aui-list-item-media" style="width:3rem;">
+                            <img src="img/icon_header.png" class="aui-img-round" id="userlogo">
+                        </div>
+                        <div class="aui-list-item-inner">
+                            <div class="aui-list-item-text text-white aui-font-size-18" id="username">匿名</div>
+                            <div class="aui-list-item-text text-white">
+                                <div><i class="aui-iconfont aui-icon-mobile aui-font-size-14"></i><span id="userphone"></span></div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <section class="aui-content aui-grid ">
+                <div class="aui-row aui-margin-t-10">
+                    <div class="aui-col-xs-4 aui-border-r">
+                        <big class="aui-text-warning" id="user-amount">0.00</big>
+                        <div class="aui-gird-lable aui-font-size-12">余额</div>
+                    </div>
+                    <div class="aui-col-xs-4 aui-border-r">
+                        <big class="aui-text-success" id="user-point">0</big>
+                        <div class="aui-gird-lable aui-font-size-12">积分</div>
+                    </div>
+                    <div class="aui-col-xs-4 ">
+                        <big class="aui-text-danger" id="user-coupon">0</big>
+                        <div class="aui-gird-lable aui-font-size-12">优惠券</div>
+                    </div>
+                </div>
+            </section>
+            
+        </section>
+        <section class="aui-content">
+            <ul class="aui-list aui-list-in aui-margin-b-15">
+                <li class="aui-list-item">
+                    <div class="aui-list-item-label-icon">
+                        <i class="aui-iconfont aui-icon-cert aui-text-info"></i>
+                    </div>
+                    <div class="aui-list-item-inner aui-list-item-arrow">
+                        <div class="aui-list-item-title">银行卡</div>
+                        <div class="aui-list-item-right" id="userbank"></div>
+                    </div>
+                </li>
+                <li class="aui-list-item">
+                    <div class="aui-list-item-label-icon">
+                        <i class="aui-iconfont aui-icon-pencil aui-text-danger"></i>
+                    </div>
+                    <div class="aui-list-item-inner aui-list-item-arrow">
+                        <div class="aui-list-item-title">签约代扣免密付</div>
+                        <div class="aui-list-item-right" id="usersign"></div>
+                    </div>
+                </li>
+            </ul>
+            <ul class="aui-list aui-list-in">
+                <li class="aui-list-item" id="usersec">
+                    <div class="aui-list-item-label-icon">
+                        <i class="aui-iconfont aui-icon-lock aui-text-info"></i>
+                    </div>
+                    <div class="aui-list-item-inner aui-list-item-arrow">
+                        <div class="aui-list-item-title">账户安全</div>
+                    </div>
+                </li>
+            </ul>
+        </section>
+    </div>
+    <footer class="aui-bar aui-bar-tab aui-border-t" id="footer">
+        <div class="aui-bar-tab-item aui-active" tapmode onclick="switchTo(1)" id="tab1">
+            <i class="aui-iconfont aui-icon-home"></i>
+            <div class="aui-bar-tab-label">首页</div>
+        </div>
+        <div class="aui-bar-tab-item" tapmode onclick="switchTo(2)" id="tab2">
+            <i class="aui-iconfont aui-icon-my"></i>
+            <div class="aui-bar-tab-label">我的</div>
+        </div>
+    </footer>
+</body>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/lib/aui-tab.js"></script>
+<script type="text/javascript" src="js/lib/aui-dialog.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
+<script type="text/javascript" src="js/main.js"></script>
+<script type="text/javascript">
+var tab = new auiTab({
+    element: document.getElementById("footer"),
+}, function(ret) {
+    console.log(ret)
+    if (ret.index == 1) {
+        $("#main1").show();
+        $("#main2").hide();
+    } else if (ret.index == 2) {
+        $("#main1").hide();
+        $("#main2").show();
+    }
+});
+$("#maincontent").css("top", $("#maintop").height())
+</script>
+
+</html>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/main1.html b/platforms/android/app/src/main/assets/www/main1.html
new file mode 100644
index 0000000..73db78e
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/main1.html
@@ -0,0 +1,175 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <link rel="stylesheet" type="text/css" href="mobileui/style.css">
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="viewport-fit=cover, initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
+    <link rel="stylesheet" type="text/css" href="mobileui/css/imports.css">
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <title>大理市民卡</title>
+</head>
+
+<body class="has-footer">
+    <div class="footer  shadow white tab tab-bottom" style="border-top: 1px solid #F2F5F5">
+        <button class="icon ion-ios-home-outline active " style="color: #49bce9;" onclick="openTab('myTabAbout')">首页</button>
+        <button class="icon ion-ios-person-outline " style="color: #49bce9;" onclick="openTab('myTabEvents')">我的</button>
+    </div>
+    <div class="tab-content active" id="myTabAbout">
+        <div>
+            <div class="mainbg cover padding align-center" style="padding:32px 20px 20px 20px;">
+                <h1 class="text-white align-left" style="font-size: 26px;">下午好!乔伟</h1>
+                <div class="space"></div>
+                <div class="item no-border row align-center">
+                    <div class="col text-red" id="scanBtn">
+                        <img src="img/icon_scan.png" style="width:48px;">
+                        <h1 class="text-white" style="margin-top:5px;font-size: 18px;">扫一扫</h1>
+                    </div>
+                    <div class="col text-grey" id="qrcodeBtn" >
+                        <img src="img/icon_qrcode.png" style="width:48px;">
+                        <h1 class="text-white" style="margin-top:5px;font-size: 18px;">付款码</h1>
+                    </div>
+                </div>
+            </div>
+            <div class="cover padding align-center white">
+                <div class="item no-border row align-center">
+                    <div class="col text-grey" id="cardBtn">
+                        <img src="img/icon_card.png" style="width:28px;height: 28px">
+                        <h1 style="margin-top:5px;font-size: 14px;">市民卡挂失</h1>
+                    </div>
+                    <div class="col text-grey" id="billBtn">
+                        <img src="img/icon_bill.png" style="width:28px;height: 28px">
+                        <h1 style="margin-top:5px;font-size: 14px;">账单查询</h1>
+                    </div>
+                    <div class="col text-grey" id="secBtn">
+                        <img src="img/icon_securty.png" style="width:28px;height: 28px">
+                        <h1 style="margin-top:5px;font-size: 14px;">账户安全</h1>
+                    </div>
+                </div>
+            </div>
+            
+        </div>
+        <div class="content" style="top:280px;bottom:52px;">
+            <div class="list white" style="border:0;">
+                <div class="item">
+                    <h2>近期交易</h2>
+                    <div class="right" style="font-size: 16px;color:#49bce9" id="moreBtn">更多></div>
+                </div>
+            </div>
+            <div class="list white" style="margin-bottom: 6px;">
+                <div class="item" onclick="app.toBillDetail()">
+                    <div class="left">
+                        <img class="avatar circle" src="img/icon_meal.png" style="width: 44px;height:44px;">
+                    </div>
+                    <h2>食堂就餐</h2>
+                    <p class="text-grey" style="font-size: 12px;">今天 15:20</p>
+                    <div class="right">
+                        <ul>
+                            <li class="text-strong">+ 1002.5</li>
+                            <li class="text-red text-strong">&nbsp;</li>
+                        </ul>
+                    </div>
+                </div>
+                <div class="item" style="padding:10px;">
+                    <div class="left">
+                        <img class="avatar circle" src="img/icon_water.png" style="width: 44px;height:44px;">
+                    </div>
+                    <h2>生活用水</h2>
+                    <p class="text-grey" style="font-size: 12px;">今天 15:20</p>
+                    <div class="right">
+                        <ul>
+                            <li class=" text-strong">- 0.01</li>
+                            <li class="text-red text-strong">&nbsp;</li>
+                        </ul>
+                    </div>
+                </div>
+                <div class="item">
+                    <div class="left">
+                        <img class="avatar circle" src="img/icon_car.png" style="width: 44px;height:44px;">
+                    </div>
+                    <h2>交通出行</h2>
+                    <p class="text-grey" style="font-size: 12px;">今天 15:20</p>
+                    <div class="right">
+                        <ul>
+                            <li class="text-strong">-1.00</li>
+                            <li class="text-red text-strong">&nbsp;</li>
+                        </ul>
+                    </div>
+                </div>
+                <div class="item">
+                    <div class="left">
+                        <img class="avatar circle" src="img/icon_meal.png" style="width: 44px;height:44px;">
+                    </div>
+                    <h2>食堂就餐</h2>
+                    <p class="text-grey" style="font-size: 12px;">今天 15:20</p>
+                    <div class="right">
+                        <ul>
+                            <li class="text-strong">+ 1002.5</li>
+                            <li class="text-red text-strong">&nbsp;</li>
+                        </ul>
+                    </div>
+                </div>
+                <div class="item">
+                    <div class="align-center" style="color: #999">
+                        暂无数据
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="tab-content" id="myTabEvents">
+        <div class="mainbg" style="height: 3.90625vh;width: 100%"></div>
+        <div class="header mainbg" style="top: 3.6vh">
+            <h1 class="align-center text-white">我的</h1>
+        </div>
+        <div style="padding-top: 48px;">
+            <div class="row padding mainbg">
+                <div class="col-25 padding">
+                    <img class="avatar circle" src="img/icon_card.png" />
+                </div>
+                <div class="col padding">
+                    <h1 class="text-big text-white">张三</h1>
+                    <p class="text-white">134****4553</p>
+                </div>
+            </div>
+            <div class="list white">
+                <div class="item">
+                    <h2>银行卡</h2>
+                    <div class="right">
+                        <small class="maincolor">已绑定</small><i class="icon ion-ios-arrow-right"></i>
+                    </div>
+                </div>
+                <div class="item">
+                    <h2>签约代扣免密付</h2>
+                    <div class="right">
+                        <small class="maincolor">已签约</small><i class="icon ion-ios-arrow-right"></i>
+                    </div>
+                </div>
+            </div>
+            <div class="list white" style="margin-top: 8px;">
+                <div class="item">
+                    <h2>账户安全</h2>
+                    <div class="right">
+                        <i class="icon ion-ios-arrow-right"></i>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</body>
+
+</html>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="mobileui/mobileui.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
+<script type="text/javascript" src="mobileui/js/button.min.js"></script>
+<script type="text/javascript" src="mobileui/js/loading.min.js"></script>
+<script type="text/javascript" src="mobileui/js/toast.min.js"></script>
+<script type="text/javascript" src="mobileui/js/tab.min.js"></script>
+<script type="text/javascript" src="mobileui/js/page.min.js"></script>
+<script type="text/javascript" src="js/login.js"></script>
+<script type="text/javascript">
+</script>
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/alert.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/alert.min.css
new file mode 100755
index 0000000..272cda2
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/alert.min.css
@@ -0,0 +1 @@
+.alert-mobileui{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;z-index:99999;}.alert-mobileui .alert{font-family:Roboto,Noto,sans-serif;-webkit-font-smoothing:antialiased;position:relative;border-radius:4px;box-shadow:0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12),0 8px 10px -5px rgba(0,0,0,.4);max-width:270px}.platform-ios .alert-mobileui .alert{font-family:-apple-system,'Helvetica Neue',Helvetica,Arial,'Lucida Grande',sans-serif;border-radius:8px;background-color:#fff!important;box-shadow:none}.alert-mobileui .alert h1{text-align:left;font-size:20px;font-weight:500;padding:22px 22px 0 24px}.platform-ios .alert-mobileui .alert h1{font-size:17px;font-weight:500;text-align:center;color:#000!important;padding:0;padding-top:22px}.alert-mobileui .alert p{text-align:left;font-size:16px;font-weight:400;line-height:20px;padding:0 24px;margin-top:24px;margin-bottom:24px;min-height:0;opacity:.8}.platform-ios .alert-mobileui .alert p{font-size:14px;text-align:center;color:#000!important}.alert-mobileui .alert .buttons{display:inline-block;box-sizing:border-box;width:100%}.alert-mobileui .alert .buttons button{text-transform:uppercase;display:inline-block;width:auto;min-width:70px;float:right;background:0 0;border-top:none;font-size:14px;font-weight:600;outline:0;margin-right:5px;text-transform:uppercase}.platform-ios .alert-mobileui .alert .buttons button{width:100%;text-align:center;text-transform:none;font-weight:400;font-size:16px;border-top:1px solid #ddd;padding:0 8px;margin-right:0;color:rgba(24,103,194,.81)!important;background:0 0!important}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/base.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/base.min.css
new file mode 100755
index 0000000..17e3958
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/base.min.css
@@ -0,0 +1 @@
+*{-webkit-tap-highlight-color:transparent;margin:0;padding:0;box-sizing:border-box;outline:0}body{-webkit-touch-callout:none;-webkit-text-size-adjust:none;-webkit-user-select:none;background-color:#fff;font-size:14px;height:100%;margin:0;padding:0;width:100%}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:400}*{box-sizing:border-box;outline:0}body{font-family:Roboto,"Helvetica Neue",sans-serif;-webkit-overflow-scrolling:touch;overflow:hidden;position:absolute}body.platform-ios{font-family:-apple-system,"Helvetica Neue",Roboto,sans-serif}a{cursor:pointer;color:#000;text-decoration:none}.content{position:absolute;width:100%;overflow:auto}.left{float:left}.right{float:right}.top{position:absolute;top:0;left:0}.bottom{position:absolute;bottom:0;left:0}.align-left{text-align:left}.align-center{text-align:center}.align-right{text-align:right}.border{border-width:1px;border-style:solid}.hidden{display:none}.opacity-90{opacity:.9}.opacity-80{opacity:.8}.opacity-70{opacity:.7}.opacity-60{opacity:.6}.opacity-50{opacity:.5}.opacity-40{opacity:.4}.opacity-30{opacity:.3}.opacity-20{opacity:.2}.opacity-10{opacity:.1}.line{width:100%;height:1px;display:block;clear:both}.icon{font-size:28px}img,video{max-width:100%}p{margin-top:5px;margin-bottom:5px}.padding{padding:10px}.padding-top{padding-top:10px}.margin{margin:10px}span.padding{padding:6px;padding-top:2px;padding-bottom:2px}.radius{border-radius:4px}.radius-big{border-radius:22px}.circle{border-radius:50%}.radius-left{border-top-left-radius:4px;border-bottom-left-radius:4px}.radius-right{border-top-right-radius:4px;border-bottom-right-radius:4px}.radius-top{border-top-left-radius:4px;border-top-right-radius:4px}.ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.shadow{box-shadow:1px 1px 3px rgba(0,0,0,.2)}.space{width:100%;height:20px}.space-big{width:100%;height:50px}.space-huge{width:100%;height:100px}.margin-bottom{margin-bottom:10px}.margin-top{margin-top:10px}.text-shadow{text-shadow:1px 1px 3px rgba(0,0,0,.2)}.text-small{font-size:14px}.text-small .icon,.text-small.icon{font-size:14px!important}.icon-small{font-size:14px!important}.icon-big{font-size:50px!important}.icon-huge{font-size:65px!important}.icon-extra-huge{font-size:120px!important}.text-big{font-size:22px}.text-big .icon,.text-big.icon{font-size:22px!important}.text-extra-huge{font-size:65px}.text-extra-huge .icon,.text-extra-huge.icon{font-size:65px!important}.text-huge{font-size:32px}.text-huge .icon,.text-huge.icon{font-size:32px!important}.text-light{font-weight:300}.text-bold{font-weight:700}.text-strong{font-weight:800}.float-bottom-right{position:fixed;right:15px;bottom:15px}.float-bottom-left{position:fixed;left:15px;bottom:15px}.float-bottom-center{position:fixed;margin:auto;left:0;bottom:15px}.icon-circle{width:40px;height:40px;border-radius:50%;text-align:center;display:flex;align-items:center;justify-content:center}.icon-circle-small{width:25px;height:25px;border-radius:50%;text-align:center;display:flex;align-items:center;justify-content:center}.icon-circle-small i{font-size:15px}.icon-circle-big{width:80px;height:80px;border-radius:50%;text-align:center;display:flex;align-items:center;justify-content:center}.icon-circle-big i{font-size:70px}.backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#000;opacity:.01;z-index:9999;transition-duration:280ms}.backdrop.show{opacity:.4}.mark{border-left-width:8px!important}.red{color:rgba(255,255,255,.9);background-color:#f44336!important}.red-100,.red-200,.red-300,.red-50{color:rgba(0,0,0,.8)}.red-50,input[type=checkbox].red-50.switch::after{background-color:#ffebee!important}.red-100,input[type=checkbox].red-100.switch::after{background-color:#ffcdd2!important}.red-200,input[type=checkbox].red-200.switch::after{background-color:#ef9a9a!important}.red-300,input[type=checkbox].red-300.switch::after{background-color:#e57373!important}.pink,.red-400,.red-500,.red-600,.red-700,.red-800,.red-900{color:rgba(255,255,255,.9)}.red-400,input[type=checkbox].red-400.switch::after{background-color:#ef5350!important}.red-500,input[type=checkbox].red-500.switch::after{background-color:#f44336!important}.red-600,input[type=checkbox].red-600.switch::after{background-color:#e53935!important}.red-700,input[type=checkbox].red-700.switch::after{background-color:#d32f2f!important}.red-800,input[type=checkbox].red-800.switch::after{background-color:#c62828!important}.red-900,input[type=checkbox].red-900.switch::after{background-color:#b71c1c!important}.pink,input[type=checkbox].pink.switch::after{background-color:#e91e63!important}.pink-100,.pink-200,.pink-50{color:rgba(0,0,0,.8)}.pink-50,input[type=checkbox].pink-50.switch::after{background-color:#fce4ec!important}.pink-100,input[type=checkbox].pink-100.switch::after{background-color:#f8bbd0!important}.pink-200,input[type=checkbox].pink-200.switch::after{background-color:#f48fb1!important}.Pink-300,.pink-400,.pink-500,.pink-600,.pink-700,.pink-800,.pink-900,.purple{color:rgba(255,255,255,.9)}.Pink-300,input[type=checkbox].Pink-300.switch::after{background-color:#f06292!important}.pink-400,input[type=checkbox].pink-400.switch::after{background-color:#ec407a!important}.pink-500,input[type=checkbox].pink-500.switch::after{background-color:#e91e63!important}.pink-600,input[type=checkbox].pink-600.switch::after{background-color:#d81b60!important}.pink-700,input[type=checkbox].pink-700.switch::after{background-color:#c2185b!important}.pink-800,input[type=checkbox].pink-800.switch::after{background-color:#ad1457!important}.pink-900,input[type=checkbox].pink-900.switch::after{background-color:#880e4f!important}.purple,input[type=checkbox].purple.switch::after{background-color:#9c27b0!important}.purple-100,.purple-200,.purple-50{color:rgba(0,0,0,.8)}.purple-50,input[type=checkbox].purple-50.switch::after{background-color:#f3e5f5!important}.purple-100,input[type=checkbox].purple-100.switch::after{background-color:#e1bee7!important}.purple-200,input[type=checkbox].purple-200.switch::after{background-color:#ce93d8!important}.deep-purple,.purple-300,.purple-400,.purple-500,.purple-600,.purple-700,.purple-800,.purple-900{color:rgba(255,255,255,.9)}.purple-300,input[type=checkbox].purple-300.switch::after{background-color:#ba68c8!important}.purple-400,input[type=checkbox].purple-400.switch::after{background-color:#ab47bc!important}.purple-500,input[type=checkbox].purple-500.switch::after{background-color:#9c27b0!important}.purple-600,input[type=checkbox].purple-600.switch::after{background-color:#8e24aa!important}.purple-700,input[type=checkbox].purple-700.switch::after{background-color:#7b1fa2!important}.purple-800,input[type=checkbox].purple-800.switch::after{background-color:#6a1b9a!important}.purple-900,input[type=checkbox].purple-900.switch::after{background-color:#4a148c!important}.deep-purple,input[type=checkbox].deep-purple.switch::after{background-color:#673ab7!important}.deep-purple-50{color:rgba(0,0,0,.8);background-color:#ede7f6!important}.deep-purple-100{color:rgba(0,0,0,.8);background-color:#d1c4e9!important}.deep-purple-200{color:rgba(0,0,0,.8);background-color:#b39ddb!important}.deep-purple-300,.deep-purple-400,.deep-purple-500,.deep-purple-600,.deep-purple-700,.deep-purple-800,.deep-purple-900,.indigo{color:rgba(255,255,255,.9)}.deep-purple-300,input[type=checkbox].deep-purple-300.switch::after{background-color:#9575cd!important}.deep-purple-400,input[type=checkbox].deep-purple-400.switch::after{background-color:#7e57c2!important}.deep-purple-500,input[type=checkbox].deep-purple-500.switch::after{background-color:#673ab7!important}.deep-purple-600,input[type=checkbox].deep-purple-600.switch::after{background-color:#5e35b1!important}.deep-purple-700,input[type=checkbox].deep-purple-700.switch::after{background-color:#512da8!important}.deep-purple-800,input[type=checkbox].deep-purple-800.switch::after{background-color:#4527a0!important}.deep-purple-900,input[type=checkbox].deep-purple-900.switch::after{background-color:#311b92!important}.indigo,input[type=checkbox].indigo.switch::after{background-color:#3f51b5!important}.indigo-100,.indigo-200,.indigo-50{color:rgba(0,0,0,.8)}.indigo-50,input[type=checkbox].indigo-50.switch::after{background-color:#e8eaf6!important}.indigo-100,input[type=checkbox].indigo-100.switch::after{background-color:#c5cae9!important}.indigo-200,input[type=checkbox].indigo-200.switch::after{background-color:#9fa8da!important}.blue,.indigo-300,.indigo-400,.indigo-500,.indigo-600,.indigo-700,.indigo-800,.indigo-900{color:rgba(255,255,255,.9)}.indigo-300,input[type=checkbox].indigo-300.switch::after{background-color:#7986cb!important}.indigo-400,input[type=checkbox].indigo-400.switch::after{background-color:#5c6bc0!important}.indigo-500,input[type=checkbox].indigo-500.switch::after{background-color:#3f51b5!important}.indigo-600,input[type=checkbox].indigo-600.switch::after{background-color:#3949ab!important}.indigo-700,input[type=checkbox].indigo-700.switch::after{background-color:#303f9f!important}.indigo-800,input[type=checkbox].indigo-800.switch::after{background-color:#283593!important}.indigo-900,input[type=checkbox].indigo-900.switch::after{background-color:#1a237e!important}.blue,input[type=checkbox].blue.switch::after{background-color:#2196f3!important}.blue-100,.blue-200,.blue-300,.blue-400,.blue-50{color:rgba(0,0,0,.8)}.blue-50,input[type=checkbox].blue-50.switch::after{background-color:#e3f2fd!important}.blue-100,input[type=checkbox].blue-100.switch::after{background-color:#bbdefb!important}.blue-200,input[type=checkbox].blue-200.switch::after{background-color:#90caf9!important}.blue-300,input[type=checkbox].blue-300.switch::after{background-color:#64b5f6!important}.blue-400,input[type=checkbox].blue-400.switch::after{background-color:#42a5f5!important}.blue-500,.blue-600,.blue-700,.blue-800,.blue-900,.light-blue{color:rgba(255,255,255,.9)}.blue-500,input[type=checkbox].blue-500.switch::after{background-color:#2196f3!important}.blue-600,input[type=checkbox].blue-600.switch::after{background-color:#1e88e5!important}.blue-700,input[type=checkbox].blue-700.switch::after{background-color:#1976d2!important}.blue-800,input[type=checkbox].blue-800.switch::after{background-color:#1565c0!important}.blue-900,input[type=checkbox].blue-900.switch::after{background-color:#0d47a1!important}.light-blue,input[type=checkbox].light-blue.switch::after{background-color:#03a9f4!important}.light-blue-100,.light-blue-200,.light-blue-300,.light-blue-400,.light-blue-50,.light-blue-500{color:rgba(0,0,0,.8)}.light-blue-50,input[type=checkbox].light-blue-50.switch::after{background-color:#e1f5fe!important}.light-blue-100,input[type=checkbox].light-blue-100.switch::after{background-color:#b3e5fc!important}.light-blue-200,input[type=checkbox].light-blue-200.switch::after{background-color:#81d4fa!important}.light-blue-300,input[type=checkbox].light-blue-300.switch::after{background-color:#4fc3f7!important}.light-blue-400,input[type=checkbox].light-blue-400.switch::after{background-color:#29b6f6!important}.light-blue-500,input[type=checkbox].light-blue-500.switch::after{background-color:#03a9f4!important}.cyan,.light-blue-600,.light-blue-700,.light-blue-800,.light-blue-900{color:rgba(255,255,255,.9)}.light-blue-600,input[type=checkbox].light-blue-600.switch::after{background-color:#039be5!important}.light-blue-700,input[type=checkbox].light-blue-700.switch::after{background-color:#0288d1!important}.light-blue-800,input[type=checkbox].light-blue-800.switch::after{background-color:#0277bd!important}.light-blue-900,input[type=checkbox].light-blue-900.switch::after{background-color:#01579b!important}.cyan,input[type=checkbox].cyan.switch::after{background-color:#00bcd4!important}.cyan-100,.cyan-200,.cyan-300,.cyan-400,.cyan-50,.cyan-500,.cyan-600{color:rgba(0,0,0,.8)}.cyan-50,input[type=checkbox].cyan-50.switch::after{background-color:#e0f7fa!important}.cyan-100,input[type=checkbox].cyan-100.switch::after{background-color:#b2ebf2!important}.cyan-200,input[type=checkbox].cyan-200.switch::after{background-color:#80deea!important}.cyan-300,input[type=checkbox].cyan-300.switch::after{background-color:#4dd0e1!important}.cyan-400,input[type=checkbox].cyan-400.switch::after{background-color:#26c6da!important}.cyan-500,input[type=checkbox].cyan-500.switch::after{background-color:#00bcd4!important}.cyan-600,input[type=checkbox].cyan-600.switch::after{background-color:#00acc1!important}.cyan-700,.cyan-800,.cyan-900,.teal{color:rgba(255,255,255,.9)}.cyan-700,input[type=checkbox].cyan-700.switch::after{background-color:#0097a7!important}.cyan-800,input[type=checkbox].cyan-800.switch::after{background-color:#00838f!important}.cyan-900,input[type=checkbox].cyan-900.switch::after{background-color:#006064!important}.teal,input[type=checkbox].teal.switch::after{background-color:#009688!important}.teal-100,.teal-200,.teal-300,.teal-400,.teal-50{color:rgba(0,0,0,.8)}.teal-50,input[type=checkbox].teal-50.switch::after{background-color:#e0f2f1!important}.teal-100,input[type=checkbox].teal-100.switch::after{background-color:#b2dfdb!important}.teal-200,input[type=checkbox].teal-200.switch::after{background-color:#80cbc4!important}.teal-300,input[type=checkbox].teal-300.switch::after{background-color:#4db6ac!important}.teal-400,input[type=checkbox].teal-400.switch::after{background-color:#26a69a!important}.green,.teal-500,.teal-600,.teal-700,.teal-800,.teal-900{color:rgba(255,255,255,.9)}.teal-500,input[type=checkbox].teal-500.switch::after{background-color:#009688!important}.teal-600,input[type=checkbox].teal-600.switch::after{background-color:#00897b!important}.teal-700,input[type=checkbox].teal-700.switch::after{background-color:#00796b!important}.teal-800,input[type=checkbox].teal-800.switch::after{background-color:#00695c!important}.teal-900,input[type=checkbox].teal-900.switch::after{background-color:#004d40!important}.green,input[type=checkbox].green.switch::after{background-color:#4caf50!important}.green-100,.green-200,.green-300,.green-400,.green-50,.green-500{color:rgba(0,0,0,.8)}.green-50,input[type=checkbox].green-50.switch::after{background-color:#e8f5e9!important}.green-100,input[type=checkbox].green-100.switch::after{background-color:#c8e6c9!important}.green-200,input[type=checkbox].green-200.switch::after{background-color:#a5d6a7!important}.green-300,input[type=checkbox].green-300.switch::after{background-color:#81c784!important}.green-400,input[type=checkbox].green-400.switch::after{background-color:#66bb6a!important}.green-500,input[type=checkbox].green-500.switch::after{background-color:#4caf50!important}.green-600,.green-700,.green-800,.green-900,.light-green{color:rgba(255,255,255,.9)}.green-600,input[type=checkbox].green-600.switch::after{background-color:#43a047!important}.green-700,input[type=checkbox].green-700.switch::after{background-color:#388e3c!important}.green-800,input[type=checkbox].green-800.switch::after{background-color:#2e7d32!important}.green-900,input[type=checkbox].green-900.switch::after{background-color:#1b5e20!important}.light-green,input[type=checkbox].light-green.switch::after{background-color:#8bc34a!important}.light-green-100,.light-green-200,.light-green-300,.light-green-400,.light-green-50,.light-green-500,.light-green-600{color:rgba(0,0,0,.8)}.light-green-50,input[type=checkbox].light-green-50.switch::after{background-color:#f1f8e9!important}.light-green-100,input[type=checkbox].light-green-100.switch::after{background-color:#dcedc8!important}.light-green-200,input[type=checkbox].light-green-200.switch::after{background-color:#c5e1a5!important}.light-green-300,input[type=checkbox].light-green-300.switch::after{background-color:#aed581!important}.light-green-400,input[type=checkbox].light-green-400.switch::after{background-color:#9ccc65!important}.light-green-500,input[type=checkbox].light-green-500.switch::after{background-color:#8bc34a!important}.light-green-600,input[type=checkbox].light-green-600.switch::after{background-color:#7cb342!important}.light-green-700,.light-green-800,.light-green-900,.lime{color:rgba(255,255,255,.9)}.light-green-700,input[type=checkbox].light-green-700.switch::after{background-color:#689f38!important}.light-green-800,input[type=checkbox].light-green-800.switch::after{background-color:#558b2f!important}.light-green-900,input[type=checkbox].light-green-900.switch::after{background-color:#33691e!important}.lime,input[type=checkbox].lime.switch::after{background-color:#cddc39!important}.lime-100,.lime-200,.lime-300,.lime-400,.lime-50,.lime-500,.lime-600,.lime-700,.lime-800{color:rgba(0,0,0,.8)}.lime-50,input[type=checkbox].lime-50.switch::after{background-color:#f9fbe7!important}.lime-100,input[type=checkbox].lime-100.switch::after{background-color:#f0f4c3!important}.lime-200,input[type=checkbox].lime-200.switch::after{background-color:#e6ee9c!important}.lime-300,input[type=checkbox].lime-300.switch::after{background-color:#dce775!important}.lime-400,input[type=checkbox].lime-400.switch::after{background-color:#d4e157!important}.lime-500,input[type=checkbox].lime-500.switch::after{background-color:#cddc39!important}.lime-600,input[type=checkbox].lime-600.switch::after{background-color:#c0ca33!important}.lime-700,input[type=checkbox].lime-700.switch::after{background-color:#afb42b!important}.lime-800,input[type=checkbox].lime-800.switch::after{background-color:#9e9d24!important}.lime-900,.yellow{color:rgba(255,255,255,.9)}.lime-900,input[type=checkbox].lime-900.switch::after{background-color:#827717!important}.yellow,input[type=checkbox].yellow.switch::after{background-color:#ffeb3b!important}.yellow-100,.yellow-200,.yellow-300,.yellow-50,.yellow-500,.yellow-600,.yellow-700,.yellow-800,.yellow-900{color:rgba(0,0,0,.8)}.yellow-50,input[type=checkbox].yellow-50.switch::after{background-color:#fffde7!important}.yellow-100,input[type=checkbox].yellow-100.switch::after{background-color:#fff9c4!important}.yellow-200,input[type=checkbox].yellow-200.switch::after{background-color:#fff59d!important}.yellow-300,input[type=checkbox].yellow-300.switch::after{background-color:#fff176!important}.yellow-400{color:rgba(0,0,0,.8);background-color:#ffee58!important}.yellow-500,input[type=checkbox].yellow-500.switch::after{background-color:#ffeb3b!important}.yellow-600,input[type=checkbox].yellow-600.switch::after{background-color:#fdd835!important}.yellow-700,input[type=checkbox].yellow-700.switch::after{background-color:#fbc02d!important}.yellow-800,input[type=checkbox].yellow-800.switch::after{background-color:#f9a825!important}.yellow-900,input[type=checkbox].yellow-900.switch::after{background-color:#f57f17!important}.amber{color:rgba(255,255,255,.9);background-color:#ffc107!important}.amber-100,.amber-200,.amber-300,.amber-50,.amber-500,.amber-600,.amber-700,.amber-800,.amber-900{color:rgba(0,0,0,.8)}.amber-50,input[type=checkbox].amber-50.switch::after{background-color:#fff8e1!important}.amber-100,input[type=checkbox].amber-100.switch::after{background-color:#ffecb3!important}.amber-200,input[type=checkbox].amber-200.switch::after{background-color:#ffe082!important}.amber-300,input[type=checkbox].amber-300.switch::after{background-color:#ffd54f!important}.amber-400{color:rgba(0,0,0,.8);background-color:#ffca28!important}.amber-500,input[type=checkbox].amber-500.switch::after{background-color:#ffc107!important}.amber-600,input[type=checkbox].amber-600.switch::after{background-color:#ffb300!important}.amber-700,input[type=checkbox].amber-700.switch::after{background-color:#ffa000!important}.amber-800,input[type=checkbox].amber-800.switch::after{background-color:#ff8f00!important}.amber-900,input[type=checkbox].amber-900.switch::after{background-color:#ff6f00!important}.orange{color:rgba(255,255,255,.9);background-color:#ff9800!important}.orange-100,.orange-200,.orange-300,.orange-400,.orange-50,.orange-500,.orange-600,.orange-700{color:rgba(0,0,0,.8)}.orange-50,input[type=checkbox].orange-50.switch::after{background-color:#fff3e0!important}.orange-100,input[type=checkbox].orange-100.switch::after{background-color:#ffe0b2!important}.orange-200,input[type=checkbox].orange-200.switch::after{background-color:#ffcc80!important}.orange-300,input[type=checkbox].orange-300.switch::after{background-color:#ffb74d!important}.orange-400,input[type=checkbox].orange-400.switch::after{background-color:#ffa726!important}.orange-500,input[type=checkbox].orange-500.switch::after{background-color:#ff9800!important}.orange-600,input[type=checkbox].orange-600.switch::after{background-color:#fb8c00!important}.orange-700,input[type=checkbox].orange-700.switch::after{background-color:#f57c00!important}.deep-orange,.orange-800,.orange-900{color:rgba(255,255,255,.9)}.orange-800,input[type=checkbox].orange-800.switch::after{background-color:#ef6c00!important}.orange-900,input[type=checkbox].orange-900.switch::after{background-color:#e65100!important}.deep-orange,input[type=checkbox].deep-orange.switch::after{background-color:#ff5722!important}.deep-orange-100,.deep-orange-200,.deep-orange-300,.deep-orange-400,.deep-orange-50{color:rgba(0,0,0,.8)}.deep-orange-50,input[type=checkbox].deep-orange-50.switch::after{background-color:#fbe9e7!important}.deep-orange-100,input[type=checkbox].deep-orange-100.switch::after{background-color:#ffccbc!important}.deep-orange-200,input[type=checkbox].deep-orange-200.switch::after{background-color:#ffab91!important}.deep-orange-300,input[type=checkbox].deep-orange-300.switch::after{background-color:#ff8a65!important}.deep-orange-400,input[type=checkbox].deep-orange-400.switch::after{background-color:#ff7043!important}.brown,.deep-orange-500,.deep-orange-600,.deep-orange-700,.deep-orange-800,.deep-orange-900{color:rgba(255,255,255,.9)}.deep-orange-500,input[type=checkbox].deep-orange-500.switch::after{background-color:#ff5722!important}.deep-orange-600,input[type=checkbox].deep-orange-600.switch::after{background-color:#f4511e!important}.deep-orange-700,input[type=checkbox].deep-orange-700.switch::after{background-color:#e64a19!important}.deep-orange-800,input[type=checkbox].deep-orange-800.switch::after{background-color:#d84315!important}.deep-orange-900,input[type=checkbox].deep-orange-900.switch::after{background-color:#bf360c!important}.brown,input[type=checkbox].brown.switch::after{background-color:#795548!important}.brown-100,.brown-200,.brown-50{color:rgba(0,0,0,.8)}.brown-50,input[type=checkbox].brown-50.switch::after{background-color:#efebe9!important}.brown-100,input[type=checkbox].brown-100.switch::after{background-color:#d7ccc8!important}.brown-200,input[type=checkbox].brown-200.switch::after{background-color:#bcaaa4!important}.brown-300,.brown-400,.brown-500,.brown-600,.brown-700,.brown-800,.brown-900,.grey{color:rgba(255,255,255,.9)}.brown-300,input[type=checkbox].brown-300.switch::after{background-color:#a1887f!important}.brown-400,input[type=checkbox].brown-400.switch::after{background-color:#8d6e63!important}.brown-500,input[type=checkbox].brown-500.switch::after{background-color:#795548!important}.brown-600,input[type=checkbox].brown-600.switch::after{background-color:#6d4c41!important}.brown-700,input[type=checkbox].brown-700.switch::after{background-color:#5d4037!important}.brown-800,input[type=checkbox].brown-800.switch::after{background-color:#4e342e!important}.brown-900,input[type=checkbox].brown-900.switch::after{background-color:#3e2723!important}.grey,input[type=checkbox].grey.switch::after{background-color:#9e9e9e!important}.grey-100,.grey-200,.grey-300,.grey-400,.grey-50,.grey-500{color:rgba(0,0,0,.8)}.grey-50,input[type=checkbox].grey-50.switch::after{background-color:#fafafa!important}.grey-100,input[type=checkbox].grey-100.switch::after{background-color:#f5f5f5!important}.grey-200,input[type=checkbox].grey-200.switch::after{background-color:#eee!important}.grey-300,input[type=checkbox].grey-300.switch::after{background-color:#e0e0e0!important}.grey-400,input[type=checkbox].grey-400.switch::after{background-color:#bdbdbd!important}.grey-500,input[type=checkbox].grey-500.switch::after{background-color:#9e9e9e!important}.blue-grey,.grey-600,.grey-700,.grey-800,.grey-900{color:rgba(255,255,255,.9)}.grey-600,input[type=checkbox].grey-600.switch::after{background-color:#757575!important}.grey-700,input[type=checkbox].grey-700.switch::after{background-color:#616161!important}.grey-800,input[type=checkbox].grey-800.switch::after{background-color:#424242!important}.grey-900,input[type=checkbox].grey-900.switch::after{background-color:#212121!important}.blue-grey,input[type=checkbox].blue-grey.switch::after{background-color:#607d8b!important}.blue-grey-100,.blue-grey-200,.blue-grey-300,.blue-grey-50{color:rgba(0,0,0,.8)}.blue-grey-50,input[type=checkbox].blue-grey-50.switch::after{background-color:#eceff1!important}.blue-grey-100,input[type=checkbox].blue-grey-100.switch::after{background-color:#cfd8dc!important}.blue-grey-200,input[type=checkbox].blue-grey-200.switch::after{background-color:#b0bec5!important}.blue-grey-300,input[type=checkbox].blue-grey-300.switch::after{background-color:#90a4ae!important}.black,.blue-grey-400,.blue-grey-500,.blue-grey-600,.blue-grey-700,.blue-grey-800,.blue-grey-900{color:rgba(255,255,255,.9)}.blue-grey-400,input[type=checkbox].blue-grey-400.switch::after{background-color:#78909c!important}.transparent{background-color:rgba(0,0,0,0)!important}.blue-grey-500,input[type=checkbox].blue-grey-500.switch::after{background-color:#607d8b!important}.blue-grey-600,input[type=checkbox].blue-grey-600.switch::after{background-color:#546e7a!important}.blue-grey-700,input[type=checkbox].blue-grey-700.switch::after{background-color:#455a64!important}.blue-grey-800,input[type=checkbox].blue-grey-800.switch::after{background-color:#37474f!important}.blue-grey-900,input[type=checkbox].blue-grey-900.switch::after{background-color:#263238!important}.black,input[type=checkbox].black.switch::after{background-color:#000!important}.black-opacity-90{background-color:rgba(0,0,0,.9)}.black-opacity-70{background-color:rgba(0,0,0,.7)}.black-opacity-50{background-color:rgba(0,0,0,.5)}.black-opacity-30{background-color:rgba(0,0,0,.3)}.black-opacity-10{background-color:rgba(0,0,0,.1)}.white{color:rgba(0,0,0,.8);background-color:#fff!important}.white-opacity-90{background-color:rgba(255,255,255,.9)}.white-opacity-70{background-color:rgba(255,255,255,.7)}.white-opacity-50{background-color:rgba(255,255,255,.5)}.white-opacity-30{background-color:rgba(255,255,255,.3)}.white-opacity-10{background-color:rgba(255,255,255,.1)}.text-red,i.red{color:#f44336}.text-red-50,i.red-50{color:#ffebee}.text-red-100,i.red-100{color:#ffcdd2}.text-red-200,i.red-200{color:#ef9a9a}.text-red-300,i.red-300{color:#e57373}.text-red-400,i.red-400{color:#ef5350}.text-red-500,i.red-500{color:#f44336}.text-red-600,i.red-600{color:#e53935}.text-red-700,i.red-700{color:#d32f2f}.text-red-800,i.red-800{color:#c62828}.text-red-900,i.red-900{color:#b71c1c}.text-pink,i.pink{color:#e91e63}.text-pink-50,i.pink-50{color:#fce4ec}.text-pink-100,i.pink-100{color:#f8bbd0}.text-pink-200,i.pink-200{color:#f48fb1}.text-Pink-300,i.Pink-300{color:#f06292}.text-pink-400,i.pink-400{color:#ec407a}.text-pink-500,i.pink-500{color:#e91e63}.text-pink-600,i.pink-600{color:#d81b60}.text-pink-700,i.pink-700{color:#c2185b}.text-pink-800,i.pink-800{color:#ad1457}.text-pink-900,i.pink-900{color:#880e4f}.text-purple,i.purple{color:#9c27b0}.text-purple-50,i.purple-50{color:#f3e5f5}.text-purple-100,i.purple-100{color:#e1bee7}.text-purple-200,i.purple-200{color:#ce93d8}.text-purple-300,i.purple-300{color:#ba68c8}.text-purple-400,i.purple-400{color:#ab47bc}.text-purple-500,i.purple-500{color:#9c27b0}.text-purple-600,i.purple-600{color:#8e24aa}.text-purple-700,i.purple-700{color:#7b1fa2}.text-purple-800,i.purple-800{color:#6a1b9a}.text-purple-900,i.purple-900{color:#4a148c}.text-deep-purple,i.deep-purple{color:#673ab7}.text-deep-purple-50,i.deep-purple-50{color:#ede7f6}.text-deep-purple-100,i.deep-purple-100{color:#d1c4e9}.text-deep-purple-200,i.deep-purple-200{color:#b39ddb}.text-deep-purple-300,i.deep-purple-300{color:#9575cd}.text-deep-purple-400,i.deep-purple-400{color:#7e57c2}.text-deep-purple-500,i.deep-purple-500{color:#673ab7}.text-deep-purple-600,i.deep-purple-600{color:#5e35b1}.text-deep-purple-700,i.deep-purple-700{color:#512da8}.text-deep-purple-800,i.deep-purple-800{color:#4527a0}.text-deep-purple-900,i.deep-purple-900{color:#311b92}.text-indigo,i.indigo{color:#3f51b5}.text-indigo-50,i.indigo-50{color:#e8eaf6}.text-indigo-100,i.indigo-100{color:#c5cae9}.text-indigo-200,i.indigo-200{color:#9fa8da}.text-indigo-300,i.indigo-300{color:#7986cb}.text-indigo-400,i.indigo-400{color:#5c6bc0}.text-indigo-500,i.indigo-500{color:#3f51b5}.text-indigo-600,i.indigo-600{color:#3949ab}.text-indigo-700,i.indigo-700{color:#303f9f}.text-indigo-800,i.indigo-800{color:#283593}.text-indigo-900,i.indigo-900{color:#1a237e}.text-blue,i.blue{color:#2196f3}.text-blue-50,i.blue-50{color:#e3f2fd}.text-blue-100,i.blue-100{color:#bbdefb}.text-blue-200,i.blue-200{color:#90caf9}.text-blue-300,i.blue-300{color:#64b5f6}.text-blue-400,i.blue-400{color:#42a5f5}.text-blue-500,i.blue-500{color:#2196f3}.text-blue-600,i.blue-600{color:#1e88e5}.text-blue-700,i.blue-700{color:#1976d2}.text-blue-800,i.blue-800{color:#1565c0}.text-blue-900,i.blue-900{color:#0d47a1}.text-light-blue,i.light-blue{color:#03a9f4}.text-light-blue-50,i.light-blue-50{color:#e1f5fe}.text-light-blue-100,i.light-blue-100{color:#b3e5fc}.text-light-blue-200,i.light-blue-200{color:#81d4fa}.text-light-blue-300,i.light-blue-300{color:#4fc3f7}.text-light-blue-400,i.light-blue-400{color:#29b6f6}.text-light-blue-500,i.light-blue-500{color:#03a9f4}.text-light-blue-600,i.light-blue-600{color:#039be5}.text-light-blue-700,i.light-blue-700{color:#0288d1}.text-light-blue-800,i.light-blue-800{color:#0277bd}.text-light-blue-900,i.light-blue-900{color:#01579b}.text-cyan,i.cyan{color:#00bcd4}.text-cyan-50,i.cyan-50{color:#e0f7fa}.text-cyan-100,i.cyan-100{color:#b2ebf2}.text-cyan-200,i.cyan-200{color:#80deea}.text-cyan-300,i.cyan-300{color:#4dd0e1}.text-cyan-400,i.cyan-400{color:#26c6da}.text-cyan-500,i.cyan-500{color:#00bcd4}.text-cyan-600,i.cyan-600{color:#00acc1}.text-cyan-700,i.cyan-700{color:#0097a7}.text-cyan-800,i.cyan-800{color:#00838f}.text-cyan-900,i.cyan-900{color:#006064}.text-teal,i.teal{color:#009688}.text-teal-50,i.teal-50{color:#e0f2f1}.text-teal-100,i.teal-100{color:#b2dfdb}.text-teal-200,i.teal-200{color:#80cbc4}.text-teal-300,i.teal-300{color:#4db6ac}.text-teal-400,i.teal-400{color:#26a69a}.text-teal-500,i.teal-500{color:#009688}.text-teal-600,i.teal-600{color:#00897b}.text-teal-700,i.teal-700{color:#00796b}.text-teal-800,i.teal-800{color:#00695c}.text-teal-900,i.teal-900{color:#004d40}.text-green,i.green{color:#4caf50}.text-green-50,i.green-50{color:#e8f5e9}.text-green-100,i.green-100{color:#c8e6c9}.text-green-200,i.green-200{color:#a5d6a7}.text-green-300,i.green-300{color:#81c784}.text-green-400,i.green-400{color:#66bb6a}.text-green-500,i.green-500{color:#4caf50}.text-green-600,i.green-600{color:#43a047}.text-green-700,i.green-700{color:#388e3c}.text-green-800,i.green-800{color:#2e7d32}.text-green-900,i.green-900{color:#1b5e20}.text-light-green,i.light-green{color:#8bc34a}.text-light-green-50,i.light-green-50{color:#f1f8e9}.text-light-green-100,i.light-green-100{color:#dcedc8}.text-light-green-200,i.light-green-200{color:#c5e1a5}.text-light-green-300,i.light-green-300{color:#aed581}.text-light-green-400,i.light-green-400{color:#9ccc65}.text-light-green-500,i.light-green-500{color:#8bc34a}.text-light-green-600,i.light-green-600{color:#7cb342}.text-light-green-700,i.light-green-700{color:#689f38}.text-light-green-800,i.light-green-800{color:#558b2f}.text-light-green-900,i.light-green-900{color:#33691e}.text-lime,i.lime{color:#cddc39}.text-lime-50,i.lime-50{color:#f9fbe7}.text-lime-100,i.lime-100{color:#f0f4c3}.text-lime-200,i.lime-200{color:#e6ee9c}.text-lime-300,i.lime-300{color:#dce775}.text-lime-400,i.lime-400{color:#d4e157}.text-lime-500,i.lime-500{color:#cddc39}.text-lime-600,i.lime-600{color:#c0ca33}.text-lime-700,i.lime-700{color:#afb42b}.text-lime-800,i.lime-800{color:#9e9d24}.text-lime-900,i.lime-900{color:#827717}.text-yellow,i.yellow{color:#ffeb3b}.text-yellow-50,i.yellow-50{color:#fffde7}.text-yellow-100,i.yellow-100{color:#fff9c4}.text-yellow-200,i.yellow-200{color:#fff59d}.text-yellow-300,i.yellow-300{color:#fff176}.text-yellow-400,i.yellow-400{color:#ffee58}.text-yellow-500,i.yellow-500{color:#ffeb3b}.text-yellow-600,i.yellow-600{color:#fdd835}.text-yellow-700,i.yellow-700{color:#fbc02d}.text-yellow-800,i.yellow-800{color:#f9a825}.text-yellow-900,i.yellow-900{color:#f57f17}.text-amber,i.amber{color:#ffc107}.text-amber-50,i.amber-50{color:#fff8e1}.text-amber-100,i.amber-100{color:#ffecb3}.text-amber-200,i.amber-200{color:#ffe082}.text-amber-300,i.amber-300{color:#ffd54f}.text-amber-400,i.amber-400{color:#ffca28}.text-amber-500,i.amber-500{color:#ffc107}.text-amber-600,i.amber-600{color:#ffb300}.text-amber-700,i.amber-700{color:#ffa000}.text-amber-800,i.amber-800{color:#ff8f00}.text-amber-900,i.amber-900{color:#ff6f00}.text-orange,i.orange{color:#ff9800}.text-orange-50,i.orange-50{color:#fff3e0}.text-orange-100,i.orange-100{color:#ffe0b2}.text-orange-200,i.orange-200{color:#ffcc80}.text-orange-300,i.orange-300{color:#ffb74d}.text-orange-400,i.orange-400{color:#ffa726}.text-orange-500,i.orange-500{color:#ff9800}.text-orange-600,i.orange-600{color:#fb8c00}.text-orange-700,i.orange-700{color:#f57c00}.text-orange-800,i.orange-800{color:#ef6c00}.text-orange-900,i.orange-900{color:#e65100}.text-deep-orange,i.deep-orange{color:#ff5722}.text-deep-orange-50,i.deep-orange-50{color:#fbe9e7}.text-deep-orange-100,i.deep-orange-100{color:#ffccbc}.text-deep-orange-200,i.deep-orange-200{color:#ffab91}.text-deep-orange-300,i.deep-orange-300{color:#ff8a65}.text-deep-orange-400,i.deep-orange-400{color:#ff7043}.text-deep-orange-500,i.deep-orange-500{color:#ff5722}.text-deep-orange-600,i.deep-orange-600{color:#f4511e}.text-deep-orange-700,i.deep-orange-700{color:#e64a19}.text-deep-orange-800,i.deep-orange-800{color:#d84315}.text-deep-orange-900,i.deep-orange-900{color:#bf360c}.text-brown,i.brown{color:#795548}.text-brown-50,i.brown-50{color:#efebe9}.text-brown-100,i.brown-100{color:#d7ccc8}.text-brown-200,i.brown-200{color:#bcaaa4}.text-brown-300,i.brown-300{color:#a1887f}.text-brown-400,i.brown-400{color:#8d6e63}.text-brown-500,i.brown-500{color:#795548}.text-brown-600,i.brown-600{color:#6d4c41}.text-brown-700,i.brown-700{color:#5d4037}.text-brown-800,i.brown-800{color:#4e342e}.text-brown-900,i.brown-900{color:#3e2723}.text-grey,i.grey{color:#9e9e9e}.text-grey-50,i.grey-50{color:#fafafa}.text-grey-100,i.grey-100{color:#f5f5f5}.text-grey-200,i.grey-200{color:#eee}.text-grey-300,i.grey-300{color:#e0e0e0}.text-grey-400,i.grey-400{color:#bdbdbd}.text-grey-500,i.grey-500{color:#9e9e9e}.text-grey-600,i.grey-600{color:#757575}.text-grey-700,i.grey-700{color:#616161}.text-grey-800,i.grey-800{color:#424242}.text-grey-900,i.grey-900{color:#212121}.text-blue-grey,i.blue-grey{color:#607d8b}.text-blue-grey-50,i.blue-grey-50{color:#eceff1}.text-blue-grey-100,i.blue-grey-100{color:#cfd8dc}.text-blue-grey-200,i.blue-grey-200{color:#b0bec5}.text-blue-grey-300,i.blue-grey-300{color:#90a4ae}.text-blue-grey-400,i.blue-grey-400{color:#78909c}.text-blue-grey-500,i.blue-grey-500{color:#607d8b}.text-blue-grey-600,i.blue-grey-600{color:#546e7a}.text-blue-grey-700,i.blue-grey-700{color:#455a64}.text-blue-grey-800,i.blue-grey-800{color:#37474f}.text-blue-grey-900,i.blue-grey-900{color:#263238}.text-black,i.black{color:#000}.text-white,i.white{color:#fff}.border-red{border:1px solid #f44336}.border-red-50{border:1px solid #ffebee}.border-red-100{border:1px solid #ffcdd2}.border-red-200{border:1px solid #ef9a9a}.border-red-300{border:1px solid #e57373}.border-red-400{border:1px solid #ef5350}.border-red-500{border:1px solid #f44336}.border-red-600{border:1px solid #e53935}.border-red-700{border:1px solid #d32f2f}.border-red-800{border:1px solid #c62828}.border-red-900{border:1px solid #b71c1c}.border-pink{border:1px solid #e91e63}.border-pink-50{border:1px solid #fce4ec}.border-pink-100{border:1px solid #f8bbd0}.border-pink-200{border:1px solid #f48fb1}.border-pink-300{border:1px solid #f06292}.border-pink-400{border:1px solid #ec407a}.border-pink-500{border:1px solid #e91e63}.border-pink-600{border:1px solid #d81b60}.border-pink-700{border:1px solid #c2185b}.border-pink-800{border:1px solid #ad1457}.border-pink-900{border:1px solid #880e4f}.border-purple{border:1px solid #9c27b0}.border-purple-50{border:1px solid #f3e5f5}.border-purple-100{border:1px solid #e1bee7}.border-purple-200{border:1px solid #ce93d8}.border-purple-300{border:1px solid #ba68c8}.border-purple-400{border:1px solid #ab47bc}.border-purple-500{border:1px solid #9c27b0}.border-purple-600{border:1px solid #8e24aa}.border-purple-700{border:1px solid #7b1fa2}.border-purple-800{border:1px solid #6a1b9a}.border-purple-900{border:1px solid #4a148c}.border-deep-purple{border:1px solid #673ab7}.border-deep-purple-50{border:1px solid #ede7f6}.border-deep-purple-100{border:1px solid #d1c4e9}.border-deep-purple-200{border:1px solid #b39ddb}.border-deep-purple-300{border:1px solid #9575cd}.border-deep-purple-400{border:1px solid #7e57c2}.border-deep-purple-500{border:1px solid #673ab7}.border-deep-purple-600{border:1px solid #5e35b1}.border-deep-purple-700{border:1px solid #512da8}.border-deep-purple-800{border:1px solid #4527a0}.border-deep-purple-900{border:1px solid #311b92}.border-indigo{border:1px solid #3f51b5}.border-indigo-50{border:1px solid #e8eaf6}.border-indigo-100{border:1px solid #c5cae9}.border-indigo-200{border:1px solid #9fa8da}.border-indigo-300{border:1px solid #7986cb}.border-indigo-400{border:1px solid #5c6bc0}.border-indigo-500{border:1px solid #3f51b5}.border-indigo-600{border:1px solid #3949ab}.border-indigo-700{border:1px solid #303f9f}.border-indigo-800{border:1px solid #283593}.border-indigo-900{border:1px solid #1a237e}.border-blue{border:1px solid #2196f3}.border-blue-50{border:1px solid #e3f2fd}.border-blue-100{border:1px solid #bbdefb}.border-blue-200{border:1px solid #90caf9}.border-blue-300{border:1px solid #64b5f6}.border-blue-400{border:1px solid #42a5f5}.border-blue-500{border:1px solid #2196f3}.border-blue-600{border:1px solid #1e88e5}.border-blue-700{border:1px solid #1976d2}.border-blue-800{border:1px solid #1565c0}.border-blue-900{border:1px solid #0d47a1}.border-light-blue{border:1px solid #03a9f4}.border-light-blue-50{border:1px solid #e1f5fe}.border-light-blue-100{border:1px solid #b3e5fc}.border-light-blue-200{border:1px solid #81d4fa}.border-light-blue-300{border:1px solid #4fc3f7}.border-light-blue-400{border:1px solid #29b6f6}.border-light-blue-500{border:1px solid #03a9f4}.border-light-blue-600{border:1px solid #039be5}.border-light-blue-700{border:1px solid #0288d1}.border-light-blue-800{border:1px solid #0277bd}.border-light-blue-900{border:1px solid #01579b}.border-cyan{border:1px solid #00bcd4}.border-cyan-50{border:1px solid #e0f7fa}.border-cyan-100{border:1px solid #b2ebf2}.border-cyan-200{border:1px solid #80deea}.border-cyan-300{border:1px solid #4dd0e1}.border-cyan-400{border:1px solid #26c6da}.border-cyan-500{border:1px solid #00bcd4}.border-cyan-600{border:1px solid #00acc1}.border-cyan-700{border:1px solid #0097a7}.border-cyan-800{border:1px solid #00838f}.border-cyan-900{border:1px solid #006064}.border-teal{border:1px solid #009688}.border-teal-50{border:1px solid #e0f2f1}.border-teal-100{border:1px solid #b2dfdb}.border-teal-200{border:1px solid #80cbc4}.border-teal-300{border:1px solid #4db6ac}.border-teal-400{border:1px solid #26a69a}.border-teal-500{border:1px solid #009688}.border-teal-600{border:1px solid #00897b}.border-teal-700{border:1px solid #00796b}.border-teal-800{border:1px solid #00695c}.border-teal-900{border:1px solid #004d40}.border-green{border:1px solid #4caf50}.border-green-50{border:1px solid #e8f5e9}.border-green-100{border:1px solid #c8e6c9}.border-green-200{border:1px solid #a5d6a7}.border-green-300{border:1px solid #81c784}.border-green-400{border:1px solid #66bb6a}.border-green-500{border:1px solid #4caf50}.border-green-600{border:1px solid #43a047}.border-green-700{border:1px solid #388e3c}.border-green-800{border:1px solid #2e7d32}.border-green-900{border:1px solid #1b5e20}.border-light-green{border:1px solid #8bc34a}.border-light-green-50{border:1px solid #f1f8e9}.border-light-green-100{border:1px solid #dcedc8}.border-light-green-200{border:1px solid #c5e1a5}.border-light-green-300{border:1px solid #aed581}.border-light-green-400{border:1px solid #9ccc65}.border-light-green-500{border:1px solid #8bc34a}.border-light-green-600{border:1px solid #7cb342}.border-light-green-700{border:1px solid #689f38}.border-light-green-800{border:1px solid #558b2f}.border-light-green-900{border:1px solid #33691e}.border-lime{border:1px solid #cddc39}.border-lime-50{border:1px solid #f9fbe7}.border-lime-100{border:1px solid #f0f4c3}.border-lime-200{border:1px solid #e6ee9c}.border-lime-300{border:1px solid #dce775}.border-lime-400{border:1px solid #d4e157}.border-lime-500{border:1px solid #cddc39}.border-lime-600{border:1px solid #c0ca33}.border-lime-700{border:1px solid #afb42b}.border-lime-800{border:1px solid #9e9d24}.border-lime-900{border:1px solid #827717}.border-yellow{border:1px solid #ffeb3b}.border-yellow-50{border:1px solid #fffde7}.border-yellow-100{border:1px solid #fff9c4}.border-yellow-200{border:1px solid #fff59d}.border-yellow-300{border:1px solid #fff176}.border-yellow-400{border:1px solid #ffee58}.border-yellow-500{border:1px solid #ffeb3b}.border-yellow-600{border:1px solid #fdd835}.border-yellow-700{border:1px solid #fbc02d}.border-yellow-800{border:1px solid #f9a825}.border-yellow-900{border:1px solid #f57f17}.border-amber{border:1px solid #ffc107}.border-amber-50{border:1px solid #fff8e1}.border-amber-100{border:1px solid #ffecb3}.border-amber-200{border:1px solid #ffe082}.border-amber-300{border:1px solid #ffd54f}.border-amber-400{border:1px solid #ffca28}.border-amber-500{border:1px solid #ffc107}.border-amber-600{border:1px solid #ffb300}.border-amber-700{border:1px solid #ffa000}.border-amber-800{border:1px solid #ff8f00}.border-amber-900{border:1px solid #ff6f00}.border-orange{border:1px solid #ff9800}.border-orange-50{border:1px solid #fff3e0}.border-orange-100{border:1px solid #ffe0b2}.border-orange-200{border:1px solid #ffcc80}.border-orange-300{border:1px solid #ffb74d}.border-orange-400{border:1px solid #ffa726}.border-orange-500{border:1px solid #ff9800}.border-orange-600{border:1px solid #fb8c00}.border-orange-700{border:1px solid #f57c00}.border-orange-800{border:1px solid #ef6c00}.border-orange-900{border:1px solid #e65100}.border-deep-orange{border:1px solid #ff5722}.border-deep-orange-50{border:1px solid #fbe9e7}.border-deep-orange-100{border:1px solid #ffccbc}.border-deep-orange-200{border:1px solid #ffab91}.border-deep-orange-300{border:1px solid #ff8a65}.border-deep-orange-400{border:1px solid #ff7043}.border-deep-orange-500{border:1px solid #ff5722}.border-deep-orange-600{border:1px solid #f4511e}.border-deep-orange-700{border:1px solid #e64a19}.border-deep-orange-800{border:1px solid #d84315}.border-deep-orange-900{border:1px solid #bf360c}.border-brown{border:1px solid #795548}.border-brown-50{border:1px solid #efebe9}.border-brown-100{border:1px solid #d7ccc8}.border-brown-200{border:1px solid #bcaaa4}.border-brown-300{border:1px solid #a1887f}.border-brown-400{border:1px solid #8d6e63}.border-brown-500{border:1px solid #795548}.border-brown-600{border:1px solid #6d4c41}.border-brown-700{border:1px solid #5d4037}.border-brown-800{border:1px solid #4e342e}.border-brown-900{border:1px solid #3e2723}.border-grey{border:1px solid #9e9e9e}.border-grey-50{border:1px solid #fafafa}.border-grey-100{border:1px solid #f5f5f5}.border-grey-200{border:1px solid #eee}.border-grey-300{border:1px solid #e0e0e0}.border-grey-400{border:1px solid #bdbdbd}.border-grey-500{border:1px solid #9e9e9e}.border-grey-600{border:1px solid #757575}.border-grey-700{border:1px solid #616161}.border-grey-800{border:1px solid #424242}.border-grey-900{border:1px solid #212121}.border-blue-grey{border:1px solid #607d8b}.border-blue-grey-50{border:1px solid #eceff1}.border-blue-grey-100{border:1px solid #cfd8dc}.border-blue-grey-200{border:1px solid #b0bec5}.border-blue-grey-300{border:1px solid #90a4ae}.border-blue-grey-400{border:1px solid #78909c}.border-blue-grey-500{border:1px solid #607d8b}.border-blue-grey-600{border:1px solid #546e7a}.border-blue-grey-700{border:1px solid #455a64}.border-blue-grey-800{border:1px solid #37474f}.border-blue-grey-900{border:1px solid #263238}.border-black{border:1px solid #000}.border-white{border:1px solid #fff}@font-face{font-family:Roboto;font-style:normal;font-weight:300;src:local('Roboto Light'),local('Roboto-Light'),url(fonts/robotolight.woff2) format('woff2');unicode-range:U+0460-052F,U+20B4,U+2DE0-2DFF,U+A640-A69F}@font-face{font-family:Roboto;font-style:normal;font-weight:400;src:local('Roboto'),local('Roboto-Regular'),url(fonts/sTdaA6j0Psb920Vjv-mrzH-_kf6ByYO6CLYdB4HQE-Y.woff2) format('woff2');unicode-range:U+0460-052F,U+20B4,U+2DE0-2DFF,U+A640-A69F}@font-face{font-family:Roboto;font-style:normal;font-weight:900;src:local('Roboto Black'),local('Roboto-Black'),url(fonts/robotoblack.woff2) format('woff2');unicode-range:U+0460-052F,U+20B4,U+2DE0-2DFF,U+A640-A69F}@font-face{font-family:Ionicons;src:url(fonts/ionicons.woff?v=2.0.0) format("woff");font-weight:400;font-style:normal}i.icon{background:0 0!important}.ion,.ion-alert-circled:before,.ion-alert:before,.ion-android-add-circle:before,.ion-android-add:before,.ion-android-alarm-clock:before,.ion-android-alert:before,.ion-android-apps:before,.ion-android-archive:before,.ion-android-arrow-back:before,.ion-android-arrow-down:before,.ion-android-arrow-dropdown-circle:before,.ion-android-arrow-dropdown:before,.ion-android-arrow-dropleft-circle:before,.ion-android-arrow-dropleft:before,.ion-android-arrow-dropright-circle:before,.ion-android-arrow-dropright:before,.ion-android-arrow-dropup-circle:before,.ion-android-arrow-dropup:before,.ion-android-arrow-forward:before,.ion-android-arrow-up:before,.ion-android-attach:before,.ion-android-bar:before,.ion-android-bicycle:before,.ion-android-boat:before,.ion-android-bookmark:before,.ion-android-bulb:before,.ion-android-bus:before,.ion-android-calendar:before,.ion-android-call:before,.ion-android-camera:before,.ion-android-cancel:before,.ion-android-car:before,.ion-android-cart:before,.ion-android-chat:before,.ion-android-checkbox-blank:before,.ion-android-checkbox-outline-blank:before,.ion-android-checkbox-outline:before,.ion-android-checkbox:before,.ion-android-checkmark-circle:before,.ion-android-clipboard:before,.ion-android-close:before,.ion-android-cloud-circle:before,.ion-android-cloud-done:before,.ion-android-cloud-outline:before,.ion-android-cloud:before,.ion-android-color-palette:before,.ion-android-compass:before,.ion-android-contact:before,.ion-android-contacts:before,.ion-android-contract:before,.ion-android-create:before,.ion-android-delete:before,.ion-android-desktop:before,.ion-android-document:before,.ion-android-done-all:before,.ion-android-done:before,.ion-android-download:before,.ion-android-drafts:before,.ion-android-exit:before,.ion-android-expand:before,.ion-android-favorite-outline:before,.ion-android-favorite:before,.ion-android-film:before,.ion-android-folder-open:before,.ion-android-folder:before,.ion-android-funnel:before,.ion-android-globe:before,.ion-android-hand:before,.ion-android-hangout:before,.ion-android-happy:before,.ion-android-home:before,.ion-android-image:before,.ion-android-laptop:before,.ion-android-list:before,.ion-android-locate:before,.ion-android-lock:before,.ion-android-mail:before,.ion-android-map:before,.ion-android-menu:before,.ion-android-microphone-off:before,.ion-android-microphone:before,.ion-android-more-horizontal:before,.ion-android-more-vertical:before,.ion-android-navigate:before,.ion-android-notifications-none:before,.ion-android-notifications-off:before,.ion-android-notifications:before,.ion-android-open:before,.ion-android-options:before,.ion-android-people:before,.ion-android-person-add:before,.ion-android-person:before,.ion-android-phone-landscape:before,.ion-android-phone-portrait:before,.ion-android-pin:before,.ion-android-plane:before,.ion-android-playstore:before,.ion-android-print:before,.ion-android-radio-button-off:before,.ion-android-radio-button-on:before,.ion-android-refresh:before,.ion-android-remove-circle:before,.ion-android-remove:before,.ion-android-restaurant:before,.ion-android-sad:before,.ion-android-search:before,.ion-android-send:before,.ion-android-settings:before,.ion-android-share-alt:before,.ion-android-share:before,.ion-android-star-half:before,.ion-android-star-outline:before,.ion-android-star:before,.ion-android-stopwatch:before,.ion-android-subway:before,.ion-android-sunny:before,.ion-android-sync:before,.ion-android-textsms:before,.ion-android-time:before,.ion-android-train:before,.ion-android-unlock:before,.ion-android-upload:before,.ion-android-volume-down:before,.ion-android-volume-mute:before,.ion-android-volume-off:before,.ion-android-volume-up:before,.ion-android-walk:before,.ion-android-warning:before,.ion-android-watch:before,.ion-android-wifi:before,.ion-aperture:before,.ion-archive:before,.ion-arrow-down-a:before,.ion-arrow-down-b:before,.ion-arrow-down-c:before,.ion-arrow-expand:before,.ion-arrow-graph-down-left:before,.ion-arrow-graph-down-right:before,.ion-arrow-graph-up-left:before,.ion-arrow-graph-up-right:before,.ion-arrow-left-a:before,.ion-arrow-left-b:before,.ion-arrow-left-c:before,.ion-arrow-move:before,.ion-arrow-resize:before,.ion-arrow-return-left:before,.ion-arrow-return-right:before,.ion-arrow-right-a:before,.ion-arrow-right-b:before,.ion-arrow-right-c:before,.ion-arrow-shrink:before,.ion-arrow-swap:before,.ion-arrow-up-a:before,.ion-arrow-up-b:before,.ion-arrow-up-c:before,.ion-asterisk:before,.ion-at:before,.ion-backspace-outline:before,.ion-backspace:before,.ion-bag:before,.ion-battery-charging:before,.ion-battery-empty:before,.ion-battery-full:before,.ion-battery-half:before,.ion-battery-low:before,.ion-beaker:before,.ion-beer:before,.ion-bluetooth:before,.ion-bonfire:before,.ion-bookmark:before,.ion-bowtie:before,.ion-briefcase:before,.ion-bug:before,.ion-calculator:before,.ion-calendar:before,.ion-camera:before,.ion-card:before,.ion-cash:before,.ion-chatbox-working:before,.ion-chatbox:before,.ion-chatboxes:before,.ion-chatbubble-working:before,.ion-chatbubble:before,.ion-chatbubbles:before,.ion-checkmark-circled:before,.ion-checkmark-round:before,.ion-checkmark:before,.ion-chevron-down:before,.ion-chevron-left:before,.ion-chevron-right:before,.ion-chevron-up:before,.ion-clipboard:before,.ion-clock:before,.ion-close-circled:before,.ion-close-round:before,.ion-close:before,.ion-closed-captioning:before,.ion-cloud:before,.ion-code-download:before,.ion-code-working:before,.ion-code:before,.ion-coffee:before,.ion-compass:before,.ion-compose:before,.ion-connection-bars:before,.ion-contrast:before,.ion-crop:before,.ion-cube:before,.ion-disc:before,.ion-document-text:before,.ion-document:before,.ion-drag:before,.ion-earth:before,.ion-easel:before,.ion-edit:before,.ion-egg:before,.ion-eject:before,.ion-email-unread:before,.ion-email:before,.ion-erlenmeyer-flask-bubbles:before,.ion-erlenmeyer-flask:before,.ion-eye-disabled:before,.ion-eye:before,.ion-female:before,.ion-filing:before,.ion-film-marker:before,.ion-fireball:before,.ion-flag:before,.ion-flame:before,.ion-flash-off:before,.ion-flash:before,.ion-folder:before,.ion-fork-repo:before,.ion-fork:before,.ion-forward:before,.ion-funnel:before,.ion-gear-a:before,.ion-gear-b:before,.ion-grid:before,.ion-hammer:before,.ion-happy-outline:before,.ion-happy:before,.ion-headphone:before,.ion-heart-broken:before,.ion-heart:before,.ion-help-buoy:before,.ion-help-circled:before,.ion-help:before,.ion-home:before,.ion-icecream:before,.ion-image:before,.ion-images:before,.ion-information-circled:before,.ion-information:before,.ion-ionic:before,.ion-ios-alarm-outline:before,.ion-ios-alarm:before,.ion-ios-albums-outline:before,.ion-ios-albums:before,.ion-ios-americanfootball-outline:before,.ion-ios-americanfootball:before,.ion-ios-analytics-outline:before,.ion-ios-analytics:before,.ion-ios-arrow-back:before,.ion-ios-arrow-down:before,.ion-ios-arrow-forward:before,.ion-ios-arrow-left:before,.ion-ios-arrow-right:before,.ion-ios-arrow-thin-down:before,.ion-ios-arrow-thin-left:before,.ion-ios-arrow-thin-right:before,.ion-ios-arrow-thin-up:before,.ion-ios-arrow-up:before,.ion-ios-at-outline:before,.ion-ios-at:before,.ion-ios-barcode-outline:before,.ion-ios-barcode:before,.ion-ios-baseball-outline:before,.ion-ios-baseball:before,.ion-ios-basketball-outline:before,.ion-ios-basketball:before,.ion-ios-bell-outline:before,.ion-ios-bell:before,.ion-ios-body-outline:before,.ion-ios-body:before,.ion-ios-bolt-outline:before,.ion-ios-bolt:before,.ion-ios-book-outline:before,.ion-ios-book:before,.ion-ios-bookmarks-outline:before,.ion-ios-bookmarks:before,.ion-ios-box-outline:before,.ion-ios-box:before,.ion-ios-briefcase-outline:before,.ion-ios-briefcase:before,.ion-ios-browsers-outline:before,.ion-ios-browsers:before,.ion-ios-calculator-outline:before,.ion-ios-calculator:before,.ion-ios-calendar-outline:before,.ion-ios-calendar:before,.ion-ios-camera-outline:before,.ion-ios-camera:before,.ion-ios-cart-outline:before,.ion-ios-cart:before,.ion-ios-chatboxes-outline:before,.ion-ios-chatboxes:before,.ion-ios-chatbubble-outline:before,.ion-ios-chatbubble:before,.ion-ios-checkmark-empty:before,.ion-ios-checkmark-outline:before,.ion-ios-checkmark:before,.ion-ios-circle-filled:before,.ion-ios-circle-outline:before,.ion-ios-clock-outline:before,.ion-ios-clock:before,.ion-ios-close-empty:before,.ion-ios-close-outline:before,.ion-ios-close:before,.ion-ios-cloud-download-outline:before,.ion-ios-cloud-download:before,.ion-ios-cloud-outline:before,.ion-ios-cloud-upload-outline:before,.ion-ios-cloud-upload:before,.ion-ios-cloud:before,.ion-ios-cloudy-night-outline:before,.ion-ios-cloudy-night:before,.ion-ios-cloudy-outline:before,.ion-ios-cloudy:before,.ion-ios-cog-outline:before,.ion-ios-cog:before,.ion-ios-color-filter-outline:before,.ion-ios-color-filter:before,.ion-ios-color-wand-outline:before,.ion-ios-color-wand:before,.ion-ios-compose-outline:before,.ion-ios-compose:before,.ion-ios-contact-outline:before,.ion-ios-contact:before,.ion-ios-copy-outline:before,.ion-ios-copy:before,.ion-ios-crop-strong:before,.ion-ios-crop:before,.ion-ios-download-outline:before,.ion-ios-download:before,.ion-ios-drag:before,.ion-ios-email-outline:before,.ion-ios-email:before,.ion-ios-eye-outline:before,.ion-ios-eye:before,.ion-ios-fastforward-outline:before,.ion-ios-fastforward:before,.ion-ios-filing-outline:before,.ion-ios-filing:before,.ion-ios-film-outline:before,.ion-ios-film:before,.ion-ios-flag-outline:before,.ion-ios-flag:before,.ion-ios-flame-outline:before,.ion-ios-flame:before,.ion-ios-flask-outline:before,.ion-ios-flask:before,.ion-ios-flower-outline:before,.ion-ios-flower:before,.ion-ios-folder-outline:before,.ion-ios-folder:before,.ion-ios-football-outline:before,.ion-ios-football:before,.ion-ios-game-controller-a-outline:before,.ion-ios-game-controller-a:before,.ion-ios-game-controller-b-outline:before,.ion-ios-game-controller-b:before,.ion-ios-gear-outline:before,.ion-ios-gear:before,.ion-ios-glasses-outline:before,.ion-ios-glasses:before,.ion-ios-grid-view-outline:before,.ion-ios-grid-view:before,.ion-ios-heart-outline:before,.ion-ios-heart:before,.ion-ios-help-empty:before,.ion-ios-help-outline:before,.ion-ios-help:before,.ion-ios-home-outline:before,.ion-ios-home:before,.ion-ios-infinite-outline:before,.ion-ios-infinite:before,.ion-ios-information-empty:before,.ion-ios-information-outline:before,.ion-ios-information:before,.ion-ios-ionic-outline:before,.ion-ios-keypad-outline:before,.ion-ios-keypad:before,.ion-ios-lightbulb-outline:before,.ion-ios-lightbulb:before,.ion-ios-list-outline:before,.ion-ios-list:before,.ion-ios-location-outline:before,.ion-ios-location:before,.ion-ios-locked-outline:before,.ion-ios-locked:before,.ion-ios-loop-strong:before,.ion-ios-loop:before,.ion-ios-medical-outline:before,.ion-ios-medical:before,.ion-ios-medkit-outline:before,.ion-ios-medkit:before,.ion-ios-mic-off:before,.ion-ios-mic-outline:before,.ion-ios-mic:before,.ion-ios-minus-empty:before,.ion-ios-minus-outline:before,.ion-ios-minus:before,.ion-ios-monitor-outline:before,.ion-ios-monitor:before,.ion-ios-moon-outline:before,.ion-ios-moon:before,.ion-ios-more-outline:before,.ion-ios-more:before,.ion-ios-musical-note:before,.ion-ios-musical-notes:before,.ion-ios-navigate-outline:before,.ion-ios-navigate:before,.ion-ios-nutrition-outline:before,.ion-ios-nutrition:before,.ion-ios-paper-outline:before,.ion-ios-paper:before,.ion-ios-paperplane-outline:before,.ion-ios-paperplane:before,.ion-ios-partlysunny-outline:before,.ion-ios-partlysunny:before,.ion-ios-pause-outline:before,.ion-ios-pause:before,.ion-ios-paw-outline:before,.ion-ios-paw:before,.ion-ios-people-outline:before,.ion-ios-people:before,.ion-ios-person-outline:before,.ion-ios-person:before,.ion-ios-personadd-outline:before,.ion-ios-personadd:before,.ion-ios-photos-outline:before,.ion-ios-photos:before,.ion-ios-pie-outline:before,.ion-ios-pie:before,.ion-ios-pint-outline:before,.ion-ios-pint:before,.ion-ios-play-outline:before,.ion-ios-play:before,.ion-ios-plus-empty:before,.ion-ios-plus-outline:before,.ion-ios-plus:before,.ion-ios-pricetag-outline:before,.ion-ios-pricetag:before,.ion-ios-pricetags-outline:before,.ion-ios-pricetags:before,.ion-ios-printer-outline:before,.ion-ios-printer:before,.ion-ios-pulse-strong:before,.ion-ios-pulse:before,.ion-ios-rainy-outline:before,.ion-ios-rainy:before,.ion-ios-recording-outline:before,.ion-ios-recording:before,.ion-ios-redo-outline:before,.ion-ios-redo:before,.ion-ios-refresh-empty:before,.ion-ios-refresh-outline:before,.ion-ios-refresh:before,.ion-ios-reload:before,.ion-ios-reverse-camera-outline:before,.ion-ios-reverse-camera:before,.ion-ios-rewind-outline:before,.ion-ios-rewind:before,.ion-ios-rose-outline:before,.ion-ios-rose:before,.ion-ios-search-strong:before,.ion-ios-search:before,.ion-ios-settings-strong:before,.ion-ios-settings:before,.ion-ios-shuffle-strong:before,.ion-ios-shuffle:before,.ion-ios-skipbackward-outline:before,.ion-ios-skipbackward:before,.ion-ios-skipforward-outline:before,.ion-ios-skipforward:before,.ion-ios-snowy:before,.ion-ios-speedometer-outline:before,.ion-ios-speedometer:before,.ion-ios-star-half:before,.ion-ios-star-outline:before,.ion-ios-star:before,.ion-ios-stopwatch-outline:before,.ion-ios-stopwatch:before,.ion-ios-sunny-outline:before,.ion-ios-sunny:before,.ion-ios-telephone-outline:before,.ion-ios-telephone:before,.ion-ios-tennisball-outline:before,.ion-ios-tennisball:before,.ion-ios-thunderstorm-outline:before,.ion-ios-thunderstorm:before,.ion-ios-time-outline:before,.ion-ios-time:before,.ion-ios-timer-outline:before,.ion-ios-timer:before,.ion-ios-toggle-outline:before,.ion-ios-toggle:before,.ion-ios-trash-outline:before,.ion-ios-trash:before,.ion-ios-undo-outline:before,.ion-ios-undo:before,.ion-ios-unlocked-outline:before,.ion-ios-unlocked:before,.ion-ios-upload-outline:before,.ion-ios-upload:before,.ion-ios-videocam-outline:before,.ion-ios-videocam:before,.ion-ios-volume-high:before,.ion-ios-volume-low:before,.ion-ios-wineglass-outline:before,.ion-ios-wineglass:before,.ion-ios-world-outline:before,.ion-ios-world:before,.ion-ipad:before,.ion-iphone:before,.ion-ipod:before,.ion-jet:before,.ion-key:before,.ion-knife:before,.ion-laptop:before,.ion-leaf:before,.ion-levels:before,.ion-lightbulb:before,.ion-link:before,.ion-load-a:before,.ion-load-b:before,.ion-load-c:before,.ion-load-d:before,.ion-location:before,.ion-lock-combination:before,.ion-locked:before,.ion-log-in:before,.ion-log-out:before,.ion-loop:before,.ion-magnet:before,.ion-male:before,.ion-man:before,.ion-map:before,.ion-medkit:before,.ion-merge:before,.ion-mic-a:before,.ion-mic-b:before,.ion-mic-c:before,.ion-minus-circled:before,.ion-minus-round:before,.ion-minus:before,.ion-model-s:before,.ion-monitor:before,.ion-more:before,.ion-mouse:before,.ion-music-note:before,.ion-navicon-round:before,.ion-navicon:before,.ion-navigate:before,.ion-network:before,.ion-no-smoking:before,.ion-nuclear:before,.ion-outlet:before,.ion-paintbrush:before,.ion-paintbucket:before,.ion-paper-airplane:before,.ion-paperclip:before,.ion-pause:before,.ion-person-add:before,.ion-person-stalker:before,.ion-person:before,.ion-pie-graph:before,.ion-pin:before,.ion-pinpoint:before,.ion-pizza:before,.ion-plane:before,.ion-planet:before,.ion-play:before,.ion-playstation:before,.ion-plus-circled:before,.ion-plus-round:before,.ion-plus:before,.ion-podium:before,.ion-pound:before,.ion-power:before,.ion-pricetag:before,.ion-pricetags:before,.ion-printer:before,.ion-pull-request:before,.ion-qr-scanner:before,.ion-quote:before,.ion-radio-waves:before,.ion-record:before,.ion-refresh:before,.ion-reply-all:before,.ion-reply:before,.ion-ribbon-a:before,.ion-ribbon-b:before,.ion-sad-outline:before,.ion-sad:before,.ion-scissors:before,.ion-search:before,.ion-settings:before,.ion-share:before,.ion-shuffle:before,.ion-skip-backward:before,.ion-skip-forward:before,.ion-social-android-outline:before,.ion-social-android:before,.ion-social-angular-outline:before,.ion-social-angular:before,.ion-social-apple-outline:before,.ion-social-apple:before,.ion-social-bitcoin-outline:before,.ion-social-bitcoin:before,.ion-social-buffer-outline:before,.ion-social-buffer:before,.ion-social-chrome-outline:before,.ion-social-chrome:before,.ion-social-codepen-outline:before,.ion-social-codepen:before,.ion-social-css3-outline:before,.ion-social-css3:before,.ion-social-designernews-outline:before,.ion-social-designernews:before,.ion-social-dribbble-outline:before,.ion-social-dribbble:before,.ion-social-dropbox-outline:before,.ion-social-dropbox:before,.ion-social-euro-outline:before,.ion-social-euro:before,.ion-social-facebook-outline:before,.ion-social-facebook:before,.ion-social-foursquare-outline:before,.ion-social-foursquare:before,.ion-social-freebsd-devil:before,.ion-social-github-outline:before,.ion-social-github:before,.ion-social-google-outline:before,.ion-social-google:before,.ion-social-googleplus-outline:before,.ion-social-googleplus:before,.ion-social-hackernews-outline:before,.ion-social-hackernews:before,.ion-social-html5-outline:before,.ion-social-html5:before,.ion-social-instagram-outline:before,.ion-social-instagram:before,.ion-social-javascript-outline:before,.ion-social-javascript:before,.ion-social-linkedin-outline:before,.ion-social-linkedin:before,.ion-social-markdown:before,.ion-social-nodejs:before,.ion-social-octocat:before,.ion-social-pinterest-outline:before,.ion-social-pinterest:before,.ion-social-python:before,.ion-social-reddit-outline:before,.ion-social-reddit:before,.ion-social-rss-outline:before,.ion-social-rss:before,.ion-social-sass:before,.ion-social-skype-outline:before,.ion-social-skype:before,.ion-social-snapchat-outline:before,.ion-social-snapchat:before,.ion-social-tumblr-outline:before,.ion-social-tumblr:before,.ion-social-tux:before,.ion-social-twitch-outline:before,.ion-social-twitch:before,.ion-social-twitter-outline:before,.ion-social-twitter:before,.ion-social-usd-outline:before,.ion-social-usd:before,.ion-social-vimeo-outline:before,.ion-social-vimeo:before,.ion-social-whatsapp-outline:before,.ion-social-whatsapp:before,.ion-social-windows-outline:before,.ion-social-windows:before,.ion-social-wordpress-outline:before,.ion-social-wordpress:before,.ion-social-yahoo-outline:before,.ion-social-yahoo:before,.ion-social-yen-outline:before,.ion-social-yen:before,.ion-social-youtube-outline:before,.ion-social-youtube:before,.ion-soup-can-outline:before,.ion-soup-can:before,.ion-speakerphone:before,.ion-speedometer:before,.ion-spoon:before,.ion-star:before,.ion-stats-bars:before,.ion-steam:before,.ion-stop:before,.ion-thermometer:before,.ion-thumbsdown:before,.ion-thumbsup:before,.ion-toggle-filled:before,.ion-toggle:before,.ion-transgender:before,.ion-trash-a:before,.ion-trash-b:before,.ion-trophy:before,.ion-tshirt-outline:before,.ion-tshirt:before,.ion-umbrella:before,.ion-university:before,.ion-unlocked:before,.ion-upload:before,.ion-usb:before,.ion-videocamera:before,.ion-volume-high:before,.ion-volume-low:before,.ion-volume-medium:before,.ion-volume-mute:before,.ion-wand:before,.ion-waterdrop:before,.ion-wifi:before,.ion-wineglass:before,.ion-woman:before,.ion-wrench:before,.ion-xbox:before,.ionicons{display:inline-block;font-family:Ionicons;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;text-rendering:auto;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;min-width:22px;text-align:center}.ion-alert:before{content:"\f101"}.ion-alert-circled:before{content:"\f100"}.ion-android-add:before{content:"\f2c7"}.ion-android-add-circle:before{content:"\f359"}.ion-android-alarm-clock:before{content:"\f35a"}.ion-android-alert:before{content:"\f35b"}.ion-android-apps:before{content:"\f35c"}.ion-android-archive:before{content:"\f2c9"}.ion-android-arrow-back:before{content:"\f2ca"}.ion-android-arrow-down:before{content:"\f35d"}.ion-android-arrow-dropdown:before{content:"\f35f"}.ion-android-arrow-dropdown-circle:before{content:"\f35e"}.ion-android-arrow-dropleft:before{content:"\f361"}.ion-android-arrow-dropleft-circle:before{content:"\f360"}.ion-android-arrow-dropright:before{content:"\f363"}.ion-android-arrow-dropright-circle:before{content:"\f362"}.ion-android-arrow-dropup:before{content:"\f365"}.ion-android-arrow-dropup-circle:before{content:"\f364"}.ion-android-arrow-forward:before{content:"\f30f"}.ion-android-arrow-up:before{content:"\f366"}.ion-android-attach:before{content:"\f367"}.ion-android-bar:before{content:"\f368"}.ion-android-bicycle:before{content:"\f369"}.ion-android-boat:before{content:"\f36a"}.ion-android-bookmark:before{content:"\f36b"}.ion-android-bulb:before{content:"\f36c"}.ion-android-bus:before{content:"\f36d"}.ion-android-calendar:before{content:"\f2d1"}.ion-android-call:before{content:"\f2d2"}.ion-android-camera:before{content:"\f2d3"}.ion-android-cancel:before{content:"\f36e"}.ion-android-car:before{content:"\f36f"}.ion-android-cart:before{content:"\f370"}.ion-android-chat:before{content:"\f2d4"}.ion-android-checkbox:before{content:"\f374"}.ion-android-checkbox-blank:before{content:"\f371"}.ion-android-checkbox-outline:before{content:"\f373"}.ion-android-checkbox-outline-blank:before{content:"\f372"}.ion-android-checkmark-circle:before{content:"\f375"}.ion-android-clipboard:before{content:"\f376"}.ion-android-close:before{content:"\f2d7"}.ion-android-cloud:before{content:"\f37a"}.ion-android-cloud-circle:before{content:"\f377"}.ion-android-cloud-done:before{content:"\f378"}.ion-android-cloud-outline:before{content:"\f379"}.ion-android-color-palette:before{content:"\f37b"}.ion-android-compass:before{content:"\f37c"}.ion-android-contact:before{content:"\f2d8"}.ion-android-contacts:before{content:"\f2d9"}.ion-android-contract:before{content:"\f37d"}.ion-android-create:before{content:"\f37e"}.ion-android-delete:before{content:"\f37f"}.ion-android-desktop:before{content:"\f380"}.ion-android-document:before{content:"\f381"}.ion-android-done:before{content:"\f383"}.ion-android-done-all:before{content:"\f382"}.ion-android-download:before{content:"\f2dd"}.ion-android-drafts:before{content:"\f384"}.ion-android-exit:before{content:"\f385"}.ion-android-expand:before{content:"\f386"}.ion-android-favorite:before{content:"\f388"}.ion-android-favorite-outline:before{content:"\f387"}.ion-android-film:before{content:"\f389"}.ion-android-folder:before{content:"\f2e0"}.ion-android-folder-open:before{content:"\f38a"}.ion-android-funnel:before{content:"\f38b"}.ion-android-globe:before{content:"\f38c"}.ion-android-hand:before{content:"\f2e3"}.ion-android-hangout:before{content:"\f38d"}.ion-android-happy:before{content:"\f38e"}.ion-android-home:before{content:"\f38f"}.ion-android-image:before{content:"\f2e4"}.ion-android-laptop:before{content:"\f390"}.ion-android-list:before{content:"\f391"}.ion-android-locate:before{content:"\f2e9"}.ion-android-lock:before{content:"\f392"}.ion-android-mail:before{content:"\f2eb"}.ion-android-map:before{content:"\f393"}.ion-android-menu:before{content:"\f394"}.ion-android-microphone:before{content:"\f2ec"}.ion-android-microphone-off:before{content:"\f395"}.ion-android-more-horizontal:before{content:"\f396"}.ion-android-more-vertical:before{content:"\f397"}.ion-android-navigate:before{content:"\f398"}.ion-android-notifications:before{content:"\f39b"}.ion-android-notifications-none:before{content:"\f399"}.ion-android-notifications-off:before{content:"\f39a"}.ion-android-open:before{content:"\f39c"}.ion-android-options:before{content:"\f39d"}.ion-android-people:before{content:"\f39e"}.ion-android-person:before{content:"\f3a0"}.ion-android-person-add:before{content:"\f39f"}.ion-android-phone-landscape:before{content:"\f3a1"}.ion-android-phone-portrait:before{content:"\f3a2"}.ion-android-pin:before{content:"\f3a3"}.ion-android-plane:before{content:"\f3a4"}.ion-android-playstore:before{content:"\f2f0"}.ion-android-print:before{content:"\f3a5"}.ion-android-radio-button-off:before{content:"\f3a6"}.ion-android-radio-button-on:before{content:"\f3a7"}.ion-android-refresh:before{content:"\f3a8"}.ion-android-remove:before{content:"\f2f4"}.ion-android-remove-circle:before{content:"\f3a9"}.ion-android-restaurant:before{content:"\f3aa"}.ion-android-sad:before{content:"\f3ab"}.ion-android-search:before{content:"\f2f5"}.ion-android-send:before{content:"\f2f6"}.ion-android-settings:before{content:"\f2f7"}.ion-android-share:before{content:"\f2f8"}.ion-android-share-alt:before{content:"\f3ac"}.ion-android-star:before{content:"\f2fc"}.ion-android-star-half:before{content:"\f3ad"}.ion-android-star-outline:before{content:"\f3ae"}.ion-android-stopwatch:before{content:"\f2fd"}.ion-android-subway:before{content:"\f3af"}.ion-android-sunny:before{content:"\f3b0"}.ion-android-sync:before{content:"\f3b1"}.ion-android-textsms:before{content:"\f3b2"}.ion-android-time:before{content:"\f3b3"}.ion-android-train:before{content:"\f3b4"}.ion-android-unlock:before{content:"\f3b5"}.ion-android-upload:before{content:"\f3b6"}.ion-android-volume-down:before{content:"\f3b7"}.ion-android-volume-mute:before{content:"\f3b8"}.ion-android-volume-off:before{content:"\f3b9"}.ion-android-volume-up:before{content:"\f3ba"}.ion-android-walk:before{content:"\f3bb"}.ion-android-warning:before{content:"\f3bc"}.ion-android-watch:before{content:"\f3bd"}.ion-android-wifi:before{content:"\f305"}.ion-aperture:before{content:"\f313"}.ion-archive:before{content:"\f102"}.ion-arrow-down-a:before{content:"\f103"}.ion-arrow-down-b:before{content:"\f104"}.ion-arrow-down-c:before{content:"\f105"}.ion-arrow-expand:before{content:"\f25e"}.ion-arrow-graph-down-left:before{content:"\f25f"}.ion-arrow-graph-down-right:before{content:"\f260"}.ion-arrow-graph-up-left:before{content:"\f261"}.ion-arrow-graph-up-right:before{content:"\f262"}.ion-arrow-left-a:before{content:"\f106"}.ion-arrow-left-b:before{content:"\f107"}.ion-arrow-left-c:before{content:"\f108"}.ion-arrow-move:before{content:"\f263"}.ion-arrow-resize:before{content:"\f264"}.ion-arrow-return-left:before{content:"\f265"}.ion-arrow-return-right:before{content:"\f266"}.ion-arrow-right-a:before{content:"\f109"}.ion-arrow-right-b:before{content:"\f10a"}.ion-arrow-right-c:before{content:"\f10b"}.ion-arrow-shrink:before{content:"\f267"}.ion-arrow-swap:before{content:"\f268"}.ion-arrow-up-a:before{content:"\f10c"}.ion-arrow-up-b:before{content:"\f10d"}.ion-arrow-up-c:before{content:"\f10e"}.ion-asterisk:before{content:"\f314"}.ion-at:before{content:"\f10f"}.ion-backspace:before{content:"\f3bf"}.ion-backspace-outline:before{content:"\f3be"}.ion-bag:before{content:"\f110"}.ion-battery-charging:before{content:"\f111"}.ion-battery-empty:before{content:"\f112"}.ion-battery-full:before{content:"\f113"}.ion-battery-half:before{content:"\f114"}.ion-battery-low:before{content:"\f115"}.ion-beaker:before{content:"\f269"}.ion-beer:before{content:"\f26a"}.ion-bluetooth:before{content:"\f116"}.ion-bonfire:before{content:"\f315"}.ion-bookmark:before{content:"\f26b"}.ion-bowtie:before{content:"\f3c0"}.ion-briefcase:before{content:"\f26c"}.ion-bug:before{content:"\f2be"}.ion-calculator:before{content:"\f26d"}.ion-calendar:before{content:"\f117"}.ion-camera:before{content:"\f118"}.ion-card:before{content:"\f119"}.ion-cash:before{content:"\f316"}.ion-chatbox:before{content:"\f11b"}.ion-chatbox-working:before{content:"\f11a"}.ion-chatboxes:before{content:"\f11c"}.ion-chatbubble:before{content:"\f11e"}.ion-chatbubble-working:before{content:"\f11d"}.ion-chatbubbles:before{content:"\f11f"}.ion-checkmark:before{content:"\f122"}.ion-checkmark-circled:before{content:"\f120"}.ion-checkmark-round:before{content:"\f121"}.ion-chevron-down:before{content:"\f123"}.ion-chevron-left:before{content:"\f124"}.ion-chevron-right:before{content:"\f125"}.ion-chevron-up:before{content:"\f126"}.ion-clipboard:before{content:"\f127"}.ion-clock:before{content:"\f26e"}.ion-close:before{content:"\f12a"}.ion-close-circled:before{content:"\f128"}.ion-close-round:before{content:"\f129"}.ion-closed-captioning:before{content:"\f317"}.ion-cloud:before{content:"\f12b"}.ion-code:before{content:"\f271"}.ion-code-download:before{content:"\f26f"}.ion-code-working:before{content:"\f270"}.ion-coffee:before{content:"\f272"}.ion-compass:before{content:"\f273"}.ion-compose:before{content:"\f12c"}.ion-connection-bars:before{content:"\f274"}.ion-contrast:before{content:"\f275"}.ion-crop:before{content:"\f3c1"}.ion-cube:before{content:"\f318"}.ion-disc:before{content:"\f12d"}.ion-document:before{content:"\f12f"}.ion-document-text:before{content:"\f12e"}.ion-drag:before{content:"\f130"}.ion-earth:before{content:"\f276"}.ion-easel:before{content:"\f3c2"}.ion-edit:before{content:"\f2bf"}.ion-egg:before{content:"\f277"}.ion-eject:before{content:"\f131"}.ion-email:before{content:"\f132"}.ion-email-unread:before{content:"\f3c3"}.ion-erlenmeyer-flask:before{content:"\f3c5"}.ion-erlenmeyer-flask-bubbles:before{content:"\f3c4"}.ion-eye:before{content:"\f133"}.ion-eye-disabled:before{content:"\f306"}.ion-female:before{content:"\f278"}.ion-filing:before{content:"\f134"}.ion-film-marker:before{content:"\f135"}.ion-fireball:before{content:"\f319"}.ion-flag:before{content:"\f279"}.ion-flame:before{content:"\f31a"}.ion-flash:before{content:"\f137"}.ion-flash-off:before{content:"\f136"}.ion-folder:before{content:"\f139"}.ion-fork:before{content:"\f27a"}.ion-fork-repo:before{content:"\f2c0"}.ion-forward:before{content:"\f13a"}.ion-funnel:before{content:"\f31b"}.ion-gear-a:before{content:"\f13d"}.ion-gear-b:before{content:"\f13e"}.ion-grid:before{content:"\f13f"}.ion-hammer:before{content:"\f27b"}.ion-happy:before{content:"\f31c"}.ion-happy-outline:before{content:"\f3c6"}.ion-headphone:before{content:"\f140"}.ion-heart:before{content:"\f141"}.ion-heart-broken:before{content:"\f31d"}.ion-help:before{content:"\f143"}.ion-help-buoy:before{content:"\f27c"}.ion-help-circled:before{content:"\f142"}.ion-home:before{content:"\f144"}.ion-icecream:before{content:"\f27d"}.ion-image:before{content:"\f147"}.ion-images:before{content:"\f148"}.ion-information:before{content:"\f14a"}.ion-information-circled:before{content:"\f149"}.ion-ionic:before{content:"\f14b"}.ion-ios-alarm:before{content:"\f3c8"}.ion-ios-alarm-outline:before{content:"\f3c7"}.ion-ios-albums:before{content:"\f3ca"}.ion-ios-albums-outline:before{content:"\f3c9"}.ion-ios-americanfootball:before{content:"\f3cc"}.ion-ios-americanfootball-outline:before{content:"\f3cb"}.ion-ios-analytics:before{content:"\f3ce"}.ion-ios-analytics-outline:before{content:"\f3cd"}.ion-ios-arrow-back:before{content:"\f3cf"}.ion-ios-arrow-down:before{content:"\f3d0"}.ion-ios-arrow-forward:before{content:"\f3d1"}.ion-ios-arrow-left:before{content:"\f3d2"}.ion-ios-arrow-right:before{content:"\f3d3"}.ion-ios-arrow-thin-down:before{content:"\f3d4"}.ion-ios-arrow-thin-left:before{content:"\f3d5"}.ion-ios-arrow-thin-right:before{content:"\f3d6"}.ion-ios-arrow-thin-up:before{content:"\f3d7"}.ion-ios-arrow-up:before{content:"\f3d8"}.ion-ios-at:before{content:"\f3da"}.ion-ios-at-outline:before{content:"\f3d9"}.ion-ios-barcode:before{content:"\f3dc"}.ion-ios-barcode-outline:before{content:"\f3db"}.ion-ios-baseball:before{content:"\f3de"}.ion-ios-baseball-outline:before{content:"\f3dd"}.ion-ios-basketball:before{content:"\f3e0"}.ion-ios-basketball-outline:before{content:"\f3df"}.ion-ios-bell:before{content:"\f3e2"}.ion-ios-bell-outline:before{content:"\f3e1"}.ion-ios-body:before{content:"\f3e4"}.ion-ios-body-outline:before{content:"\f3e3"}.ion-ios-bolt:before{content:"\f3e6"}.ion-ios-bolt-outline:before{content:"\f3e5"}.ion-ios-book:before{content:"\f3e8"}.ion-ios-book-outline:before{content:"\f3e7"}.ion-ios-bookmarks:before{content:"\f3ea"}.ion-ios-bookmarks-outline:before{content:"\f3e9"}.ion-ios-box:before{content:"\f3ec"}.ion-ios-box-outline:before{content:"\f3eb"}.ion-ios-briefcase:before{content:"\f3ee"}.ion-ios-briefcase-outline:before{content:"\f3ed"}.ion-ios-browsers:before{content:"\f3f0"}.ion-ios-browsers-outline:before{content:"\f3ef"}.ion-ios-calculator:before{content:"\f3f2"}.ion-ios-calculator-outline:before{content:"\f3f1"}.ion-ios-calendar:before{content:"\f3f4"}.ion-ios-calendar-outline:before{content:"\f3f3"}.ion-ios-camera:before{content:"\f3f6"}.ion-ios-camera-outline:before{content:"\f3f5"}.ion-ios-cart:before{content:"\f3f8"}.ion-ios-cart-outline:before{content:"\f3f7"}.ion-ios-chatboxes:before{content:"\f3fa"}.ion-ios-chatboxes-outline:before{content:"\f3f9"}.ion-ios-chatbubble:before{content:"\f3fc"}.ion-ios-chatbubble-outline:before{content:"\f3fb"}.ion-ios-checkmark:before{content:"\f3ff"}.ion-ios-checkmark-empty:before{content:"\f3fd"}.ion-ios-checkmark-outline:before{content:"\f3fe"}.ion-ios-circle-filled:before{content:"\f400"}.ion-ios-circle-outline:before{content:"\f401"}.ion-ios-clock:before{content:"\f403"}.ion-ios-clock-outline:before{content:"\f402"}.ion-ios-close:before{content:"\f406"}.ion-ios-close-empty:before{content:"\f404"}.ion-ios-close-outline:before{content:"\f405"}.ion-ios-cloud:before{content:"\f40c"}.ion-ios-cloud-download:before{content:"\f408"}.ion-ios-cloud-download-outline:before{content:"\f407"}.ion-ios-cloud-outline:before{content:"\f409"}.ion-ios-cloud-upload:before{content:"\f40b"}.ion-ios-cloud-upload-outline:before{content:"\f40a"}.ion-ios-cloudy:before{content:"\f410"}.ion-ios-cloudy-night:before{content:"\f40e"}.ion-ios-cloudy-night-outline:before{content:"\f40d"}.ion-ios-cloudy-outline:before{content:"\f40f"}.ion-ios-cog:before{content:"\f412"}.ion-ios-cog-outline:before{content:"\f411"}.ion-ios-color-filter:before{content:"\f414"}.ion-ios-color-filter-outline:before{content:"\f413"}.ion-ios-color-wand:before{content:"\f416"}.ion-ios-color-wand-outline:before{content:"\f415"}.ion-ios-compose:before{content:"\f418"}.ion-ios-compose-outline:before{content:"\f417"}.ion-ios-contact:before{content:"\f41a"}.ion-ios-contact-outline:before{content:"\f419"}.ion-ios-copy:before{content:"\f41c"}.ion-ios-copy-outline:before{content:"\f41b"}.ion-ios-crop:before{content:"\f41e"}.ion-ios-crop-strong:before{content:"\f41d"}.ion-ios-download:before{content:"\f420"}.ion-ios-download-outline:before{content:"\f41f"}.ion-ios-drag:before{content:"\f421"}.ion-ios-email:before{content:"\f423"}.ion-ios-email-outline:before{content:"\f422"}.ion-ios-eye:before{content:"\f425"}.ion-ios-eye-outline:before{content:"\f424"}.ion-ios-fastforward:before{content:"\f427"}.ion-ios-fastforward-outline:before{content:"\f426"}.ion-ios-filing:before{content:"\f429"}.ion-ios-filing-outline:before{content:"\f428"}.ion-ios-film:before{content:"\f42b"}.ion-ios-film-outline:before{content:"\f42a"}.ion-ios-flag:before{content:"\f42d"}.ion-ios-flag-outline:before{content:"\f42c"}.ion-ios-flame:before{content:"\f42f"}.ion-ios-flame-outline:before{content:"\f42e"}.ion-ios-flask:before{content:"\f431"}.ion-ios-flask-outline:before{content:"\f430"}.ion-ios-flower:before{content:"\f433"}.ion-ios-flower-outline:before{content:"\f432"}.ion-ios-folder:before{content:"\f435"}.ion-ios-folder-outline:before{content:"\f434"}.ion-ios-football:before{content:"\f437"}.ion-ios-football-outline:before{content:"\f436"}.ion-ios-game-controller-a:before{content:"\f439"}.ion-ios-game-controller-a-outline:before{content:"\f438"}.ion-ios-game-controller-b:before{content:"\f43b"}.ion-ios-game-controller-b-outline:before{content:"\f43a"}.ion-ios-gear:before{content:"\f43d"}.ion-ios-gear-outline:before{content:"\f43c"}.ion-ios-glasses:before{content:"\f43f"}.ion-ios-glasses-outline:before{content:"\f43e"}.ion-ios-grid-view:before{content:"\f441"}.ion-ios-grid-view-outline:before{content:"\f440"}.ion-ios-heart:before{content:"\f443"}.ion-ios-heart-outline:before{content:"\f442"}.ion-ios-help:before{content:"\f446"}.ion-ios-help-empty:before{content:"\f444"}.ion-ios-help-outline:before{content:"\f445"}.ion-ios-home:before{content:"\f448"}.ion-ios-home-outline:before{content:"\f447"}.ion-ios-infinite:before{content:"\f44a"}.ion-ios-infinite-outline:before{content:"\f449"}.ion-ios-information:before{content:"\f44d"}.ion-ios-information-empty:before{content:"\f44b"}.ion-ios-information-outline:before{content:"\f44c"}.ion-ios-ionic-outline:before{content:"\f44e"}.ion-ios-keypad:before{content:"\f450"}.ion-ios-keypad-outline:before{content:"\f44f"}.ion-ios-lightbulb:before{content:"\f452"}.ion-ios-lightbulb-outline:before{content:"\f451"}.ion-ios-list:before{content:"\f454"}.ion-ios-list-outline:before{content:"\f453"}.ion-ios-location:before{content:"\f456"}.ion-ios-location-outline:before{content:"\f455"}.ion-ios-locked:before{content:"\f458"}.ion-ios-locked-outline:before{content:"\f457"}.ion-ios-loop:before{content:"\f45a"}.ion-ios-loop-strong:before{content:"\f459"}.ion-ios-medical:before{content:"\f45c"}.ion-ios-medical-outline:before{content:"\f45b"}.ion-ios-medkit:before{content:"\f45e"}.ion-ios-medkit-outline:before{content:"\f45d"}.ion-ios-mic:before{content:"\f461"}.ion-ios-mic-off:before{content:"\f45f"}.ion-ios-mic-outline:before{content:"\f460"}.ion-ios-minus:before{content:"\f464"}.ion-ios-minus-empty:before{content:"\f462"}.ion-ios-minus-outline:before{content:"\f463"}.ion-ios-monitor:before{content:"\f466"}.ion-ios-monitor-outline:before{content:"\f465"}.ion-ios-moon:before{content:"\f468"}.ion-ios-moon-outline:before{content:"\f467"}.ion-ios-more:before{content:"\f46a"}.ion-ios-more-outline:before{content:"\f469"}.ion-ios-musical-note:before{content:"\f46b"}.ion-ios-musical-notes:before{content:"\f46c"}.ion-ios-navigate:before{content:"\f46e"}.ion-ios-navigate-outline:before{content:"\f46d"}.ion-ios-nutrition:before{content:"\f470"}.ion-ios-nutrition-outline:before{content:"\f46f"}.ion-ios-paper:before{content:"\f472"}.ion-ios-paper-outline:before{content:"\f471"}.ion-ios-paperplane:before{content:"\f474"}.ion-ios-paperplane-outline:before{content:"\f473"}.ion-ios-partlysunny:before{content:"\f476"}.ion-ios-partlysunny-outline:before{content:"\f475"}.ion-ios-pause:before{content:"\f478"}.ion-ios-pause-outline:before{content:"\f477"}.ion-ios-paw:before{content:"\f47a"}.ion-ios-paw-outline:before{content:"\f479"}.ion-ios-people:before{content:"\f47c"}.ion-ios-people-outline:before{content:"\f47b"}.ion-ios-person:before{content:"\f47e"}.ion-ios-person-outline:before{content:"\f47d"}.ion-ios-personadd:before{content:"\f480"}.ion-ios-personadd-outline:before{content:"\f47f"}.ion-ios-photos:before{content:"\f482"}.ion-ios-photos-outline:before{content:"\f481"}.ion-ios-pie:before{content:"\f484"}.ion-ios-pie-outline:before{content:"\f483"}.ion-ios-pint:before{content:"\f486"}.ion-ios-pint-outline:before{content:"\f485"}.ion-ios-play:before{content:"\f488"}.ion-ios-play-outline:before{content:"\f487"}.ion-ios-plus:before{content:"\f48b"}.ion-ios-plus-empty:before{content:"\f489"}.ion-ios-plus-outline:before{content:"\f48a"}.ion-ios-pricetag:before{content:"\f48d"}.ion-ios-pricetag-outline:before{content:"\f48c"}.ion-ios-pricetags:before{content:"\f48f"}.ion-ios-pricetags-outline:before{content:"\f48e"}.ion-ios-printer:before{content:"\f491"}.ion-ios-printer-outline:before{content:"\f490"}.ion-ios-pulse:before{content:"\f493"}.ion-ios-pulse-strong:before{content:"\f492"}.ion-ios-rainy:before{content:"\f495"}.ion-ios-rainy-outline:before{content:"\f494"}.ion-ios-recording:before{content:"\f497"}.ion-ios-recording-outline:before{content:"\f496"}.ion-ios-redo:before{content:"\f499"}.ion-ios-redo-outline:before{content:"\f498"}.ion-ios-refresh:before{content:"\f49c"}.ion-ios-refresh-empty:before{content:"\f49a"}.ion-ios-refresh-outline:before{content:"\f49b"}.ion-ios-reload:before{content:"\f49d"}.ion-ios-reverse-camera:before{content:"\f49f"}.ion-ios-reverse-camera-outline:before{content:"\f49e"}.ion-ios-rewind:before{content:"\f4a1"}.ion-ios-rewind-outline:before{content:"\f4a0"}.ion-ios-rose:before{content:"\f4a3"}.ion-ios-rose-outline:before{content:"\f4a2"}.ion-ios-search:before{content:"\f4a5"}.ion-ios-search-strong:before{content:"\f4a4"}.ion-ios-settings:before{content:"\f4a7"}.ion-ios-settings-strong:before{content:"\f4a6"}.ion-ios-shuffle:before{content:"\f4a9"}.ion-ios-shuffle-strong:before{content:"\f4a8"}.ion-ios-skipbackward:before{content:"\f4ab"}.ion-ios-skipbackward-outline:before{content:"\f4aa"}.ion-ios-skipforward:before{content:"\f4ad"}.ion-ios-skipforward-outline:before{content:"\f4ac"}.ion-ios-snowy:before{content:"\f4ae"}.ion-ios-speedometer:before{content:"\f4b0"}.ion-ios-speedometer-outline:before{content:"\f4af"}.ion-ios-star:before{content:"\f4b3"}.ion-ios-star-half:before{content:"\f4b1"}.ion-ios-star-outline:before{content:"\f4b2"}.ion-ios-stopwatch:before{content:"\f4b5"}.ion-ios-stopwatch-outline:before{content:"\f4b4"}.ion-ios-sunny:before{content:"\f4b7"}.ion-ios-sunny-outline:before{content:"\f4b6"}.ion-ios-telephone:before{content:"\f4b9"}.ion-ios-telephone-outline:before{content:"\f4b8"}.ion-ios-tennisball:before{content:"\f4bb"}.ion-ios-tennisball-outline:before{content:"\f4ba"}.ion-ios-thunderstorm:before{content:"\f4bd"}.ion-ios-thunderstorm-outline:before{content:"\f4bc"}.ion-ios-time:before{content:"\f4bf"}.ion-ios-time-outline:before{content:"\f4be"}.ion-ios-timer:before{content:"\f4c1"}.ion-ios-timer-outline:before{content:"\f4c0"}.ion-ios-toggle:before{content:"\f4c3"}.ion-ios-toggle-outline:before{content:"\f4c2"}.ion-ios-trash:before{content:"\f4c5"}.ion-ios-trash-outline:before{content:"\f4c4"}.ion-ios-undo:before{content:"\f4c7"}.ion-ios-undo-outline:before{content:"\f4c6"}.ion-ios-unlocked:before{content:"\f4c9"}.ion-ios-unlocked-outline:before{content:"\f4c8"}.ion-ios-upload:before{content:"\f4cb"}.ion-ios-upload-outline:before{content:"\f4ca"}.ion-ios-videocam:before{content:"\f4cd"}.ion-ios-videocam-outline:before{content:"\f4cc"}.ion-ios-volume-high:before{content:"\f4ce"}.ion-ios-volume-low:before{content:"\f4cf"}.ion-ios-wineglass:before{content:"\f4d1"}.ion-ios-wineglass-outline:before{content:"\f4d0"}.ion-ios-world:before{content:"\f4d3"}.ion-ios-world-outline:before{content:"\f4d2"}.ion-ipad:before{content:"\f1f9"}.ion-iphone:before{content:"\f1fa"}.ion-ipod:before{content:"\f1fb"}.ion-jet:before{content:"\f295"}.ion-key:before{content:"\f296"}.ion-knife:before{content:"\f297"}.ion-laptop:before{content:"\f1fc"}.ion-leaf:before{content:"\f1fd"}.ion-levels:before{content:"\f298"}.ion-lightbulb:before{content:"\f299"}.ion-link:before{content:"\f1fe"}.ion-load-a:before{content:"\f29a"}.ion-load-b:before{content:"\f29b"}.ion-load-c:before{content:"\f29c"}.ion-load-d:before{content:"\f29d"}.ion-location:before{content:"\f1ff"}.ion-lock-combination:before{content:"\f4d4"}.ion-locked:before{content:"\f200"}.ion-log-in:before{content:"\f29e"}.ion-log-out:before{content:"\f29f"}.ion-loop:before{content:"\f201"}.ion-magnet:before{content:"\f2a0"}.ion-male:before{content:"\f2a1"}.ion-man:before{content:"\f202"}.ion-map:before{content:"\f203"}.ion-medkit:before{content:"\f2a2"}.ion-merge:before{content:"\f33f"}.ion-mic-a:before{content:"\f204"}.ion-mic-b:before{content:"\f205"}.ion-mic-c:before{content:"\f206"}.ion-minus:before{content:"\f209"}.ion-minus-circled:before{content:"\f207"}.ion-minus-round:before{content:"\f208"}.ion-model-s:before{content:"\f2c1"}.ion-monitor:before{content:"\f20a"}.ion-more:before{content:"\f20b"}.ion-mouse:before{content:"\f340"}.ion-music-note:before{content:"\f20c"}.ion-navicon:before{content:"\f20e"}.ion-navicon-round:before{content:"\f20d"}.ion-navigate:before{content:"\f2a3"}.ion-network:before{content:"\f341"}.ion-no-smoking:before{content:"\f2c2"}.ion-nuclear:before{content:"\f2a4"}.ion-outlet:before{content:"\f342"}.ion-paintbrush:before{content:"\f4d5"}.ion-paintbucket:before{content:"\f4d6"}.ion-paper-airplane:before{content:"\f2c3"}.ion-paperclip:before{content:"\f20f"}.ion-pause:before{content:"\f210"}.ion-person:before{content:"\f213"}.ion-person-add:before{content:"\f211"}.ion-person-stalker:before{content:"\f212"}.ion-pie-graph:before{content:"\f2a5"}.ion-pin:before{content:"\f2a6"}.ion-pinpoint:before{content:"\f2a7"}.ion-pizza:before{content:"\f2a8"}.ion-plane:before{content:"\f214"}.ion-planet:before{content:"\f343"}.ion-play:before{content:"\f215"}.ion-playstation:before{content:"\f30a"}.ion-plus:before{content:"\f218"}.ion-plus-circled:before{content:"\f216"}.ion-plus-round:before{content:"\f217"}.ion-podium:before{content:"\f344"}.ion-pound:before{content:"\f219"}.ion-power:before{content:"\f2a9"}.ion-pricetag:before{content:"\f2aa"}.ion-pricetags:before{content:"\f2ab"}.ion-printer:before{content:"\f21a"}.ion-pull-request:before{content:"\f345"}.ion-qr-scanner:before{content:"\f346"}.ion-quote:before{content:"\f347"}.ion-radio-waves:before{content:"\f2ac"}.ion-record:before{content:"\f21b"}.ion-refresh:before{content:"\f21c"}.ion-reply:before{content:"\f21e"}.ion-reply-all:before{content:"\f21d"}.ion-ribbon-a:before{content:"\f348"}.ion-ribbon-b:before{content:"\f349"}.ion-sad:before{content:"\f34a"}.ion-sad-outline:before{content:"\f4d7"}.ion-scissors:before{content:"\f34b"}.ion-search:before{content:"\f21f"}.ion-settings:before{content:"\f2ad"}.ion-share:before{content:"\f220"}.ion-shuffle:before{content:"\f221"}.ion-skip-backward:before{content:"\f222"}.ion-skip-forward:before{content:"\f223"}.ion-social-android:before{content:"\f225"}.ion-social-android-outline:before{content:"\f224"}.ion-social-angular:before{content:"\f4d9"}.ion-social-angular-outline:before{content:"\f4d8"}.ion-social-apple:before{content:"\f227"}.ion-social-apple-outline:before{content:"\f226"}.ion-social-bitcoin:before{content:"\f2af"}.ion-social-bitcoin-outline:before{content:"\f2ae"}.ion-social-buffer:before{content:"\f229"}.ion-social-buffer-outline:before{content:"\f228"}.ion-social-chrome:before{content:"\f4db"}.ion-social-chrome-outline:before{content:"\f4da"}.ion-social-codepen:before{content:"\f4dd"}.ion-social-codepen-outline:before{content:"\f4dc"}.ion-social-css3:before{content:"\f4df"}.ion-social-css3-outline:before{content:"\f4de"}.ion-social-designernews:before{content:"\f22b"}.ion-social-designernews-outline:before{content:"\f22a"}.ion-social-dribbble:before{content:"\f22d"}.ion-social-dribbble-outline:before{content:"\f22c"}.ion-social-dropbox:before{content:"\f22f"}.ion-social-dropbox-outline:before{content:"\f22e"}.ion-social-euro:before{content:"\f4e1"}.ion-social-euro-outline:before{content:"\f4e0"}.ion-social-facebook:before{content:"\f231"}.ion-social-facebook-outline:before{content:"\f230"}.ion-social-foursquare:before{content:"\f34d"}.ion-social-foursquare-outline:before{content:"\f34c"}.ion-social-freebsd-devil:before{content:"\f2c4"}.ion-social-github:before{content:"\f233"}.ion-social-github-outline:before{content:"\f232"}.ion-social-google:before{content:"\f34f"}.ion-social-google-outline:before{content:"\f34e"}.ion-social-googleplus:before{content:"\f235"}.ion-social-googleplus-outline:before{content:"\f234"}.ion-social-hackernews:before{content:"\f237"}.ion-social-hackernews-outline:before{content:"\f236"}.ion-social-html5:before{content:"\f4e3"}.ion-social-html5-outline:before{content:"\f4e2"}.ion-social-instagram:before{content:"\f351"}.ion-social-instagram-outline:before{content:"\f350"}.ion-social-javascript:before{content:"\f4e5"}.ion-social-javascript-outline:before{content:"\f4e4"}.ion-social-linkedin:before{content:"\f239"}.ion-social-linkedin-outline:before{content:"\f238"}.ion-social-markdown:before{content:"\f4e6"}.ion-social-nodejs:before{content:"\f4e7"}.ion-social-octocat:before{content:"\f4e8"}.ion-social-pinterest:before{content:"\f2b1"}.ion-social-pinterest-outline:before{content:"\f2b0"}.ion-social-python:before{content:"\f4e9"}.ion-social-reddit:before{content:"\f23b"}.ion-social-reddit-outline:before{content:"\f23a"}.ion-social-rss:before{content:"\f23d"}.ion-social-rss-outline:before{content:"\f23c"}.ion-social-sass:before{content:"\f4ea"}.ion-social-skype:before{content:"\f23f"}.ion-social-skype-outline:before{content:"\f23e"}.ion-social-snapchat:before{content:"\f4ec"}.ion-social-snapchat-outline:before{content:"\f4eb"}.ion-social-tumblr:before{content:"\f241"}.ion-social-tumblr-outline:before{content:"\f240"}.ion-social-tux:before{content:"\f2c5"}.ion-social-twitch:before{content:"\f4ee"}.ion-social-twitch-outline:before{content:"\f4ed"}.ion-social-twitter:before{content:"\f243"}.ion-social-twitter-outline:before{content:"\f242"}.ion-social-usd:before{content:"\f353"}.ion-social-usd-outline:before{content:"\f352"}.ion-social-vimeo:before{content:"\f245"}.ion-social-vimeo-outline:before{content:"\f244"}.ion-social-whatsapp:before{content:"\f4f0"}.ion-social-whatsapp-outline:before{content:"\f4ef"}.ion-social-windows:before{content:"\f247"}.ion-social-windows-outline:before{content:"\f246"}.ion-social-wordpress:before{content:"\f249"}.ion-social-wordpress-outline:before{content:"\f248"}.ion-social-yahoo:before{content:"\f24b"}.ion-social-yahoo-outline:before{content:"\f24a"}.ion-social-yen:before{content:"\f4f2"}.ion-social-yen-outline:before{content:"\f4f1"}.ion-social-youtube:before{content:"\f24d"}.ion-social-youtube-outline:before{content:"\f24c"}.ion-soup-can:before{content:"\f4f4"}.ion-soup-can-outline:before{content:"\f4f3"}.ion-speakerphone:before{content:"\f2b2"}.ion-speedometer:before{content:"\f2b3"}.ion-spoon:before{content:"\f2b4"}.ion-star:before{content:"\f24e"}.ion-stats-bars:before{content:"\f2b5"}.ion-steam:before{content:"\f30b"}.ion-stop:before{content:"\f24f"}.ion-thermometer:before{content:"\f2b6"}.ion-thumbsdown:before{content:"\f250"}.ion-thumbsup:before{content:"\f251"}.ion-toggle:before{content:"\f355"}.ion-toggle-filled:before{content:"\f354"}.ion-transgender:before{content:"\f4f5"}.ion-trash-a:before{content:"\f252"}.ion-trash-b:before{content:"\f253"}.ion-trophy:before{content:"\f356"}.ion-tshirt:before{content:"\f4f7"}.ion-tshirt-outline:before{content:"\f4f6"}.ion-umbrella:before{content:"\f2b7"}.ion-university:before{content:"\f357"}.ion-unlocked:before{content:"\f254"}.ion-upload:before{content:"\f255"}.ion-usb:before{content:"\f2b8"}.ion-videocamera:before{content:"\f256"}.ion-volume-high:before{content:"\f257"}.ion-volume-low:before{content:"\f258"}.ion-volume-medium:before{content:"\f259"}.ion-volume-mute:before{content:"\f25a"}.ion-wand:before{content:"\f358"}.ion-waterdrop:before{content:"\f25b"}.ion-wifi:before{content:"\f25c"}.ion-wineglass:before{content:"\f2b9"}.ion-woman:before{content:"\f25d"}.ion-wrench:before{content:"\f2ba"}.ion-xbox:before{content:"\f30c"}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/button.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/button.min.css
new file mode 100755
index 0000000..68b7f1b
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/button.min.css
@@ -0,0 +1 @@
+button{-webkit-transition:color .2s ease;-moz-transition:color .2s ease;-ms-transition:color .2s ease;-o-transition:color .2s ease;transition:color .2s ease;font-size:14px;border:none;background-color:rgba(0,0,0,0);color:#444;position:relative;display:inline-block;margin:0;padding:0 12px;min-height:42px;vertical-align:top;text-align:center;text-overflow:ellipsis;font-size:16px;line-height:42px;cursor:pointer;overflow:hidden}button[disabled]{opacity:.8}button .icon{position:absolute;left:10px}button.circle{width:42px;height:42px;text-align:center;padding:0;line-height:0;font-size:22px;z-index:10}button.icon-text{padding-left:40px}button.icon-text i{font-size:22px}button.icon-text.icon-right{padding-left:12px;padding-right:40px;position:relative}button.icon-right i{position:absolute;right:12px;text-align:right;margin-top:2px}button[class*=border-]{min-height:40px;line-height:40px}button.full{width:100%}.buttons-group.big button,button.big{font-size:22px;min-height:50px;line-height:50px}button.circle.big{width:50px;height:50px;font-size:28px}button.big.icon-text{padding-left:40px}button.big.icon-text.icon-right{padding-left:12px;padding-right:40px}button.big.icon-text i{font-size:26px}.buttons-group.small button,button.small{font-size:12px;min-height:30px;line-height:30px}button.circle.small{width:30px;height:30px;font-size:18px}button.small.icon-text{padding-left:30px}button.small.icon-text.icon-right{padding-left:12px;padding-right:35px}button.small.icon-text i{font-size:18px}.buttons-group.huge button,button.huge{font-size:32px;min-height:70px;line-height:70px}button.circle.huge{width:70px;height:70px;font-size:32px}button.huge.icon-text{padding-left:40px}button.huge.icon-text.icon-right{padding-left:12px;padding-right:40px}button.huge.icon-text i{font-size:32px}.buttons-group{display:inline-block}.buttons-group button{float:left;margin-left:-1px}.buttons-group button:first-child{margin-left:0}.buttons-group.full{display:flex}.buttons-group.full button{flex:1}.ripple{position:absolute;background:rgba(255,255,255,.25);border-radius:100%;-webkit-transform:scale(0);-moz-transform:scale(0);-ms-transform:scale(0);-o-transform:scale(0);transform:scale(0);pointer-events:none}.ripple.show{-webkit-animation:ripple .5s ease-out;-moz-animation:ripple .5s ease-out;-o-animation:ripple .5s ease-out;animation:ripple .5s ease-out}@-webkit-keyframes ripple{to{-webkit-transform:scale(1.5);opacity:0}}@-moz-keyframes ripple{to{-moz-transform:scale(1.5);opacity:0}}@-o-keyframes ripple{to{-o-transform:scale(1.5);opacity:0}}@keyframes ripple{to{transform:scale(1.5);opacity:0}}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/chart-bar.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/chart-bar.min.css
new file mode 100755
index 0000000..69d4056
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/chart-bar.min.css
@@ -0,0 +1 @@
+.chart-bar{display:table;table-layout:fixed;width:100%;height:250px;background-image:linear-gradient(to top,rgba(0,0,0,.1) 2%,rgba(0,0,0,0) 2%);background-size:100% 50px;background-position:left top}.chart-bar.line-white{background-image:linear-gradient(to top,rgba(255,255,255,.1) 2%,rgba(255,255,255,0) 2%)}.chart-bar.no-line{background-image:none}.chart-bar li{position:relative;display:table-cell;vertical-align:bottom;height:250px}.chart-bar li span{margin:0 5px;display:block}.chart-bar li div{width:100%;text-align:center;padding:5px}.chart-bar li span::before{position:relative;top:0;width:100%;padding-top:5px;padding-bottom:5px;display:block;text-align:center;content:attr(title);word-wrap:break-word;overflow:hidden;opacity:.7}.chart-bar.size-1{width:80px}.chart-bar.size-1,.chart-bar.size-1 li{height:40px}.chart-bar.size-1 li span{margin:0 2px}.chart-bar.size-2{width:150px}.chart-bar.size-2,.chart-bar.size-2 li{height:60px}.chart-bar.size-2 li span{margin:0 4px}.chart-bar.size-3{width:250px}.chart-bar.size-3,.chart-bar.size-3 li{height:80px}.chart-bar.size-3 li span{margin:0 5px}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/chartist-plugin-tooltip.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/chartist-plugin-tooltip.min.css
new file mode 100755
index 0000000..3d4a9ac
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/chartist-plugin-tooltip.min.css
@@ -0,0 +1 @@
+.chartist-tooltip{position:absolute;display:inline-block;opacity:0;min-width:5em;padding:.5em;background:#f4c63d;color:#453d3f;font-family:Oxygen,Helvetica,Arial,sans-serif;font-weight:700;text-align:center;pointer-events:none;z-index:1;-webkit-transition:opacity .2s linear;-moz-transition:opacity .2s linear;-o-transition:opacity .2s linear;transition:opacity .2s linear}.chartist-tooltip:before{content:"";position:absolute;top:100%;left:50%;width:0;height:0;margin-left:-15px;border:15px solid transparent;border-top-color:#f4c63d}.chartist-tooltip.tooltip-show{opacity:1}.ct-area,.ct-line{pointer-events:none}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/chartist.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/chartist.min.css
new file mode 100755
index 0000000..9170721
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/chartist.min.css
@@ -0,0 +1 @@
+.ct-double-octave:after,.ct-major-eleventh:after,.ct-major-second:after,.ct-major-seventh:after,.ct-major-sixth:after,.ct-major-tenth:after,.ct-major-third:after,.ct-major-twelfth:after,.ct-minor-second:after,.ct-minor-seventh:after,.ct-minor-sixth:after,.ct-minor-third:after,.ct-octave:after,.ct-perfect-fifth:after,.ct-perfect-fourth:after,.ct-square:after{content:"";clear:both}.ct-label{fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;line-height:1}.ct-grid-background,.ct-line{fill:none}.ct-chart-bar .ct-label,.ct-chart-line .ct-label{display:block;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}.ct-chart-donut .ct-label,.ct-chart-pie .ct-label{dominant-baseline:central}.ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-vertical.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-label.ct-vertical.ct-end{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-start{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-end{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:end}.ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-point{stroke-width:10px;stroke-linecap:round}.ct-line{stroke-width:4px}.ct-area{stroke:none;fill-opacity:.1}.ct-bar{fill:none;stroke-width:10px}.ct-slice-donut{fill:none;stroke-width:60px}.ct-series-a .ct-bar,.ct-series-a .ct-line,.ct-series-a .ct-point,.ct-series-a .ct-slice-donut{stroke:#d70206}.ct-series-a .ct-area,.ct-series-a .ct-slice-donut-solid,.ct-series-a .ct-slice-pie{fill:#d70206}.ct-series-b .ct-bar,.ct-series-b .ct-line,.ct-series-b .ct-point,.ct-series-b .ct-slice-donut{stroke:#f05b4f}.ct-series-b .ct-area,.ct-series-b .ct-slice-donut-solid,.ct-series-b .ct-slice-pie{fill:#f05b4f}.ct-series-c .ct-bar,.ct-series-c .ct-line,.ct-series-c .ct-point,.ct-series-c .ct-slice-donut{stroke:#f4c63d}.ct-series-c .ct-area,.ct-series-c .ct-slice-donut-solid,.ct-series-c .ct-slice-pie{fill:#f4c63d}.ct-series-d .ct-bar,.ct-series-d .ct-line,.ct-series-d .ct-point,.ct-series-d .ct-slice-donut{stroke:#d17905}.ct-series-d .ct-area,.ct-series-d .ct-slice-donut-solid,.ct-series-d .ct-slice-pie{fill:#d17905}.ct-series-e .ct-bar,.ct-series-e .ct-line,.ct-series-e .ct-point,.ct-series-e .ct-slice-donut{stroke:#453d3f}.ct-series-e .ct-area,.ct-series-e .ct-slice-donut-solid,.ct-series-e .ct-slice-pie{fill:#453d3f}.ct-series-f .ct-bar,.ct-series-f .ct-line,.ct-series-f .ct-point,.ct-series-f .ct-slice-donut{stroke:#59922b}.ct-series-f .ct-area,.ct-series-f .ct-slice-donut-solid,.ct-series-f .ct-slice-pie{fill:#59922b}.ct-series-g .ct-bar,.ct-series-g .ct-line,.ct-series-g .ct-point,.ct-series-g .ct-slice-donut{stroke:#0544d3}.ct-series-g .ct-area,.ct-series-g .ct-slice-donut-solid,.ct-series-g .ct-slice-pie{fill:#0544d3}.ct-series-h .ct-bar,.ct-series-h .ct-line,.ct-series-h .ct-point,.ct-series-h .ct-slice-donut{stroke:#6b0392}.ct-series-h .ct-area,.ct-series-h .ct-slice-donut-solid,.ct-series-h .ct-slice-pie{fill:#6b0392}.ct-series-i .ct-bar,.ct-series-i .ct-line,.ct-series-i .ct-point,.ct-series-i .ct-slice-donut{stroke:#f05b4f}.ct-series-i .ct-area,.ct-series-i .ct-slice-donut-solid,.ct-series-i .ct-slice-pie{fill:#f05b4f}.ct-series-j .ct-bar,.ct-series-j .ct-line,.ct-series-j .ct-point,.ct-series-j .ct-slice-donut{stroke:#dda458}.ct-series-j .ct-area,.ct-series-j .ct-slice-donut-solid,.ct-series-j .ct-slice-pie{fill:#dda458}.ct-series-k .ct-bar,.ct-series-k .ct-line,.ct-series-k .ct-point,.ct-series-k .ct-slice-donut{stroke:#eacf7d}.ct-series-k .ct-area,.ct-series-k .ct-slice-donut-solid,.ct-series-k .ct-slice-pie{fill:#eacf7d}.ct-series-l .ct-bar,.ct-series-l .ct-line,.ct-series-l .ct-point,.ct-series-l .ct-slice-donut{stroke:#86797d}.ct-series-l .ct-area,.ct-series-l .ct-slice-donut-solid,.ct-series-l .ct-slice-pie{fill:#86797d}.ct-series-m .ct-bar,.ct-series-m .ct-line,.ct-series-m .ct-point,.ct-series-m .ct-slice-donut{stroke:#b2c326}.ct-series-m .ct-area,.ct-series-m .ct-slice-donut-solid,.ct-series-m .ct-slice-pie{fill:#b2c326}.ct-series-n .ct-bar,.ct-series-n .ct-line,.ct-series-n .ct-point,.ct-series-n .ct-slice-donut{stroke:#6188e2}.ct-series-n .ct-area,.ct-series-n .ct-slice-donut-solid,.ct-series-n .ct-slice-pie{fill:#6188e2}.ct-series-o .ct-bar,.ct-series-o .ct-line,.ct-series-o .ct-point,.ct-series-o .ct-slice-donut{stroke:#a748ca}.ct-series-o .ct-area,.ct-series-o .ct-slice-donut-solid,.ct-series-o .ct-slice-pie{fill:#a748ca}.ct-square{display:block;position:relative;width:100%}.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-square:after{display:table}.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-minor-second{display:block;position:relative;width:100%}.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-minor-second:after{display:table}.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-major-second{display:block;position:relative;width:100%}.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-major-second:after{display:table}.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-minor-third{display:block;position:relative;width:100%}.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-minor-third:after{display:table}.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-major-third{display:block;position:relative;width:100%}.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-major-third:after{display:table}.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-perfect-fourth:after{display:table}.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-perfect-fifth:after{display:table}.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-sixth{display:block;position:relative;width:100%}.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-minor-sixth:after{display:table}.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-golden-section{display:block;position:relative;width:100%}.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-golden-section:after{content:"";display:table;clear:both}.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-major-sixth{display:block;position:relative;width:100%}.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-major-sixth:after{display:table}.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-seventh{display:block;position:relative;width:100%}.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-minor-seventh:after{display:table}.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-seventh{display:block;position:relative;width:100%}.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-major-seventh:after{display:table}.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-octave{display:block;position:relative;width:100%}.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-octave:after{display:table}.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-major-tenth{display:block;position:relative;width:100%}.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-major-tenth:after{display:table}.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-major-eleventh{display:block;position:relative;width:100%}.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-major-eleventh:after{display:table}.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-twelfth{display:block;position:relative;width:100%}.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-major-twelfth:after{display:table}.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-double-octave{display:block;position:relative;width:100%}.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-double-octave:after{display:table}.ct-double-octave>svg{display:block;position:absolute;top:0;left:0}.chartist-big .ct-series-a .ct-bar,.chartist-big .ct-series-a .ct-line,.chartist-big .ct-series-a .ct-point,.chartist-big .ct-series-a .ct-slice-donut,.chartist-big .ct-series-b .ct-bar,.chartist-big .ct-series-b .ct-line,.chartist-big .ct-series-b .ct-point,.chartist-big .ct-series-b .ct-slice-donut,.chartist-big .ct-series-c .ct-bar,.chartist-big .ct-series-c .ct-line,.chartist-big .ct-series-c .ct-point,.chartist-big .ct-series-c .ct-slice-donut,.chartist-big .ct-series-d .ct-bar,.chartist-big .ct-series-d .ct-line,.chartist-big .ct-series-d .ct-point,.chartist-big .ct-series-d .ct-slice-donut{stroke-width:20px}.chartist-huge .ct-series-a .ct-bar,.chartist-huge .ct-series-a .ct-line,.chartist-huge .ct-series-a .ct-point,.chartist-huge .ct-series-a .ct-slice-donut,.chartist-huge .ct-series-b .ct-bar,.chartist-huge .ct-series-b .ct-line,.chartist-huge .ct-series-b .ct-point,.chartist-huge .ct-series-b .ct-slice-donut,.chartist-huge .ct-series-c .ct-bar,.chartist-huge .ct-series-c .ct-line,.chartist-huge .ct-series-c .ct-point,.chartist-huge .ct-series-c .ct-slice-donut,.chartist-huge .ct-series-d .ct-bar,.chartist-huge .ct-series-d .ct-line,.chartist-huge .ct-series-d .ct-point,.chartist-huge .ct-series-d .ct-slice-donut{stroke-width:30px}.chartist-white.text-black .ct-label{fill:#000;color:#000}.chartist-white.text-white .ct-label{fill:#fff;color:#fff}.chartist-white .ct-label{fill:rgba(255,255,255,.4);color:rgba(255,255,255,.4)}.chartist-white .ct-grid{stroke:rgba(255,255,255,.2)}.chartist-white .ct-series-a .ct-bar,.chartist-white .ct-series-a .ct-line,.chartist-white .ct-series-a .ct-point,.chartist-white .ct-series-a .ct-slice-donut{stroke:rgba(255,255,255,1)}.chartist-white .ct-series-b .ct-bar,.chartist-white .ct-series-b .ct-line,.chartist-white .ct-series-b .ct-point,.chartist-white .ct-series-b .ct-slice-donut{stroke:rgba(255,255,255,.7)}.chartist-white .ct-series-c .ct-bar,.chartist-white .ct-series-c .ct-line,.chartist-white .ct-series-c .ct-point,.chartist-white .ct-series-c .ct-slice-donut{stroke:rgba(255,255,255,.4)}.chartist-white .ct-series-d .ct-bar,.chartist-white .ct-series-d .ct-line,.chartist-white .ct-series-d .ct-point,.chartist-white .ct-series-d .ct-slice-donut{stroke:rgba(255,255,255,.2)}.chartist-white .ct-series-a .ct-area,.chartist-white .ct-series-a .ct-slice-donut-solid,.chartist-white .ct-series-a .ct-slice-pie{fill:rgba(255,255,255,1)}.chartist-white .ct-series-b .ct-area,.chartist-white .ct-series-b .ct-slice-donut-solid,.chartist-white .ct-series-b .ct-slice-pie{fill:rgba(255,255,255,.7)}.chartist-white .ct-series-c .ct-area,.chartist-white .ct-series-c .ct-slice-donut-solid,.chartist-white .ct-series-c .ct-slice-pie{fill:rgba(255,255,255,.4)}.chartist-white .ct-series-d .ct-area,.chartist-white .ct-series-d .ct-slice-donut-solid,.chartist-white .ct-series-d .ct-slice-pie{fill:rgba(255,255,255,.2)}.chartist-red.text-black .ct-label{fill:#000;color:#000}.chartist-red.text-white .ct-label{fill:#fff;color:#fff}.chartist-red .ct-label{fill:rgba(244,67,54,.4);color:rgba(244,67,54,.4)}.chartist-red .ct-grid{stroke:rgba(244,67,54,.2)}.chartist-red .ct-series-a .ct-bar,.chartist-red .ct-series-a .ct-line,.chartist-red .ct-series-a .ct-point,.chartist-red .ct-series-a .ct-slice-donut{stroke:rgba(244,67,54,1)}.chartist-red .ct-series-b .ct-bar,.chartist-red .ct-series-b .ct-line,.chartist-red .ct-series-b .ct-point,.chartist-red .ct-series-b .ct-slice-donut{stroke:rgba(244,67,54,.7)}.chartist-red .ct-series-c .ct-bar,.chartist-red .ct-series-c .ct-line,.chartist-red .ct-series-c .ct-point,.chartist-red .ct-series-c .ct-slice-donut{stroke:rgba(244,67,54,.4)}.chartist-red .ct-series-d .ct-bar,.chartist-red .ct-series-d .ct-line,.chartist-red .ct-series-d .ct-point,.chartist-red .ct-series-d .ct-slice-donut{stroke:rgba(244,67,54,.2)}.chartist-red .ct-series-a .ct-area,.chartist-red .ct-series-a .ct-slice-donut-solid,.chartist-red .ct-series-a .ct-slice-pie{fill:rgba(244,67,54,1)}.chartist-red .ct-series-b .ct-area,.chartist-red .ct-series-b .ct-slice-donut-solid,.chartist-red .ct-series-b .ct-slice-pie{fill:rgba(244,67,54,.7)}.chartist-red .ct-series-c .ct-area,.chartist-red .ct-series-c .ct-slice-donut-solid,.chartist-red .ct-series-c .ct-slice-pie{fill:rgba(244,67,54,.4)}.chartist-red .ct-series-d .ct-area,.chartist-red .ct-series-d .ct-slice-donut-solid,.chartist-red .ct-series-d .ct-slice-pie{fill:rgba(244,67,54,.2)}.chartist-pink.text-black .ct-label{fill:#000;color:#000}.chartist-pink.text-white .ct-label{fill:#fff;color:#fff}.chartist-pink .ct-label{fill:rgba(233,30,99,.4);color:rgba(233,30,99,.4)}.chartist-pink .ct-grid{stroke:rgba(233,30,99,.2)}.chartist-pink .ct-series-a .ct-bar,.chartist-pink .ct-series-a .ct-line,.chartist-pink .ct-series-a .ct-point,.chartist-pink .ct-series-a .ct-slice-donut{stroke:rgba(233,30,99,1)}.chartist-pink .ct-series-b .ct-bar,.chartist-pink .ct-series-b .ct-line,.chartist-pink .ct-series-b .ct-point,.chartist-pink .ct-series-b .ct-slice-donut{stroke:rgba(233,30,99,.7)}.chartist-pink .ct-series-c .ct-bar,.chartist-pink .ct-series-c .ct-line,.chartist-pink .ct-series-c .ct-point,.chartist-pink .ct-series-c .ct-slice-donut{stroke:rgba(233,30,99,.4)}.chartist-pink .ct-series-d .ct-bar,.chartist-pink .ct-series-d .ct-line,.chartist-pink .ct-series-d .ct-point,.chartist-pink .ct-series-d .ct-slice-donut{stroke:rgba(233,30,99,.2)}.chartist-pink .ct-series-a .ct-area,.chartist-pink .ct-series-a .ct-slice-donut-solid,.chartist-pink .ct-series-a .ct-slice-pie{fill:rgba(233,30,99,1)}.chartist-pink .ct-series-b .ct-area,.chartist-pink .ct-series-b .ct-slice-donut-solid,.chartist-pink .ct-series-b .ct-slice-pie{fill:rgba(233,30,99,.7)}.chartist-pink .ct-series-c .ct-area,.chartist-pink .ct-series-c .ct-slice-donut-solid,.chartist-pink .ct-series-c .ct-slice-pie{fill:rgba(233,30,99,.4)}.chartist-pink .ct-series-d .ct-area,.chartist-pink .ct-series-d .ct-slice-donut-solid,.chartist-pink .ct-series-d .ct-slice-pie{fill:rgba(233,30,99,.2)}.chartist-purple.text-black .ct-label{fill:#000;color:#000}.chartist-purple.text-white .ct-label{fill:#fff;color:#fff}.chartist-purple .ct-label{fill:rgba(156,39,176,.4);color:rgba(156,39,176,.4)}.chartist-purple .ct-grid{stroke:rgba(156,39,176,.2)}.chartist-purple .ct-series-a .ct-bar,.chartist-purple .ct-series-a .ct-line,.chartist-purple .ct-series-a .ct-point,.chartist-purple .ct-series-a .ct-slice-donut{stroke:rgba(156,39,176,1)}.chartist-purple .ct-series-b .ct-bar,.chartist-purple .ct-series-b .ct-line,.chartist-purple .ct-series-b .ct-point,.chartist-purple .ct-series-b .ct-slice-donut{stroke:rgba(156,39,176,.7)}.chartist-purple .ct-series-c .ct-bar,.chartist-purple .ct-series-c .ct-line,.chartist-purple .ct-series-c .ct-point,.chartist-purple .ct-series-c .ct-slice-donut{stroke:rgba(156,39,176,.4)}.chartist-purple .ct-series-d .ct-bar,.chartist-purple .ct-series-d .ct-line,.chartist-purple .ct-series-d .ct-point,.chartist-purple .ct-series-d .ct-slice-donut{stroke:rgba(156,39,176,.2)}.chartist-purple .ct-series-a .ct-area,.chartist-purple .ct-series-a .ct-slice-donut-solid,.chartist-purple .ct-series-a .ct-slice-pie{fill:rgba(156,39,176,1)}.chartist-purple .ct-series-b .ct-area,.chartist-purple .ct-series-b .ct-slice-donut-solid,.chartist-purple .ct-series-b .ct-slice-pie{fill:rgba(156,39,176,.7)}.chartist-purple .ct-series-c .ct-area,.chartist-purple .ct-series-c .ct-slice-donut-solid,.chartist-purple .ct-series-c .ct-slice-pie{fill:rgba(156,39,176,.4)}.chartist-purple .ct-series-d .ct-area,.chartist-purple .ct-series-d .ct-slice-donut-solid,.chartist-purple .ct-series-d .ct-slice-pie{fill:rgba(156,39,176,.2)}.chartist-deep.text-white-purple .ct-label{fill:#fff;color:#fff}.chartist-deep-purple .ct-label{fill:rgba(103,58,183,.4);color:rgba(103,58,183,.4)}.chartist-deep-purple .ct-grid{stroke:rgba(103,58,183,.2)}.chartist-deep-purple .ct-series-a .ct-bar,.chartist-deep-purple .ct-series-a .ct-line,.chartist-deep-purple .ct-series-a .ct-point,.chartist-deep-purple .ct-series-a .ct-slice-donut{stroke:rgba(103,58,183,1)}.chartist-deep-purple .ct-series-b .ct-bar,.chartist-deep-purple .ct-series-b .ct-line,.chartist-deep-purple .ct-series-b .ct-point,.chartist-deep-purple .ct-series-b .ct-slice-donut{stroke:rgba(103,58,183,.7)}.chartist-deep-purple .ct-series-c .ct-bar,.chartist-deep-purple .ct-series-c .ct-line,.chartist-deep-purple .ct-series-c .ct-point,.chartist-deep-purple .ct-series-c .ct-slice-donut{stroke:rgba(103,58,183,.4)}.chartist-deep-purple .ct-series-d .ct-bar,.chartist-deep-purple .ct-series-d .ct-line,.chartist-deep-purple .ct-series-d .ct-point,.chartist-deep-purple .ct-series-d .ct-slice-donut{stroke:rgba(103,58,183,.2)}.chartist-deep-purple .ct-series-a .ct-area,.chartist-deep-purple .ct-series-a .ct-slice-donut-solid,.chartist-deep-purple .ct-series-a .ct-slice-pie{fill:rgba(103,58,183,1)}.chartist-deep-purple .ct-series-b .ct-area,.chartist-deep-purple .ct-series-b .ct-slice-donut-solid,.chartist-deep-purple .ct-series-b .ct-slice-pie{fill:rgba(103,58,183,.7)}.chartist-deep-purple .ct-series-c .ct-area,.chartist-deep-purple .ct-series-c .ct-slice-donut-solid,.chartist-deep-purple .ct-series-c .ct-slice-pie{fill:rgba(103,58,183,.4)}.chartist-deep-purple .ct-series-d .ct-area,.chartist-deep-purple .ct-series-d .ct-slice-donut-solid,.chartist-deep-purple .ct-series-d .ct-slice-pie{fill:rgba(103,58,183,.2)}.chartist-indigo.text-black .ct-label{fill:#000;color:#000}.chartist-indigo.text-white .ct-label{fill:#fff;color:#fff}.chartist-indigo .ct-label{fill:rgba(63,81,181,.4);color:rgba(63,81,181,.4)}.chartist-indigo .ct-grid{stroke:rgba(63,81,181,.2)}.chartist-indigo .ct-series-a .ct-bar,.chartist-indigo .ct-series-a .ct-line,.chartist-indigo .ct-series-a .ct-point,.chartist-indigo .ct-series-a .ct-slice-donut{stroke:rgba(63,81,181,1)}.chartist-indigo .ct-series-b .ct-bar,.chartist-indigo .ct-series-b .ct-line,.chartist-indigo .ct-series-b .ct-point,.chartist-indigo .ct-series-b .ct-slice-donut{stroke:rgba(63,81,181,.7)}.chartist-indigo .ct-series-c .ct-bar,.chartist-indigo .ct-series-c .ct-line,.chartist-indigo .ct-series-c .ct-point,.chartist-indigo .ct-series-c .ct-slice-donut{stroke:rgba(63,81,181,.4)}.chartist-indigo .ct-series-d .ct-bar,.chartist-indigo .ct-series-d .ct-line,.chartist-indigo .ct-series-d .ct-point,.chartist-indigo .ct-series-d .ct-slice-donut{stroke:rgba(63,81,181,.2)}.chartist-indigo .ct-series-a .ct-area,.chartist-indigo .ct-series-a .ct-slice-donut-solid,.chartist-indigo .ct-series-a .ct-slice-pie{fill:rgba(63,81,181,1)}.chartist-indigo .ct-series-b .ct-area,.chartist-indigo .ct-series-b .ct-slice-donut-solid,.chartist-indigo .ct-series-b .ct-slice-pie{fill:rgba(63,81,181,.7)}.chartist-indigo .ct-series-c .ct-area,.chartist-indigo .ct-series-c .ct-slice-donut-solid,.chartist-indigo .ct-series-c .ct-slice-pie{fill:rgba(63,81,181,.4)}.chartist-indigo .ct-series-d .ct-area,.chartist-indigo .ct-series-d .ct-slice-donut-solid,.chartist-indigo .ct-series-d .ct-slice-pie{fill:rgba(63,81,181,.2)}.chartist-blue.text-black .ct-label{fill:#000;color:#000}.chartist-blue.text-white .ct-label{fill:#fff;color:#fff}.chartist-blue .ct-label{fill:rgba(33,150,243,.4);color:rgba(33,150,243,.4)}.chartist-blue .ct-grid{stroke:rgba(33,150,243,.2)}.chartist-blue .ct-series-a .ct-bar,.chartist-blue .ct-series-a .ct-line,.chartist-blue .ct-series-a .ct-point,.chartist-blue .ct-series-a .ct-slice-donut{stroke:rgba(33,150,243,1)}.chartist-blue .ct-series-b .ct-bar,.chartist-blue .ct-series-b .ct-line,.chartist-blue .ct-series-b .ct-point,.chartist-blue .ct-series-b .ct-slice-donut{stroke:rgba(33,150,243,.7)}.chartist-blue .ct-series-c .ct-bar,.chartist-blue .ct-series-c .ct-line,.chartist-blue .ct-series-c .ct-point,.chartist-blue .ct-series-c .ct-slice-donut{stroke:rgba(33,150,243,.4)}.chartist-blue .ct-series-d .ct-bar,.chartist-blue .ct-series-d .ct-line,.chartist-blue .ct-series-d .ct-point,.chartist-blue .ct-series-d .ct-slice-donut{stroke:rgba(33,150,243,.2)}.chartist-blue .ct-series-a .ct-area,.chartist-blue .ct-series-a .ct-slice-donut-solid,.chartist-blue .ct-series-a .ct-slice-pie{fill:rgba(33,150,243,1)}.chartist-blue .ct-series-b .ct-area,.chartist-blue .ct-series-b .ct-slice-donut-solid,.chartist-blue .ct-series-b .ct-slice-pie{fill:rgba(33,150,243,.7)}.chartist-blue .ct-series-c .ct-area,.chartist-blue .ct-series-c .ct-slice-donut-solid,.chartist-blue .ct-series-c .ct-slice-pie{fill:rgba(33,150,243,.4)}.chartist-blue .ct-series-d .ct-area,.chartist-blue .ct-series-d .ct-slice-donut-solid,.chartist-blue .ct-series-d .ct-slice-pie{fill:rgba(33,150,243,.2)}.chartist-light.text-white-blue .ct-label{fill:#fff;color:#fff}.chartist-light-blue .ct-label{fill:rgba(3,169,244,.4);color:rgba(3,169,244,.4)}.chartist-light-blue .ct-grid{stroke:rgba(3,169,244,.2)}.chartist-light-blue .ct-series-a .ct-bar,.chartist-light-blue .ct-series-a .ct-line,.chartist-light-blue .ct-series-a .ct-point,.chartist-light-blue .ct-series-a .ct-slice-donut{stroke:rgba(3,169,244,1)}.chartist-light-blue .ct-series-b .ct-bar,.chartist-light-blue .ct-series-b .ct-line,.chartist-light-blue .ct-series-b .ct-point,.chartist-light-blue .ct-series-b .ct-slice-donut{stroke:rgba(3,169,244,.7)}.chartist-light-blue .ct-series-c .ct-bar,.chartist-light-blue .ct-series-c .ct-line,.chartist-light-blue .ct-series-c .ct-point,.chartist-light-blue .ct-series-c .ct-slice-donut{stroke:rgba(3,169,244,.4)}.chartist-light-blue .ct-series-d .ct-bar,.chartist-light-blue .ct-series-d .ct-line,.chartist-light-blue .ct-series-d .ct-point,.chartist-light-blue .ct-series-d .ct-slice-donut{stroke:rgba(3,169,244,.2)}.chartist-light-blue .ct-series-a .ct-area,.chartist-light-blue .ct-series-a .ct-slice-donut-solid,.chartist-light-blue .ct-series-a .ct-slice-pie{fill:rgba(3,169,244,1)}.chartist-light-blue .ct-series-b .ct-area,.chartist-light-blue .ct-series-b .ct-slice-donut-solid,.chartist-light-blue .ct-series-b .ct-slice-pie{fill:rgba(3,169,244,.7)}.chartist-light-blue .ct-series-c .ct-area,.chartist-light-blue .ct-series-c .ct-slice-donut-solid,.chartist-light-blue .ct-series-c .ct-slice-pie{fill:rgba(3,169,244,.4)}.chartist-light-blue .ct-series-d .ct-area,.chartist-light-blue .ct-series-d .ct-slice-donut-solid,.chartist-light-blue .ct-series-d .ct-slice-pie{fill:rgba(3,169,244,.2)}.chartist-cyan.text-black .ct-label{fill:#000;color:#000}.chartist-cyan.text-white .ct-label{fill:#fff;color:#fff}.chartist-cyan .ct-label{fill:rgba(0,188,212,.4);color:rgba(0,188,212,.4)}.chartist-cyan .ct-grid{stroke:rgba(0,188,212,.2)}.chartist-cyan .ct-series-a .ct-bar,.chartist-cyan .ct-series-a .ct-line,.chartist-cyan .ct-series-a .ct-point,.chartist-cyan .ct-series-a .ct-slice-donut{stroke:rgba(0,188,212,1)}.chartist-cyan .ct-series-b .ct-bar,.chartist-cyan .ct-series-b .ct-line,.chartist-cyan .ct-series-b .ct-point,.chartist-cyan .ct-series-b .ct-slice-donut{stroke:rgba(0,188,212,.7)}.chartist-cyan .ct-series-c .ct-bar,.chartist-cyan .ct-series-c .ct-line,.chartist-cyan .ct-series-c .ct-point,.chartist-cyan .ct-series-c .ct-slice-donut{stroke:rgba(0,188,212,.4)}.chartist-cyan .ct-series-d .ct-bar,.chartist-cyan .ct-series-d .ct-line,.chartist-cyan .ct-series-d .ct-point,.chartist-cyan .ct-series-d .ct-slice-donut{stroke:rgba(0,188,212,.2)}.chartist-cyan .ct-series-a .ct-area,.chartist-cyan .ct-series-a .ct-slice-donut-solid,.chartist-cyan .ct-series-a .ct-slice-pie{fill:rgba(0,188,212,1)}.chartist-cyan .ct-series-b .ct-area,.chartist-cyan .ct-series-b .ct-slice-donut-solid,.chartist-cyan .ct-series-b .ct-slice-pie{fill:rgba(0,188,212,.7)}.chartist-cyan .ct-series-c .ct-area,.chartist-cyan .ct-series-c .ct-slice-donut-solid,.chartist-cyan .ct-series-c .ct-slice-pie{fill:rgba(0,188,212,.4)}.chartist-cyan .ct-series-d .ct-area,.chartist-cyan .ct-series-d .ct-slice-donut-solid,.chartist-cyan .ct-series-d .ct-slice-pie{fill:rgba(0,188,212,.2)}.chartist-teal.text-black .ct-label{fill:#000;color:#000}.chartist-teal.text-white .ct-label{fill:#fff;color:#fff}.chartist-teal .ct-label{fill:rgba(0,150,136,.4);color:rgba(0,150,136,.4)}.chartist-teal .ct-grid{stroke:rgba(0,150,136,.2)}.chartist-teal .ct-series-a .ct-bar,.chartist-teal .ct-series-a .ct-line,.chartist-teal .ct-series-a .ct-point,.chartist-teal .ct-series-a .ct-slice-donut{stroke:rgba(0,150,136,1)}.chartist-teal .ct-series-b .ct-bar,.chartist-teal .ct-series-b .ct-line,.chartist-teal .ct-series-b .ct-point,.chartist-teal .ct-series-b .ct-slice-donut{stroke:rgba(0,150,136,.7)}.chartist-teal .ct-series-c .ct-bar,.chartist-teal .ct-series-c .ct-line,.chartist-teal .ct-series-c .ct-point,.chartist-teal .ct-series-c .ct-slice-donut{stroke:rgba(0,150,136,.4)}.chartist-teal .ct-series-d .ct-bar,.chartist-teal .ct-series-d .ct-line,.chartist-teal .ct-series-d .ct-point,.chartist-teal .ct-series-d .ct-slice-donut{stroke:rgba(0,150,136,.2)}.chartist-teal .ct-series-a .ct-area,.chartist-teal .ct-series-a .ct-slice-donut-solid,.chartist-teal .ct-series-a .ct-slice-pie{fill:rgba(0,150,136,1)}.chartist-teal .ct-series-b .ct-area,.chartist-teal .ct-series-b .ct-slice-donut-solid,.chartist-teal .ct-series-b .ct-slice-pie{fill:rgba(0,150,136,.7)}.chartist-teal .ct-series-c .ct-area,.chartist-teal .ct-series-c .ct-slice-donut-solid,.chartist-teal .ct-series-c .ct-slice-pie{fill:rgba(0,150,136,.4)}.chartist-teal .ct-series-d .ct-area,.chartist-teal .ct-series-d .ct-slice-donut-solid,.chartist-teal .ct-series-d .ct-slice-pie{fill:rgba(0,150,136,.2)}.chartist-green.text-black .ct-label{fill:#000;color:#000}.chartist-green.text-white .ct-label{fill:#fff;color:#fff}.chartist-green .ct-label{fill:rgba(76,175,79,.4);color:rgba(76,175,79,.4)}.chartist-green .ct-grid{stroke:rgba(76,175,79,.2)}.chartist-green .ct-series-a .ct-bar,.chartist-green .ct-series-a .ct-line,.chartist-green .ct-series-a .ct-point,.chartist-green .ct-series-a .ct-slice-donut{stroke:rgba(76,175,79,1)}.chartist-green .ct-series-b .ct-bar,.chartist-green .ct-series-b .ct-line,.chartist-green .ct-series-b .ct-point,.chartist-green .ct-series-b .ct-slice-donut{stroke:rgba(76,175,79,.7)}.chartist-green .ct-series-c .ct-bar,.chartist-green .ct-series-c .ct-line,.chartist-green .ct-series-c .ct-point,.chartist-green .ct-series-c .ct-slice-donut{stroke:rgba(76,175,79,.4)}.chartist-green .ct-series-d .ct-bar,.chartist-green .ct-series-d .ct-line,.chartist-green .ct-series-d .ct-point,.chartist-green .ct-series-d .ct-slice-donut{stroke:rgba(76,175,79,.2)}.chartist-green .ct-series-a .ct-area,.chartist-green .ct-series-a .ct-slice-donut-solid,.chartist-green .ct-series-a .ct-slice-pie{fill:rgba(76,175,79,1)}.chartist-green .ct-series-b .ct-area,.chartist-green .ct-series-b .ct-slice-donut-solid,.chartist-green .ct-series-b .ct-slice-pie{fill:rgba(76,175,79,.7)}.chartist-green .ct-series-c .ct-area,.chartist-green .ct-series-c .ct-slice-donut-solid,.chartist-green .ct-series-c .ct-slice-pie{fill:rgba(76,175,79,.4)}.chartist-green .ct-series-d .ct-area,.chartist-green .ct-series-d .ct-slice-donut-solid,.chartist-green .ct-series-d .ct-slice-pie{fill:rgba(76,175,79,.2)}.chartist-lime.text-black .ct-label{fill:#000;color:#000}.chartist-lime.text-white .ct-label{fill:#fff;color:#fff}.chartist-lime .ct-label{fill:rgba(205,220,57,.4);color:rgba(205,220,57,.4)}.chartist-lime .ct-grid{stroke:rgba(205,220,57,.2)}.chartist-lime .ct-series-a .ct-bar,.chartist-lime .ct-series-a .ct-line,.chartist-lime .ct-series-a .ct-point,.chartist-lime .ct-series-a .ct-slice-donut{stroke:rgba(205,220,57,1)}.chartist-lime .ct-series-b .ct-bar,.chartist-lime .ct-series-b .ct-line,.chartist-lime .ct-series-b .ct-point,.chartist-lime .ct-series-b .ct-slice-donut{stroke:rgba(205,220,57,.7)}.chartist-lime .ct-series-c .ct-bar,.chartist-lime .ct-series-c .ct-line,.chartist-lime .ct-series-c .ct-point,.chartist-lime .ct-series-c .ct-slice-donut{stroke:rgba(205,220,57,.4)}.chartist-lime .ct-series-d .ct-bar,.chartist-lime .ct-series-d .ct-line,.chartist-lime .ct-series-d .ct-point,.chartist-lime .ct-series-d .ct-slice-donut{stroke:rgba(205,220,57,.2)}.chartist-lime .ct-series-a .ct-area,.chartist-lime .ct-series-a .ct-slice-donut-solid,.chartist-lime .ct-series-a .ct-slice-pie{fill:rgba(205,220,57,1)}.chartist-lime .ct-series-b .ct-area,.chartist-lime .ct-series-b .ct-slice-donut-solid,.chartist-lime .ct-series-b .ct-slice-pie{fill:rgba(205,220,57,.7)}.chartist-lime .ct-series-c .ct-area,.chartist-lime .ct-series-c .ct-slice-donut-solid,.chartist-lime .ct-series-c .ct-slice-pie{fill:rgba(205,220,57,.4)}.chartist-lime .ct-series-d .ct-area,.chartist-lime .ct-series-d .ct-slice-donut-solid,.chartist-lime .ct-series-d .ct-slice-pie{fill:rgba(205,220,57,.2)}.chartist-yellow.text-black .ct-label{fill:#000;color:#000}.chartist-yellow.text-white .ct-label{fill:#fff;color:#fff}.chartist-yellow .ct-label{fill:rgba(255,235,59,.4);color:rgba(255,235,59,.4)}.chartist-yellow .ct-grid{stroke:rgba(255,235,59,.2)}.chartist-yellow .ct-series-a .ct-bar,.chartist-yellow .ct-series-a .ct-line,.chartist-yellow .ct-series-a .ct-point,.chartist-yellow .ct-series-a .ct-slice-donut{stroke:rgba(255,235,59,1)}.chartist-yellow .ct-series-b .ct-bar,.chartist-yellow .ct-series-b .ct-line,.chartist-yellow .ct-series-b .ct-point,.chartist-yellow .ct-series-b .ct-slice-donut{stroke:rgba(255,235,59,.7)}.chartist-yellow .ct-series-c .ct-bar,.chartist-yellow .ct-series-c .ct-line,.chartist-yellow .ct-series-c .ct-point,.chartist-yellow .ct-series-c .ct-slice-donut{stroke:rgba(255,235,59,.4)}.chartist-yellow .ct-series-d .ct-bar,.chartist-yellow .ct-series-d .ct-line,.chartist-yellow .ct-series-d .ct-point,.chartist-yellow .ct-series-d .ct-slice-donut{stroke:rgba(255,235,59,.2)}.chartist-yellow .ct-series-a .ct-area,.chartist-yellow .ct-series-a .ct-slice-donut-solid,.chartist-yellow .ct-series-a .ct-slice-pie{fill:rgba(255,235,59,1)}.chartist-yellow .ct-series-b .ct-area,.chartist-yellow .ct-series-b .ct-slice-donut-solid,.chartist-yellow .ct-series-b .ct-slice-pie{fill:rgba(255,235,59,.7)}.chartist-yellow .ct-series-c .ct-area,.chartist-yellow .ct-series-c .ct-slice-donut-solid,.chartist-yellow .ct-series-c .ct-slice-pie{fill:rgba(255,235,59,.4)}.chartist-yellow .ct-series-d .ct-area,.chartist-yellow .ct-series-d .ct-slice-donut-solid,.chartist-yellow .ct-series-d .ct-slice-pie{fill:rgba(255,235,59,.2)}.chartist-amber.text-black .ct-label{fill:#000;color:#000}.chartist-amber.text-white .ct-label{fill:#fff;color:#fff}.chartist-amber .ct-label{fill:rgba(255,193,7,.4);color:rgba(255,193,7,.4)}.chartist-amber .ct-grid{stroke:rgba(255,193,7,.2)}.chartist-amber .ct-series-a .ct-bar,.chartist-amber .ct-series-a .ct-line,.chartist-amber .ct-series-a .ct-point,.chartist-amber .ct-series-a .ct-slice-donut{stroke:rgba(255,193,7,1)}.chartist-amber .ct-series-b .ct-bar,.chartist-amber .ct-series-b .ct-line,.chartist-amber .ct-series-b .ct-point,.chartist-amber .ct-series-b .ct-slice-donut{stroke:rgba(255,193,7,.7)}.chartist-amber .ct-series-c .ct-bar,.chartist-amber .ct-series-c .ct-line,.chartist-amber .ct-series-c .ct-point,.chartist-amber .ct-series-c .ct-slice-donut{stroke:rgba(255,193,7,.4)}.chartist-amber .ct-series-d .ct-bar,.chartist-amber .ct-series-d .ct-line,.chartist-amber .ct-series-d .ct-point,.chartist-amber .ct-series-d .ct-slice-donut{stroke:rgba(255,193,7,.2)}.chartist-amber .ct-series-a .ct-area,.chartist-amber .ct-series-a .ct-slice-donut-solid,.chartist-amber .ct-series-a .ct-slice-pie{fill:rgba(255,193,7,1)}.chartist-amber .ct-series-b .ct-area,.chartist-amber .ct-series-b .ct-slice-donut-solid,.chartist-amber .ct-series-b .ct-slice-pie{fill:rgba(255,193,7,.7)}.chartist-amber .ct-series-c .ct-area,.chartist-amber .ct-series-c .ct-slice-donut-solid,.chartist-amber .ct-series-c .ct-slice-pie{fill:rgba(255,193,7,.4)}.chartist-amber .ct-series-d .ct-area,.chartist-amber .ct-series-d .ct-slice-donut-solid,.chartist-amber .ct-series-d .ct-slice-pie{fill:rgba(255,193,7,.2)}.chartist-orange.text-black .ct-label{fill:#000;color:#000}.chartist-orange.text-white .ct-label{fill:#fff;color:#fff}.chartist-orange .ct-label{fill:rgba(255,152,0,.4);color:rgba(255,152,0,.4)}.chartist-orange .ct-grid{stroke:rgba(255,152,0,.2)}.chartist-orange .ct-series-a .ct-bar,.chartist-orange .ct-series-a .ct-line,.chartist-orange .ct-series-a .ct-point,.chartist-orange .ct-series-a .ct-slice-donut{stroke:rgba(255,152,0,1)}.chartist-orange .ct-series-b .ct-bar,.chartist-orange .ct-series-b .ct-line,.chartist-orange .ct-series-b .ct-point,.chartist-orange .ct-series-b .ct-slice-donut{stroke:rgba(255,152,0,.7)}.chartist-orange .ct-series-c .ct-bar,.chartist-orange .ct-series-c .ct-line,.chartist-orange .ct-series-c .ct-point,.chartist-orange .ct-series-c .ct-slice-donut{stroke:rgba(255,152,0,.4)}.chartist-orange .ct-series-d .ct-bar,.chartist-orange .ct-series-d .ct-line,.chartist-orange .ct-series-d .ct-point,.chartist-orange .ct-series-d .ct-slice-donut{stroke:rgba(255,152,0,.2)}.chartist-orange .ct-series-a .ct-area,.chartist-orange .ct-series-a .ct-slice-donut-solid,.chartist-orange .ct-series-a .ct-slice-pie{fill:rgba(255,152,0,1)}.chartist-orange .ct-series-b .ct-area,.chartist-orange .ct-series-b .ct-slice-donut-solid,.chartist-orange .ct-series-b .ct-slice-pie{fill:rgba(255,152,0,.7)}.chartist-orange .ct-series-c .ct-area,.chartist-orange .ct-series-c .ct-slice-donut-solid,.chartist-orange .ct-series-c .ct-slice-pie{fill:rgba(255,152,0,.4)}.chartist-orange .ct-series-d .ct-area,.chartist-orange .ct-series-d .ct-slice-donut-solid,.chartist-orange .ct-series-d .ct-slice-pie{fill:rgba(255,152,0,.2)}.chartist-brown.text-black .ct-label{fill:#000;color:#000}.chartist-brown.text-white .ct-label{fill:#fff;color:#fff}.chartist-brown .ct-label{fill:rgba(121,85,72,.4);color:rgba(121,85,72,.4)}.chartist-brown .ct-grid{stroke:rgba(121,85,72,.2)}.chartist-brown .ct-series-a .ct-bar,.chartist-brown .ct-series-a .ct-line,.chartist-brown .ct-series-a .ct-point,.chartist-brown .ct-series-a .ct-slice-donut{stroke:rgba(121,85,72,1)}.chartist-brown .ct-series-b .ct-bar,.chartist-brown .ct-series-b .ct-line,.chartist-brown .ct-series-b .ct-point,.chartist-brown .ct-series-b .ct-slice-donut{stroke:rgba(121,85,72,.7)}.chartist-brown .ct-series-c .ct-bar,.chartist-brown .ct-series-c .ct-line,.chartist-brown .ct-series-c .ct-point,.chartist-brown .ct-series-c .ct-slice-donut{stroke:rgba(121,85,72,.4)}.chartist-brown .ct-series-d .ct-bar,.chartist-brown .ct-series-d .ct-line,.chartist-brown .ct-series-d .ct-point,.chartist-brown .ct-series-d .ct-slice-donut{stroke:rgba(121,85,72,.2)}.chartist-brown .ct-series-a .ct-area,.chartist-brown .ct-series-a .ct-slice-donut-solid,.chartist-brown .ct-series-a .ct-slice-pie{fill:rgba(121,85,72,1)}.chartist-brown .ct-series-b .ct-area,.chartist-brown .ct-series-b .ct-slice-donut-solid,.chartist-brown .ct-series-b .ct-slice-pie{fill:rgba(121,85,72,.7)}.chartist-brown .ct-series-c .ct-area,.chartist-brown .ct-series-c .ct-slice-donut-solid,.chartist-brown .ct-series-c .ct-slice-pie{fill:rgba(121,85,72,.4)}.chartist-brown .ct-series-d .ct-area,.chartist-brown .ct-series-d .ct-slice-donut-solid,.chartist-brown .ct-series-d .ct-slice-pie{fill:rgba(121,85,72,.2)}.chartist-grey.text-black .ct-label{fill:#000;color:#000}.chartist-grey.text-white .ct-label{fill:#fff;color:#fff}.chartist-grey .ct-label{fill:rgba(158,158,158,.4);color:rgba(158,158,158,.4)}.chartist-grey .ct-grid{stroke:rgba(158,158,158,.2)}.chartist-grey .ct-series-a .ct-bar,.chartist-grey .ct-series-a .ct-line,.chartist-grey .ct-series-a .ct-point,.chartist-grey .ct-series-a .ct-slice-donut{stroke:rgba(158,158,158,1)}.chartist-grey .ct-series-b .ct-bar,.chartist-grey .ct-series-b .ct-line,.chartist-grey .ct-series-b .ct-point,.chartist-grey .ct-series-b .ct-slice-donut{stroke:rgba(158,158,158,.7)}.chartist-grey .ct-series-c .ct-bar,.chartist-grey .ct-series-c .ct-line,.chartist-grey .ct-series-c .ct-point,.chartist-grey .ct-series-c .ct-slice-donut{stroke:rgba(158,158,158,.4)}.chartist-grey .ct-series-d .ct-bar,.chartist-grey .ct-series-d .ct-line,.chartist-grey .ct-series-d .ct-point,.chartist-grey .ct-series-d .ct-slice-donut{stroke:rgba(158,158,158,.2)}.chartist-grey .ct-series-a .ct-area,.chartist-grey .ct-series-a .ct-slice-donut-solid,.chartist-grey .ct-series-a .ct-slice-pie{fill:rgba(158,158,158,1)}.chartist-grey .ct-series-b .ct-area,.chartist-grey .ct-series-b .ct-slice-donut-solid,.chartist-grey .ct-series-b .ct-slice-pie{fill:rgba(158,158,158,.7)}.chartist-grey .ct-series-c .ct-area,.chartist-grey .ct-series-c .ct-slice-donut-solid,.chartist-grey .ct-series-c .ct-slice-pie{fill:rgba(158,158,158,.4)}.chartist-grey .ct-series-d .ct-area,.chartist-grey .ct-series-d .ct-slice-donut-solid,.chartist-grey .ct-series-d .ct-slice-pie{fill:rgba(158,158,158,.2)}.chartist-blue.text-white-grey .ct-label{fill:#fff;color:#fff}.chartist-blue-grey .ct-label{fill:rgba(96,125,139,.4);color:rgba(96,125,139,.4)}.chartist-blue-grey .ct-grid{stroke:rgba(96,125,139,.2)}.chartist-blue-grey .ct-series-a .ct-bar,.chartist-blue-grey .ct-series-a .ct-line,.chartist-blue-grey .ct-series-a .ct-point,.chartist-blue-grey .ct-series-a .ct-slice-donut{stroke:rgba(96,125,139,1)}.chartist-blue-grey .ct-series-b .ct-bar,.chartist-blue-grey .ct-series-b .ct-line,.chartist-blue-grey .ct-series-b .ct-point,.chartist-blue-grey .ct-series-b .ct-slice-donut{stroke:rgba(96,125,139,.7)}.chartist-blue-grey .ct-series-c .ct-bar,.chartist-blue-grey .ct-series-c .ct-line,.chartist-blue-grey .ct-series-c .ct-point,.chartist-blue-grey .ct-series-c .ct-slice-donut{stroke:rgba(96,125,139,.4)}.chartist-blue-grey .ct-series-d .ct-bar,.chartist-blue-grey .ct-series-d .ct-line,.chartist-blue-grey .ct-series-d .ct-point,.chartist-blue-grey .ct-series-d .ct-slice-donut{stroke:rgba(96,125,139,.2)}.chartist-blue-grey .ct-series-a .ct-area,.chartist-blue-grey .ct-series-a .ct-slice-donut-solid,.chartist-blue-grey .ct-series-a .ct-slice-pie{fill:rgba(96,125,139,1)}.chartist-blue-grey .ct-series-b .ct-area,.chartist-blue-grey .ct-series-b .ct-slice-donut-solid,.chartist-blue-grey .ct-series-b .ct-slice-pie{fill:rgba(96,125,139,.7)}.chartist-blue-grey .ct-series-c .ct-area,.chartist-blue-grey .ct-series-c .ct-slice-donut-solid,.chartist-blue-grey .ct-series-c .ct-slice-pie{fill:rgba(96,125,139,.4)}.chartist-blue-grey .ct-series-d .ct-area,.chartist-blue-grey .ct-series-d .ct-slice-donut-solid,.chartist-blue-grey .ct-series-d .ct-slice-pie{fill:rgba(96,125,139,.2)}.chartist-black.text-black .ct-label{fill:#000;color:#000}.chartist-black.text-white .ct-label{fill:#fff;color:#fff}.chartist-black .ct-label{fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4)}.chartist-black .ct-grid{stroke:rgba(0,0,0,.2)}.chartist-black .ct-series-a .ct-bar,.chartist-black .ct-series-a .ct-line,.chartist-black .ct-series-a .ct-point,.chartist-black .ct-series-a .ct-slice-donut{stroke:rgba(0,0,0,1)}.chartist-black .ct-series-b .ct-bar,.chartist-black .ct-series-b .ct-line,.chartist-black .ct-series-b .ct-point,.chartist-black .ct-series-b .ct-slice-donut{stroke:rgba(0,0,0,.7)}.chartist-black .ct-series-c .ct-bar,.chartist-black .ct-series-c .ct-line,.chartist-black .ct-series-c .ct-point,.chartist-black .ct-series-c .ct-slice-donut{stroke:rgba(0,0,0,.4)}.chartist-black .ct-series-d .ct-bar,.chartist-black .ct-series-d .ct-line,.chartist-black .ct-series-d .ct-point,.chartist-black .ct-series-d .ct-slice-donut{stroke:rgba(0,0,0,.2)}.chartist-black .ct-series-a .ct-area,.chartist-black .ct-series-a .ct-slice-donut-solid,.chartist-black .ct-series-a .ct-slice-pie{fill:rgba(0,0,0,1)}.chartist-black .ct-series-b .ct-area,.chartist-black .ct-series-b .ct-slice-donut-solid,.chartist-black .ct-series-b .ct-slice-pie{fill:rgba(0,0,0,.7)}.chartist-black .ct-series-c .ct-area,.chartist-black .ct-series-c .ct-slice-donut-solid,.chartist-black .ct-series-c .ct-slice-pie{fill:rgba(0,0,0,.4)}.chartist-black .ct-series-d .ct-area,.chartist-black .ct-series-d .ct-slice-donut-solid,.chartist-black .ct-series-d .ct-slice-pie{fill:rgba(0,0,0,.2)}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/chartjs.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/chartjs.min.css
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/chartjs.min.css
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/cover.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/cover.min.css
new file mode 100755
index 0000000..3b133ba
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/cover.min.css
@@ -0,0 +1 @@
+.cover{padding:15px;background-position:50% 50%;background-size:cover;background-repeat:no-repeat;width:100%;position:relative}.cover.cover-200{height:300px}.cover.cover-200{height:300px}.cover.cover-400{height:400px}.cover.cover-500{height:500px}.cover.no-padding{padding:0}.cover .avatar{height:100px;border-width:4px;margin-bottom:5px}.cover .item .avatar{height:50px}.cover .float-bottom-center,.cover .float-bottom-left,.cover .float-bottom-right{margin-bottom:-30px;z-index:99;position:absolute}.cover .big.float-bottom-center,.cover .big.float-bottom-left,.cover .big.float-bottom-right{margin-bottom:-35px}.cover .small.float-bottom-center,.cover .small.float-bottom-left,.cover .small.float-bottom-right{margin-bottom:-25px}.cover .float-bottom-center{left:50%;margin-left:-21px}.cover .small.float-bottom-center{left:50%;margin-left:-15px}.cover .big.float-bottom-center{left:50%;margin-left:-25px}.cover .gradient{background:-webkit-linear-gradient(top,rgba(0,0,0,0) 0,rgba(0,0,0,.65) 100%);background:linear-gradient(to bottom,rgba(0,0,0,0) 0,rgba(0,0,0,.65) 100%);width:100%;padding-bottom:10px;padding-top:20px}.cover.blend-multiply{background-blend-mode:multiply}.cover.blend-screen{background-blend-mode:screen}.cover.blend-overlay{background-blend-mode:overlay}.cover.blend-darken{background-blend-mode:darken}.cover.blend-lighten{background-blend-mode:lighten}.cover.blend-color-dodge{background-blend-mode:color-dodge}.cover.blend-color-burn{background-blend-mode:color-burn}.cover.blend-hard-light{background-blend-mode:hard-light}.cover.blend-soft-light{background-blend-mode:soft-light}.cover.blend-luminosity{background-blend-mode:luminosity}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/fonts/ionicons.woff b/platforms/android/app/src/main/assets/www/mobileui/css/fonts/ionicons.woff
new file mode 100644
index 0000000..5f3a14e
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/fonts/ionicons.woff
Binary files differ
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/fonts/roboto.woff2 b/platforms/android/app/src/main/assets/www/mobileui/css/fonts/roboto.woff2
new file mode 100644
index 0000000..46f1cde
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/fonts/roboto.woff2
Binary files differ
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/fonts/robotoblack.woff2 b/platforms/android/app/src/main/assets/www/mobileui/css/fonts/robotoblack.woff2
new file mode 100644
index 0000000..f193280
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/fonts/robotoblack.woff2
Binary files differ
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/fonts/robotolight.woff2 b/platforms/android/app/src/main/assets/www/mobileui/css/fonts/robotolight.woff2
new file mode 100644
index 0000000..eacda32
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/fonts/robotolight.woff2
Binary files differ
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/gfont.css b/platforms/android/app/src/main/assets/www/mobileui/css/gfont.css
new file mode 100644
index 0000000..c0fb730
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/gfont.css
@@ -0,0 +1,304 @@
+/* latin */
+@font-face {
+  font-family: 'Chewy';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Chewy Regular'), local('Chewy-Regular'), url(https://fonts.gstatic.com/s/chewy/v10/uK_94ruUb-k-wn52KjI9OPec.woff2) format('woff2');
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'Dosis';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Dosis Regular'), local('Dosis-Regular'), url(https://fonts.gstatic.com/s/dosis/v8/HhyaU5sn9vOmLzlmC_WoEoZKdbA.woff2) format('woff2');
+  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'Dosis';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Dosis Regular'), local('Dosis-Regular'), url(https://fonts.gstatic.com/s/dosis/v8/HhyaU5sn9vOmLzloC_WoEoZK.woff2) format('woff2');
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* latin */
+@font-face {
+  font-family: 'Monoton';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Monoton'), local('Monoton-Regular'), url(https://fonts.gstatic.com/s/monoton/v8/5h1aiZUrOngCibe4TkHLQka4BU4.woff2) format('woff2');
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* cyrillic-ext */
+@font-face {
+  font-family: 'Open Sans';
+  font-style: normal;
+  font-weight: 300;
+  src: local('Open Sans Light'), local('OpenSans-Light'), url(https://fonts.gstatic.com/s/opensans/v16/mem5YaGs126MiZpBA-UN_r8OX-hpKKSTj5PW.woff2) format('woff2');
+  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
+}
+/* cyrillic */
+@font-face {
+  font-family: 'Open Sans';
+  font-style: normal;
+  font-weight: 300;
+  src: local('Open Sans Light'), local('OpenSans-Light'), url(https://fonts.gstatic.com/s/opensans/v16/mem5YaGs126MiZpBA-UN_r8OVuhpKKSTj5PW.woff2) format('woff2');
+  unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+}
+/* greek-ext */
+@font-face {
+  font-family: 'Open Sans';
+  font-style: normal;
+  font-weight: 300;
+  src: local('Open Sans Light'), local('OpenSans-Light'), url(https://fonts.gstatic.com/s/opensans/v16/mem5YaGs126MiZpBA-UN_r8OXuhpKKSTj5PW.woff2) format('woff2');
+  unicode-range: U+1F00-1FFF;
+}
+/* greek */
+@font-face {
+  font-family: 'Open Sans';
+  font-style: normal;
+  font-weight: 300;
+  src: local('Open Sans Light'), local('OpenSans-Light'), url(https://fonts.gstatic.com/s/opensans/v16/mem5YaGs126MiZpBA-UN_r8OUehpKKSTj5PW.woff2) format('woff2');
+  unicode-range: U+0370-03FF;
+}
+/* vietnamese */
+@font-face {
+  font-family: 'Open Sans';
+  font-style: normal;
+  font-weight: 300;
+  src: local('Open Sans Light'), local('OpenSans-Light'), url(https://fonts.gstatic.com/s/opensans/v16/mem5YaGs126MiZpBA-UN_r8OXehpKKSTj5PW.woff2) format('woff2');
+  unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'Open Sans';
+  font-style: normal;
+  font-weight: 300;
+  src: local('Open Sans Light'), local('OpenSans-Light'), url(https://fonts.gstatic.com/s/opensans/v16/mem5YaGs126MiZpBA-UN_r8OXOhpKKSTj5PW.woff2) format('woff2');
+  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'Open Sans';
+  font-style: normal;
+  font-weight: 300;
+  src: local('Open Sans Light'), local('OpenSans-Light'), url(https://fonts.gstatic.com/s/opensans/v16/mem5YaGs126MiZpBA-UN_r8OUuhpKKSTjw.woff2) format('woff2');
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'Raleway';
+  font-style: normal;
+  font-weight: 300;
+  src: local('Raleway Light'), local('Raleway-Light'), url(https://fonts.gstatic.com/s/raleway/v13/1Ptrg8zYS_SKggPNwIYqWqhPANqczVsq4A.woff2) format('woff2');
+  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'Raleway';
+  font-style: normal;
+  font-weight: 300;
+  src: local('Raleway Light'), local('Raleway-Light'), url(https://fonts.gstatic.com/s/raleway/v13/1Ptrg8zYS_SKggPNwIYqWqZPANqczVs.woff2) format('woff2');
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'Raleway';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Raleway'), local('Raleway-Regular'), url(https://fonts.gstatic.com/s/raleway/v13/1Ptug8zYS_SKggPNyCMIT4ttDfCmxA.woff2) format('woff2');
+  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'Raleway';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Raleway'), local('Raleway-Regular'), url(https://fonts.gstatic.com/s/raleway/v13/1Ptug8zYS_SKggPNyC0IT4ttDfA.woff2) format('woff2');
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'Raleway';
+  font-style: normal;
+  font-weight: 700;
+  src: local('Raleway Bold'), local('Raleway-Bold'), url(https://fonts.gstatic.com/s/raleway/v13/1Ptrg8zYS_SKggPNwJYtWqhPANqczVsq4A.woff2) format('woff2');
+  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'Raleway';
+  font-style: normal;
+  font-weight: 700;
+  src: local('Raleway Bold'), local('Raleway-Bold'), url(https://fonts.gstatic.com/s/raleway/v13/1Ptrg8zYS_SKggPNwJYtWqZPANqczVs.woff2) format('woff2');
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* cyrillic-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 300;
+  src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmSU5fCRc4AMP6lbBP.woff2) format('woff2');
+  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
+}
+/* cyrillic */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 300;
+  src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmSU5fABc4AMP6lbBP.woff2) format('woff2');
+  unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+}
+/* greek-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 300;
+  src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmSU5fCBc4AMP6lbBP.woff2) format('woff2');
+  unicode-range: U+1F00-1FFF;
+}
+/* greek */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 300;
+  src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmSU5fBxc4AMP6lbBP.woff2) format('woff2');
+  unicode-range: U+0370-03FF;
+}
+/* vietnamese */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 300;
+  src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmSU5fCxc4AMP6lbBP.woff2) format('woff2');
+  unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 300;
+  src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmSU5fChc4AMP6lbBP.woff2) format('woff2');
+  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 300;
+  src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmSU5fBBc4AMP6lQ.woff2) format('woff2');
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* cyrillic-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v19/KFOmCnqEu92Fr1Mu72xKKTU1Kvnz.woff2) format('woff2');
+  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
+}
+/* cyrillic */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v19/KFOmCnqEu92Fr1Mu5mxKKTU1Kvnz.woff2) format('woff2');
+  unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+}
+/* greek-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v19/KFOmCnqEu92Fr1Mu7mxKKTU1Kvnz.woff2) format('woff2');
+  unicode-range: U+1F00-1FFF;
+}
+/* greek */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v19/KFOmCnqEu92Fr1Mu4WxKKTU1Kvnz.woff2) format('woff2');
+  unicode-range: U+0370-03FF;
+}
+/* vietnamese */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v19/KFOmCnqEu92Fr1Mu7WxKKTU1Kvnz.woff2) format('woff2');
+  unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v19/KFOmCnqEu92Fr1Mu7GxKKTU1Kvnz.woff2) format('woff2');
+  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v19/KFOmCnqEu92Fr1Mu4mxKKTU1Kg.woff2) format('woff2');
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* cyrillic-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 900;
+  src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmYUtfCRc4AMP6lbBP.woff2) format('woff2');
+  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
+}
+/* cyrillic */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 900;
+  src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmYUtfABc4AMP6lbBP.woff2) format('woff2');
+  unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+}
+/* greek-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 900;
+  src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmYUtfCBc4AMP6lbBP.woff2) format('woff2');
+  unicode-range: U+1F00-1FFF;
+}
+/* greek */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 900;
+  src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmYUtfBxc4AMP6lbBP.woff2) format('woff2');
+  unicode-range: U+0370-03FF;
+}
+/* vietnamese */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 900;
+  src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmYUtfCxc4AMP6lbBP.woff2) format('woff2');
+  unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 900;
+  src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmYUtfChc4AMP6lbBP.woff2) format('woff2');
+  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 900;
+  src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmYUtfBBc4AMP6lQ.woff2) format('woff2');
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/grid.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/grid.min.css
new file mode 100755
index 0000000..d3e0e6e
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/grid.min.css
@@ -0,0 +1 @@
+.row{display:-webkit-box;display:-ms-flexbox;display:flex}.row-between{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.row-around{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-pack:distribute;justify-content:space-around}.row-stretch{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch}.column{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.wrap{-ms-flex-wrap:wrap;flex-wrap:wrap}.vertical-align-top{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.vertical-align-center{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.vertical-align-bottom{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}.horizontal-align-left{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.horizontal-align-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.horizontal-align-right{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.row-center{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.col{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;position:relative}.col-10{position:relative;-ms-flex-preferred-size:10%;flex-basis:10%}.col-20{position:relative;-ms-flex-preferred-size:20%;flex-basis:20%}.col-25{position:relative;-ms-flex-preferred-size:25%;flex-basis:25%}.col-33,.col-34{position:relative;-ms-flex-preferred-size:33.3333%;flex-basis:33.3333%}.col-50{position:relative;-ms-flex-preferred-size:50%;flex-basis:50%}.col-66,.col-67{position:relative;-ms-flex-preferred-size:66.6666%;flex-basis:66.6666%}.col-75{position:relative;-ms-flex-preferred-size:75%;flex-basis:75%}.col-80{position:relative;-ms-flex-preferred-size:80%;flex-basis:80%}.col-90{position:relative;-ms-flex-preferred-size:100%;flex-basis:100%}.full-width{width:100%;margin:0 auto}.full-height{height:100%;margin:0 auto}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/header.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/header.min.css
new file mode 100755
index 0000000..0981cb8
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/header.min.css
@@ -0,0 +1 @@
+.footer,.header{font-size:18px;display:inline-block;width:100%;position:fixed;top:0;left:0;height:52px;z-index:9}.footer{top:initial;bottom:0}.header.sub{top:52px}.footer.sub{top:initial;bottom:52px}.has-header{padding-top:52px!important}.has-header.has-sub-header{padding-top:104px!important}.has-footer{padding-bottom:52px!important}.has-footer.has-sub-footer{padding-bottom:104px!important}.footer .left,.footer .right,.footer .title,.footer h1,.header .left,.header .right,.header .title,.header h1{margin-top:15px;margin-bottom:5px}.header .avatar{height:40px;margin-top:-8px;margin-left:4px}.header .border-big{border-width:2px;border-style:solid}.footer h2,.header h2{padding-top:8px;padding-left:10px}.footer p,.header p{padding-left:10px;margin:0;margin-top:-4px}.footer .left,.header .left{padding-left:5px}.footer .right,.header .right{padding-right:5px}.footer .title,.footer h1,.header .title,.header h1{margin-bottom:15px;padding-left:10px;padding-right:15px;display:inline-block}.footer button,.header button{margin-top:-10px}.footer button.icon,.header button.icon{font-size:30px;margin-top:-10px;z-index:99;background:0 0;border:none;padding:0 6px}.footer button.icon:not([class*=red]):not([class*=pink]):not([class*=white]):not([class*=purple]):not([class*=indigo]):not([class*=blue]):not([class*=cyan]):not([class*=teal]):not([class*=green]):not([class*=lime]):not([class*=yellow]):not([class*=amber]):not([class*=orange]):not([class*=brown]):not([class*=grey]):not([class*=black]):not([class*=white]),.header button.icon:not([class*=red]):not([class*=pink]):not([class*=white]):not([class*=purple]):not([class*=indigo]):not([class*=blue]):not([class*=cyan]):not([class*=teal]):not([class*=green]):not([class*=lime]):not([class*=yellow]):not([class*=amber]):not([class*=orange]):not([class*=brown]):not([class*=grey]):not([class*=black]):not([class*=white]){color:#fff}.footer button.icon.left,.footer button.icon.right,.header button.icon.left,.header button.icon.right{margin-top:5px;margin-bottom:5px}.footer button.icon.left,.header button.icon.left{margin-left:5px}.footer button.icon.right,.header button.icon.right{margin-right:5px}.footer .title.align-center,.footer h1.align-center,.footer p.align-center,.header .title.align-center,.header h1.align-center,.header p.align-center{width:100%;position:inherit;padding-right:15px;left:0;z-index:9}.footer .icon-badge,.header .icon-badge{position:absolute;margin-left:-6px;margin-top:-8px;border-radius:8px;z-index:999}.footer .buttons-group,.header .buttons-group{margin-top:15px;margin-left:5px;margin-right:5px}.footer .buttons-group.small,.header .buttons-group.small{margin-top:20px;margin-left:10px;margin-right:10px}.header input::-webkit-input-placeholder{color:rgba(0,0,0,.8)}.header input.placeholder-white::-webkit-input-placeholder{color:rgba(255,255,255,.8)}.header input{padding:15px;position:absolute}.header .left+input{padding-right:50px}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/horizontal-scroll.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/horizontal-scroll.min.css
new file mode 100755
index 0000000..2ce80d4
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/horizontal-scroll.min.css
@@ -0,0 +1 @@
+.horizontal-scroll{width:100%;position:relative;border:1px solid #ddd;display:flex;display:-moz-flex;display:-ms-flexbox;flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch}.horizontal-scroll.no-scroll-bar::-webkit-scrollbar{display:none}.horizontal-scroll .item{padding:15px;display:inline-block;flex:0 0 auto;width:100%;border-right:1px solid #ddd;position:relative;font-size:18px}.horizontal-scroll .item.hidden{display:none}.horizontal-scroll .item.mark{border-right:0;border-bottom:0;border-top:0}.item .block{display:-webkit-box;display:flex}.horizontal-scroll .item.mark.margin-right{border-right:0;margin-right:10px}.horizontal-scroll .item.space-small{padding-left:5px;padding-right:5px}.horizontal-scroll.space-small .item{padding-left:5px;padding-right:5px}.horizontal-scroll .item.no-space-left{padding-left:0!important}.horizontal-scroll .item.no-space-right{padding-right:0!important}.horizontal-scroll.no-space-left .item{padding-left:0!important}.horizontal-scroll.no-space-right .item{padding-right:0!important}.horizontal-scroll.no-space-top .item{padding-top:0!important}.horizontal-scroll.no-space-bottom .item{padding-bottom:0!important}.horizontal-scroll.no-space .item{padding-left:0!important;padding-right:0!important;padding-top:0!important;padding-bottom:0!important}.horizontal-scroll .item.row{display:-moz-flex;display:-ms-flexbox;display:flex}.horizontal-scroll .item.full{width:100%}.horizontal-scroll .item.three-fourth{width:75%}.horizontal-scroll .item.half{width:50%}.horizontal-scroll .item.one-fourth{width:25%}.horizontal-scroll .item h1,.horizontal-scroll .item h2{font-size:16px;margin:0;padding:0}.horizontal-scroll .item h1{margin-top:7px}.horizontal-scroll .item p{font-size:14px;margin:0;padding:0;line-height:20px}.horizontal-scroll .left{margin-right:10px;min-width:25px}.horizontal-scroll .right{margin-right:20px;position:absolute;top:0;right:0;height:100%;display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-align:center;-webkit-align-items:center;-webkit-box-align:center;align-items:center}.horizontal-scroll .right i{margin-left:5px}.horizontal-scroll .align-top{-ms-flex-align:center;-webkit-align-items:center;align-items:baseline;margin-top:10px}.horizontal-scroll .avatar{height:50px}.avatar-badge{position:absolute;margin-left:-4px;margin-top:-3px;border-radius:8px}.horizontal-scroll .item small,.horizontal-scroll .item small .icon{font-size:14px}.horizontal-scroll .item .icon{font-size:18px}.horizontal-scroll .item .icon.text-huge{font-size:32px}.horizontal-scroll .left .icon,.horizontal-scroll .right .icon{vertical-align:-webkit-baseline-middle}.horizontal-scroll .border-big{border-width:3px;border-style:solid}.horizontal-scroll.no-border{border:0}.horizontal-scroll .item.no-border.border-right,.horizontal-scroll.no-border .item.border-right{border-right-width:1px;border-right-style:solid}.horizontal-scroll .item.no-border,.horizontal-scroll.no-border .item{border:none}.horizontal-scroll .item:last-child{border-right:0}.horizontal-scroll .item .right .icon,.horizontal-scroll .item .right.icon{font-size:24px;padding:0;margin:0}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/imports.css b/platforms/android/app/src/main/assets/www/mobileui/css/imports.css
new file mode 100755
index 0000000..510317d
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/imports.css
@@ -0,0 +1,30 @@
+@import url("./alert.min.css");
+@import url("./base.min.css");
+@import url("./button.min.css");
+@import url("./chart-bar.min.css");
+@import url("./chartist.min.css");
+@import url("./chartist-plugin-tooltip.min.css");
+@import url("./chartjs.min.css");
+@import url("./cover.min.css");
+@import url("./grid.min.css");
+@import url("./header.min.css");
+@import url("./horizontal-scroll.min.css");
+@import url("./include.min.css");
+@import url("./input.min.css");
+@import url("./jquery.min.css");
+@import url("./list.min.css");
+@import url("./loading.min.css");
+@import url("./menu.min.css");
+@import url("./mobileui-colors.min.css");
+@import url("./mobileuijs.min.css");
+@import url("./momentjs.min.css");
+@import url("./page.min.css");
+@import url("./popover.min.css");
+@import url("./progress-circle.min.css");
+@import url("./progress-semicircle.min.css");
+@import url("./progressbarjs.min.css");
+@import url("./pulltorefresh.min.css");
+@import url("./swiper.min.css");
+@import url("./tab.min.css");
+@import url("./timeline.min.css");
+@import url("./toast.min.css");
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/include.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/include.min.css
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/include.min.css
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/input.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/input.min.css
new file mode 100755
index 0000000..e68a220
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/input.min.css
@@ -0,0 +1 @@
+input,select,textarea{border:none;background:0 0;font-size:14px;width:100%;-webkit-flex:1;-ms-flex:1;flex:1}input[disabled],select[disabled],textarea[disabled]{opacity:.8}label{font-size:14px}.item.label-fixed,.label-fixed{display:-moz-flex!important;display:-ms-flexbox!important;display:flex!important;width:100%}.label-fixed label{-webkit-flex:0 0 100px;-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px;max-width:200px}.label-float label{margin-bottom:0;-webkit-transform:translate3d(0,27px,0);transform:translate3d(0,27px,0);-webkit-transform-origin:left top;transform-origin:left top;transition:-webkit-transform 150ms ease-in-out;transition:transform 150ms ease-in-out;transition:transform 150ms ease-in-out,-webkit-transform 150ms ease-in-out;align-self:stretch;-webkit-flex:initial;-ms-flex:initial;flex:initial;display:block}.label-float label.focus{-webkit-transform:translate3d(0,0,0) scale(.8);transform:translate3d(0,0,0) scale(.8)}.item.icon{display:flex}.item.icon.radius{border-radius:6px}.item.icon:not([class*=text-]){color:#9f9f9f}.item input::-webkit-input-placeholder{color:rgba(0,0,0,.6)}.item input.placeholder-white::-webkit-input-placeholder{color:rgba(255,255,255,.6)}.item.icon:before{position:absolute}.item.icon.icon-right:before{right:20px}.item.icon input,.item.icon select{padding-left:30px}.item.icon.icon-right input,.item.icon.icon-right select{padding-left:0;padding-right:30px}input[type=checkbox]{width:17px;height:17px;z-index:1;border:0;vertical-align:top;outline:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:2px}.platform-ios input[type=checkbox]{height:23px;width:23px;border-radius:50%}input[type=checkbox]:not(:checked){background-color:#fff!important;box-shadow:inset 0 0 0 2px rgba(0,0,0,.5)}.platform-ios input[type=checkbox]:not(:checked){box-shadow:inset 0 0 0 1px rgba(0,0,0,.4)}input[type=checkbox]:disabled{opacity:.4}input[type=checkbox]::before{content:'';position:absolute;margin-top:1px;margin-left:5px;width:5px;height:10px;border-width:2px;border-top-width:0;border-left-width:0;border-style:solid;border-color:#fff;-webkit-transform:rotate(45deg);transform:rotate(45deg)}.platform-ios input[type=checkbox]::before{margin-top:5px;margin-left:9px;width:4px;height:9px;border-width:1px;border-top-width:0;border-left-width:0}input[type=checkbox].switch{width:36px;height:14px;box-shadow:inset 0 0 0 30px rgba(255,255,255,.4);border-radius:28px;-webkit-transition-property:all;transition-property:all;-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.platform-ios input[type=checkbox].switch{height:32px;width:51px;box-shadow:inset 0 0 0 2px rgba(0,0,0,.05)}input[type=checkbox].switch:not(:checked){background-color:#fff!important;box-shadow:inset 0 0 0 30px rgba(0,0,0,.35)}.platform-ios input[type=checkbox].switch:not(:checked){box-shadow:inset 0 0 0 2px rgba(0,0,0,.1)}input[type=checkbox].switch::before{content:'';border-radius:28px;height:20px;width:20px;margin-left:-1px;margin-top:-3px;-webkit-transition-duration:.35s;transition-duration:.35s;box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.4);border:0}.platform-ios input[type=checkbox].switch::before{height:28px;width:28px;box-shadow:0 0 0 1px #e4e4e4,0 3px 2px rgba(0,0,0,.25);margin-top:2px;margin-left:2px;background-color:#fff!important}input[type=checkbox].switch:checked::before{margin-left:16px}input[type=checkbox].switch:not(:checked)::before{background-color:#fff!important}.platform-ios input[type=checkbox].switch:checked::before{margin-left:21px;box-shadow:0 3px 2px rgba(0,0,0,.25);background-color:#fff}input[type=radio]{width:20px;height:20px;border-radius:50%;position:relative;overflow:hidden;z-index:1;vertical-align:top;outline:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:0 0}.platform-ios input[type=radio]{background:0 0!important}input[type=radio]::after{content:'';width:100%;height:100%;position:absolute;border-radius:50%}.platform-ios input[type=radio]:not(:checked)::after{box-shadow:none}input[type=radio]:not(:checked)::after{box-shadow:inset 0 0 0 2px rgba(0,0,0,.4);background-color:#fff!important}input[type=radio]:checked::before{content:'';width:10px;height:10px;position:absolute;border:3px solid #fff;z-index:1;border-radius:50%;margin-top:2px;margin-left:2px}input[type=radio]:disabled{opacity:.4}.platform-ios input[type=radio]::after{background:0 0!important}.platform-ios input[type=radio]:checked::before{position:absolute;margin-top:4px;margin-left:7px;width:5px;height:12px;border-width:2px;border-top-width:0;border-left-width:0;border-style:solid;-webkit-transform:rotate(45deg);transform:rotate(45deg);border-radius:0}.item.range{position:relative;-ms-flex-item-align:center;-webkit-align-self:center;align-self:center}.item.range input{position:absolute;height:28px;width:calc(100% - 110px);margin:4px 0 5px 0;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none;background:-webkit-gradient(linear,50% 0,50% 100%,color-stop(0,#ccc),color-stop(100%,#ccc));background:linear-gradient(to right,#ccc 0,#ccc 100%);background-position:center;background-size:100% 2px;background-repeat:no-repeat;outline:0;border:none;box-sizing:content-box;-ms-background-position-y:500px}input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;background-color:#666;width:13px;height:13px;border-radius:50%}input[type=range]:active::-webkit-slider-thumb{width:20px;height:20px}.platform-ios input[type=range]::-webkit-slider-thumb{background-color:#fff;box-shadow:1px 1px 5px rgba(0,0,0,.3);width:25px;height:25px;border:1px solid rgba(0,0,0,.05);border-radius:50%}input[type=checkbox].red-50.switch::before,input[type=radio].red-50::after{background-color:#ffebee}input[type=checkbox].red-100.switch::before,input[type=radio].red-100::after{background-color:#ffcdd2}input[type=checkbox].red-200.switch::before,input[type=radio].red-200::after{background-color:#ef9a9a}input[type=checkbox].red-300.switch::before,input[type=radio].red-300::after{background-color:#e57373}input[type=checkbox].red-400.switch::before,input[type=radio].red-400::after{background-color:#ef5350}input[type=checkbox].red-500.switch::before,input[type=radio].red-500::after{background-color:#f44336}input[type=checkbox].red-600.switch::before,input[type=radio].red-600::after{background-color:#e53935}input[type=checkbox].red-700.switch::before,input[type=radio].red-700::after{background-color:#d32f2f}input[type=checkbox].red-800.switch::before,input[type=radio].red-800::after{background-color:#c62828}input[type=checkbox].red-900.switch::before,input[type=radio].red-900::after{background-color:#b71c1c}input[type=checkbox].pink.switch::before,input[type=radio].pink::after{background-color:#e91e63}input[type=checkbox].pink-50.switch::before,input[type=radio].pink-50::after{background-color:#fce4ec}input[type=checkbox].pink-100.switch::before,input[type=radio].pink-100::after{background-color:#f8bbd0}input[type=checkbox].pink-200.switch::before,input[type=radio].pink-200::after{background-color:#f48fb1}input[type=checkbox].Pink-300.switch::before,input[type=radio].Pink-300::after{background-color:#f06292}input[type=checkbox].pink-400.switch::before,input[type=radio].pink-400::after{background-color:#ec407a}input[type=checkbox].pink-500.switch::before,input[type=radio].pink-500::after{background-color:#e91e63}input[type=checkbox].pink-600.switch::before,input[type=radio].pink-600::after{background-color:#d81b60}input[type=checkbox].pink-700.switch::before,input[type=radio].pink-700::after{background-color:#c2185b}input[type=checkbox].pink-800.switch::before,input[type=radio].pink-800::after{background-color:#ad1457}input[type=checkbox].pink-900.switch::before,input[type=radio].pink-900::after{background-color:#880e4f}input[type=checkbox].purple.switch::before,input[type=radio].purple::after{background-color:#9c27b0}input[type=checkbox].purple-50.switch::before,input[type=radio].purple-50::after{background-color:#f3e5f5}input[type=checkbox].purple-100.switch::before,input[type=radio].purple-100::after{background-color:#e1bee7}input[type=checkbox].purple-200.switch::before,input[type=radio].purple-200::after{background-color:#ce93d8}input[type=checkbox].Purple-300.switch::before,input[type=radio].Purple-300::after{background-color:#ba68c8}input[type=checkbox].Purple-400.switch::before,input[type=radio].Purple-400::after{background-color:#ab47bc}input[type=checkbox].purple-500.switch::before,input[type=radio].purple-500::after{background-color:#9c27b0}input[type=checkbox].purple-600.switch::before,input[type=radio].purple-600::after{background-color:#8e24aa}input[type=checkbox].purple-700.switch::before,input[type=radio].purple-700::after{background-color:#7b1fa2}input[type=checkbox].purple-800.switch::before,input[type=radio].purple-800::after{background-color:#6a1b9a}input[type=checkbox].purple-900.switch::before,input[type=radio].purple-900::after{background-color:#4a148c}input[type=checkbox].deep-purple.switch::before,input[type=radio].deep-purple::after{background-color:#673ab7}input[type=checkbox].deep-purple-300.switch::before,input[type=radio].deep-purple-300::after{background-color:#9575cd}input[type=checkbox].deep-purple-400.switch::before,input[type=radio].deep-purple-400::after{background-color:#7e57c2}input[type=checkbox].deep-purple-500.switch::before,input[type=radio].deep-purple-500::after{background-color:#673ab7}input[type=checkbox].deep-purple-600.switch::before,input[type=radio].deep-purple-600::after{background-color:#5e35b1}input[type=checkbox].deep-purple-700.switch::before,input[type=radio].deep-purple-700::after{background-color:#512da8}input[type=checkbox].deep-purple-800.switch::before,input[type=radio].deep-purple-800::after{background-color:#4527a0}input[type=checkbox].deep-purple-900.switch::before,input[type=radio].deep-purple-900::after{background-color:#311b92}input[type=checkbox].indigo.switch::before,input[type=radio].indigo::after{background-color:#3f51b5}input[type=checkbox].indigo-50.switch::before,input[type=radio].indigo-50::after{background-color:#e8eaf6}input[type=checkbox].indigo-100.switch::before,input[type=radio].indigo-100::after{background-color:#c5cae9}input[type=checkbox].indigo-200.switch::before,input[type=radio].indigo-200::after{background-color:#9fa8da}input[type=checkbox].indigo-300.switch::before,input[type=radio].indigo-300::after{background-color:#7986cb}input[type=checkbox].indigo-400.switch::before,input[type=radio].indigo-400::after{background-color:#5c6bc0}input[type=checkbox].indigo-500.switch::before,input[type=radio].indigo-500::after{background-color:#3f51b5}input[type=checkbox].indigo-600.switch::before,input[type=radio].indigo-600::after{background-color:#3949ab}input[type=checkbox].indigo-700.switch::before,input[type=radio].indigo-700::after{background-color:#303f9f}input[type=checkbox].indigo-800.switch::before,input[type=radio].indigo-800::after{background-color:#283593}input[type=checkbox].indigo-900.switch::before,input[type=radio].indigo-900::after{background-color:#1a237e}input[type=checkbox].blue.switch::before,input[type=radio].blue::after{background-color:#2196f3}input[type=checkbox].blue-50.switch::before,input[type=radio].blue-50::after{background-color:#e3f2fd}input[type=checkbox].blue-100.switch::before,input[type=radio].blue-100::after{background-color:#bbdefb}input[type=checkbox].blue-200.switch::before,input[type=radio].blue-200::after{background-color:#90caf9}input[type=checkbox].blue-300.switch::before,input[type=radio].blue-300::after{background-color:#64b5f6}input[type=checkbox].blue-400.switch::before,input[type=radio].blue-400::after{background-color:#42a5f5}input[type=checkbox].blue-500.switch::before,input[type=radio].blue-500::after{background-color:#2196f3}input[type=checkbox].blue-600.switch::before,input[type=radio].blue-600::after{background-color:#1e88e5}input[type=checkbox].blue-700.switch::before,input[type=radio].blue-700::after{background-color:#1976d2}input[type=checkbox].blue-800.switch::before,input[type=radio].blue-800::after{background-color:#1565c0}input[type=checkbox].blue-900.switch::before,input[type=radio].blue-900::after{background-color:#0d47a1}input[type=checkbox].light-blue.switch::before,input[type=radio].light-blue::after{background-color:#03a9f4}input[type=checkbox].light-blue-50.switch::before,input[type=radio].light-blue-50::after{background-color:#e1f5fe}input[type=checkbox].light-blue-100.switch::before,input[type=radio].light-blue-100::after{background-color:#b3e5fc}input[type=checkbox].light-blue-200.switch::before,input[type=radio].light-blue-200::after{background-color:#81d4fa}input[type=checkbox].light-blue-300.switch::before,input[type=radio].light-blue-300::after{background-color:#4fc3f7}input[type=checkbox].light-blue-400.switch::before,input[type=radio].light-blue-400::after{background-color:#29b6f6}input[type=checkbox].light-blue-500.switch::before,input[type=radio].light-blue-500::after{background-color:#03a9f4}input[type=checkbox].light-blue-600.switch::before,input[type=radio].light-blue-600::after{background-color:#039be5}input[type=checkbox].light-blue-700.switch::before,input[type=radio].light-blue-700::after{background-color:#0288d1}input[type=checkbox].light-blue-800.switch::before,input[type=radio].light-blue-800::after{background-color:#0277bd}input[type=checkbox].light-blue-900.switch::before,input[type=radio].light-blue-900::after{background-color:#01579b}input[type=checkbox].cyan.switch::before,input[type=radio].cyan::after{background-color:#00bcd4}input[type=checkbox].cyan-50.switch::before,input[type=radio].cyan-50::after{background-color:#e0f7fa}input[type=checkbox].cyan-100.switch::before,input[type=radio].cyan-100::after{background-color:#b2ebf2}input[type=checkbox].cyan-200.switch::before,input[type=radio].cyan-200::after{background-color:#80deea}input[type=checkbox].cyan-300.switch::before,input[type=radio].cyan-300::after{background-color:#4dd0e1}input[type=checkbox].cyan-400.switch::before,input[type=radio].cyan-400::after{background-color:#26c6da}input[type=checkbox].cyan-500.switch::before,input[type=radio].cyan-500::after{background-color:#00bcd4}input[type=checkbox].cyan-600.switch::before,input[type=radio].cyan-600::after{background-color:#00acc1}input[type=checkbox].cyan-700.switch::before,input[type=radio].cyan-700::after{background-color:#0097a7}input[type=checkbox].cyan-800.switch::before,input[type=radio].cyan-800::after{background-color:#00838f}input[type=checkbox].cyan-900.switch::before,input[type=radio].cyan-900::after{background-color:#006064}input[type=checkbox].teal.switch::before,input[type=radio].teal::after{background-color:#009688}input[type=checkbox].teal-50.switch::before,input[type=radio].teal-50::after{background-color:#e0f2f1}input[type=checkbox].teal-100.switch::before,input[type=radio].teal-100::after{background-color:#b2dfdb}input[type=checkbox].teal-200.switch::before,input[type=radio].teal-200::after{background-color:#80cbc4}input[type=checkbox].teal-300.switch::before,input[type=radio].teal-300::after{background-color:#4db6ac}input[type=checkbox].teal-400.switch::before,input[type=radio].teal-400::after{background-color:#26a69a}input[type=checkbox].teal-500.switch::before,input[type=radio].teal-500::after{background-color:#009688}input[type=checkbox].teal-600.switch::before,input[type=radio].teal-600::after{background-color:#00897b}input[type=checkbox].teal-700.switch::before,input[type=radio].teal-700::after{background-color:#00796b}input[type=checkbox].teal-800.switch::before,input[type=radio].teal-800::after{background-color:#00695c}input[type=checkbox].teal-900.switch::before,input[type=radio].teal-900::after{background-color:#004d40}input[type=checkbox].green.switch::before,input[type=radio].green::after{background-color:#4caf50}input[type=checkbox].green-50.switch::before,input[type=radio].green-50::after{background-color:#e8f5e9}input[type=checkbox].green-100.switch::before,input[type=radio].green-100::after{background-color:#c8e6c9}input[type=checkbox].green-200.switch::before,input[type=radio].green-200::after{background-color:#a5d6a7}input[type=checkbox].green-300.switch::before,input[type=radio].green-300::after{background-color:#81c784}input[type=checkbox].green-400.switch::before,input[type=radio].green-400::after{background-color:#66bb6a}input[type=checkbox].green-500.switch::before,input[type=radio].green-500::after{background-color:#4caf50}input[type=checkbox].green-600.switch::before,input[type=radio].green-600::after{background-color:#43a047}input[type=checkbox].green-700.switch::before,input[type=radio].green-700::after{background-color:#388e3c}input[type=checkbox].green-800.switch::before,input[type=radio].green-800::after{background-color:#2e7d32}input[type=checkbox].green-900.switch::before,input[type=radio].green-900::after{background-color:#1b5e20}input[type=checkbox].light-green.switch::before,input[type=radio].light-green::after{background-color:#8bc34a}input[type=checkbox].light-green-50.switch::before,input[type=radio].light-green-50::after{background-color:#f1f8e9}input[type=checkbox].light-green-100.switch::before,input[type=radio].light-green-100::after{background-color:#dcedc8}input[type=checkbox].light-green-200.switch::before,input[type=radio].light-green-200::after{background-color:#c5e1a5}input[type=checkbox].light-green-300.switch::before,input[type=radio].light-green-300::after{background-color:#aed581}input[type=checkbox].light-green-400.switch::before,input[type=radio].light-green-400::after{background-color:#9ccc65}input[type=checkbox].light-green-500.switch::before,input[type=radio].light-green-500::after{background-color:#8bc34a}input[type=checkbox].light-green-600.switch::before,input[type=radio].light-green-600::after{background-color:#7cb342}input[type=checkbox].light-green-700.switch::before,input[type=radio].light-green-700::after{background-color:#689f38}input[type=checkbox].light-green-800.switch::before,input[type=radio].light-green-800::after{background-color:#558b2f}input[type=checkbox].light-green-900.switch::before,input[type=radio].light-green-900::after{background-color:#33691e}input[type=checkbox].lime.switch::before,input[type=radio].lime::after{background-color:#cddc39}input[type=checkbox].lime-50.switch::before,input[type=radio].lime-50::after{background-color:#f9fbe7}input[type=checkbox].lime-100.switch::before,input[type=radio].lime-100::after{background-color:#f0f4c3}input[type=checkbox].lime-200.switch::before,input[type=radio].lime-200::after{background-color:#e6ee9c}input[type=checkbox].lime-300.switch::before,input[type=radio].lime-300::after{background-color:#dce775}input[type=checkbox].lime-400.switch::before,input[type=radio].lime-400::after{background-color:#d4e157}input[type=checkbox].lime-500.switch::before,input[type=radio].lime-500::after{background-color:#cddc39}input[type=checkbox].lime-600.switch::before,input[type=radio].lime-600::after{background-color:#c0ca33}input[type=checkbox].lime-700.switch::before,input[type=radio].lime-700::after{background-color:#afb42b}input[type=checkbox].lime-800.switch::before,input[type=radio].lime-800::after{background-color:#9e9d24}input[type=checkbox].lime-900.switch::before,input[type=radio].lime-900::after{background-color:#827717}input[type=checkbox].yellow.switch::before,input[type=radio].yellow::after{background-color:#ffeb3b}input[type=checkbox].yellow-50.switch::before,input[type=radio].yellow-50::after{background-color:#fffde7}input[type=checkbox].yellow-100.switch::before,input[type=radio].yellow-100::after{background-color:#fff9c4}input[type=checkbox].yellow-200.switch::before,input[type=radio].yellow-200::after{background-color:#fff59d}input[type=checkbox].yellow-300.switch::before,input[type=radio].yellow-300::after{background-color:#fff176}input[type=checkbox].yellow-500.switch::before,input[type=radio].yellow-500::after{background-color:#ffeb3b}input[type=checkbox].yellow-600.switch::before,input[type=radio].yellow-600::after{background-color:#fdd835}input[type=checkbox].yellow-700.switch::before,input[type=radio].yellow-700::after{background-color:#fbc02d}input[type=checkbox].yellow-800.switch::before,input[type=radio].yellow-800::after{background-color:#f9a825}input[type=checkbox].yellow-900.switch::before,input[type=radio].yellow-900::after{background-color:#f57f17}input[type=checkbox].amber-50.switch::before,input[type=radio].amber-50::after{background-color:#fff8e1}input[type=checkbox].amber-100.switch::before,input[type=radio].amber-100::after{background-color:#ffecb3}input[type=checkbox].amber-200.switch::before,input[type=radio].amber-200::after{background-color:#ffe082}input[type=checkbox].amber-300.switch::before,input[type=radio].amber-300::after{background-color:#ffd54f}input[type=checkbox].amber-500.switch::before,input[type=radio].amber-500::after{background-color:#ffc107}input[type=checkbox].amber-600.switch::before,input[type=radio].amber-600::after{background-color:#ffb300}input[type=checkbox].amber-700.switch::before,input[type=radio].amber-700::after{background-color:#ffa000}input[type=checkbox].amber-800.switch::before,input[type=radio].amber-800::after{background-color:#ff8f00}input[type=checkbox].amber-900.switch::before,input[type=radio].amber-900::after{background-color:#ff6f00}input[type=checkbox].orange-50.switch::before,input[type=radio].orange-50::after{background-color:#fff3e0}input[type=checkbox].orange-100.switch::before,input[type=radio].orange-100::after{background-color:#ffe0b2}input[type=checkbox].orange-200.switch::before,input[type=radio].orange-200::after{background-color:#ffcc80}input[type=checkbox].orange-300.switch::before,input[type=radio].orange-300::after{background-color:#ffb74d}input[type=checkbox].orange-400.switch::before,input[type=radio].orange-400::after{background-color:#ffa726}input[type=checkbox].orange-500.switch::before,input[type=radio].orange-500::after{background-color:#ff9800}input[type=checkbox].orange-600.switch::before,input[type=radio].orange-600::after{background-color:#fb8c00}input[type=checkbox].orange-700.switch::before,input[type=radio].orange-700::after{background-color:#f57c00}input[type=checkbox].orange-800.switch::before,input[type=radio].orange-800::after{background-color:#ef6c00}input[type=checkbox].orange-900.switch::before,input[type=radio].orange-900::after{background-color:#e65100}input[type=checkbox].deep-orange.switch::before,input[type=radio].deep-orange::after{background-color:#ff5722}input[type=checkbox].deep-orange-50.switch::before,input[type=radio].deep-orange-50::after{background-color:#fbe9e7}input[type=checkbox].deep-orange-100.switch::before,input[type=radio].deep-orange-100::after{background-color:#ffccbc}input[type=checkbox].deep-orange-200.switch::before,input[type=radio].deep-orange-200::after{background-color:#ffab91}input[type=checkbox].deep-orange-300.switch::before,input[type=radio].deep-orange-300::after{background-color:#ff8a65}input[type=checkbox].deep-orange-400.switch::before,input[type=radio].deep-orange-400::after{background-color:#ff7043}input[type=checkbox].deep-orange-500.switch::before,input[type=radio].deep-orange-500::after{background-color:#ff5722}input[type=checkbox].deep-orange-600.switch::before,input[type=radio].deep-orange-600::after{background-color:#f4511e}input[type=checkbox].deep-orange-700.switch::before,input[type=radio].deep-orange-700::after{background-color:#e64a19}input[type=checkbox].deep-orange-800.switch::before,input[type=radio].deep-orange-800::after{background-color:#d84315}input[type=checkbox].deep-orange-900.switch::before,input[type=radio].deep-orange-900::after{background-color:#bf360c}input[type=checkbox].brown.switch::before,input[type=radio].brown::after{background-color:#795548}input[type=checkbox].brown-50.switch::before,input[type=radio].brown-50::after{background-color:#efebe9}input[type=checkbox].brown-100.switch::before,input[type=radio].brown-100::after{background-color:#d7ccc8}input[type=checkbox].brown-200.switch::before,input[type=radio].brown-200::after{background-color:#bcaaa4}input[type=checkbox].brown-300.switch::before,input[type=radio].brown-300::after{background-color:#a1887f}input[type=checkbox].brown-400.switch::before,input[type=radio].brown-400::after{background-color:#8d6e63}input[type=checkbox].brown-500.switch::before,input[type=radio].brown-500::after{background-color:#795548}input[type=checkbox].brown-600.switch::before,input[type=radio].brown-600::after{background-color:#6d4c41}input[type=checkbox].brown-700.switch::before,input[type=radio].brown-700::after{background-color:#5d4037}input[type=checkbox].brown-800.switch::before,input[type=radio].brown-800::after{background-color:#4e342e}input[type=checkbox].brown-900.switch::before,input[type=radio].brown-900::after{background-color:#3e2723}input[type=checkbox].grey.switch::before,input[type=radio].grey::after{background-color:#9e9e9e}input[type=checkbox].grey-50.switch::before,input[type=radio].grey-50::after{background-color:#fafafa}input[type=checkbox].grey-100.switch::before,input[type=radio].grey-100::after{background-color:#f5f5f5}input[type=checkbox].grey-200.switch::before,input[type=radio].grey-200::after{background-color:#eee}input[type=checkbox].grey-300.switch::before,input[type=radio].grey-300::after{background-color:#e0e0e0}input[type=checkbox].grey-400.switch::before,input[type=radio].grey-400::after{background-color:#bdbdbd}input[type=checkbox].grey-500.switch::before,input[type=radio].grey-500::after{background-color:#9e9e9e}input[type=checkbox].grey-600.switch::before,input[type=radio].grey-600::after{background-color:#757575}input[type=checkbox].grey-700.switch::before,input[type=radio].grey-700::after{background-color:#616161}input[type=checkbox].grey-800.switch::before,input[type=radio].grey-800::after{background-color:#424242}input[type=checkbox].grey-900.switch::before,input[type=radio].grey-900::after{background-color:#212121}input[type=checkbox].blue-grey.switch::before,input[type=radio].blue-grey::after{background-color:#607d8b}input[type=checkbox].blue-grey-50.switch::before,input[type=radio].blue-grey-50::after{background-color:#eceff1}input[type=checkbox].blue-grey-100.switch::before,input[type=radio].blue-grey-100::after{background-color:#cfd8dc}input[type=checkbox].blue-grey-200.switch::before,input[type=radio].blue-grey-200::after{background-color:#b0bec5}input[type=checkbox].blue-grey-300.switch::before,input[type=radio].blue-grey-300::after{background-color:#90a4ae}input[type=checkbox].blue-grey-400.switch::before,input[type=radio].blue-grey-400::after{background-color:#78909c}input[type=checkbox].blue-grey-500.switch::before,input[type=radio].blue-grey-500::after{background-color:#607d8b}input[type=checkbox].blue-grey-600.switch::before,input[type=radio].blue-grey-600::after{background-color:#546e7a}input[type=checkbox].blue-grey-700.switch::before,input[type=radio].blue-grey-700::after{background-color:#455a64}input[type=checkbox].blue-grey-800.switch::before,input[type=radio].blue-grey-800::after{background-color:#37474f}input[type=checkbox].blue-grey-900.switch::before,input[type=radio].blue-grey-900::after{background-color:#263238}input[type=checkbox].black.switch::before,input[type=radio].black::after{background-color:#000}.platform-ios input[type=radio].red-50::before{border-color:#ffebee}.platform-ios input[type=radio].red-100::before{border-color:#ffcdd2}.platform-ios input[type=radio].red-200::before{border-color:#ef9a9a}.platform-ios input[type=radio].red-300::before{border-color:#e57373}.platform-ios input[type=radio].red-400::before{border-color:#ef5350}.platform-ios input[type=radio].red-500::before{border-color:#f44336}.platform-ios input[type=radio].red-600::before{border-color:#e53935}.platform-ios input[type=radio].red-700::before{border-color:#d32f2f}.platform-ios input[type=radio].red-800::before{border-color:#c62828}.platform-ios input[type=radio].red-900::before{border-color:#b71c1c}.platform-ios input[type=radio].pink::before{border-color:#e91e63}.platform-ios input[type=radio].pink-50::before{border-color:#fce4ec}.platform-ios input[type=radio].pink-100::before{border-color:#f8bbd0}.platform-ios input[type=radio].pink-200::before{border-color:#f48fb1}.platform-ios input[type=radio].Pink-300::before{border-color:#f06292}.platform-ios input[type=radio].pink-400::before{border-color:#ec407a}.platform-ios input[type=radio].pink-500::before{border-color:#e91e63}.platform-ios input[type=radio].pink-600::before{border-color:#d81b60}.platform-ios input[type=radio].pink-700::before{border-color:#c2185b}.platform-ios input[type=radio].pink-800::before{border-color:#ad1457}.platform-ios input[type=radio].pink-900::before{border-color:#880e4f}.platform-ios input[type=radio].purple::before{border-color:#9c27b0}.platform-ios input[type=radio].purple-50::before{border-color:#f3e5f5}.platform-ios input[type=radio].purple-100::before{border-color:#e1bee7}.platform-ios input[type=radio].purple-200::before{border-color:#ce93d8}.platform-ios input[type=radio].Purple-300::before{border-color:#ba68c8}.platform-ios input[type=radio].Purple-400::before{border-color:#ab47bc}.platform-ios input[type=radio].purple-500::before{border-color:#9c27b0}.platform-ios input[type=radio].purple-600::before{border-color:#8e24aa}.platform-ios input[type=radio].purple-700::before{border-color:#7b1fa2}.platform-ios input[type=radio].purple-800::before{border-color:#6a1b9a}.platform-ios input[type=radio].purple-900::before{border-color:#4a148c}.platform-ios input[type=radio].deep-purple::before{border-color:#673ab7}.platform-ios input[type=radio].deep-purple-300::before{border-color:#9575cd}.platform-ios input[type=radio].deep-purple-400::before{border-color:#7e57c2}.platform-ios input[type=radio].deep-purple-500::before{border-color:#673ab7}.platform-ios input[type=radio].deep-purple-600::before{border-color:#5e35b1}.platform-ios input[type=radio].deep-purple-700::before{border-color:#512da8}.platform-ios input[type=radio].deep-purple-800::before{border-color:#4527a0}.platform-ios input[type=radio].deep-purple-900::before{border-color:#311b92}.platform-ios input[type=radio].indigo::before{border-color:#3f51b5}.platform-ios input[type=radio].indigo-50::before{border-color:#e8eaf6}.platform-ios input[type=radio].indigo-100::before{border-color:#c5cae9}.platform-ios input[type=radio].indigo-200::before{border-color:#9fa8da}.platform-ios input[type=radio].indigo-300::before{border-color:#7986cb}.platform-ios input[type=radio].indigo-400::before{border-color:#5c6bc0}.platform-ios input[type=radio].indigo-500::before{border-color:#3f51b5}.platform-ios input[type=radio].indigo-600::before{border-color:#3949ab}.platform-ios input[type=radio].indigo-700::before{border-color:#303f9f}.platform-ios input[type=radio].indigo-800::before{border-color:#283593}.platform-ios input[type=radio].indigo-900::before{border-color:#1a237e}.platform-ios input[type=radio].blue::before{border-color:#2196f3}.platform-ios input[type=radio].blue-50::before{border-color:#e3f2fd}.platform-ios input[type=radio].blue-100::before{border-color:#bbdefb}.platform-ios input[type=radio].blue-200::before{border-color:#90caf9}.platform-ios input[type=radio].blue-300::before{border-color:#64b5f6}.platform-ios input[type=radio].blue-400::before{border-color:#42a5f5}.platform-ios input[type=radio].blue-500::before{border-color:#2196f3}.platform-ios input[type=radio].blue-600::before{border-color:#1e88e5}.platform-ios input[type=radio].blue-700::before{border-color:#1976d2}.platform-ios input[type=radio].blue-800::before{border-color:#1565c0}.platform-ios input[type=radio].blue-900::before{border-color:#0d47a1}.platform-ios input[type=radio].light-blue::before{border-color:#03a9f4}.platform-ios input[type=radio].light-blue-50::before{border-color:#e1f5fe}.platform-ios input[type=radio].light-blue-100::before{border-color:#b3e5fc}.platform-ios input[type=radio].light-blue-200::before{border-color:#81d4fa}.platform-ios input[type=radio].light-blue-300::before{border-color:#4fc3f7}.platform-ios input[type=radio].light-blue-400::before{border-color:#29b6f6}.platform-ios input[type=radio].light-blue-500::before{border-color:#03a9f4}.platform-ios input[type=radio].light-blue-600::before{border-color:#039be5}.platform-ios input[type=radio].light-blue-700::before{border-color:#0288d1}.platform-ios input[type=radio].light-blue-800::before{border-color:#0277bd}.platform-ios input[type=radio].light-blue-900::before{border-color:#01579b}.platform-ios input[type=radio].cyan::before{border-color:#00bcd4}.platform-ios input[type=radio].cyan-50::before{border-color:#e0f7fa}.platform-ios input[type=radio].cyan-100::before{border-color:#b2ebf2}.platform-ios input[type=radio].cyan-200::before{border-color:#80deea}.platform-ios input[type=radio].cyan-300::before{border-color:#4dd0e1}.platform-ios input[type=radio].cyan-400::before{border-color:#26c6da}.platform-ios input[type=radio].cyan-500::before{border-color:#00bcd4}.platform-ios input[type=radio].cyan-600::before{border-color:#00acc1}.platform-ios input[type=radio].cyan-700::before{border-color:#0097a7}.platform-ios input[type=radio].cyan-800::before{border-color:#00838f}.platform-ios input[type=radio].cyan-900::before{border-color:#006064}.platform-ios input[type=radio].teal::before{border-color:#009688}.platform-ios input[type=radio].teal-50::before{border-color:#e0f2f1}.platform-ios input[type=radio].teal-100::before{border-color:#b2dfdb}.platform-ios input[type=radio].teal-200::before{border-color:#80cbc4}.platform-ios input[type=radio].teal-300::before{border-color:#4db6ac}.platform-ios input[type=radio].teal-400::before{border-color:#26a69a}.platform-ios input[type=radio].teal-500::before{border-color:#009688}.platform-ios input[type=radio].teal-600::before{border-color:#00897b}.platform-ios input[type=radio].teal-700::before{border-color:#00796b}.platform-ios input[type=radio].teal-800::before{border-color:#00695c}.platform-ios input[type=radio].teal-900::before{border-color:#004d40}.platform-ios input[type=radio].green::before{border-color:#4caf50}.platform-ios input[type=radio].green-50::before{border-color:#e8f5e9}.platform-ios input[type=radio].green-100::before{border-color:#c8e6c9}.platform-ios input[type=radio].green-200::before{border-color:#a5d6a7}.platform-ios input[type=radio].green-300::before{border-color:#81c784}.platform-ios input[type=radio].green-400::before{border-color:#66bb6a}.platform-ios input[type=radio].green-500::before{border-color:#4caf50}.platform-ios input[type=radio].green-600::before{border-color:#43a047}.platform-ios input[type=radio].green-700::before{border-color:#388e3c}.platform-ios input[type=radio].green-800::before{border-color:#2e7d32}.platform-ios input[type=radio].green-900::before{border-color:#1b5e20}.platform-ios input[type=radio].light-green::before{border-color:#8bc34a}.platform-ios input[type=radio].light-green-50::before{border-color:#f1f8e9}.platform-ios input[type=radio].light-green-100::before{border-color:#dcedc8}.platform-ios input[type=radio].light-green-200::before{border-color:#c5e1a5}.platform-ios input[type=radio].light-green-300::before{border-color:#aed581}.platform-ios input[type=radio].light-green-400::before{border-color:#9ccc65}.platform-ios input[type=radio].light-green-500::before{border-color:#8bc34a}.platform-ios input[type=radio].light-green-600::before{border-color:#7cb342}.platform-ios input[type=radio].light-green-700::before{border-color:#689f38}.platform-ios input[type=radio].light-green-800::before{border-color:#558b2f}.platform-ios input[type=radio].light-green-900::before{border-color:#33691e}.platform-ios input[type=radio].lime::before{border-color:#cddc39}.platform-ios input[type=radio].lime-50::before{border-color:#f9fbe7}.platform-ios input[type=radio].lime-100::before{border-color:#f0f4c3}.platform-ios input[type=radio].lime-200::before{border-color:#e6ee9c}.platform-ios input[type=radio].lime-300::before{border-color:#dce775}.platform-ios input[type=radio].lime-400::before{border-color:#d4e157}.platform-ios input[type=radio].lime-500::before{border-color:#cddc39}.platform-ios input[type=radio].lime-600::before{border-color:#c0ca33}.platform-ios input[type=radio].lime-700::before{border-color:#afb42b}.platform-ios input[type=radio].lime-800::before{border-color:#9e9d24}.platform-ios input[type=radio].lime-900::before{border-color:#827717}.platform-ios input[type=radio].yellow::before{border-color:#ffeb3b}.platform-ios input[type=radio].yellow-50::before{border-color:#fffde7}.platform-ios input[type=radio].yellow-100::before{border-color:#fff9c4}.platform-ios input[type=radio].yellow-200::before{border-color:#fff59d}.platform-ios input[type=radio].yellow-300::before{border-color:#fff176}.platform-ios input[type=radio].yellow-500::before{border-color:#ffeb3b}.platform-ios input[type=radio].yellow-600::before{border-color:#fdd835}.platform-ios input[type=radio].yellow-700::before{border-color:#fbc02d}.platform-ios input[type=radio].yellow-800::before{border-color:#f9a825}.platform-ios input[type=radio].yellow-900::before{border-color:#f57f17}.platform-ios input[type=radio].amber-50::before{border-color:#fff8e1}.platform-ios input[type=radio].amber-100::before{border-color:#ffecb3}.platform-ios input[type=radio].amber-200::before{border-color:#ffe082}.platform-ios input[type=radio].amber-300::before{border-color:#ffd54f}.platform-ios input[type=radio].amber-500::before{border-color:#ffc107}.platform-ios input[type=radio].amber-600::before{border-color:#ffb300}.platform-ios input[type=radio].amber-700::before{border-color:#ffa000}.platform-ios input[type=radio].amber-800::before{border-color:#ff8f00}.platform-ios input[type=radio].amber-900::before{border-color:#ff6f00}.platform-ios input[type=radio].orange-50::before{border-color:#fff3e0}.platform-ios input[type=radio].orange-100::before{border-color:#ffe0b2}.platform-ios input[type=radio].orange-200::before{border-color:#ffcc80}.platform-ios input[type=radio].orange-300::before{border-color:#ffb74d}.platform-ios input[type=radio].orange-400::before{border-color:#ffa726}.platform-ios input[type=radio].orange-500::before{border-color:#ff9800}.platform-ios input[type=radio].orange-600::before{border-color:#fb8c00}.platform-ios input[type=radio].orange-700::before{border-color:#f57c00}.platform-ios input[type=radio].orange-800::before{border-color:#ef6c00}.platform-ios input[type=radio].orange-900::before{border-color:#e65100}.platform-ios input[type=radio].deep-orange::before{border-color:#ff5722}.platform-ios input[type=radio].deep-orange-50::before{border-color:#fbe9e7}.platform-ios input[type=radio].deep-orange-100::before{border-color:#ffccbc}.platform-ios input[type=radio].deep-orange-200::before{border-color:#ffab91}.platform-ios input[type=radio].deep-orange-300::before{border-color:#ff8a65}.platform-ios input[type=radio].deep-orange-400::before{border-color:#ff7043}.platform-ios input[type=radio].deep-orange-500::before{border-color:#ff5722}.platform-ios input[type=radio].deep-orange-600::before{border-color:#f4511e}.platform-ios input[type=radio].deep-orange-700::before{border-color:#e64a19}.platform-ios input[type=radio].deep-orange-800::before{border-color:#d84315}.platform-ios input[type=radio].deep-orange-900::before{border-color:#bf360c}.platform-ios input[type=radio].brown::before{border-color:#795548}.platform-ios input[type=radio].brown-50::before{border-color:#efebe9}.platform-ios input[type=radio].brown-100::before{border-color:#d7ccc8}.platform-ios input[type=radio].brown-200::before{border-color:#bcaaa4}.platform-ios input[type=radio].brown-300::before{border-color:#a1887f}.platform-ios input[type=radio].brown-400::before{border-color:#8d6e63}.platform-ios input[type=radio].brown-500::before{border-color:#795548}.platform-ios input[type=radio].brown-600::before{border-color:#6d4c41}.platform-ios input[type=radio].brown-700::before{border-color:#5d4037}.platform-ios input[type=radio].brown-800::before{border-color:#4e342e}.platform-ios input[type=radio].brown-900::before{border-color:#3e2723}.platform-ios input[type=radio].grey::before{border-color:#9e9e9e}.platform-ios input[type=radio].grey-50::before{border-color:#fafafa}.platform-ios input[type=radio].grey-100::before{border-color:#f5f5f5}.platform-ios input[type=radio].grey-200::before{border-color:#eee}.platform-ios input[type=radio].grey-300::before{border-color:#e0e0e0}.platform-ios input[type=radio].grey-400::before{border-color:#bdbdbd}.platform-ios input[type=radio].grey-500::before{border-color:#9e9e9e}.platform-ios input[type=radio].grey-600::before{border-color:#757575}.platform-ios input[type=radio].grey-700::before{border-color:#616161}.platform-ios input[type=radio].grey-800::before{border-color:#424242}.platform-ios input[type=radio].grey-900::before{border-color:#212121}.platform-ios input[type=radio].blue-grey::before{border-color:#607d8b}.platform-ios input[type=radio].blue-grey-50::before{border-color:#eceff1}.platform-ios input[type=radio].blue-grey-100::before{border-color:#cfd8dc}.platform-ios input[type=radio].blue-grey-200::before{border-color:#b0bec5}.platform-ios input[type=radio].blue-grey-300::before{border-color:#90a4ae}.platform-ios input[type=radio].blue-grey-400::before{border-color:#78909c}.platform-ios input[type=radio].blue-grey-500::before{border-color:#607d8b}.platform-ios input[type=radio].blue-grey-600::before{border-color:#546e7a}.platform-ios input[type=radio].blue-grey-700::before{border-color:#455a64}.platform-ios input[type=radio].blue-grey-800::before{border-color:#37474f}.platform-ios input[type=radio].blue-grey-900::before{border-color:#263238}.platform-ios input[type=radio].black::before{border-color:#000}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/list.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/list.min.css
new file mode 100755
index 0000000..0a6114a
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/list.min.css
@@ -0,0 +1 @@
+.list{width:100%;position:relative;border:1px solid #F2F5F5}.list .item{padding:10px 15px;;display:inline-block;border-bottom:1px solid #F2F5F5;width:100%;position:relative;font-size:18px}.list .item.hidden{display:none}.list ol,.list ul{list-style:none}.list .item.space-small{padding-top:5px;padding-bottom:5px}.list .item.mark{border-right:0;border-top:0}.item .block{display:-webkit-box;display:flex}.list .item.mark.margin-button{border-bottom:0;margin-bottom:10px}.list .item.no-space-top{padding-top:0!important}.list .item.no-space-bottom{padding-bottom:0!important}.list .item.row{display:-moz-flex;display:-ms-flexbox;display:flex}.list.no-border{border:0}.list .item.no-border.border-bottom,.list.no-border .item.border-bottom{border-bottom-width:1px;border-bottom-style:solid}.list .item.no-border,.list.no-border .item{border:none}.list .item.cover{padding:0;margin-left:20px;height:200px;width:-webkit-calc(100% - 40px);width:-moz-calc(100% - 40px);width:calc(100% - 40px)}.list .item.full{padding:0;display:flex}.list .item h1,.list .item h2{font-size:16px;margin:0;padding:0}.list .item h1{margin-top:7px}.list .item p{font-size:14px;margin:0;padding:0;line-height:20px}.list .item:last-child{border-bottom:0}.list .left{margin-right:10px;min-width:25px}.list .right{margin-right:20px;position:absolute;top:0;right:0;height:100%;display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-align:center;-webkit-align-items:center;-webkit-box-align:center;align-items:center}.list .right i{margin-left:5px}.list .align-top{-ms-flex-align:center;-webkit-align-items:center;align-items:baseline;margin-top:10px}.list .avatar{height:50px}.avatar-badge{position:absolute;margin-left:-4px;margin-top:-3px;border-radius:8px}.list .item small,.list .item small .icon{font-size:14px}.list .item .icon{font-size:18px}.list .item .icon.text-huge{font-size:32px}.list .left .icon,.list .right .icon{vertical-align:-webkit-baseline-middle}.list .border-big{border-width:3px;border-style:solid}.list .item[onclick]:active,.list a.item:active{background-color:rgba(0,0,0,.1);cursor:pointer}.list .item .right .icon,.list .item .right.icon{font-size:24px;padding:0;margin:0}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/loading.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/loading.min.css
new file mode 100755
index 0000000..65c5258
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/loading.min.css
@@ -0,0 +1 @@
+.alert-loading .alert{padding:24px;text-align:center}.loading-circle{fill:transparent;stroke:#009688;stroke-width:5;-webkit-animation:dash 2s ease infinite,rotate 2s linear infinite;-moz-animation:dash 2s ease infinite,rotate 2s linear infinite;-o-animation:dash 2s ease infinite,rotate 2s linear infinite;animation:dash 2s ease infinite,rotate 2s linear infinite;margin:auto}.loading-circle.loading-element{zoom:.55;margin-top:-20px;margin-left:-20px;position:absolute}button .loading-circle.loading-element{left:50%;margin-left:-20px;top:50%;margin-top:-20px}.loading-circle.with-message.loading-element{margin-left:-50px;margin-top:17px;top:auto;left:auto}.loading-circle.loading-element.left{float:left;position:inherit;margin-left:0}.loading-circle.loading-element.right{float:right;position:inherit;margin-left:0}.loading-circle.white-loading{stroke:rgba(255,255,255,.8)}.loading-circle.with-message{margin-right:10px}.platform-ios .loading-circle{fill:#868686;-webkit-animation:none;-moz-animation:none;-o-animation:none;animation:none;stroke:none;stroke-width:0}.platform-ios .loading-circle.loading-element.white-loading{fill:rgba(255,255,255,.8)}.platform-ios .loading-circle path:nth-of-type(1){-webkit-animation:pulse 1s infinite linear;-moz-animation:pulse 1s infinite linear;-o-animation:pulse 1s infinite linear;animation:pulse 1s infinite linear}.platform-ios .loading-circle path:nth-of-type(2){-webkit-animation:pulse 1s -83ms infinite linear;-moz-animation:pulse 1s -83ms infinite linear;-o-animation:pulse 1s -83ms infinite linear;animation:pulse 1s -83ms infinite linear}.platform-ios .loading-circle path:nth-of-type(3){-webkit-animation:pulse 1s -.166s infinite linear;-moz-animation:pulse 1s -.166s infinite linear;-o-animation:pulse 1s -.166s infinite linear;animation:pulse 1s -.166s infinite linear}.platform-ios .loading-circle path:nth-of-type(4){-webkit-animation:pulse 1s -.249s infinite linear;-moz-animation:pulse 1s -.249s infinite linear;-o-animation:pulse 1s -.249s infinite linear;animation:pulse 1s -.249s infinite linear}.platform-ios .loading-circle path:nth-of-type(5){-webkit-animation:pulse 1s -.332s infinite linear;-moz-animation:pulse 1s -.332s infinite linear;-o-animation:pulse 1s -.332s infinite linear;animation:pulse 1s -.332s infinite linear}.platform-ios .loading-circle path:nth-of-type(6){-webkit-animation:pulse 1s -.415s infinite linear;-moz-animation:pulse 1s -.415s infinite linear;-o-animation:pulse 1s -.415s infinite linear;animation:pulse 1s -.415s infinite linear}.platform-ios .loading-circle path:nth-of-type(7){-webkit-animation:pulse 1s -.498s infinite linear;-moz-animation:pulse 1s -.498s infinite linear;-o-animation:pulse 1s -.498s infinite linear;animation:pulse 1s -.498s infinite linear}.platform-ios .loading-circle path:nth-of-type(8){-webkit-animation:pulse 1s -.581s infinite linear;-moz-animation:pulse 1s -.581s infinite linear;-o-animation:pulse 1s -.581s infinite linear;animation:pulse 1s -.581s infinite linear}.platform-ios .loading-circle path:nth-of-type(9){-webkit-animation:pulse 1s -.664s infinite linear;-moz-animation:pulse 1s -.664s infinite linear;-o-animation:pulse 1s -.664s infinite linear;animation:pulse 1s -.664s infinite linear}.platform-ios .loading-circle path:nth-of-type(10){-webkit-animation:pulse 1s -.747s infinite linear;-moz-animation:pulse 1s -.747s infinite linear;-o-animation:pulse 1s -.747s infinite linear;animation:pulse 1s -.747s infinite linear}.platform-ios .alert-loading .loading-circle path:nth-of-type(11){-webkit-animation:pulse 1s -.83s infinite linear;-moz-animation:pulse 1s -.83s infinite linear;-o-animation:pulse 1s -.83s infinite linear;animation:pulse 1s -.83s infinite linear}.platform-ios .alert-loading .loading-circle path:nth-of-type(12){-webkit-animation:pulse 1s -.913s infinite linear;-moz-animation:pulse 1s -.913s infinite linear;-o-animation:pulse 1s -.913s infinite linear;animation:pulse 1s -.913s infinite linear}.platform-ios .loading-circle.white-loading path:nth-of-type(1){-webkit-animation:pulse-white 1s infinite linear;-moz-animation:pulse-white 1s infinite linear;-o-animation:pulse-white 1s infinite linear;animation:pulse-white 1s infinite linear}.platform-ios .loading-circle.white-loading path:nth-of-type(2){-webkit-animation:pulse-white 1s -83ms infinite linear;-moz-animation:pulse-white 1s -83ms infinite linear;-o-animation:pulse-white 1s -83ms infinite linear;animation:pulse-white 1s -83ms infinite linear}.platform-ios .loading-circle.white-loading path:nth-of-type(3){-webkit-animation:pulse-white 1s -.166s infinite linear;-moz-animation:pulse-white 1s -.166s infinite linear;-o-animation:pulse-white 1s -.166s infinite linear;animation:pulse-white 1s -.166s infinite linear}.platform-ios .loading-circle.white-loading path:nth-of-type(4){-webkit-animation:pulse-white 1s -.249s infinite linear;-moz-animation:pulse-white 1s -.249s infinite linear;-o-animation:pulse-white 1s -.249s infinite linear;animation:pulse-white 1s -.249s infinite linear}.platform-ios .loading-circle.white-loading path:nth-of-type(5){-webkit-animation:pulse-white 1s -.332s infinite linear;-moz-animation:pulse-white 1s -.332s infinite linear;-o-animation:pulse-white 1s -.332s infinite linear;animation:pulse-white 1s -.332s infinite linear}.platform-ios .loading-circle.white-loading path:nth-of-type(6){-webkit-animation:pulse-white 1s -.415s infinite linear;-moz-animation:pulse-white 1s -.415s infinite linear;-o-animation:pulse-white 1s -.415s infinite linear;animation:pulse-white 1s -.415s infinite linear}.platform-ios .loading-circle.white-loading path:nth-of-type(7){-webkit-animation:pulse-white 1s -.498s infinite linear;-moz-animation:pulse-white 1s -.498s infinite linear;-o-animation:pulse-white 1s -.498s infinite linear;animation:pulse-white 1s -.498s infinite linear}.platform-ios .loading-circle.white-loading path:nth-of-type(8){-webkit-animation:pulse-white 1s -.581s infinite linear;-moz-animation:pulse-white 1s -.581s infinite linear;-o-animation:pulse-white 1s -.581s infinite linear;animation:pulse-white 1s -.581s infinite linear}.platform-ios .loading-circle.white-loading path:nth-of-type(9){-webkit-animation:pulse-white 1s -.664s infinite linear;-moz-animation:pulse-white 1s -.664s infinite linear;-o-animation:pulse-white 1s -.664s infinite linear;animation:pulse-white 1s -.664s infinite linear}.platform-ios .loading-circle.white-loading path:nth-of-type(10){-webkit-animation:pulse-white 1s -.747s infinite linear;-moz-animation:pulse-white 1s -.747s infinite linear;-o-animation:pulse-white 1s -.747s infinite linear;animation:pulse-white 1s -.747s infinite linear}.platform-ios .alert-loading.white-loading .loading-circle path:nth-of-type(11){-webkit-animation:pulse-white 1s -.83s infinite linear;-moz-animation:pulse-white 1s -.83s infinite linear;-o-animation:pulse-white 1s -.83s infinite linear;animation:pulse-white 1s -.83s infinite linear}.platform-ios .alert-loading.white-loading .loading-circle path:nth-of-type(12){-webkit-animation:pulse-white 1s -.913s infinite linear;-moz-animation:pulse-white 1s -.913s infinite linear;-o-animation:pulse-white 1s -.913s infinite linear;animation:pulse-white 1s -.913s infinite linear}@-webkit-keyframes pulse{50%{fill:#868686}to{fill:rgba(134,134,134,.4)}}@-moz-keyframes pulse{50%{fill:#868686}to{fill:rgba(134,134,134,.4)}}@-o-keyframes pulse{50%{fill:#868686}to{fill:rgba(134,134,134,.4)}}@keyframes pulse{50%{fill:#868686}to{fill:rgba(134,134,134,.4)}}@-webkit-keyframes pulse-white{50%{fill:rgba(255,255,255,.8)}to{fill:rgba(255,255,255,.2)}}@-moz-keyframes pulse-white{50%{fill:rgba(255,255,255,.8)}to{fill:rgba(255,255,255,.2)}}@-o-keyframes pulse-white{50%{fill:rgba(255,255,255,.8)}to{fill:rgba(255,255,255,.2)}}@keyframes pulse-white{50%{fill:rgba(255,255,255,.8)}to{fill:rgba(255,255,255,.2)}}@-webkit-keyframes iosIntro{from{-webkit-transform:scale(0);opacity:0}to{-webkit-transform:scale(1);opacity:1}}@-moz-keyframes iosIntro{from{-moz-transform:scale(0);opacity:0}to{-moz-transform:scale(1);opacity:1}}@-o-keyframes iosIntro{from{-o-transform:scale(0);opacity:0}to{-o-transform:scale(1);opacity:1}}@keyframes iosIntro{from{transform:scale(0);opacity:0}to{transform:scale(1);opacity:1}}.alert-mobileui.alert-loading .alert p{margin:0;margin-top:15px!important;text-align:center}@-webkit-keyframes dash{0%{stroke-dasharray:1,95;stroke-dashoffset:0}50%{stroke-dasharray:85,95;stroke-dashoffset:-25}100%{stroke-dasharray:85,95;stroke-dashoffset:-93}}@-moz-keyframes dash{0%{stroke-dasharray:1,95;stroke-dashoffset:0}50%{stroke-dasharray:85,95;stroke-dashoffset:-25}100%{stroke-dasharray:85,95;stroke-dashoffset:-93}}@-o-keyframes dash{0%{stroke-dasharray:1,95;stroke-dashoffset:0}50%{stroke-dasharray:85,95;stroke-dashoffset:-25}100%{stroke-dasharray:85,95;stroke-dashoffset:-93}}@keyframes dash{0%{stroke-dasharray:1,95;stroke-dashoffset:0}50%{stroke-dasharray:85,95;stroke-dashoffset:-25}100%{stroke-dasharray:85,95;stroke-dashoffset:-93}}@-webkit-keyframes rotate{0%{-webkit-transform:rotate(0)}100%{-webkit-transform:rotate(360deg)}}@-moz-keyframes rotate{0%{-moz-transform:rotate(0)}100%{-moz-transform:rotate(360deg)}}@-o-keyframes rotate{0%{-o-transform:rotate(0)}100%{-o-transform:rotate(360deg)}}@keyframes rotate{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/menu.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/menu.min.css
new file mode 100755
index 0000000..dbfc1cd
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/menu.min.css
@@ -0,0 +1 @@
+.menu{position:fixed;top:0;left:0;width:300px;height:100%;z-index:99999;transform:translateX(-312px);-webkit-transform:translateX(-312px);-moz-transform:translateX(-312px);-o-transform:translateX(-312px);transition-duration:280ms;-webkit-transition-duration:280ms;-moz-transition-duration:280ms;-o-transition-duration:280ms;box-shadow:0 0 10px rgba(0,0,0,.25);overflow:auto}.menu.cover{width:300px}.menu.menu-right{right:0;left:auto;transform:translateX(105%);-webkit-transform:translateX(105%);-moz-transform:translateX(105%);-o-transform:translateX(105%)}.menu.open{transform:translateX(0);-webkit-transform:translateX(0);-moz-transform:translateX(0);-o-transform:translateX(0)}.menu.menu-right.open{margin-left:-312px}.platform-ios .backdrop-menu{opacity:.01}.platform-ios .menu{width:264px;box-shadow:none;transition-duration:0s;-webkit-transition-duration:0s;-moz-transition-duration:0s;-o-transition-duration:0s;transform:translateX(-264px);-webkit-transform:translateX(-264px);-moz-transform:translateX(-264px);-o-transform:translateX(-264px);box-shadow:none}.platform-ios .menu.cover{width:264px}.platform-ios .menu.menu-right{transform:translateX(105%);-webkit-transform:translateX(105%);-moz-transform:translateX(105%);-o-transform:translateX(105%);transition-duration:0s;-webkit-transition-duration:0s;-moz-transition-duration:0s;-o-transition-duration:0s}.platform-ios .menu.open{transform:translateX(-264px);-webkit-transform:translateX(-264px);-moz-transform:translateX(-264px);-o-transform:translateX(-264px);margin-left:-1px}.platform-ios .menu.menu-right.open{margin-left:-263px;transform:none;-webkit-transform:none;-moz-transform:none;-o-transform:none;box-shadow:0 0 10px rgba(0,0,0,.25)}.platform-ios .body,.platform-ios body{transition-duration:0s;-webkit-transition-duration:0s;-moz-transition-duration:0s;-o-transition-duration:0s}.platform-ios .body.side-menu,.platform-ios.side-menu{transform:translateX(264px);-webkit-transform:translateX(264px);-moz-transform:translateX(264px);-o-transform:translateX(264px);border-left:1px solid rgba(0,0,0,.15);overflow:hidden}.platform-ios .body.side-menu-right,.platform-ios .header.side-menu-right,.platform-ios.side-menu-right{margin-left:-264px}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/mobileui-colors.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/mobileui-colors.min.css
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/mobileui-colors.min.css
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/mobileuijs.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/mobileuijs.min.css
new file mode 100755
index 0000000..d4e2495
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/mobileuijs.min.css
@@ -0,0 +1 @@
+[data]{display:none!important}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/page.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/page.min.css
new file mode 100755
index 0000000..b0e3759
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/page.min.css
@@ -0,0 +1 @@
+.page{position:absolute;top:60px;left:0;display:block;width:100%;height:100%;opacity:.01;contain:strict;background-color:#fff;overflow:auto}.platform-ios .page{top:0;left:100%;opacity:1}.page.show{opacity:1;top:0}.platform-ios .page.show{opacity:1;top:0;left:0}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/popover.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/popover.min.css
new file mode 100755
index 0000000..9b4ffcb
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/popover.min.css
@@ -0,0 +1 @@
+.popover{position:absolute;z-index:10001;border-radius:3px;box-shadow:0 3px 12px 2px rgba(0,0,0,.3);overflow:hidden;display:none;background-color:#fff}.platform-ios .popover{border-radius:10px;box-shadow:none}.popover-arrow{z-index:10000;position:absolute;width:14px;height:14px;border-radius:3px;background-color:#fff;-webkit-transform:rotate(45deg);transform:rotate(45deg)}.popover.show{display:block}.popover .item,.popover .list{border-width:0}.popover .list .item h1{margin:0}.popover .item{display:table!important;overflow:hidden;white-space:nowrap;padding:10px}.platform-ios .popover .item{border-width:1px}.popover .item:first-child{padding-top:15px}.popover .item:last-child{padding-bottom:15px}.backdrop-popover{opacity:.01}.platform-ios .backdrop-popover{opacity:.08}.popover .item[data]{display:none!important}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/progress-circle.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/progress-circle.min.css
new file mode 100755
index 0000000..5e0642d
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/progress-circle.min.css
@@ -0,0 +1 @@
+.progress-circle,.progress-circle-js{margin:auto}.progress-circle-title{opacity:.8}.progress-circle-subtitle{opacity:.6}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/progress-circular.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/progress-circular.min.css
new file mode 100755
index 0000000..169eb97
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/progress-circular.min.css
@@ -0,0 +1 @@
+.progress-circular{position:relative;font-size:30px;font-weight:300;width:100px;height:100px;border-radius:50%;background-color:rgba(0,0,0,.2);display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center}.progress-circular>span{text-align:center;width:100%;white-space:nowrap;-webkit-box-flex:0;-webkit-flex:none;-ms-flex:none;flex:none;z-index:5}.progress-circular::before{content:'';position:absolute;width:100px;height:100px;clip:rect(0,1em,1em,.5em)}.progress-circular::after{position:absolute;content:" ";border-radius:50%;background-color:#f5f5f5;width:94px;height:94px;text-align:center;white-space:nowrap;-webkit-box-flex:0;-webkit-flex:none;-ms-flex:none;flex:none}.progress-circular.background-blue::after{background-color:#2196f3!important}.progress-circular.background-blue>span{color:rgba(255,255,255,.9)}.progress-circular>span::before{content:'';position:absolute;left:0;top:0;border:2px solid #fff;width:100px;height:100px;clip:rect(0,150px,150px,0);border-radius:50%;-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg);text-align:center;white-space:nowrap;-webkit-box-flex:0;-webkit-flex:none;-ms-flex:none;flex:none}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/progress-semicircle.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/progress-semicircle.min.css
new file mode 100755
index 0000000..1fa5a65
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/progress-semicircle.min.css
@@ -0,0 +1 @@
+.progress-semicircle,.progress-semicircle-js{margin:auto}.progress-semicircle-title{opacity:.8}.progress-semicircle-subtitle{opacity:.6}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/progressbarjs.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/progressbarjs.min.css
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/progressbarjs.min.css
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/swiper.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/swiper.min.css
new file mode 100755
index 0000000..1beff1c
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/swiper.min.css
@@ -0,0 +1 @@
+.swiper-container{margin-left:auto;margin-right:auto;position:relative;overflow:hidden;z-index:1}.swiper-container-fullscreen{height:100%}.swipper-gallery{height:300px}.swiper-container-no-flexbox .swiper-slide{float:left}.swiper-container-vertical>.swiper-wrapper{-webkit-box-orient:vertical;-moz-box-orient:vertical;-ms-flex-direction:column;-webkit-flex-direction:column;flex-direction:column}.swiper-wrapper{position:relative;width:100%;z-index:1;height:100%;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex;-webkit-transition-property:-webkit-transform;-moz-transition-property:-moz-transform;-o-transition-property:-o-transform;-ms-transition-property:-ms-transform;transition-property:transform;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.swiper-container-android .swiper-slide,.swiper-wrapper{-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);-o-transform:translate(0,0);-ms-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.swiper-container-multirow>.swiper-wrapper{-webkit-box-lines:multiple;-moz-box-lines:multiple;-ms-flex-wrap:wrap;-webkit-flex-wrap:wrap;flex-wrap:wrap}.swiper-container-free-mode>.swiper-wrapper{-webkit-transition-timing-function:ease-out;-moz-transition-timing-function:ease-out;-ms-transition-timing-function:ease-out;-o-transition-timing-function:ease-out;transition-timing-function:ease-out;margin:0 auto}.swiper-slide{-webkit-flex-shrink:0;-ms-flex:0 0 auto;flex-shrink:0;width:100%;height:100%;position:relative}.swiper-slide.vertical-align-center{display:flex;flex-direction:column;justify-content:center;padding:30px;text-align:center}.swiper-slide i{font-size:120px}.swiper-slide h1{font-size:40px;font-weight:600;width:100%}.swiper-slide h2{font-size:30px;font-weight:600;width:100%}.swiper-slide .margin-bottom{margin-bottom:25px}.swiper-container-autoheight,.swiper-container-autoheight .swiper-slide{height:auto}.swiper-container-autoheight .swiper-wrapper{-webkit-box-align:start;-ms-flex-align:start;-webkit-align-items:flex-start;align-items:flex-start;-webkit-transition-property:-webkit-transform,height;-moz-transition-property:-moz-transform;-o-transition-property:-o-transform;-ms-transition-property:-ms-transform;transition-property:transform,height}.swiper-container .swiper-notification{position:absolute;left:0;top:0;pointer-events:none;opacity:0;z-index:-1000}.swiper-wp8-horizontal{-ms-touch-action:pan-y;touch-action:pan-y}.swiper-wp8-vertical{-ms-touch-action:pan-x;touch-action:pan-x}.swiper-button-next,.swiper-button-prev{position:absolute;top:50%;width:27px;height:44px;margin-top:-22px;z-index:10;cursor:pointer;-moz-background-size:27px 44px;-webkit-background-size:27px 44px;background-size:27px 44px;background-position:center;background-repeat:no-repeat}.swiper-button-next.swiper-button-disabled,.swiper-button-prev.swiper-button-disabled{opacity:.35;cursor:auto;pointer-events:none}.swiper-button-prev,.swiper-container-rtl .swiper-button-next{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23007aff'%2F%3E%3C%2Fsvg%3E");left:10px;right:auto}.swiper-button-prev.swiper-button-black,.swiper-container-rtl .swiper-button-next.swiper-button-black{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23000000'%2F%3E%3C%2Fsvg%3E")}.swiper-button-prev.swiper-button-white,.swiper-container-rtl .swiper-button-next.swiper-button-white{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23ffffff'%2F%3E%3C%2Fsvg%3E")}.swiper-button-next,.swiper-container-rtl .swiper-button-prev{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23007aff'%2F%3E%3C%2Fsvg%3E");right:10px;left:auto}.swiper-button-next.swiper-button-black,.swiper-container-rtl .swiper-button-prev.swiper-button-black{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23000000'%2F%3E%3C%2Fsvg%3E")}.swiper-button-next.swiper-button-white,.swiper-container-rtl .swiper-button-prev.swiper-button-white{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23ffffff'%2F%3E%3C%2Fsvg%3E")}.swiper-pagination{position:absolute;text-align:center;-webkit-transition:.3s;-moz-transition:.3s;-o-transition:.3s;transition:.3s;-webkit-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0);z-index:10}.swiper-pagination.swiper-pagination-hidden{opacity:0}.swiper-container-horizontal>.swiper-pagination-bullets,.swiper-pagination-custom,.swiper-pagination-fraction{bottom:10px;left:0;width:100%}.swiper-pagination-bullet{width:8px;height:8px;display:inline-block;border-radius:100%;background:#000;opacity:.2}button.swiper-pagination-bullet{border:none;margin:0;padding:0;box-shadow:none;-moz-appearance:none;-ms-appearance:none;-webkit-appearance:none;appearance:none}.swiper-pagination-clickable .swiper-pagination-bullet{cursor:pointer}.swiper-pagination-white .swiper-pagination-bullet{background:#fff}.swiper-pagination-bullet-active{opacity:1;background:#007aff}.swiper-pagination-white .swiper-pagination-bullet-active{background:#fff}.swiper-pagination-black .swiper-pagination-bullet-active{background:#000}.swiper-container-vertical>.swiper-pagination-bullets{right:10px;top:50%;-webkit-transform:translate3d(0,-50%,0);-moz-transform:translate3d(0,-50%,0);-o-transform:translate(0,-50%);-ms-transform:translate3d(0,-50%,0);transform:translate3d(0,-50%,0)}.swiper-container-vertical>.swiper-pagination-bullets .swiper-pagination-bullet{margin:5px 0;display:block}.swiper-container-horizontal>.swiper-pagination-bullets .swiper-pagination-bullet{margin:0 5px}.swiper-pagination-progress{background:rgba(0,0,0,.25);position:absolute}.swiper-pagination-progress .swiper-pagination-progressbar{background:#007aff;position:absolute;left:0;top:0;width:100%;height:100%;-webkit-transform:scale(0);-ms-transform:scale(0);-o-transform:scale(0);transform:scale(0);-webkit-transform-origin:left top;-moz-transform-origin:left top;-ms-transform-origin:left top;-o-transform-origin:left top;transform-origin:left top}.swiper-container-rtl .swiper-pagination-progress .swiper-pagination-progressbar{-webkit-transform-origin:right top;-moz-transform-origin:right top;-ms-transform-origin:right top;-o-transform-origin:right top;transform-origin:right top}.swiper-container-horizontal>.swiper-pagination-progress{width:100%;height:4px;left:0;top:0}.swiper-container-vertical>.swiper-pagination-progress{width:4px;height:100%;left:0;top:0}.swiper-pagination-progress.swiper-pagination-white{background:rgba(255,255,255,.5)}.swiper-pagination-progress.swiper-pagination-white .swiper-pagination-progressbar{background:#fff}.swiper-pagination-progress.swiper-pagination-black .swiper-pagination-progressbar{background:#000}.swiper-container-3d{-webkit-perspective:1200px;-moz-perspective:1200px;-o-perspective:1200px;perspective:1200px}.swiper-container-3d .swiper-cube-shadow,.swiper-container-3d .swiper-slide,.swiper-container-3d .swiper-slide-shadow-bottom,.swiper-container-3d .swiper-slide-shadow-left,.swiper-container-3d .swiper-slide-shadow-right,.swiper-container-3d .swiper-slide-shadow-top,.swiper-container-3d .swiper-wrapper{-webkit-transform-style:preserve-3d;-moz-transform-style:preserve-3d;-ms-transform-style:preserve-3d;transform-style:preserve-3d}.swiper-container-3d .swiper-slide-shadow-bottom,.swiper-container-3d .swiper-slide-shadow-left,.swiper-container-3d .swiper-slide-shadow-right,.swiper-container-3d .swiper-slide-shadow-top{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none;z-index:10}.swiper-container-3d .swiper-slide-shadow-left{background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,0)));background-image:-webkit-linear-gradient(right,rgba(0,0,0,.5),rgba(0,0,0,0));background-image:-moz-linear-gradient(right,rgba(0,0,0,.5),rgba(0,0,0,0));background-image:-o-linear-gradient(right,rgba(0,0,0,.5),rgba(0,0,0,0));background-image:linear-gradient(to left,rgba(0,0,0,.5),rgba(0,0,0,0))}.swiper-container-3d .swiper-slide-shadow-right{background-image:-webkit-gradient(linear,right top,left top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,0)));background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5),rgba(0,0,0,0));background-image:-moz-linear-gradient(left,rgba(0,0,0,.5),rgba(0,0,0,0));background-image:-o-linear-gradient(left,rgba(0,0,0,.5),rgba(0,0,0,0));background-image:linear-gradient(to right,rgba(0,0,0,.5),rgba(0,0,0,0))}.swiper-container-3d .swiper-slide-shadow-top{background-image:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,.5)),to(rgba(0,0,0,0)));background-image:-webkit-linear-gradient(bottom,rgba(0,0,0,.5),rgba(0,0,0,0));background-image:-moz-linear-gradient(bottom,rgba(0,0,0,.5),rgba(0,0,0,0));background-image:-o-linear-gradient(bottom,rgba(0,0,0,.5),rgba(0,0,0,0));background-image:linear-gradient(to top,rgba(0,0,0,.5),rgba(0,0,0,0))}.swiper-container-3d .swiper-slide-shadow-bottom{background-image:-webkit-gradient(linear,left bottom,left top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,0)));background-image:-webkit-linear-gradient(top,rgba(0,0,0,.5),rgba(0,0,0,0));background-image:-moz-linear-gradient(top,rgba(0,0,0,.5),rgba(0,0,0,0));background-image:-o-linear-gradient(top,rgba(0,0,0,.5),rgba(0,0,0,0));background-image:linear-gradient(to bottom,rgba(0,0,0,.5),rgba(0,0,0,0))}.swiper-container-coverflow .swiper-wrapper,.swiper-container-flip .swiper-wrapper{-ms-perspective:1200px}.swiper-container-cube,.swiper-container-flip{overflow:visible}.swiper-container-cube .swiper-slide,.swiper-container-flip .swiper-slide{pointer-events:none;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;backface-visibility:hidden;z-index:1}.swiper-container-cube .swiper-slide .swiper-slide,.swiper-container-flip .swiper-slide .swiper-slide{pointer-events:none}.swiper-container-cube .swiper-slide-active,.swiper-container-cube .swiper-slide-active .swiper-slide-active,.swiper-container-flip .swiper-slide-active,.swiper-container-flip .swiper-slide-active .swiper-slide-active{pointer-events:auto}.swiper-container-cube .swiper-slide-shadow-bottom,.swiper-container-cube .swiper-slide-shadow-left,.swiper-container-cube .swiper-slide-shadow-right,.swiper-container-cube .swiper-slide-shadow-top,.swiper-container-flip .swiper-slide-shadow-bottom,.swiper-container-flip .swiper-slide-shadow-left,.swiper-container-flip .swiper-slide-shadow-right,.swiper-container-flip .swiper-slide-shadow-top{z-index:0;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;backface-visibility:hidden}.swiper-container-cube .swiper-slide{visibility:hidden;-webkit-transform-origin:0 0;-moz-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;width:100%;height:100%}.swiper-container-cube.swiper-container-rtl .swiper-slide{-webkit-transform-origin:100% 0;-moz-transform-origin:100% 0;-ms-transform-origin:100% 0;transform-origin:100% 0}.swiper-container-cube .swiper-slide-active,.swiper-container-cube .swiper-slide-next,.swiper-container-cube .swiper-slide-next+.swiper-slide,.swiper-container-cube .swiper-slide-prev{pointer-events:auto;visibility:visible}.swiper-container-cube .swiper-cube-shadow{position:absolute;left:0;bottom:0;width:100%;height:100%;background:#000;opacity:.6;-webkit-filter:blur(50px);filter:blur(50px);z-index:0}.swiper-container-fade.swiper-container-free-mode .swiper-slide{-webkit-transition-timing-function:ease-out;-moz-transition-timing-function:ease-out;-ms-transition-timing-function:ease-out;-o-transition-timing-function:ease-out;transition-timing-function:ease-out}.swiper-container-fade .swiper-slide{pointer-events:none;-webkit-transition-property:opacity;-moz-transition-property:opacity;-o-transition-property:opacity;transition-property:opacity}.swiper-container-fade .swiper-slide .swiper-slide{pointer-events:none}.swiper-container-fade .swiper-slide-active,.swiper-container-fade .swiper-slide-active .swiper-slide-active{pointer-events:auto}.swiper-zoom-container{width:100%;height:100%;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex;-webkit-box-pack:center;-moz-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-box-align:center;-moz-box-align:center;-ms-flex-align:center;-webkit-align-items:center;align-items:center;text-align:center}.swiper-zoom-container>canvas,.swiper-zoom-container>img,.swiper-zoom-container>svg{max-width:100%;max-height:100%;object-fit:contain}.swiper-scrollbar{border-radius:10px;position:relative;-ms-touch-action:none;background:rgba(0,0,0,.1)}.swiper-container-horizontal>.swiper-scrollbar{position:absolute;left:1%;bottom:3px;z-index:50;height:5px;width:98%}.swiper-container-vertical>.swiper-scrollbar{position:absolute;right:3px;top:1%;z-index:50;width:5px;height:98%}.swiper-scrollbar-drag{height:100%;width:100%;position:relative;background:rgba(0,0,0,.5);border-radius:10px;left:0;top:0}.swiper-scrollbar-cursor-drag{cursor:move}.swiper-lazy-preloader{width:42px;height:42px;position:absolute;left:50%;top:50%;margin-left:-21px;margin-top:-21px;z-index:10;-webkit-transform-origin:50%;-moz-transform-origin:50%;transform-origin:50%;-webkit-animation:swiper-preloader-spin 1s steps(12,end) infinite;-moz-animation:swiper-preloader-spin 1s steps(12,end) infinite;animation:swiper-preloader-spin 1s steps(12,end) infinite}.swiper-lazy-preloader:after{display:block;content:"";width:100%;height:100%;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20viewBox%3D'0%200%20120%20120'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20xmlns%3Axlink%3D'http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink'%3E%3Cdefs%3E%3Cline%20id%3D'l'%20x1%3D'60'%20x2%3D'60'%20y1%3D'7'%20y2%3D'27'%20stroke%3D'%236c6c6c'%20stroke-width%3D'11'%20stroke-linecap%3D'round'%2F%3E%3C%2Fdefs%3E%3Cg%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(30%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(60%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(90%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(120%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(150%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.37'%20transform%3D'rotate(180%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.46'%20transform%3D'rotate(210%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.56'%20transform%3D'rotate(240%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.66'%20transform%3D'rotate(270%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.75'%20transform%3D'rotate(300%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.85'%20transform%3D'rotate(330%2060%2C60)'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");background-position:50%;-webkit-background-size:100%;background-size:100%;background-repeat:no-repeat}.swiper-lazy-preloader-white:after{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20viewBox%3D'0%200%20120%20120'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20xmlns%3Axlink%3D'http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink'%3E%3Cdefs%3E%3Cline%20id%3D'l'%20x1%3D'60'%20x2%3D'60'%20y1%3D'7'%20y2%3D'27'%20stroke%3D'%23fff'%20stroke-width%3D'11'%20stroke-linecap%3D'round'%2F%3E%3C%2Fdefs%3E%3Cg%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(30%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(60%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(90%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(120%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(150%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.37'%20transform%3D'rotate(180%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.46'%20transform%3D'rotate(210%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.56'%20transform%3D'rotate(240%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.66'%20transform%3D'rotate(270%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.75'%20transform%3D'rotate(300%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.85'%20transform%3D'rotate(330%2060%2C60)'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E")}@-webkit-keyframes swiper-preloader-spin{100%{-webkit-transform:rotate(360deg)}}@keyframes swiper-preloader-spin{100%{transform:rotate(360deg)}}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/tab.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/tab.min.css
new file mode 100755
index 0000000..9904384
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/tab.min.css
@@ -0,0 +1 @@
+.tab{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.tab-content{display:none}.tab-content.active{display:block}.tab button{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;font-size:13px!important;text-transform:uppercase;opacity:.6;margin:0}.footer.tab button.icon{margin-top:0}.header.tab.shadow{box-shadow:2px 2px 3px rgba(0,0,0,.2)}.platform-ios .tab button{text-transform:none}.tab button.active{opacity:1}.tab button.icon{font-size:14px;line-height:16px}.tab button::before{display:block;font-size:25px}.tab button.active::after{content:'';position:absolute;bottom:0;left:0;width:100%;height:3px;/*background-color:#fff*/}.tab button .badge{width:20px;height:20px;margin-left:10px;text-align:center;font-size:14px;font-weight:700;border-radius:50%;margin-top:10px;position:absolute;line-height:18px;padding-top:1px}.tab.footer button.active::after{top:0}.header.tab.footer.shadow{box-shadow:-2px -2px 3px rgba(0,0,0,.2)}.platform-ios .tab button.active::after{display:none}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/timeline.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/timeline.min.css
new file mode 100755
index 0000000..0b85d62
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/timeline.min.css
@@ -0,0 +1 @@
+.timeline{font-size:14px;padding:2px}.timeline .marker{position:relative}.timeline .marker::before{background:rgba(0,0,0,.3);content:"";height:100%;width:2px;margin:0 auto;position:absolute;margin-top:10px;z-index:0;left:18px}.timeline .row:last-child .marker::before{display:none}.timeline .icon-circle,.timeline .icon-circle-big,.timeline .icon-circle-small{margin:0 auto;margin-top:10px;position:absolute;margin-left:7px}.timeline .icon-circle i::before,.timeline .icon-circle-big i::before,.timeline .icon-circle-small i::before{margin-top:4px}.timeline .avatar-group{-webkit-transform:translateX(10px);transform:translateX(10px)}.timeline .avatar-photo{background:#eaeaea;width:30px;height:30px;overflow:hidden;text-align:center;border:1px solid #d7d2d2}.timeline .avatar-photo small{margin-top:100px}.timeline .circle-more{background:#eaeaea;width:30px;height:30px;overflow:hidden;text-align:center;border-radius:50%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#bdbbbb;border:1px solid #d7d2d2;font-size:12px}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/css/toast.min.css b/platforms/android/app/src/main/assets/www/mobileui/css/toast.min.css
new file mode 100755
index 0000000..8ee986c
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/css/toast.min.css
@@ -0,0 +1 @@
+.toast{z-index:999999;position:absolute;left:0;padding:20px;text-align:center;width:100%;opacity:0;transition:opacity .25s ease-in-out;-moz-transition:opacity .25s ease-in-out;-webkit-transition:opacity .25s ease-in-out}.toast.show{opacity:1}.toast.toast-bottom{bottom:10px}.toast.toast-top{top:10px}.toast.toast-center{display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex;justify-content:center;-webkit-box-align:center;-moz-box-align:center;-ms-flex-align:center;-webkit-align-items:center;align-items:center;height:100%;top:0}.toast div{padding:10px;display:inline-block}.toast .full{display:block;width:100%}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/alert.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/alert.min.js
new file mode 100755
index 0000000..78b8212
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/alert.min.js
@@ -0,0 +1 @@
+window.alert=function(e,t){var a={};"object"==typeof e?a=e:(a.message=e,a.title=t),a.id||(a.id="ALERT"+(new Date).getTime()),a.buttons&&a.buttons.length||(a.buttons=[{label:"OK",onclick:function(){closeAlert()}}]);var n=document.getElementsByTagName("body")[0];event&&event.target&&event.target.parentNode&&event.target.parentNode.className.indexOf("body")>=0&&(n=event.target.parentNode);var d=document.createElement("div");d.className="backdrop show backdrop-alert",d.id=a.id+"_BACKDROP",n.appendChild(d);var l=document.createElement("div");l.className="alert-mobileui",l.id=a.id,d.parentNode.appendChild(l);var o=document.createElement("div");if(a.class||(a.class="white"),o.className="alert "+a.class,a.width&&(o.style.maxWidth=a.width),l.appendChild(o),a.title){var r="<h1>"+a.title+"</h1>";o.insertAdjacentHTML("beforeend",r)}if(a.message){var s="<p>"+a.message+"</p>";o.insertAdjacentHTML("beforeend",s)}a.template&&o.insertAdjacentHTML("beforeend",document.getElementById(a.template).innerHTML);var c=document.createElement("div");c.className="buttons",o.appendChild(c);for(var i in a.buttons){var m=document.createElement("button");a.buttons[i].class||(a.buttons[i].class="text-teal"),m.className=a.buttons[i].class;var p=document.createTextNode(a.buttons[i].label);m.appendChild(p),a.buttons[i].onclick||(a.buttons[i].onclick=closeAlert),m.addEventListener("click",a.buttons[i].onclick),c.appendChild(m)}var u=new CustomEvent("alertOpened");document.dispatchEvent(u)},window.closeAlert=function(e){alertId=e,alertId||(alertId=event.target.parentNode.parentNode.parentNode.id);var t=document.getElementById(alertId);t.parentNode.removeChild(t);var a=document.getElementById(alertId+"_BACKDROP");a.parentNode.removeChild(a)};
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/base.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/base.min.js
new file mode 100755
index 0000000..d6d093c
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/base.min.js
@@ -0,0 +1 @@
+var userAgent=navigator.userAgent||navigator.vendor||window.opera,SO={name:"unknown",code:0};/android/i.test(userAgent)&&(SO.name="Android",SO.class="platform-android",SO.code=1);/iPad|iPhone|iPod/.test(userAgent)&&!window.MSStream&&(SO.name="iOS",SO.class="platform-ios",SO.code=2);/windows phone/i.test(userAgent)&&(SO.name="Windows Phone",SO.class="platform-wp",SO.code=3);SO.class&&document.getElementsByTagName("body").length&&(document.getElementsByTagName("body")[0].className+=" "+SO.class);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/button.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/button.min.js
new file mode 100755
index 0000000..4e7054c
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/button.min.js
@@ -0,0 +1 @@
+document.addEventListener("click",function(e){if(1!==SO.code)return!1;var t=e.target;if("button"!==t.tagName.toLowerCase())return!1;var o=t.getBoundingClientRect(),s=t.querySelector(".ripple");s||((s=document.createElement("span")).className="ripple",s.style.height=s.style.width=Math.max(o.width,o.height)+"px",t.appendChild(s)),s.classList.remove("show");var a=e.pageY-o.top-s.offsetHeight/2-document.body.scrollTop,l=e.pageX-o.left-s.offsetWidth/2-document.body.scrollLeft;return s.style.top=a+"px",s.style.left=l+"px",s.classList.add("show"),!1},!1);
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/chart-bar.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/chart-bar.min.js
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/chart-bar.min.js
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/chartist-plugin-tooltip.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/chartist-plugin-tooltip.min.js
new file mode 100755
index 0000000..259aae0
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/chartist-plugin-tooltip.min.js
@@ -0,0 +1 @@
+!function(t,e){"function"==typeof define&&define.amd?define(["chartist"],function(o){return t.returnExportsGlobal=e(o)}):"object"==typeof exports?module.exports=e(require("chartist")):t["Chartist.plugins.tooltip"]=e(Chartist)}(this,function(t){return function(t,e,o){"use strict";function n(t){a(t,"tooltip-show")||(t.className=t.className+" tooltip-show")}function i(t){var e=new RegExp("tooltip-show\\s*","gi");t.className=t.className.replace(e,"").trim()}function a(t,e){return(" "+t.getAttribute("class")+" ").indexOf(" "+e+" ")>-1}function r(t,e){do{t=t.nextSibling}while(t&&!a(t,e));return t}var s={currency:void 0,currencyFormatCallback:void 0,tooltipOffset:{x:0,y:-20},anchorToPoint:!1,appendToBody:!1,class:void 0,pointClass:"ct-point"};o.plugins=o.plugins||{},o.plugins.tooltip=function(c){return c=o.extend({},s,c),function(s){function l(t,e,o){f.addEventListener(t,function(t){e&&!a(t.target,e)||o(t)})}function p(e){g=g||d.offsetHeight;var o,n,i=-(m=m||d.offsetWidth)/2+c.tooltipOffset.x,a=-g+c.tooltipOffset.y;if(c.appendToBody)d.style.top=e.pageY+a+"px",d.style.left=e.pageX+i+"px";else{var r=f.getBoundingClientRect(),s=e.pageX-r.left-t.pageXOffset,l=e.pageY-r.top-t.pageYOffset;!0===c.anchorToPoint&&e.target.x2&&e.target.y2&&(o=parseInt(e.target.x2.baseVal.value),n=parseInt(e.target.y2.baseVal.value)),d.style.top=(n||l)+a+"px",d.style.left=(o||s)+i+"px"}}var u=c.pointClass;s.constructor.name==o.Bar.prototype.constructor.name?u="ct-bar":s.constructor.name==o.Pie.prototype.constructor.name&&(u=s.options.donut?"ct-slice-donut":"ct-slice-pie");var f=s.container,d=f.querySelector(".chartist-tooltip");d||(d=e.createElement("div"),d.className=c.class?"chartist-tooltip "+c.class:"chartist-tooltip",c.appendToBody?e.body.appendChild(d):f.appendChild(d));var g=d.offsetHeight,m=d.offsetWidth;i(d),l("mouseover",u,function(t){var i=t.target,a="",l=(s instanceof o.Pie?i:i.parentNode)?i.parentNode.getAttribute("ct:meta")||i.parentNode.getAttribute("ct:series-name"):"",u=i.getAttribute("ct:meta")||l||"",f=!!u,h=i.getAttribute("ct:value");if(c.transformTooltipTextFnc&&"function"==typeof c.transformTooltipTextFnc&&(h=c.transformTooltipTextFnc(h)),c.tooltipFnc&&"function"==typeof c.tooltipFnc)a=c.tooltipFnc(u,h);else{if(c.metaIsHTML){var y=e.createElement("textarea");y.innerHTML=u,u=y.value}if(u='<span class="chartist-tooltip-meta">'+u+"</span>",f)a+=u+"<br>";else if(s instanceof o.Pie){var v=r(i,"ct-label");v&&(a+=function(t){return t.innerText||t.textContent}(v)+"<br>")}h&&(c.currency&&(h=void 0!=c.currencyFormatCallback?c.currencyFormatCallback(h,c):c.currency+h.replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g,"$1,")),h='<span class="chartist-tooltip-value">'+h+"</span>",a+=h)}a&&(d.innerHTML=a,p(t),n(d),g=d.offsetHeight,m=d.offsetWidth)}),l("mouseout",u,function(){i(d)}),l("mousemove",null,function(t){!1===c.anchorToPoint&&p(t)})}}}(window,document,t),t.plugins.tooltip});
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/chartist.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/chartist.min.js
new file mode 100755
index 0000000..924d43a
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/chartist.min.js
@@ -0,0 +1 @@
+!function(e,t){"function"==typeof define&&define.amd?define("Chartist",[],function(){return e.Chartist=t()}):"object"==typeof module&&module.exports?module.exports=t():e.Chartist=t()}(this,function(){var e={version:"0.11.0"};return function(e,t,i){"use strict";i.namespaces={svg:"http://www.w3.org/2000/svg",xmlns:"http://www.w3.org/2000/xmlns/",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",ct:"http://gionkunz.github.com/chartist-js/ct"},i.noop=function(e){return e},i.alphaNumerate=function(e){return String.fromCharCode(97+e%26)},i.extend=function(e){var t,n,s;for(e=e||{},t=1;t<arguments.length;t++){n=arguments[t];for(var r in n)"object"!=typeof(s=n[r])||null===s||s instanceof Array?e[r]=s:e[r]=i.extend(e[r],s)}return e},i.replaceAll=function(e,t,i){return e.replace(new RegExp(t,"g"),i)},i.ensureUnit=function(e,t){return"number"==typeof e&&(e+=t),e},i.quantity=function(e){if("string"==typeof e){var t=/^(\d+)\s*(.*)$/g.exec(e);return{value:+t[1],unit:t[2]||void 0}}return{value:e}},i.querySelector=function(e){return e instanceof Node?e:t.querySelector(e)},i.times=function(e){return Array.apply(null,new Array(e))},i.sum=function(e,t){return e+(t||0)},i.mapMultiply=function(e){return function(t){return t*e}},i.mapAdd=function(e){return function(t){return t+e}},i.serialMap=function(e,t){var n=[],s=Math.max.apply(null,e.map(function(e){return e.length}));return i.times(s).forEach(function(i,s){var r=e.map(function(e){return e[s]});n[s]=t.apply(null,r)}),n},i.roundWithPrecision=function(e,t){var n=Math.pow(10,t||i.precision);return Math.round(e*n)/n},i.precision=8,i.escapingMap={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"},i.serialize=function(e){return null===e||void 0===e?e:("number"==typeof e?e=""+e:"object"==typeof e&&(e=JSON.stringify({data:e})),Object.keys(i.escapingMap).reduce(function(e,t){return i.replaceAll(e,t,i.escapingMap[t])},e))},i.deserialize=function(e){if("string"!=typeof e)return e;e=Object.keys(i.escapingMap).reduce(function(e,t){return i.replaceAll(e,i.escapingMap[t],t)},e);try{e=void 0!==(e=JSON.parse(e)).data?e.data:e}catch(e){}return e},i.createSvg=function(e,t,n,s){var r;return t=t||"100%",n=n||"100%",Array.prototype.slice.call(e.querySelectorAll("svg")).filter(function(e){return e.getAttributeNS(i.namespaces.xmlns,"ct")}).forEach(function(t){e.removeChild(t)}),r=new i.Svg("svg").attr({width:t,height:n}).addClass(s),r._node.style.width=t,r._node.style.height=n,e.appendChild(r._node),r},i.normalizeData=function(e,t,n){var s,r={raw:e,normalized:{}};return r.normalized.series=i.getDataArray({series:e.series||[]},t,n),s=r.normalized.series.every(function(e){return e instanceof Array})?Math.max.apply(null,r.normalized.series.map(function(e){return e.length})):r.normalized.series.length,r.normalized.labels=(e.labels||[]).slice(),Array.prototype.push.apply(r.normalized.labels,i.times(Math.max(0,s-r.normalized.labels.length)).map(function(){return""})),t&&i.reverseData(r.normalized),r},i.safeHasProperty=function(e,t){return null!==e&&"object"==typeof e&&e.hasOwnProperty(t)},i.isDataHoleValue=function(e){return null===e||void 0===e||"number"==typeof e&&isNaN(e)},i.reverseData=function(e){e.labels.reverse(),e.series.reverse();for(var t=0;t<e.series.length;t++)"object"==typeof e.series[t]&&void 0!==e.series[t].data?e.series[t].data.reverse():e.series[t]instanceof Array&&e.series[t].reverse()},i.getDataArray=function(e,t,n){function s(e){if(i.safeHasProperty(e,"value"))return s(e.value);if(i.safeHasProperty(e,"data"))return s(e.data);if(e instanceof Array)return e.map(s);if(!i.isDataHoleValue(e)){if(n){var t={};return"string"==typeof n?t[n]=i.getNumberOrUndefined(e):t.y=i.getNumberOrUndefined(e),t.x=e.hasOwnProperty("x")?i.getNumberOrUndefined(e.x):t.x,t.y=e.hasOwnProperty("y")?i.getNumberOrUndefined(e.y):t.y,t}return i.getNumberOrUndefined(e)}}return e.series.map(s)},i.normalizePadding=function(e,t){return t=t||0,"number"==typeof e?{top:e,right:e,bottom:e,left:e}:{top:"number"==typeof e.top?e.top:t,right:"number"==typeof e.right?e.right:t,bottom:"number"==typeof e.bottom?e.bottom:t,left:"number"==typeof e.left?e.left:t}},i.getMetaData=function(e,t){var i=e.data?e.data[t]:e[t];return i?i.meta:void 0},i.orderOfMagnitude=function(e){return Math.floor(Math.log(Math.abs(e))/Math.LN10)},i.projectLength=function(e,t,i){return t/i.range*e},i.getAvailableHeight=function(e,t){return Math.max((i.quantity(t.height).value||e.height())-(t.chartPadding.top+t.chartPadding.bottom)-t.axisX.offset,0)},i.getHighLow=function(e,t,n){function s(e){if(void 0!==e)if(e instanceof Array)for(var t=0;t<e.length;t++)s(e[t]);else{var i=n?+e[n]:+e;a&&i>r.high&&(r.high=i),o&&i<r.low&&(r.low=i)}}var r={high:void 0===(t=i.extend({},t,n?t["axis"+n.toUpperCase()]:{})).high?-Number.MAX_VALUE:+t.high,low:void 0===t.low?Number.MAX_VALUE:+t.low},a=void 0===t.high,o=void 0===t.low;return(a||o)&&s(e),(t.referenceValue||0===t.referenceValue)&&(r.high=Math.max(t.referenceValue,r.high),r.low=Math.min(t.referenceValue,r.low)),r.high<=r.low&&(0===r.low?r.high=1:r.low<0?r.high=0:r.high>0?r.low=0:(r.high=1,r.low=0)),r},i.isNumeric=function(e){return null!==e&&isFinite(e)},i.isFalseyButZero=function(e){return!e&&0!==e},i.getNumberOrUndefined=function(e){return i.isNumeric(e)?+e:void 0},i.isMultiValue=function(e){return"object"==typeof e&&("x"in e||"y"in e)},i.getMultiValue=function(e,t){return i.isMultiValue(e)?i.getNumberOrUndefined(e[t||"y"]):i.getNumberOrUndefined(e)},i.rho=function(e){function t(e,i){return e%i==0?i:t(i,e%i)}function i(e){return e*e+1}if(1===e)return e;var n,s=2,r=2;if(e%2==0)return 2;do{s=i(s)%e,r=i(i(r))%e,n=t(Math.abs(s-r),e)}while(1===n);return n},i.getBounds=function(e,t,n,s){function r(e,t){return e===(e+=t)&&(e*=1+(t>0?p:-p)),e}var a,o,l,u=0,c={high:t.high,low:t.low};c.valueRange=c.high-c.low,c.oom=i.orderOfMagnitude(c.valueRange),c.step=Math.pow(10,c.oom),c.min=Math.floor(c.low/c.step)*c.step,c.max=Math.ceil(c.high/c.step)*c.step,c.range=c.max-c.min,c.numberOfSteps=Math.round(c.range/c.step);var h=i.projectLength(e,c.step,c)<n,d=s?i.rho(c.range):0;if(s&&i.projectLength(e,1,c)>=n)c.step=1;else if(s&&d<c.step&&i.projectLength(e,d,c)>=n)c.step=d;else for(;;){if(h&&i.projectLength(e,c.step,c)<=n)c.step*=2;else{if(h||!(i.projectLength(e,c.step/2,c)>=n))break;if(c.step/=2,s&&c.step%1!=0){c.step*=2;break}}if(u++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}var p=2.221e-16;for(c.step=Math.max(c.step,p),o=c.min,l=c.max;o+c.step<=c.low;)o=r(o,c.step);for(;l-c.step>=c.high;)l=r(l,-c.step);c.min=o,c.max=l,c.range=c.max-c.min;var m=[];for(a=c.min;a<=c.max;a=r(a,c.step)){var f=i.roundWithPrecision(a);f!==m[m.length-1]&&m.push(f)}return c.values=m,c},i.polarToCartesian=function(e,t,i,n){var s=(n-90)*Math.PI/180;return{x:e+i*Math.cos(s),y:t+i*Math.sin(s)}},i.createChartRect=function(e,t,n){var s=!(!t.axisX&&!t.axisY),r=s?t.axisY.offset:0,a=s?t.axisX.offset:0,o=e.width()||i.quantity(t.width).value||0,l=e.height()||i.quantity(t.height).value||0,u=i.normalizePadding(t.chartPadding,n);o=Math.max(o,r+u.left+u.right),l=Math.max(l,a+u.top+u.bottom);var c={padding:u,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}};return s?("start"===t.axisX.position?(c.y2=u.top+a,c.y1=Math.max(l-u.bottom,c.y2+1)):(c.y2=u.top,c.y1=Math.max(l-u.bottom-a,c.y2+1)),"start"===t.axisY.position?(c.x1=u.left+r,c.x2=Math.max(o-u.right,c.x1+1)):(c.x1=u.left,c.x2=Math.max(o-u.right-r,c.x1+1))):(c.x1=u.left,c.x2=Math.max(o-u.right,c.x1+1),c.y2=u.top,c.y1=Math.max(l-u.bottom,c.y2+1)),c},i.createGrid=function(e,t,n,s,r,a,o,l){var u={};u[n.units.pos+"1"]=e,u[n.units.pos+"2"]=e,u[n.counterUnits.pos+"1"]=s,u[n.counterUnits.pos+"2"]=s+r;var c=a.elem("line",u,o.join(" "));l.emit("draw",i.extend({type:"grid",axis:n,index:t,group:a,element:c},u))},i.createGridBackground=function(e,t,i,n){var s=e.elem("rect",{x:t.x1,y:t.y2,width:t.width(),height:t.height()},i,!0);n.emit("draw",{type:"gridBackground",group:e,element:s})},i.createLabel=function(e,n,s,r,a,o,l,u,c,h,d){var p,m={};if(m[a.units.pos]=e+l[a.units.pos],m[a.counterUnits.pos]=l[a.counterUnits.pos],m[a.units.len]=n,m[a.counterUnits.len]=Math.max(0,o-10),h){var f=t.createElement("span");f.className=c.join(" "),f.setAttribute("xmlns",i.namespaces.xhtml),f.innerText=r[s],f.style[a.units.len]=Math.round(m[a.units.len])+"px",f.style[a.counterUnits.len]=Math.round(m[a.counterUnits.len])+"px",p=u.foreignObject(f,i.extend({style:"overflow: visible;"},m))}else p=u.elem("text",m,c.join(" ")).text(r[s]);d.emit("draw",i.extend({type:"label",axis:a,index:s,group:u,element:p,text:r[s]},m))},i.getSeriesOption=function(e,t,i){if(e.name&&t.series&&t.series[e.name]){var n=t.series[e.name];return n.hasOwnProperty(i)?n[i]:t[i]}return t[i]},i.optionsProvider=function(t,n,s){function r(t){var r=a;if(a=i.extend({},l),n)for(o=0;o<n.length;o++){e.matchMedia(n[o][0]).matches&&(a=i.extend(a,n[o][1]))}s&&t&&s.emit("optionsChanged",{previousOptions:r,currentOptions:a})}var a,o,l=i.extend({},t),u=[];if(!e.matchMedia)throw"window.matchMedia not found! Make sure you're using a polyfill.";if(n)for(o=0;o<n.length;o++){var c=e.matchMedia(n[o][0]);c.addListener(r),u.push(c)}return r(),{removeMediaQueryListeners:function(){u.forEach(function(e){e.removeListener(r)})},getCurrentOptions:function(){return i.extend({},a)}}},i.splitIntoSegments=function(e,t,n){n=i.extend({},{increasingX:!1,fillHoles:!1},n);for(var s=[],r=!0,a=0;a<e.length;a+=2)void 0===i.getMultiValue(t[a/2].value)?n.fillHoles||(r=!0):(n.increasingX&&a>=2&&e[a]<=e[a-2]&&(r=!0),r&&(s.push({pathCoordinates:[],valueData:[]}),r=!1),s[s.length-1].pathCoordinates.push(e[a],e[a+1]),s[s.length-1].valueData.push(t[a/2]));return s}}(window,document,e),function(e,t,i){"use strict";i.Interpolation={},i.Interpolation.none=function(e){return e=i.extend({},{fillHoles:!1},e),function(t,n){for(var s=new i.Svg.Path,r=!0,a=0;a<t.length;a+=2){var o=t[a],l=t[a+1],u=n[a/2];void 0!==i.getMultiValue(u.value)?(r?s.move(o,l,!1,u):s.line(o,l,!1,u),r=!1):e.fillHoles||(r=!0)}return s}},i.Interpolation.simple=function(e){e=i.extend({},{divisor:2,fillHoles:!1},e);var t=1/Math.max(1,e.divisor);return function(n,s){for(var r,a,o,l=new i.Svg.Path,u=0;u<n.length;u+=2){var c=n[u],h=n[u+1],d=(c-r)*t,p=s[u/2];void 0!==p.value?(void 0===o?l.move(c,h,!1,p):l.curve(r+d,a,c-d,h,c,h,!1,p),r=c,a=h,o=p):e.fillHoles||(r=c=o=void 0)}return l}},i.Interpolation.cardinal=function(e){e=i.extend({},{tension:1,fillHoles:!1},e);var t=Math.min(1,Math.max(0,e.tension)),n=1-t;return function s(r,a){var o=i.splitIntoSegments(r,a,{fillHoles:e.fillHoles});if(o.length){if(o.length>1){var l=[];return o.forEach(function(e){l.push(s(e.pathCoordinates,e.valueData))}),i.Svg.Path.join(l)}if(r=o[0].pathCoordinates,a=o[0].valueData,r.length<=4)return i.Interpolation.none()(r,a);for(var u=(new i.Svg.Path).move(r[0],r[1],!1,a[0]),c=0,h=r.length;h-2>c;c+=2){var d=[{x:+r[c-2],y:+r[c-1]},{x:+r[c],y:+r[c+1]},{x:+r[c+2],y:+r[c+3]},{x:+r[c+4],y:+r[c+5]}];h-4===c?d[3]=d[2]:c||(d[0]={x:+r[c],y:+r[c+1]}),u.curve(t*(-d[0].x+6*d[1].x+d[2].x)/6+n*d[2].x,t*(-d[0].y+6*d[1].y+d[2].y)/6+n*d[2].y,t*(d[1].x+6*d[2].x-d[3].x)/6+n*d[2].x,t*(d[1].y+6*d[2].y-d[3].y)/6+n*d[2].y,d[2].x,d[2].y,!1,a[(c+2)/2])}return u}return i.Interpolation.none()([])}},i.Interpolation.monotoneCubic=function(e){return e=i.extend({},{fillHoles:!1},e),function t(n,s){var r=i.splitIntoSegments(n,s,{fillHoles:e.fillHoles,increasingX:!0});if(r.length){if(r.length>1){var a=[];return r.forEach(function(e){a.push(t(e.pathCoordinates,e.valueData))}),i.Svg.Path.join(a)}if(n=r[0].pathCoordinates,s=r[0].valueData,n.length<=4)return i.Interpolation.none()(n,s);var o,l,u=[],c=[],h=n.length/2,d=[],p=[],m=[],f=[];for(o=0;o<h;o++)u[o]=n[2*o],c[o]=n[2*o+1];for(o=0;o<h-1;o++)m[o]=c[o+1]-c[o],f[o]=u[o+1]-u[o],p[o]=m[o]/f[o];for(d[0]=p[0],d[h-1]=p[h-2],o=1;o<h-1;o++)0===p[o]||0===p[o-1]||p[o-1]>0!=p[o]>0?d[o]=0:(d[o]=3*(f[o-1]+f[o])/((2*f[o]+f[o-1])/p[o-1]+(f[o]+2*f[o-1])/p[o]),isFinite(d[o])||(d[o]=0));for(l=(new i.Svg.Path).move(u[0],c[0],!1,s[0]),o=0;o<h-1;o++)l.curve(u[o]+f[o]/3,c[o]+d[o]*f[o]/3,u[o+1]-f[o]/3,c[o+1]-d[o+1]*f[o]/3,u[o+1],c[o+1],!1,s[o+1]);return l}return i.Interpolation.none()([])}},i.Interpolation.step=function(e){return e=i.extend({},{postpone:!0,fillHoles:!1},e),function(t,n){for(var s,r,a,o=new i.Svg.Path,l=0;l<t.length;l+=2){var u=t[l],c=t[l+1],h=n[l/2];void 0!==h.value?(void 0===a?o.move(u,c,!1,h):(e.postpone?o.line(u,r,!1,a):o.line(s,c,!1,h),o.line(u,c,!1,h)),s=u,r=c,a=h):e.fillHoles||(s=r=a=void 0)}return o}}}(window,document,e),function(e,t,i){"use strict";i.EventEmitter=function(){var e=[];return{addEventHandler:function(t,i){e[t]=e[t]||[],e[t].push(i)},removeEventHandler:function(t,i){e[t]&&(i?(e[t].splice(e[t].indexOf(i),1),0===e[t].length&&delete e[t]):delete e[t])},emit:function(t,i){e[t]&&e[t].forEach(function(e){e(i)}),e["*"]&&e["*"].forEach(function(e){e(t,i)})}}}}(window,document,e),function(e,t,i){"use strict";i.Class={extend:function(e,t){var n=t||this.prototype||i.Class,s=Object.create(n);i.Class.cloneDefinitions(s,e);var r=function(){var e,t=s.constructor||function(){};return e=this===i?Object.create(s):this,t.apply(e,Array.prototype.slice.call(arguments,0)),e};return r.prototype=s,r.super=n,r.extend=this.extend,r},cloneDefinitions:function(){var e=function(e){var t=[];if(e.length)for(var i=0;i<e.length;i++)t.push(e[i]);return t}(arguments),t=e[0];return e.splice(1,e.length-1).forEach(function(e){Object.getOwnPropertyNames(e).forEach(function(i){delete t[i],Object.defineProperty(t,i,Object.getOwnPropertyDescriptor(e,i))})}),t}}}(window,document,e),function(e,t,i){"use strict";function n(){e.addEventListener("resize",this.resizeListener),this.optionsProvider=i.optionsProvider(this.options,this.responsiveOptions,this.eventEmitter),this.eventEmitter.addEventHandler("optionsChanged",function(){this.update()}.bind(this)),this.options.plugins&&this.options.plugins.forEach(function(e){e instanceof Array?e[0](this,e[1]):e(this)}.bind(this)),this.eventEmitter.emit("data",{type:"initial",data:this.data}),this.createChart(this.optionsProvider.getCurrentOptions()),this.initializeTimeoutId=void 0}i.Base=i.Class.extend({constructor:function(e,t,s,r,a){this.container=i.querySelector(e),this.data=t||{},this.data.labels=this.data.labels||[],this.data.series=this.data.series||[],this.defaultOptions=s,this.options=r,this.responsiveOptions=a,this.eventEmitter=i.EventEmitter(),this.supportsForeignObject=i.Svg.isSupported("Extensibility"),this.supportsAnimations=i.Svg.isSupported("AnimationEventsAttribute"),this.resizeListener=function(){this.update()}.bind(this),this.container&&(this.container.__chartist__&&this.container.__chartist__.detach(),this.container.__chartist__=this),this.initializeTimeoutId=setTimeout(n.bind(this),0)},optionsProvider:void 0,container:void 0,svg:void 0,eventEmitter:void 0,createChart:function(){throw new Error("Base chart type can't be instantiated!")},update:function(e,t,n){return e&&(this.data=e||{},this.data.labels=this.data.labels||[],this.data.series=this.data.series||[],this.eventEmitter.emit("data",{type:"update",data:this.data})),t&&(this.options=i.extend({},n?this.options:this.defaultOptions,t),this.initializeTimeoutId||(this.optionsProvider.removeMediaQueryListeners(),this.optionsProvider=i.optionsProvider(this.options,this.responsiveOptions,this.eventEmitter))),this.initializeTimeoutId||this.createChart(this.optionsProvider.getCurrentOptions()),this},detach:function(){return this.initializeTimeoutId?e.clearTimeout(this.initializeTimeoutId):(e.removeEventListener("resize",this.resizeListener),this.optionsProvider.removeMediaQueryListeners()),this},on:function(e,t){return this.eventEmitter.addEventHandler(e,t),this},off:function(e,t){return this.eventEmitter.removeEventHandler(e,t),this},version:i.version,supportsForeignObject:!1})}(window,document,e),function(e,t,i){"use strict";i.Svg=i.Class.extend({constructor:function(e,n,s,r,a){e instanceof Element?this._node=e:(this._node=t.createElementNS(i.namespaces.svg,e),"svg"===e&&this.attr({"xmlns:ct":i.namespaces.ct})),n&&this.attr(n),s&&this.addClass(s),r&&(a&&r._node.firstChild?r._node.insertBefore(this._node,r._node.firstChild):r._node.appendChild(this._node))},attr:function(e,t){return"string"==typeof e?t?this._node.getAttributeNS(t,e):this._node.getAttribute(e):(Object.keys(e).forEach(function(t){if(void 0!==e[t])if(-1!==t.indexOf(":")){var n=t.split(":");this._node.setAttributeNS(i.namespaces[n[0]],t,e[t])}else this._node.setAttribute(t,e[t])}.bind(this)),this)},elem:function(e,t,n,s){return new i.Svg(e,t,n,this,s)},parent:function(){return this._node.parentNode instanceof SVGElement?new i.Svg(this._node.parentNode):null},root:function(){for(var e=this._node;"svg"!==e.nodeName;)e=e.parentNode;return new i.Svg(e)},querySelector:function(e){var t=this._node.querySelector(e);return t?new i.Svg(t):null},querySelectorAll:function(e){var t=this._node.querySelectorAll(e);return t.length?new i.Svg.List(t):null},getNode:function(){return this._node},foreignObject:function(e,n,s,r){if("string"==typeof e){var a=t.createElement("div");a.innerHTML=e,e=a.firstChild}e.setAttribute("xmlns",i.namespaces.xmlns);var o=this.elem("foreignObject",n,s,r);return o._node.appendChild(e),o},text:function(e){return this._node.appendChild(t.createTextNode(e)),this},empty:function(){for(;this._node.firstChild;)this._node.removeChild(this._node.firstChild);return this},remove:function(){return this._node.parentNode.removeChild(this._node),this.parent()},replace:function(e){return this._node.parentNode.replaceChild(e._node,this._node),e},append:function(e,t){return t&&this._node.firstChild?this._node.insertBefore(e._node,this._node.firstChild):this._node.appendChild(e._node),this},classes:function(){return this._node.getAttribute("class")?this._node.getAttribute("class").trim().split(/\s+/):[]},addClass:function(e){return this._node.setAttribute("class",this.classes(this._node).concat(e.trim().split(/\s+/)).filter(function(e,t,i){return i.indexOf(e)===t}).join(" ")),this},removeClass:function(e){var t=e.trim().split(/\s+/);return this._node.setAttribute("class",this.classes(this._node).filter(function(e){return-1===t.indexOf(e)}).join(" ")),this},removeAllClasses:function(){return this._node.setAttribute("class",""),this},height:function(){return this._node.getBoundingClientRect().height},width:function(){return this._node.getBoundingClientRect().width},animate:function(e,t,n){return void 0===t&&(t=!0),Object.keys(e).forEach(function(s){function r(e,t){var r,a,o,l={};e.easing&&(o=e.easing instanceof Array?e.easing:i.Svg.Easing[e.easing],delete e.easing),e.begin=i.ensureUnit(e.begin,"ms"),e.dur=i.ensureUnit(e.dur,"ms"),o&&(e.calcMode="spline",e.keySplines=o.join(" "),e.keyTimes="0;1"),t&&(e.fill="freeze",l[s]=e.from,this.attr(l),a=i.quantity(e.begin||0).value,e.begin="indefinite"),r=this.elem("animate",i.extend({attributeName:s},e)),t&&setTimeout(function(){try{r._node.beginElement()}catch(t){l[s]=e.to,this.attr(l),r.remove()}}.bind(this),a),n&&r._node.addEventListener("beginEvent",function(){n.emit("animationBegin",{element:this,animate:r._node,params:e})}.bind(this)),r._node.addEventListener("endEvent",function(){n&&n.emit("animationEnd",{element:this,animate:r._node,params:e}),t&&(l[s]=e.to,this.attr(l),r.remove())}.bind(this))}e[s]instanceof Array?e[s].forEach(function(e){r.bind(this)(e,!1)}.bind(this)):r.bind(this)(e[s],t)}.bind(this)),this}}),i.Svg.isSupported=function(e){return t.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#"+e,"1.1")};i.Svg.Easing={easeInSine:[.47,0,.745,.715],easeOutSine:[.39,.575,.565,1],easeInOutSine:[.445,.05,.55,.95],easeInQuad:[.55,.085,.68,.53],easeOutQuad:[.25,.46,.45,.94],easeInOutQuad:[.455,.03,.515,.955],easeInCubic:[.55,.055,.675,.19],easeOutCubic:[.215,.61,.355,1],easeInOutCubic:[.645,.045,.355,1],easeInQuart:[.895,.03,.685,.22],easeOutQuart:[.165,.84,.44,1],easeInOutQuart:[.77,0,.175,1],easeInQuint:[.755,.05,.855,.06],easeOutQuint:[.23,1,.32,1],easeInOutQuint:[.86,0,.07,1],easeInExpo:[.95,.05,.795,.035],easeOutExpo:[.19,1,.22,1],easeInOutExpo:[1,0,0,1],easeInCirc:[.6,.04,.98,.335],easeOutCirc:[.075,.82,.165,1],easeInOutCirc:[.785,.135,.15,.86],easeInBack:[.6,-.28,.735,.045],easeOutBack:[.175,.885,.32,1.275],easeInOutBack:[.68,-.55,.265,1.55]},i.Svg.List=i.Class.extend({constructor:function(e){var t=this;this.svgElements=[];for(var n=0;n<e.length;n++)this.svgElements.push(new i.Svg(e[n]));Object.keys(i.Svg.prototype).filter(function(e){return-1===["constructor","parent","querySelector","querySelectorAll","replace","append","classes","height","width"].indexOf(e)}).forEach(function(e){t[e]=function(){var n=Array.prototype.slice.call(arguments,0);return t.svgElements.forEach(function(t){i.Svg.prototype[e].apply(t,n)}),t}})}})}(window,document,e),function(e,t,i){"use strict";function n(e,t,n,s,r,a){var o=i.extend({command:r?e.toLowerCase():e.toUpperCase()},t,a?{data:a}:{});n.splice(s,0,o)}function s(e,t){e.forEach(function(i,n){r[i.command.toLowerCase()].forEach(function(s,r){t(i,s,n,r,e)})})}var r={m:["x","y"],l:["x","y"],c:["x1","y1","x2","y2","x","y"],a:["rx","ry","xAr","lAf","sf","x","y"]},a={accuracy:3};i.Svg.Path=i.Class.extend({constructor:function(e,t){this.pathElements=[],this.pos=0,this.close=e,this.options=i.extend({},a,t)},position:function(e){return void 0!==e?(this.pos=Math.max(0,Math.min(this.pathElements.length,e)),this):this.pos},remove:function(e){return this.pathElements.splice(this.pos,e),this},move:function(e,t,i,s){return n("M",{x:+e,y:+t},this.pathElements,this.pos++,i,s),this},line:function(e,t,i,s){return n("L",{x:+e,y:+t},this.pathElements,this.pos++,i,s),this},curve:function(e,t,i,s,r,a,o,l){return n("C",{x1:+e,y1:+t,x2:+i,y2:+s,x:+r,y:+a},this.pathElements,this.pos++,o,l),this},arc:function(e,t,i,s,r,a,o,l,u){return n("A",{rx:+e,ry:+t,xAr:+i,lAf:+s,sf:+r,x:+a,y:+o},this.pathElements,this.pos++,l,u),this},scale:function(e,t){return s(this.pathElements,function(i,n){i[n]*="x"===n[0]?e:t}),this},translate:function(e,t){return s(this.pathElements,function(i,n){i[n]+="x"===n[0]?e:t}),this},transform:function(e){return s(this.pathElements,function(t,i,n,s,r){var a=e(t,i,n,s,r);(a||0===a)&&(t[i]=a)}),this},parse:function(e){var t=e.replace(/([A-Za-z])([0-9])/g,"$1 $2").replace(/([0-9])([A-Za-z])/g,"$1 $2").split(/[\s,]+/).reduce(function(e,t){return t.match(/[A-Za-z]/)&&e.push([]),e[e.length-1].push(t),e},[]);"Z"===t[t.length-1][0].toUpperCase()&&t.pop();var n=t.map(function(e){var t=e.shift(),n=r[t.toLowerCase()];return i.extend({command:t},n.reduce(function(t,i,n){return t[i]=+e[n],t},{}))}),s=[this.pos,0];return Array.prototype.push.apply(s,n),Array.prototype.splice.apply(this.pathElements,s),this.pos+=n.length,this},stringify:function(){var e=Math.pow(10,this.options.accuracy);return this.pathElements.reduce(function(t,i){var n=r[i.command.toLowerCase()].map(function(t){return this.options.accuracy?Math.round(i[t]*e)/e:i[t]}.bind(this));return t+i.command+n.join(",")}.bind(this),"")+(this.close?"Z":"")},clone:function(e){var t=new i.Svg.Path(e||this.close);return t.pos=this.pos,t.pathElements=this.pathElements.slice().map(function(e){return i.extend({},e)}),t.options=i.extend({},this.options),t},splitByCommand:function(e){var t=[new i.Svg.Path];return this.pathElements.forEach(function(n){n.command===e.toUpperCase()&&0!==t[t.length-1].pathElements.length&&t.push(new i.Svg.Path),t[t.length-1].pathElements.push(n)}),t}}),i.Svg.Path.elementDescriptions=r,i.Svg.Path.join=function(e,t,n){for(var s=new i.Svg.Path(t,n),r=0;r<e.length;r++)for(var a=e[r],o=0;o<a.pathElements.length;o++)s.pathElements.push(a.pathElements[o]);return s}}(window,document,e),function(e,t,i){"use strict";var n={x:{pos:"x",len:"width",dir:"horizontal",rectStart:"x1",rectEnd:"x2",rectOffset:"y2"},y:{pos:"y",len:"height",dir:"vertical",rectStart:"y2",rectEnd:"y1",rectOffset:"x1"}};i.Axis=i.Class.extend({constructor:function(e,t,i,s){this.units=e,this.counterUnits=e===n.x?n.y:n.x,this.chartRect=t,this.axisLength=t[e.rectEnd]-t[e.rectStart],this.gridOffset=t[e.rectOffset],this.ticks=i,this.options=s},createGridAndLabels:function(e,t,n,s,r){var a=s["axis"+this.units.pos.toUpperCase()],o=this.ticks.map(this.projectValue.bind(this)),l=this.ticks.map(a.labelInterpolationFnc);o.forEach(function(u,c){var h,d={x:0,y:0};h=o[c+1]?o[c+1]-u:Math.max(this.axisLength-u,30),i.isFalseyButZero(l[c])&&""!==l[c]||("x"===this.units.pos?(u=this.chartRect.x1+u,d.x=s.axisX.labelOffset.x,"start"===s.axisX.position?d.y=this.chartRect.padding.top+s.axisX.labelOffset.y+(n?5:20):d.y=this.chartRect.y1+s.axisX.labelOffset.y+(n?5:20)):(u=this.chartRect.y1-u,d.y=s.axisY.labelOffset.y-(n?h:0),"start"===s.axisY.position?d.x=n?this.chartRect.padding.left+s.axisY.labelOffset.x:this.chartRect.x1-10:d.x=this.chartRect.x2+s.axisY.labelOffset.x+10),a.showGrid&&i.createGrid(u,c,this,this.gridOffset,this.chartRect[this.counterUnits.len](),e,[s.classNames.grid,s.classNames[this.units.dir]],r),a.showLabel&&i.createLabel(u,h,c,l,this,a.offset,d,t,[s.classNames.label,s.classNames[this.units.dir],"start"===a.position?s.classNames[a.position]:s.classNames.end],n,r))}.bind(this))},projectValue:function(e,t,i){throw new Error("Base axis can't be instantiated!")}}),i.Axis.units=n}(window,document,e),function(e,t,i){"use strict";i.AutoScaleAxis=i.Axis.extend({constructor:function(e,t,n,s){var r=s.highLow||i.getHighLow(t,s,e.pos);this.bounds=i.getBounds(n[e.rectEnd]-n[e.rectStart],r,s.scaleMinSpace||20,s.onlyInteger),this.range={min:this.bounds.min,max:this.bounds.max},i.AutoScaleAxis.super.constructor.call(this,e,n,this.bounds.values,s)},projectValue:function(e){return this.axisLength*(+i.getMultiValue(e,this.units.pos)-this.bounds.min)/this.bounds.range}})}(window,document,e),function(e,t,i){"use strict";i.FixedScaleAxis=i.Axis.extend({constructor:function(e,t,n,s){var r=s.highLow||i.getHighLow(t,s,e.pos);this.divisor=s.divisor||1,this.ticks=s.ticks||i.times(this.divisor).map(function(e,t){return r.low+(r.high-r.low)/this.divisor*t}.bind(this)),this.ticks.sort(function(e,t){return e-t}),this.range={min:r.low,max:r.high},i.FixedScaleAxis.super.constructor.call(this,e,n,this.ticks,s),this.stepLength=this.axisLength/this.divisor},projectValue:function(e){return this.axisLength*(+i.getMultiValue(e,this.units.pos)-this.range.min)/(this.range.max-this.range.min)}})}(window,document,e),function(e,t,i){"use strict";i.StepAxis=i.Axis.extend({constructor:function(e,t,n,s){i.StepAxis.super.constructor.call(this,e,n,s.ticks,s);var r=Math.max(1,s.ticks.length-(s.stretch?1:0));this.stepLength=this.axisLength/r},projectValue:function(e,t){return this.stepLength*t}})}(window,document,e),function(e,t,i){"use strict";var n={axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:i.noop,type:void 0},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:i.noop,type:void 0,scaleMinSpace:20,onlyInteger:!1},width:void 0,height:void 0,showLine:!0,showPoint:!0,showArea:!1,areaBase:0,lineSmooth:!0,showGridBackground:!1,low:void 0,high:void 0,chartPadding:{top:15,right:15,bottom:5,left:10},fullWidth:!1,reverseData:!1,classNames:{chart:"ct-chart-line",label:"ct-label",labelGroup:"ct-labels",series:"ct-series",line:"ct-line",point:"ct-point",area:"ct-area",grid:"ct-grid",gridGroup:"ct-grids",gridBackground:"ct-grid-background",vertical:"ct-vertical",horizontal:"ct-horizontal",start:"ct-start",end:"ct-end"}};i.Line=i.Base.extend({constructor:function(e,t,s,r){i.Line.super.constructor.call(this,e,t,n,i.extend({},n,s),r)},createChart:function(e){var t=i.normalizeData(this.data,e.reverseData,!0);this.svg=i.createSvg(this.container,e.width,e.height,e.classNames.chart);var s,r,a=this.svg.elem("g").addClass(e.classNames.gridGroup),o=this.svg.elem("g"),l=this.svg.elem("g").addClass(e.classNames.labelGroup),u=i.createChartRect(this.svg,e,n.padding);s=void 0===e.axisX.type?new i.StepAxis(i.Axis.units.x,t.normalized.series,u,i.extend({},e.axisX,{ticks:t.normalized.labels,stretch:e.fullWidth})):e.axisX.type.call(i,i.Axis.units.x,t.normalized.series,u,e.axisX),r=void 0===e.axisY.type?new i.AutoScaleAxis(i.Axis.units.y,t.normalized.series,u,i.extend({},e.axisY,{high:i.isNumeric(e.high)?e.high:e.axisY.high,low:i.isNumeric(e.low)?e.low:e.axisY.low})):e.axisY.type.call(i,i.Axis.units.y,t.normalized.series,u,e.axisY),s.createGridAndLabels(a,l,this.supportsForeignObject,e,this.eventEmitter),r.createGridAndLabels(a,l,this.supportsForeignObject,e,this.eventEmitter),e.showGridBackground&&i.createGridBackground(a,u,e.classNames.gridBackground,this.eventEmitter),t.raw.series.forEach(function(n,a){var l=o.elem("g");l.attr({"ct:series-name":n.name,"ct:meta":i.serialize(n.meta)}),l.addClass([e.classNames.series,n.className||e.classNames.series+"-"+i.alphaNumerate(a)].join(" "));var c=[],h=[];t.normalized.series[a].forEach(function(e,o){var l={x:u.x1+s.projectValue(e,o,t.normalized.series[a]),y:u.y1-r.projectValue(e,o,t.normalized.series[a])};c.push(l.x,l.y),h.push({value:e,valueIndex:o,meta:i.getMetaData(n,o)})}.bind(this));var d={lineSmooth:i.getSeriesOption(n,e,"lineSmooth"),showPoint:i.getSeriesOption(n,e,"showPoint"),showLine:i.getSeriesOption(n,e,"showLine"),showArea:i.getSeriesOption(n,e,"showArea"),areaBase:i.getSeriesOption(n,e,"areaBase")},p=("function"==typeof d.lineSmooth?d.lineSmooth:d.lineSmooth?i.Interpolation.monotoneCubic():i.Interpolation.none())(c,h);if(d.showPoint&&p.pathElements.forEach(function(t){var o=l.elem("line",{x1:t.x,y1:t.y,x2:t.x+.01,y2:t.y},e.classNames.point).attr({"ct:value":[t.data.value.x,t.data.value.y].filter(i.isNumeric).join(","),"ct:meta":i.serialize(t.data.meta)});this.eventEmitter.emit("draw",{type:"point",value:t.data.value,index:t.data.valueIndex,meta:t.data.meta,series:n,seriesIndex:a,axisX:s,axisY:r,group:l,element:o,x:t.x,y:t.y})}.bind(this)),d.showLine){var m=l.elem("path",{d:p.stringify()},e.classNames.line,!0);this.eventEmitter.emit("draw",{type:"line",values:t.normalized.series[a],path:p.clone(),chartRect:u,index:a,series:n,seriesIndex:a,seriesMeta:n.meta,axisX:s,axisY:r,group:l,element:m})}if(d.showArea&&r.range){var f=Math.max(Math.min(d.areaBase,r.range.max),r.range.min),g=u.y1-r.projectValue(f);p.splitByCommand("M").filter(function(e){return e.pathElements.length>1}).map(function(e){var t=e.pathElements[0],i=e.pathElements[e.pathElements.length-1];return e.clone(!0).position(0).remove(1).move(t.x,g).line(t.x,t.y).position(e.pathElements.length+1).line(i.x,g)}).forEach(function(i){var o=l.elem("path",{d:i.stringify()},e.classNames.area,!0);this.eventEmitter.emit("draw",{type:"area",values:t.normalized.series[a],path:i.clone(),series:n,seriesIndex:a,axisX:s,axisY:r,chartRect:u,index:a,group:l,element:o})}.bind(this))}}.bind(this)),this.eventEmitter.emit("created",{bounds:r.bounds,chartRect:u,axisX:s,axisY:r,svg:this.svg,options:e})}})}(window,document,e),function(e,t,i){"use strict";var n={axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:i.noop,scaleMinSpace:30,onlyInteger:!1},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:i.noop,scaleMinSpace:20,onlyInteger:!1},width:void 0,height:void 0,high:void 0,low:void 0,referenceValue:0,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,stackMode:"accumulate",horizontalBars:!1,distributeSeries:!1,reverseData:!1,showGridBackground:!1,classNames:{chart:"ct-chart-bar",horizontalBars:"ct-horizontal-bars",label:"ct-label",labelGroup:"ct-labels",series:"ct-series",bar:"ct-bar",grid:"ct-grid",gridGroup:"ct-grids",gridBackground:"ct-grid-background",vertical:"ct-vertical",horizontal:"ct-horizontal",start:"ct-start",end:"ct-end"}};i.Bar=i.Base.extend({constructor:function(e,t,s,r){i.Bar.super.constructor.call(this,e,t,n,i.extend({},n,s),r)},createChart:function(e){var t,s;e.distributeSeries?(t=i.normalizeData(this.data,e.reverseData,e.horizontalBars?"x":"y"),t.normalized.series=t.normalized.series.map(function(e){return[e]})):t=i.normalizeData(this.data,e.reverseData,e.horizontalBars?"x":"y"),this.svg=i.createSvg(this.container,e.width,e.height,e.classNames.chart+(e.horizontalBars?" "+e.classNames.horizontalBars:""));var r=this.svg.elem("g").addClass(e.classNames.gridGroup),a=this.svg.elem("g"),o=this.svg.elem("g").addClass(e.classNames.labelGroup);if(e.stackBars&&0!==t.normalized.series.length){var l=i.serialMap(t.normalized.series,function(){return Array.prototype.slice.call(arguments).map(function(e){return e}).reduce(function(e,t){return{x:e.x+(t&&t.x)||0,y:e.y+(t&&t.y)||0}},{x:0,y:0})});s=i.getHighLow([l],e,e.horizontalBars?"x":"y")}else s=i.getHighLow(t.normalized.series,e,e.horizontalBars?"x":"y");s.high=+e.high||(0===e.high?0:s.high),s.low=+e.low||(0===e.low?0:s.low);var u,c,h,d,p,m=i.createChartRect(this.svg,e,n.padding);c=e.distributeSeries&&e.stackBars?t.normalized.labels.slice(0,1):t.normalized.labels,e.horizontalBars?(u=d=void 0===e.axisX.type?new i.AutoScaleAxis(i.Axis.units.x,t.normalized.series,m,i.extend({},e.axisX,{highLow:s,referenceValue:0})):e.axisX.type.call(i,i.Axis.units.x,t.normalized.series,m,i.extend({},e.axisX,{highLow:s,referenceValue:0})),h=p=void 0===e.axisY.type?new i.StepAxis(i.Axis.units.y,t.normalized.series,m,{ticks:c}):e.axisY.type.call(i,i.Axis.units.y,t.normalized.series,m,e.axisY)):(h=d=void 0===e.axisX.type?new i.StepAxis(i.Axis.units.x,t.normalized.series,m,{ticks:c}):e.axisX.type.call(i,i.Axis.units.x,t.normalized.series,m,e.axisX),u=p=void 0===e.axisY.type?new i.AutoScaleAxis(i.Axis.units.y,t.normalized.series,m,i.extend({},e.axisY,{highLow:s,referenceValue:0})):e.axisY.type.call(i,i.Axis.units.y,t.normalized.series,m,i.extend({},e.axisY,{highLow:s,referenceValue:0})));var f=e.horizontalBars?m.x1+u.projectValue(0):m.y1-u.projectValue(0),g=[];h.createGridAndLabels(r,o,this.supportsForeignObject,e,this.eventEmitter),u.createGridAndLabels(r,o,this.supportsForeignObject,e,this.eventEmitter),e.showGridBackground&&i.createGridBackground(r,m,e.classNames.gridBackground,this.eventEmitter),t.raw.series.forEach(function(n,s){var r,o,l=s-(t.raw.series.length-1)/2;r=e.distributeSeries&&!e.stackBars?h.axisLength/t.normalized.series.length/2:e.distributeSeries&&e.stackBars?h.axisLength/2:h.axisLength/t.normalized.series[s].length/2,(o=a.elem("g")).attr({"ct:series-name":n.name,"ct:meta":i.serialize(n.meta)}),o.addClass([e.classNames.series,n.className||e.classNames.series+"-"+i.alphaNumerate(s)].join(" ")),t.normalized.series[s].forEach(function(a,c){var v,x,y,b;if(b=e.distributeSeries&&!e.stackBars?s:e.distributeSeries&&e.stackBars?0:c,v=e.horizontalBars?{x:m.x1+u.projectValue(a&&a.x?a.x:0,c,t.normalized.series[s]),y:m.y1-h.projectValue(a&&a.y?a.y:0,b,t.normalized.series[s])}:{x:m.x1+h.projectValue(a&&a.x?a.x:0,b,t.normalized.series[s]),y:m.y1-u.projectValue(a&&a.y?a.y:0,c,t.normalized.series[s])},h instanceof i.StepAxis&&(h.options.stretch||(v[h.units.pos]+=r*(e.horizontalBars?-1:1)),v[h.units.pos]+=e.stackBars||e.distributeSeries?0:l*e.seriesBarDistance*(e.horizontalBars?-1:1)),y=g[c]||f,g[c]=y-(f-v[h.counterUnits.pos]),void 0!==a){var w={};w[h.units.pos+"1"]=v[h.units.pos],w[h.units.pos+"2"]=v[h.units.pos],!e.stackBars||"accumulate"!==e.stackMode&&e.stackMode?(w[h.counterUnits.pos+"1"]=f,w[h.counterUnits.pos+"2"]=v[h.counterUnits.pos]):(w[h.counterUnits.pos+"1"]=y,w[h.counterUnits.pos+"2"]=g[c]),w.x1=Math.min(Math.max(w.x1,m.x1),m.x2),w.x2=Math.min(Math.max(w.x2,m.x1),m.x2),w.y1=Math.min(Math.max(w.y1,m.y2),m.y1),w.y2=Math.min(Math.max(w.y2,m.y2),m.y1);var E=i.getMetaData(n,c);x=o.elem("line",w,e.classNames.bar).attr({"ct:value":[a.x,a.y].filter(i.isNumeric).join(","),"ct:meta":i.serialize(E)}),this.eventEmitter.emit("draw",i.extend({type:"bar",value:a,index:c,meta:E,series:n,seriesIndex:s,axisX:d,axisY:p,chartRect:m,group:o,element:x},w))}}.bind(this))}.bind(this)),this.eventEmitter.emit("created",{bounds:u.bounds,chartRect:m,axisX:d,axisY:p,svg:this.svg,options:e})}})}(window,document,e),function(e,t,i){"use strict";function n(e,t,i){var n=t.x>e.x;return n&&"explode"===i||!n&&"implode"===i?"start":n&&"implode"===i||!n&&"explode"===i?"end":"middle"}var s={width:void 0,height:void 0,chartPadding:5,classNames:{chartPie:"ct-chart-pie",chartDonut:"ct-chart-donut",series:"ct-series",slicePie:"ct-slice-pie",sliceDonut:"ct-slice-donut",sliceDonutSolid:"ct-slice-donut-solid",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutSolid:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelPosition:"inside",labelInterpolationFnc:i.noop,labelDirection:"neutral",reverseData:!1,ignoreEmptyValues:!1};i.Pie=i.Base.extend({constructor:function(e,t,n,r){i.Pie.super.constructor.call(this,e,t,s,i.extend({},s,n),r)},createChart:function(e){var t,r,a,o,l,u=i.normalizeData(this.data),c=[],h=e.startAngle;this.svg=i.createSvg(this.container,e.width,e.height,e.donut?e.classNames.chartDonut:e.classNames.chartPie),r=i.createChartRect(this.svg,e,s.padding),a=Math.min(r.width()/2,r.height()/2),l=e.total||u.normalized.series.reduce(function(e,t){return e+t},0);var d=i.quantity(e.donutWidth);"%"===d.unit&&(d.value*=a/100),a-=e.donut&&!e.donutSolid?d.value/2:0,o="outside"===e.labelPosition||e.donut&&!e.donutSolid?a:"center"===e.labelPosition?0:e.donutSolid?a-d.value/2:a/2,o+=e.labelOffset;var p={x:r.x1+r.width()/2,y:r.y2+r.height()/2},m=1===u.raw.series.filter(function(e){return e.hasOwnProperty("value")?0!==e.value:0!==e}).length;u.raw.series.forEach(function(e,t){c[t]=this.svg.elem("g",null,null)}.bind(this)),e.showLabel&&(t=this.svg.elem("g",null,null)),u.raw.series.forEach(function(s,r){if(0!==u.normalized.series[r]||!e.ignoreEmptyValues){c[r].attr({"ct:series-name":s.name}),c[r].addClass([e.classNames.series,s.className||e.classNames.series+"-"+i.alphaNumerate(r)].join(" "));var f=l>0?h+u.normalized.series[r]/l*360:0,g=Math.max(0,h-(0===r||m?0:.2));f-g>=359.99&&(f=g+359.99);var v,x,y,b=i.polarToCartesian(p.x,p.y,a,g),w=i.polarToCartesian(p.x,p.y,a,f),E=new i.Svg.Path(!e.donut||e.donutSolid).move(w.x,w.y).arc(a,a,0,f-h>180,0,b.x,b.y);e.donut?e.donutSolid&&(y=a-d.value,v=i.polarToCartesian(p.x,p.y,y,h-(0===r||m?0:.2)),x=i.polarToCartesian(p.x,p.y,y,f),E.line(v.x,v.y),E.arc(y,y,0,f-h>180,1,x.x,x.y)):E.line(p.x,p.y);var S=e.classNames.slicePie;e.donut&&(S=e.classNames.sliceDonut,e.donutSolid&&(S=e.classNames.sliceDonutSolid));var A=c[r].elem("path",{d:E.stringify()},S);if(A.attr({"ct:value":u.normalized.series[r],"ct:meta":i.serialize(s.meta)}),e.donut&&!e.donutSolid&&(A._node.style.strokeWidth=d.value+"px"),this.eventEmitter.emit("draw",{type:"slice",value:u.normalized.series[r],totalDataSum:l,index:r,meta:s.meta,series:s,group:c[r],element:A,path:E.clone(),center:p,radius:a,startAngle:h,endAngle:f}),e.showLabel){var z;z=1===u.raw.series.length?{x:p.x,y:p.y}:i.polarToCartesian(p.x,p.y,o,h+(f-h)/2);var M;M=u.normalized.labels&&!i.isFalseyButZero(u.normalized.labels[r])?u.normalized.labels[r]:u.normalized.series[r];var O=e.labelInterpolationFnc(M,r);if(O||0===O){var C=t.elem("text",{dx:z.x,dy:z.y,"text-anchor":n(p,z,e.labelDirection)},e.classNames.label).text(""+O);this.eventEmitter.emit("draw",{type:"label",index:r,group:t,element:C,text:""+O,x:z.x,y:z.y})}}h=f}}.bind(this)),this.eventEmitter.emit("created",{chartRect:r,svg:this.svg,options:e})},determineAnchorPosition:n})}(window,document,e),e});
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/chartjs.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/chartjs.min.js
new file mode 100755
index 0000000..6fc5d34
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/chartjs.min.js
@@ -0,0 +1 @@
+!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).Chart=t()}}(function(){return function t(e,n,i){function a(r,l){if(!n[r]){if(!e[r]){var s="function"==typeof require&&require;if(!l&&s)return s(r,!0);if(o)return o(r,!0);var u=new Error("Cannot find module '"+r+"'");throw u.code="MODULE_NOT_FOUND",u}var d=n[r]={exports:{}};e[r][0].call(d.exports,function(t){var n=e[r][1][t];return a(n||t)},d,d.exports,t,e,n,i)}return n[r].exports}for(var o="function"==typeof require&&require,r=0;r<i.length;r++)a(i[r]);return a}({1:[function(t,e,n){},{}],2:[function(t,e,n){function i(t){if(t){var e=[0,0,0],n=1,i=t.match(/^#([a-fA-F0-9]{3})$/);if(i){i=i[1];for(a=0;a<e.length;a++)e[a]=parseInt(i[a]+i[a],16)}else if(i=t.match(/^#([a-fA-F0-9]{6})$/)){i=i[1];for(a=0;a<e.length;a++)e[a]=parseInt(i.slice(2*a,2*a+2),16)}else if(i=t.match(/^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/)){for(a=0;a<e.length;a++)e[a]=parseInt(i[a+1]);n=parseFloat(i[4])}else if(i=t.match(/^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/)){for(a=0;a<e.length;a++)e[a]=Math.round(2.55*parseFloat(i[a+1]));n=parseFloat(i[4])}else if(i=t.match(/(\w+)/)){if("transparent"==i[1])return[0,0,0,0];if(!(e=c[i[1]]))return}for(var a=0;a<e.length;a++)e[a]=u(e[a],0,255);return n=n||0==n?u(n,0,1):1,e[3]=n,e}}function a(t){if(t){var e=t.match(/^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/);if(e){var n=parseFloat(e[4]);return[u(parseInt(e[1]),0,360),u(parseFloat(e[2]),0,100),u(parseFloat(e[3]),0,100),u(isNaN(n)?1:n,0,1)]}}}function o(t){if(t){var e=t.match(/^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/);if(e){var n=parseFloat(e[4]);return[u(parseInt(e[1]),0,360),u(parseFloat(e[2]),0,100),u(parseFloat(e[3]),0,100),u(isNaN(n)?1:n,0,1)]}}}function r(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"rgba("+t[0]+", "+t[1]+", "+t[2]+", "+e+")"}function l(t,e){return"rgba("+Math.round(t[0]/255*100)+"%, "+Math.round(t[1]/255*100)+"%, "+Math.round(t[2]/255*100)+"%, "+(e||t[3]||1)+")"}function s(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"hsla("+t[0]+", "+t[1]+"%, "+t[2]+"%, "+e+")"}function u(t,e,n){return Math.min(Math.max(e,t),n)}function d(t){var e=t.toString(16).toUpperCase();return e.length<2?"0"+e:e}var c=t(6);e.exports={getRgba:i,getHsla:a,getRgb:function(t){var e=i(t);return e&&e.slice(0,3)},getHsl:function(t){var e=a(t);return e&&e.slice(0,3)},getHwb:o,getAlpha:function(t){var e=i(t);return e?e[3]:(e=a(t))?e[3]:(e=o(t))?e[3]:void 0},hexString:function(t){return"#"+d(t[0])+d(t[1])+d(t[2])},rgbString:function(t,e){return e<1||t[3]&&t[3]<1?r(t,e):"rgb("+t[0]+", "+t[1]+", "+t[2]+")"},rgbaString:r,percentString:function(t,e){return e<1||t[3]&&t[3]<1?l(t,e):"rgb("+Math.round(t[0]/255*100)+"%, "+Math.round(t[1]/255*100)+"%, "+Math.round(t[2]/255*100)+"%)"},percentaString:l,hslString:function(t,e){return e<1||t[3]&&t[3]<1?s(t,e):"hsl("+t[0]+", "+t[1]+"%, "+t[2]+"%)"},hslaString:s,hwbString:function(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"hwb("+t[0]+", "+t[1]+"%, "+t[2]+"%"+(void 0!==e&&1!==e?", "+e:"")+")"},keyword:function(t){return h[t.slice(0,3)]}};var h={};for(var f in c)h[c[f]]=f},{6:6}],3:[function(t,e,n){var i=t(5),a=t(2),o=function(t){if(t instanceof o)return t;if(!(this instanceof o))return new o(t);this.valid=!1,this.values={rgb:[0,0,0],hsl:[0,0,0],hsv:[0,0,0],hwb:[0,0,0],cmyk:[0,0,0,0],alpha:1};var e;"string"==typeof t?(e=a.getRgba(t))?this.setValues("rgb",e):(e=a.getHsla(t))?this.setValues("hsl",e):(e=a.getHwb(t))&&this.setValues("hwb",e):"object"==typeof t&&(void 0!==(e=t).r||void 0!==e.red?this.setValues("rgb",e):void 0!==e.l||void 0!==e.lightness?this.setValues("hsl",e):void 0!==e.v||void 0!==e.value?this.setValues("hsv",e):void 0!==e.w||void 0!==e.whiteness?this.setValues("hwb",e):void 0===e.c&&void 0===e.cyan||this.setValues("cmyk",e))};o.prototype={isValid:function(){return this.valid},rgb:function(){return this.setSpace("rgb",arguments)},hsl:function(){return this.setSpace("hsl",arguments)},hsv:function(){return this.setSpace("hsv",arguments)},hwb:function(){return this.setSpace("hwb",arguments)},cmyk:function(){return this.setSpace("cmyk",arguments)},rgbArray:function(){return this.values.rgb},hslArray:function(){return this.values.hsl},hsvArray:function(){return this.values.hsv},hwbArray:function(){var t=this.values;return 1!==t.alpha?t.hwb.concat([t.alpha]):t.hwb},cmykArray:function(){return this.values.cmyk},rgbaArray:function(){var t=this.values;return t.rgb.concat([t.alpha])},hslaArray:function(){var t=this.values;return t.hsl.concat([t.alpha])},alpha:function(t){return void 0===t?this.values.alpha:(this.setValues("alpha",t),this)},red:function(t){return this.setChannel("rgb",0,t)},green:function(t){return this.setChannel("rgb",1,t)},blue:function(t){return this.setChannel("rgb",2,t)},hue:function(t){return t&&(t%=360,t=t<0?360+t:t),this.setChannel("hsl",0,t)},saturation:function(t){return this.setChannel("hsl",1,t)},lightness:function(t){return this.setChannel("hsl",2,t)},saturationv:function(t){return this.setChannel("hsv",1,t)},whiteness:function(t){return this.setChannel("hwb",1,t)},blackness:function(t){return this.setChannel("hwb",2,t)},value:function(t){return this.setChannel("hsv",2,t)},cyan:function(t){return this.setChannel("cmyk",0,t)},magenta:function(t){return this.setChannel("cmyk",1,t)},yellow:function(t){return this.setChannel("cmyk",2,t)},black:function(t){return this.setChannel("cmyk",3,t)},hexString:function(){return a.hexString(this.values.rgb)},rgbString:function(){return a.rgbString(this.values.rgb,this.values.alpha)},rgbaString:function(){return a.rgbaString(this.values.rgb,this.values.alpha)},percentString:function(){return a.percentString(this.values.rgb,this.values.alpha)},hslString:function(){return a.hslString(this.values.hsl,this.values.alpha)},hslaString:function(){return a.hslaString(this.values.hsl,this.values.alpha)},hwbString:function(){return a.hwbString(this.values.hwb,this.values.alpha)},keyword:function(){return a.keyword(this.values.rgb,this.values.alpha)},rgbNumber:function(){var t=this.values.rgb;return t[0]<<16|t[1]<<8|t[2]},luminosity:function(){for(var t=this.values.rgb,e=[],n=0;n<t.length;n++){var i=t[n]/255;e[n]=i<=.03928?i/12.92:Math.pow((i+.055)/1.055,2.4)}return.2126*e[0]+.7152*e[1]+.0722*e[2]},contrast:function(t){var e=this.luminosity(),n=t.luminosity();return e>n?(e+.05)/(n+.05):(n+.05)/(e+.05)},level:function(t){var e=this.contrast(t);return e>=7.1?"AAA":e>=4.5?"AA":""},dark:function(){var t=this.values.rgb;return(299*t[0]+587*t[1]+114*t[2])/1e3<128},light:function(){return!this.dark()},negate:function(){for(var t=[],e=0;e<3;e++)t[e]=255-this.values.rgb[e];return this.setValues("rgb",t),this},lighten:function(t){var e=this.values.hsl;return e[2]+=e[2]*t,this.setValues("hsl",e),this},darken:function(t){var e=this.values.hsl;return e[2]-=e[2]*t,this.setValues("hsl",e),this},saturate:function(t){var e=this.values.hsl;return e[1]+=e[1]*t,this.setValues("hsl",e),this},desaturate:function(t){var e=this.values.hsl;return e[1]-=e[1]*t,this.setValues("hsl",e),this},whiten:function(t){var e=this.values.hwb;return e[1]+=e[1]*t,this.setValues("hwb",e),this},blacken:function(t){var e=this.values.hwb;return e[2]+=e[2]*t,this.setValues("hwb",e),this},greyscale:function(){var t=this.values.rgb,e=.3*t[0]+.59*t[1]+.11*t[2];return this.setValues("rgb",[e,e,e]),this},clearer:function(t){var e=this.values.alpha;return this.setValues("alpha",e-e*t),this},opaquer:function(t){var e=this.values.alpha;return this.setValues("alpha",e+e*t),this},rotate:function(t){var e=this.values.hsl,n=(e[0]+t)%360;return e[0]=n<0?360+n:n,this.setValues("hsl",e),this},mix:function(t,e){var n=this,i=t,a=void 0===e?.5:e,o=2*a-1,r=n.alpha()-i.alpha(),l=((o*r==-1?o:(o+r)/(1+o*r))+1)/2,s=1-l;return this.rgb(l*n.red()+s*i.red(),l*n.green()+s*i.green(),l*n.blue()+s*i.blue()).alpha(n.alpha()*a+i.alpha()*(1-a))},toJSON:function(){return this.rgb()},clone:function(){var t,e,n=new o,i=this.values,a=n.values;for(var r in i)i.hasOwnProperty(r)&&(t=i[r],"[object Array]"===(e={}.toString.call(t))?a[r]=t.slice(0):"[object Number]"===e?a[r]=t:console.error("unexpected color value:",t));return n}},o.prototype.spaces={rgb:["red","green","blue"],hsl:["hue","saturation","lightness"],hsv:["hue","saturation","value"],hwb:["hue","whiteness","blackness"],cmyk:["cyan","magenta","yellow","black"]},o.prototype.maxes={rgb:[255,255,255],hsl:[360,100,100],hsv:[360,100,100],hwb:[360,100,100],cmyk:[100,100,100,100]},o.prototype.getValues=function(t){for(var e=this.values,n={},i=0;i<t.length;i++)n[t.charAt(i)]=e[t][i];return 1!==e.alpha&&(n.a=e.alpha),n},o.prototype.setValues=function(t,e){var n,a=this.values,o=this.spaces,r=this.maxes,l=1;if(this.valid=!0,"alpha"===t)l=e;else if(e.length)a[t]=e.slice(0,t.length),l=e[t.length];else if(void 0!==e[t.charAt(0)]){for(n=0;n<t.length;n++)a[t][n]=e[t.charAt(n)];l=e.a}else if(void 0!==e[o[t][0]]){var s=o[t];for(n=0;n<t.length;n++)a[t][n]=e[s[n]];l=e.alpha}if(a.alpha=Math.max(0,Math.min(1,void 0===l?a.alpha:l)),"alpha"===t)return!1;var u;for(n=0;n<t.length;n++)u=Math.max(0,Math.min(r[t][n],a[t][n])),a[t][n]=Math.round(u);for(var d in o)d!==t&&(a[d]=i[t][d](a[t]));return!0},o.prototype.setSpace=function(t,e){var n=e[0];return void 0===n?this.getValues(t):("number"==typeof n&&(n=Array.prototype.slice.call(e)),this.setValues(t,n),this)},o.prototype.setChannel=function(t,e,n){var i=this.values[t];return void 0===n?i[e]:n===i[e]?this:(i[e]=n,this.setValues(t,i),this)},"undefined"!=typeof window&&(window.Color=o),e.exports=o},{2:2,5:5}],4:[function(t,e,n){function i(t){var e,n,i,a=t[0]/255,o=t[1]/255,r=t[2]/255,l=Math.min(a,o,r),s=Math.max(a,o,r),u=s-l;return s==l?e=0:a==s?e=(o-r)/u:o==s?e=2+(r-a)/u:r==s&&(e=4+(a-o)/u),(e=Math.min(60*e,360))<0&&(e+=360),i=(l+s)/2,n=s==l?0:i<=.5?u/(s+l):u/(2-s-l),[e,100*n,100*i]}function a(t){var e,n,i,a=t[0],o=t[1],r=t[2],l=Math.min(a,o,r),s=Math.max(a,o,r),u=s-l;return n=0==s?0:u/s*1e3/10,s==l?e=0:a==s?e=(o-r)/u:o==s?e=2+(r-a)/u:r==s&&(e=4+(a-o)/u),(e=Math.min(60*e,360))<0&&(e+=360),i=s/255*1e3/10,[e,n,i]}function o(t){var e=t[0],n=t[1],a=t[2];return[i(t)[0],100*(1/255*Math.min(e,Math.min(n,a))),100*(a=1-1/255*Math.max(e,Math.max(n,a)))]}function l(t){var e,n,i,a,o=t[0]/255,r=t[1]/255,l=t[2]/255;return a=Math.min(1-o,1-r,1-l),e=(1-o-a)/(1-a)||0,n=(1-r-a)/(1-a)||0,i=(1-l-a)/(1-a)||0,[100*e,100*n,100*i,100*a]}function s(t){return C[JSON.stringify(t)]}function u(t){var e=t[0]/255,n=t[1]/255,i=t[2]/255;return[100*(.4124*(e=e>.04045?Math.pow((e+.055)/1.055,2.4):e/12.92)+.3576*(n=n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92)+.1805*(i=i>.04045?Math.pow((i+.055)/1.055,2.4):i/12.92)),100*(.2126*e+.7152*n+.0722*i),100*(.0193*e+.1192*n+.9505*i)]}function d(t){var e,n,i,a=u(t),o=a[0],r=a[1],l=a[2];return o/=95.047,r/=100,l/=108.883,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,r=r>.008856?Math.pow(r,1/3):7.787*r+16/116,l=l>.008856?Math.pow(l,1/3):7.787*l+16/116,e=116*r-16,n=500*(o-r),i=200*(r-l),[e,n,i]}function c(t){var e,n,i,a,o,r=t[0]/360,l=t[1]/100,s=t[2]/100;if(0==l)return o=255*s,[o,o,o];e=2*s-(n=s<.5?s*(1+l):s+l-s*l),a=[0,0,0];for(var u=0;u<3;u++)(i=r+1/3*-(u-1))<0&&i++,i>1&&i--,o=6*i<1?e+6*(n-e)*i:2*i<1?n:3*i<2?e+(n-e)*(2/3-i)*6:e,a[u]=255*o;return a}function h(t){var e=t[0]/60,n=t[1]/100,i=t[2]/100,a=Math.floor(e)%6,o=e-Math.floor(e),r=255*i*(1-n),l=255*i*(1-n*o),s=255*i*(1-n*(1-o)),i=255*i;switch(a){case 0:return[i,s,r];case 1:return[l,i,r];case 2:return[r,i,s];case 3:return[r,l,i];case 4:return[s,r,i];case 5:return[i,r,l]}}function f(t){var e,n,i,a,o=t[0]/360,l=t[1]/100,s=t[2]/100,u=l+s;switch(u>1&&(l/=u,s/=u),e=Math.floor(6*o),n=1-s,i=6*o-e,0!=(1&e)&&(i=1-i),a=l+i*(n-l),e){default:case 6:case 0:r=n,g=a,b=l;break;case 1:r=a,g=n,b=l;break;case 2:r=l,g=n,b=a;break;case 3:r=l,g=a,b=n;break;case 4:r=a,g=l,b=n;break;case 5:r=n,g=l,b=a}return[255*r,255*g,255*b]}function p(t){var e,n,i,a=t[0]/100,o=t[1]/100,r=t[2]/100,l=t[3]/100;return e=1-Math.min(1,a*(1-l)+l),n=1-Math.min(1,o*(1-l)+l),i=1-Math.min(1,r*(1-l)+l),[255*e,255*n,255*i]}function m(t){var e,n,i,a=t[0]/100,o=t[1]/100,r=t[2]/100;return e=3.2406*a+-1.5372*o+-.4986*r,n=-.9689*a+1.8758*o+.0415*r,i=.0557*a+-.204*o+1.057*r,e=e>.0031308?1.055*Math.pow(e,1/2.4)-.055:e*=12.92,n=n>.0031308?1.055*Math.pow(n,1/2.4)-.055:n*=12.92,i=i>.0031308?1.055*Math.pow(i,1/2.4)-.055:i*=12.92,e=Math.min(Math.max(0,e),1),n=Math.min(Math.max(0,n),1),i=Math.min(Math.max(0,i),1),[255*e,255*n,255*i]}function v(t){var e,n,i,a=t[0],o=t[1],r=t[2];return a/=95.047,o/=100,r/=108.883,a=a>.008856?Math.pow(a,1/3):7.787*a+16/116,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,r=r>.008856?Math.pow(r,1/3):7.787*r+16/116,e=116*o-16,n=500*(a-o),i=200*(o-r),[e,n,i]}function x(t){var e,n,i,a,o=t[0],r=t[1],l=t[2];return o<=8?(n=100*o/903.3,a=n/100*7.787+16/116):(n=100*Math.pow((o+16)/116,3),a=Math.pow(n/100,1/3)),e=e/95.047<=.008856?e=95.047*(r/500+a-16/116)/7.787:95.047*Math.pow(r/500+a,3),i=i/108.883<=.008859?i=108.883*(a-l/200-16/116)/7.787:108.883*Math.pow(a-l/200,3),[e,n,i]}function y(t){var e,n,i,a=t[0],o=t[1],r=t[2];return e=Math.atan2(r,o),(n=360*e/2/Math.PI)<0&&(n+=360),i=Math.sqrt(o*o+r*r),[a,i,n]}function k(t){return m(x(t))}function w(t){var e,n,i,a=t[0],o=t[1];return i=t[2]/360*2*Math.PI,e=o*Math.cos(i),n=o*Math.sin(i),[a,e,n]}function M(t){return S[t]}e.exports={rgb2hsl:i,rgb2hsv:a,rgb2hwb:o,rgb2cmyk:l,rgb2keyword:s,rgb2xyz:u,rgb2lab:d,rgb2lch:function(t){return y(d(t))},hsl2rgb:c,hsl2hsv:function(t){var e,n,i=t[0],a=t[1]/100,o=t[2]/100;return 0===o?[0,0,0]:(o*=2,a*=o<=1?o:2-o,n=(o+a)/2,e=2*a/(o+a),[i,100*e,100*n])},hsl2hwb:function(t){return o(c(t))},hsl2cmyk:function(t){return l(c(t))},hsl2keyword:function(t){return s(c(t))},hsv2rgb:h,hsv2hsl:function(t){var e,n,i=t[0],a=t[1]/100,o=t[2]/100;return n=(2-a)*o,e=a*o,e/=n<=1?n:2-n,e=e||0,n/=2,[i,100*e,100*n]},hsv2hwb:function(t){return o(h(t))},hsv2cmyk:function(t){return l(h(t))},hsv2keyword:function(t){return s(h(t))},hwb2rgb:f,hwb2hsl:function(t){return i(f(t))},hwb2hsv:function(t){return a(f(t))},hwb2cmyk:function(t){return l(f(t))},hwb2keyword:function(t){return s(f(t))},cmyk2rgb:p,cmyk2hsl:function(t){return i(p(t))},cmyk2hsv:function(t){return a(p(t))},cmyk2hwb:function(t){return o(p(t))},cmyk2keyword:function(t){return s(p(t))},keyword2rgb:M,keyword2hsl:function(t){return i(M(t))},keyword2hsv:function(t){return a(M(t))},keyword2hwb:function(t){return o(M(t))},keyword2cmyk:function(t){return l(M(t))},keyword2lab:function(t){return d(M(t))},keyword2xyz:function(t){return u(M(t))},xyz2rgb:m,xyz2lab:v,xyz2lch:function(t){return y(v(t))},lab2xyz:x,lab2rgb:k,lab2lch:y,lch2lab:w,lch2xyz:function(t){return x(w(t))},lch2rgb:function(t){return k(w(t))}};var S={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},C={};for(var D in S)C[JSON.stringify(S[D])]=D},{}],5:[function(t,e,n){var i=t(4),a=function(){return new u};for(var o in i){a[o+"Raw"]=function(t){return function(e){return"number"==typeof e&&(e=Array.prototype.slice.call(arguments)),i[t](e)}}(o);var r=/(\w+)2(\w+)/.exec(o),l=r[1],s=r[2];(a[l]=a[l]||{})[s]=a[o]=function(t){return function(e){"number"==typeof e&&(e=Array.prototype.slice.call(arguments));var n=i[t](e);if("string"==typeof n||void 0===n)return n;for(var a=0;a<n.length;a++)n[a]=Math.round(n[a]);return n}}(o)}var u=function(){this.convs={}};u.prototype.routeSpace=function(t,e){var n=e[0];return void 0===n?this.getValues(t):("number"==typeof n&&(n=Array.prototype.slice.call(e)),this.setValues(t,n))},u.prototype.setValues=function(t,e){return this.space=t,this.convs={},this.convs[t]=e,this},u.prototype.getValues=function(t){var e=this.convs[t];if(!e){var n=this.space,i=this.convs[n];e=a[n][t](i),this.convs[t]=e}return e},["rgb","hsl","hsv","cmyk","keyword"].forEach(function(t){u.prototype[t]=function(e){return this.routeSpace(t,arguments)}}),e.exports=a},{4:4}],6:[function(t,e,n){e.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}},{}],7:[function(t,e,n){var i=t(28)();t(26)(i),t(40)(i),t(22)(i),t(25)(i),t(30)(i),t(21)(i),t(23)(i),t(24)(i),t(29)(i),t(32)(i),t(33)(i),t(31)(i),t(27)(i),t(34)(i),t(35)(i),t(36)(i),t(37)(i),t(38)(i),t(46)(i),t(44)(i),t(45)(i),t(47)(i),t(48)(i),t(49)(i),t(15)(i),t(16)(i),t(17)(i),t(18)(i),t(19)(i),t(20)(i),t(8)(i),t(9)(i),t(10)(i),t(11)(i),t(12)(i),t(13)(i),t(14)(i);var a=[];a.push(t(41)(i),t(42)(i),t(43)(i)),i.plugins.register(a),e.exports=i,"undefined"!=typeof window&&(window.Chart=i)},{10:10,11:11,12:12,13:13,14:14,15:15,16:16,17:17,18:18,19:19,20:20,21:21,22:22,23:23,24:24,25:25,26:26,27:27,28:28,29:29,30:30,31:31,32:32,33:33,34:34,35:35,36:36,37:37,38:38,40:40,41:41,42:42,43:43,44:44,45:45,46:46,47:47,48:48,49:49,8:8,9:9}],8:[function(t,e,n){"use strict";e.exports=function(t){t.Bar=function(e,n){return n.type="bar",new t(e,n)}}},{}],9:[function(t,e,n){"use strict";e.exports=function(t){t.Bubble=function(e,n){return n.type="bubble",new t(e,n)}}},{}],10:[function(t,e,n){"use strict";e.exports=function(t){t.Doughnut=function(e,n){return n.type="doughnut",new t(e,n)}}},{}],11:[function(t,e,n){"use strict";e.exports=function(t){t.Line=function(e,n){return n.type="line",new t(e,n)}}},{}],12:[function(t,e,n){"use strict";e.exports=function(t){t.PolarArea=function(e,n){return n.type="polarArea",new t(e,n)}}},{}],13:[function(t,e,n){"use strict";e.exports=function(t){t.Radar=function(e,n){return n.type="radar",new t(e,n)}}},{}],14:[function(t,e,n){"use strict";e.exports=function(t){t.defaults.scatter={hover:{mode:"single"},scales:{xAxes:[{type:"linear",position:"bottom",id:"x-axis-1"}],yAxes:[{type:"linear",position:"left",id:"y-axis-1"}]},tooltips:{callbacks:{title:function(){return""},label:function(t){return"("+t.xLabel+", "+t.yLabel+")"}}}},t.controllers.scatter=t.controllers.line,t.Scatter=function(e,n){return n.type="scatter",new t(e,n)}}},{}],15:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.bar={hover:{mode:"label"},scales:{xAxes:[{type:"category",categoryPercentage:.8,barPercentage:.9,gridLines:{offsetGridLines:!0}}],yAxes:[{type:"linear"}]}},t.controllers.bar=t.DatasetController.extend({dataElementType:t.elements.Rectangle,initialize:function(){var e,n=this;t.DatasetController.prototype.initialize.apply(n,arguments),(e=n.getMeta()).stack=n.getDataset().stack,e.bar=!0},update:function(t){var e,n,i=this,a=i.getMeta().data;for(i._ruler=i.getRuler(),e=0,n=a.length;e<n;++e)i.updateElement(a[e],e,t)},updateElement:function(t,n,i){var a=this,o=a.chart,r=a.getMeta(),l=a.getDataset(),s=t.custom||{},u=o.options.elements.rectangle;t._xScale=a.getScaleForId(r.xAxisID),t._yScale=a.getScaleForId(r.yAxisID),t._datasetIndex=a.index,t._index=n,t._model={datasetLabel:l.label,label:o.data.labels[n],borderSkipped:s.borderSkipped?s.borderSkipped:u.borderSkipped,backgroundColor:s.backgroundColor?s.backgroundColor:e.getValueAtIndexOrDefault(l.backgroundColor,n,u.backgroundColor),borderColor:s.borderColor?s.borderColor:e.getValueAtIndexOrDefault(l.borderColor,n,u.borderColor),borderWidth:s.borderWidth?s.borderWidth:e.getValueAtIndexOrDefault(l.borderWidth,n,u.borderWidth)},a.updateElementGeometry(t,n,i),t.pivot()},updateElementGeometry:function(t,e,n){var i=this,a=t._model,o=i.getValueScale(),r=o.getBasePixel(),l=o.isHorizontal(),s=i._ruler||i.getRuler(),u=i.calculateBarValuePixels(i.index,e),d=i.calculateBarIndexPixels(i.index,e,s);a.horizontal=l,a.base=n?r:u.base,a.x=l?n?r:u.head:d.center,a.y=l?d.center:n?r:u.head,a.height=l?d.size:void 0,a.width=l?void 0:d.size},getValueScaleId:function(){return this.getMeta().yAxisID},getIndexScaleId:function(){return this.getMeta().xAxisID},getValueScale:function(){return this.getScaleForId(this.getValueScaleId())},getIndexScale:function(){return this.getScaleForId(this.getIndexScaleId())},getStackCount:function(t){var e,n,i=this.chart,a=this.getIndexScale().options.stacked,o=void 0===t?i.data.datasets.length:t+1,r=[];for(e=0;e<o;++e)(n=i.getDatasetMeta(e)).bar&&i.isDatasetVisible(e)&&(!1===a||!0===a&&-1===r.indexOf(n.stack)||void 0===a&&(void 0===n.stack||-1===r.indexOf(n.stack)))&&r.push(n.stack);return r.length},getStackIndex:function(t){return this.getStackCount(t)-1},getRuler:function(){var t=this.getIndexScale(),n=t.options,i=this.getStackCount(),a=(t.isHorizontal()?t.width:t.height)/t.ticks.length,o=a*n.categoryPercentage,r=o/i,l=r*n.barPercentage;return l=Math.min(e.getValueOrDefault(n.barThickness,l),e.getValueOrDefault(n.maxBarThickness,1/0)),{stackCount:i,tickSize:a,categorySize:o,categorySpacing:a-o,fullBarSize:r,barSize:l,barSpacing:r-l,scale:t}},calculateBarValuePixels:function(t,e){var n,i,a,o,r,l,s=this,u=s.chart,d=s.getMeta(),c=s.getValueScale(),h=u.data.datasets,f=Number(h[t].data[e]),g=c.options.stacked,p=d.stack,m=0;if(g||void 0===g&&void 0!==p)for(n=0;n<t;++n)(i=u.getDatasetMeta(n)).bar&&i.stack===p&&i.controller.getValueScaleId()===c.id&&u.isDatasetVisible(n)&&(a=Number(h[n].data[e]),(f<0&&a<0||f>=0&&a>0)&&(m+=a));return o=c.getPixelForValue(m),r=c.getPixelForValue(m+f),l=(r-o)/2,{size:l,base:o,head:r,center:r+l/2}},calculateBarIndexPixels:function(t,e,n){var i=n.scale,a=this.chart.isCombo,o=this.getStackIndex(t),r=i.getPixelForValue(null,e,t,a),l=n.barSize;return r-=a?n.tickSize/2:0,r+=n.fullBarSize*o,r+=n.categorySpacing/2,r+=n.barSpacing/2,{size:l,base:r,head:r+l,center:r+l/2}},draw:function(){var t,n=this,i=n.chart,a=n.getMeta().data,o=n.getDataset(),r=a.length,l=0;for(e.canvas.clipArea(i.ctx,i.chartArea);l<r;++l)null===(t=o.data[l])||void 0===t||isNaN(t)||a[l].draw();e.canvas.unclipArea(i.ctx)},setHoverStyle:function(t){var n=this.chart.data.datasets[t._datasetIndex],i=t._index,a=t.custom||{},o=t._model;o.backgroundColor=a.hoverBackgroundColor?a.hoverBackgroundColor:e.getValueAtIndexOrDefault(n.hoverBackgroundColor,i,e.getHoverColor(o.backgroundColor)),o.borderColor=a.hoverBorderColor?a.hoverBorderColor:e.getValueAtIndexOrDefault(n.hoverBorderColor,i,e.getHoverColor(o.borderColor)),o.borderWidth=a.hoverBorderWidth?a.hoverBorderWidth:e.getValueAtIndexOrDefault(n.hoverBorderWidth,i,o.borderWidth)},removeHoverStyle:function(t){var n=this.chart.data.datasets[t._datasetIndex],i=t._index,a=t.custom||{},o=t._model,r=this.chart.options.elements.rectangle;o.backgroundColor=a.backgroundColor?a.backgroundColor:e.getValueAtIndexOrDefault(n.backgroundColor,i,r.backgroundColor),o.borderColor=a.borderColor?a.borderColor:e.getValueAtIndexOrDefault(n.borderColor,i,r.borderColor),o.borderWidth=a.borderWidth?a.borderWidth:e.getValueAtIndexOrDefault(n.borderWidth,i,r.borderWidth)}}),t.defaults.horizontalBar={hover:{mode:"label"},scales:{xAxes:[{type:"linear",position:"bottom"}],yAxes:[{position:"left",type:"category",categoryPercentage:.8,barPercentage:.9,gridLines:{offsetGridLines:!0}}]},elements:{rectangle:{borderSkipped:"left"}},tooltips:{callbacks:{title:function(t,e){var n="";return t.length>0&&(t[0].yLabel?n=t[0].yLabel:e.labels.length>0&&t[0].index<e.labels.length&&(n=e.labels[t[0].index])),n},label:function(t,e){return(e.datasets[t.datasetIndex].label||"")+": "+t.xLabel}}}},t.controllers.horizontalBar=t.controllers.bar.extend({getValueScaleId:function(){return this.getMeta().xAxisID},getIndexScaleId:function(){return this.getMeta().yAxisID}})}},{}],16:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.bubble={hover:{mode:"single"},scales:{xAxes:[{type:"linear",position:"bottom",id:"x-axis-0"}],yAxes:[{type:"linear",position:"left",id:"y-axis-0"}]},tooltips:{callbacks:{title:function(){return""},label:function(t,e){var n=e.datasets[t.datasetIndex].label||"",i=e.datasets[t.datasetIndex].data[t.index];return n+": ("+t.xLabel+", "+t.yLabel+", "+i.r+")"}}}},t.controllers.bubble=t.DatasetController.extend({dataElementType:t.elements.Point,update:function(t){var n=this,i=n.getMeta().data;e.each(i,function(e,i){n.updateElement(e,i,t)})},updateElement:function(n,i,a){var o=this,r=o.getMeta(),l=o.getScaleForId(r.xAxisID),s=o.getScaleForId(r.yAxisID),u=n.custom||{},d=o.getDataset(),c=d.data[i],h=o.chart.options.elements.point,f=o.index;e.extend(n,{_xScale:l,_yScale:s,_datasetIndex:f,_index:i,_model:{x:a?l.getPixelForDecimal(.5):l.getPixelForValue("object"==typeof c?c:NaN,i,f,o.chart.isCombo),y:a?s.getBasePixel():s.getPixelForValue(c,i,f),radius:a?0:u.radius?u.radius:o.getRadius(c),hitRadius:u.hitRadius?u.hitRadius:e.getValueAtIndexOrDefault(d.hitRadius,i,h.hitRadius)}}),t.DatasetController.prototype.removeHoverStyle.call(o,n,h);var g=n._model;g.skip=u.skip?u.skip:isNaN(g.x)||isNaN(g.y),n.pivot()},getRadius:function(t){return t.r||this.chart.options.elements.point.radius},setHoverStyle:function(n){var i=this;t.DatasetController.prototype.setHoverStyle.call(i,n);var a=i.chart.data.datasets[n._datasetIndex],o=n._index,r=n.custom||{};n._model.radius=r.hoverRadius?r.hoverRadius:e.getValueAtIndexOrDefault(a.hoverRadius,o,i.chart.options.elements.point.hoverRadius)+i.getRadius(a.data[o])},removeHoverStyle:function(e){var n=this;t.DatasetController.prototype.removeHoverStyle.call(n,e,n.chart.options.elements.point);var i=n.chart.data.datasets[e._datasetIndex].data[e._index],a=e.custom||{};e._model.radius=a.radius?a.radius:n.getRadius(i)}})}},{}],17:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=t.defaults;n.doughnut={animation:{animateRotate:!0,animateScale:!1},aspectRatio:1,hover:{mode:"single"},legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');var n=t.data,i=n.datasets,a=n.labels;if(i.length)for(var o=0;o<i[0].data.length;++o)e.push('<li><span style="background-color:'+i[0].backgroundColor[o]+'"></span>'),a[o]&&e.push(a[o]),e.push("</li>");return e.push("</ul>"),e.join("")},legend:{labels:{generateLabels:function(t){var n=t.data;return n.labels.length&&n.datasets.length?n.labels.map(function(i,a){var o=t.getDatasetMeta(0),r=n.datasets[0],l=o.data[a],s=l&&l.custom||{},u=e.getValueAtIndexOrDefault,d=t.options.elements.arc;return{text:i,fillStyle:s.backgroundColor?s.backgroundColor:u(r.backgroundColor,a,d.backgroundColor),strokeStyle:s.borderColor?s.borderColor:u(r.borderColor,a,d.borderColor),lineWidth:s.borderWidth?s.borderWidth:u(r.borderWidth,a,d.borderWidth),hidden:isNaN(r.data[a])||o.data[a].hidden,index:a}}):[]}},onClick:function(t,e){var n,i,a,o=e.index,r=this.chart;for(n=0,i=(r.data.datasets||[]).length;n<i;++n)(a=r.getDatasetMeta(n)).data[o]&&(a.data[o].hidden=!a.data[o].hidden);r.update()}},cutoutPercentage:50,rotation:-.5*Math.PI,circumference:2*Math.PI,tooltips:{callbacks:{title:function(){return""},label:function(t,n){var i=n.labels[t.index],a=": "+n.datasets[t.datasetIndex].data[t.index];return e.isArray(i)?(i=i.slice(),i[0]+=a):i+=a,i}}}},n.pie=e.clone(n.doughnut),e.extend(n.pie,{cutoutPercentage:0}),t.controllers.doughnut=t.controllers.pie=t.DatasetController.extend({dataElementType:t.elements.Arc,linkScales:e.noop,getRingIndex:function(t){for(var e=0,n=0;n<t;++n)this.chart.isDatasetVisible(n)&&++e;return e},update:function(t){var n=this,i=n.chart,a=i.chartArea,o=i.options,r=o.elements.arc,l=a.right-a.left-r.borderWidth,s=a.bottom-a.top-r.borderWidth,u=Math.min(l,s),d={x:0,y:0},c=n.getMeta(),h=o.cutoutPercentage,f=o.circumference;if(f<2*Math.PI){var g=o.rotation%(2*Math.PI),p=(g+=2*Math.PI*(g>=Math.PI?-1:g<-Math.PI?1:0))+f,m={x:Math.cos(g),y:Math.sin(g)},v={x:Math.cos(p),y:Math.sin(p)},b=g<=0&&0<=p||g<=2*Math.PI&&2*Math.PI<=p,x=g<=.5*Math.PI&&.5*Math.PI<=p||g<=2.5*Math.PI&&2.5*Math.PI<=p,y=g<=-Math.PI&&-Math.PI<=p||g<=Math.PI&&Math.PI<=p,k=g<=.5*-Math.PI&&.5*-Math.PI<=p||g<=1.5*Math.PI&&1.5*Math.PI<=p,w=h/100,M={x:y?-1:Math.min(m.x*(m.x<0?1:w),v.x*(v.x<0?1:w)),y:k?-1:Math.min(m.y*(m.y<0?1:w),v.y*(v.y<0?1:w))},S={x:b?1:Math.max(m.x*(m.x>0?1:w),v.x*(v.x>0?1:w)),y:x?1:Math.max(m.y*(m.y>0?1:w),v.y*(v.y>0?1:w))},C={width:.5*(S.x-M.x),height:.5*(S.y-M.y)};u=Math.min(l/C.width,s/C.height),d={x:-.5*(S.x+M.x),y:-.5*(S.y+M.y)}}i.borderWidth=n.getMaxBorderWidth(c.data),i.outerRadius=Math.max((u-i.borderWidth)/2,0),i.innerRadius=Math.max(h?i.outerRadius/100*h:0,0),i.radiusLength=(i.outerRadius-i.innerRadius)/i.getVisibleDatasetCount(),i.offsetX=d.x*i.outerRadius,i.offsetY=d.y*i.outerRadius,c.total=n.calculateTotal(),n.outerRadius=i.outerRadius-i.radiusLength*n.getRingIndex(n.index),n.innerRadius=Math.max(n.outerRadius-i.radiusLength,0),e.each(c.data,function(e,i){n.updateElement(e,i,t)})},updateElement:function(t,n,i){var a=this,o=a.chart,r=o.chartArea,l=o.options,s=l.animation,u=(r.left+r.right)/2,d=(r.top+r.bottom)/2,c=l.rotation,h=l.rotation,f=a.getDataset(),g=i&&s.animateRotate?0:t.hidden?0:a.calculateCircumference(f.data[n])*(l.circumference/(2*Math.PI)),p=i&&s.animateScale?0:a.innerRadius,m=i&&s.animateScale?0:a.outerRadius,v=e.getValueAtIndexOrDefault;e.extend(t,{_datasetIndex:a.index,_index:n,_model:{x:u+o.offsetX,y:d+o.offsetY,startAngle:c,endAngle:h,circumference:g,outerRadius:m,innerRadius:p,label:v(f.label,n,o.data.labels[n])}});var b=t._model;this.removeHoverStyle(t),i&&s.animateRotate||(b.startAngle=0===n?l.rotation:a.getMeta().data[n-1]._model.endAngle,b.endAngle=b.startAngle+b.circumference),t.pivot()},removeHoverStyle:function(e){t.DatasetController.prototype.removeHoverStyle.call(this,e,this.chart.options.elements.arc)},calculateTotal:function(){var t,n=this.getDataset(),i=this.getMeta(),a=0;return e.each(i.data,function(e,i){t=n.data[i],isNaN(t)||e.hidden||(a+=Math.abs(t))}),a},calculateCircumference:function(t){var e=this.getMeta().total;return e>0&&!isNaN(t)?2*Math.PI*(t/e):0},getMaxBorderWidth:function(t){for(var e,n,i=0,a=this.index,o=t.length,r=0;r<o;r++)e=t[r]._model?t[r]._model.borderWidth:0,n=t[r]._chart?t[r]._chart.config.data.datasets[a].hoverBorderWidth:0,i=e>i?e:i,i=n>i?n:i;return i}})}},{}],18:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){return n.getValueOrDefault(t.showLine,e.showLines)}var n=t.helpers;t.defaults.line={showLines:!0,spanGaps:!1,hover:{mode:"label"},scales:{xAxes:[{type:"category",id:"x-axis-0"}],yAxes:[{type:"linear",id:"y-axis-0"}]}},t.controllers.line=t.DatasetController.extend({datasetElementType:t.elements.Line,dataElementType:t.elements.Point,update:function(t){var i,a,o,r=this,l=r.getMeta(),s=l.dataset,u=l.data||[],d=r.chart.options,c=d.elements.line,h=r.getScaleForId(l.yAxisID),f=r.getDataset(),g=e(f,d);for(g&&(o=s.custom||{},void 0!==f.tension&&void 0===f.lineTension&&(f.lineTension=f.tension),s._scale=h,s._datasetIndex=r.index,s._children=u,s._model={spanGaps:f.spanGaps?f.spanGaps:d.spanGaps,tension:o.tension?o.tension:n.getValueOrDefault(f.lineTension,c.tension),backgroundColor:o.backgroundColor?o.backgroundColor:f.backgroundColor||c.backgroundColor,borderWidth:o.borderWidth?o.borderWidth:f.borderWidth||c.borderWidth,borderColor:o.borderColor?o.borderColor:f.borderColor||c.borderColor,borderCapStyle:o.borderCapStyle?o.borderCapStyle:f.borderCapStyle||c.borderCapStyle,borderDash:o.borderDash?o.borderDash:f.borderDash||c.borderDash,borderDashOffset:o.borderDashOffset?o.borderDashOffset:f.borderDashOffset||c.borderDashOffset,borderJoinStyle:o.borderJoinStyle?o.borderJoinStyle:f.borderJoinStyle||c.borderJoinStyle,fill:o.fill?o.fill:void 0!==f.fill?f.fill:c.fill,steppedLine:o.steppedLine?o.steppedLine:n.getValueOrDefault(f.steppedLine,c.stepped),cubicInterpolationMode:o.cubicInterpolationMode?o.cubicInterpolationMode:n.getValueOrDefault(f.cubicInterpolationMode,c.cubicInterpolationMode)},s.pivot()),i=0,a=u.length;i<a;++i)r.updateElement(u[i],i,t);for(g&&0!==s._model.tension&&r.updateBezierControlPoints(),i=0,a=u.length;i<a;++i)u[i].pivot()},getPointBackgroundColor:function(t,e){var i=this.chart.options.elements.point.backgroundColor,a=this.getDataset(),o=t.custom||{};return o.backgroundColor?i=o.backgroundColor:a.pointBackgroundColor?i=n.getValueAtIndexOrDefault(a.pointBackgroundColor,e,i):a.backgroundColor&&(i=a.backgroundColor),i},getPointBorderColor:function(t,e){var i=this.chart.options.elements.point.borderColor,a=this.getDataset(),o=t.custom||{};return o.borderColor?i=o.borderColor:a.pointBorderColor?i=n.getValueAtIndexOrDefault(a.pointBorderColor,e,i):a.borderColor&&(i=a.borderColor),i},getPointBorderWidth:function(t,e){var i=this.chart.options.elements.point.borderWidth,a=this.getDataset(),o=t.custom||{};return isNaN(o.borderWidth)?isNaN(a.pointBorderWidth)?isNaN(a.borderWidth)||(i=a.borderWidth):i=n.getValueAtIndexOrDefault(a.pointBorderWidth,e,i):i=o.borderWidth,i},updateElement:function(t,e,i){var a,o,r=this,l=r.getMeta(),s=t.custom||{},u=r.getDataset(),d=r.index,c=u.data[e],h=r.getScaleForId(l.yAxisID),f=r.getScaleForId(l.xAxisID),g=r.chart.options.elements.point,p=1===(r.chart.data.labels||[]).length||1===u.data.length||r.chart.isCombo;void 0!==u.radius&&void 0===u.pointRadius&&(u.pointRadius=u.radius),void 0!==u.hitRadius&&void 0===u.pointHitRadius&&(u.pointHitRadius=u.hitRadius),a=f.getPixelForValue("object"==typeof c?c:NaN,e,d,p),o=i?h.getBasePixel():r.calculatePointY(c,e,d),t._xScale=f,t._yScale=h,t._datasetIndex=d,t._index=e,t._model={x:a,y:o,skip:s.skip||isNaN(a)||isNaN(o),radius:s.radius||n.getValueAtIndexOrDefault(u.pointRadius,e,g.radius),pointStyle:s.pointStyle||n.getValueAtIndexOrDefault(u.pointStyle,e,g.pointStyle),backgroundColor:r.getPointBackgroundColor(t,e),borderColor:r.getPointBorderColor(t,e),borderWidth:r.getPointBorderWidth(t,e),tension:l.dataset._model?l.dataset._model.tension:0,steppedLine:!!l.dataset._model&&l.dataset._model.steppedLine,hitRadius:s.hitRadius||n.getValueAtIndexOrDefault(u.pointHitRadius,e,g.hitRadius)}},calculatePointY:function(t,e,n){var i,a,o,r=this,l=r.chart,s=r.getMeta(),u=r.getScaleForId(s.yAxisID),d=0,c=0;if(u.options.stacked){for(i=0;i<n;i++)if(a=l.data.datasets[i],"line"===(o=l.getDatasetMeta(i)).type&&o.yAxisID===u.id&&l.isDatasetVisible(i)){var h=Number(u.getRightValue(a.data[e]));h<0?c+=h||0:d+=h||0}var f=Number(u.getRightValue(t));return f<0?u.getPixelForValue(c+f):u.getPixelForValue(d+f)}return u.getPixelForValue(t)},updateBezierControlPoints:function(){function t(t,e,n){return Math.max(Math.min(t,n),e)}var e,i,a,o,r,l=this,s=l.getMeta(),u=l.chart.chartArea,d=s.data||[];if(s.dataset._model.spanGaps&&(d=d.filter(function(t){return!t._model.skip})),"monotone"===s.dataset._model.cubicInterpolationMode)n.splineCurveMonotone(d);else for(e=0,i=d.length;e<i;++e)a=d[e],o=a._model,r=n.splineCurve(n.previousItem(d,e)._model,o,n.nextItem(d,e)._model,s.dataset._model.tension),o.controlPointPreviousX=r.previous.x,o.controlPointPreviousY=r.previous.y,o.controlPointNextX=r.next.x,o.controlPointNextY=r.next.y;if(l.chart.options.elements.line.capBezierPoints)for(e=0,i=d.length;e<i;++e)o=d[e]._model,o.controlPointPreviousX=t(o.controlPointPreviousX,u.left,u.right),o.controlPointPreviousY=t(o.controlPointPreviousY,u.top,u.bottom),o.controlPointNextX=t(o.controlPointNextX,u.left,u.right),o.controlPointNextY=t(o.controlPointNextY,u.top,u.bottom)},draw:function(){var n=this,i=n.chart,a=n.getMeta(),o=a.data||[],r=i.chartArea,l=o.length,s=0;for(t.canvasHelpers.clipArea(i.ctx,r),e(n.getDataset(),i.options)&&a.dataset.draw(),t.canvasHelpers.unclipArea(i.ctx);s<l;++s)o[s].draw(r)},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],i=t._index,a=t.custom||{},o=t._model;o.radius=a.hoverRadius||n.getValueAtIndexOrDefault(e.pointHoverRadius,i,this.chart.options.elements.point.hoverRadius),o.backgroundColor=a.hoverBackgroundColor||n.getValueAtIndexOrDefault(e.pointHoverBackgroundColor,i,n.getHoverColor(o.backgroundColor)),o.borderColor=a.hoverBorderColor||n.getValueAtIndexOrDefault(e.pointHoverBorderColor,i,n.getHoverColor(o.borderColor)),o.borderWidth=a.hoverBorderWidth||n.getValueAtIndexOrDefault(e.pointHoverBorderWidth,i,o.borderWidth)},removeHoverStyle:function(t){var e=this,i=e.chart.data.datasets[t._datasetIndex],a=t._index,o=t.custom||{},r=t._model;void 0!==i.radius&&void 0===i.pointRadius&&(i.pointRadius=i.radius),r.radius=o.radius||n.getValueAtIndexOrDefault(i.pointRadius,a,e.chart.options.elements.point.radius),r.backgroundColor=e.getPointBackgroundColor(t,a),r.borderColor=e.getPointBorderColor(t,a),r.borderWidth=e.getPointBorderWidth(t,a)}})}},{}],19:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.polarArea={scale:{type:"radialLinear",angleLines:{display:!1},gridLines:{circular:!0},pointLabels:{display:!1},ticks:{beginAtZero:!0}},animation:{animateRotate:!0,animateScale:!0},startAngle:-.5*Math.PI,aspectRatio:1,legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');var n=t.data,i=n.datasets,a=n.labels;if(i.length)for(var o=0;o<i[0].data.length;++o)e.push('<li><span style="background-color:'+i[0].backgroundColor[o]+'"></span>'),a[o]&&e.push(a[o]),e.push("</li>");return e.push("</ul>"),e.join("")},legend:{labels:{generateLabels:function(t){var n=t.data;return n.labels.length&&n.datasets.length?n.labels.map(function(i,a){var o=t.getDatasetMeta(0),r=n.datasets[0],l=o.data[a].custom||{},s=e.getValueAtIndexOrDefault,u=t.options.elements.arc;return{text:i,fillStyle:l.backgroundColor?l.backgroundColor:s(r.backgroundColor,a,u.backgroundColor),strokeStyle:l.borderColor?l.borderColor:s(r.borderColor,a,u.borderColor),lineWidth:l.borderWidth?l.borderWidth:s(r.borderWidth,a,u.borderWidth),hidden:isNaN(r.data[a])||o.data[a].hidden,index:a}}):[]}},onClick:function(t,e){var n,i,a,o=e.index,r=this.chart;for(n=0,i=(r.data.datasets||[]).length;n<i;++n)a=r.getDatasetMeta(n),a.data[o].hidden=!a.data[o].hidden;r.update()}},tooltips:{callbacks:{title:function(){return""},label:function(t,e){return e.labels[t.index]+": "+t.yLabel}}}},t.controllers.polarArea=t.DatasetController.extend({dataElementType:t.elements.Arc,linkScales:e.noop,update:function(t){var n=this,i=n.chart,a=i.chartArea,o=n.getMeta(),r=i.options,l=r.elements.arc,s=Math.min(a.right-a.left,a.bottom-a.top);i.outerRadius=Math.max((s-l.borderWidth/2)/2,0),i.innerRadius=Math.max(r.cutoutPercentage?i.outerRadius/100*r.cutoutPercentage:1,0),i.radiusLength=(i.outerRadius-i.innerRadius)/i.getVisibleDatasetCount(),n.outerRadius=i.outerRadius-i.radiusLength*n.index,n.innerRadius=n.outerRadius-i.radiusLength,o.count=n.countVisibleElements(),e.each(o.data,function(e,i){n.updateElement(e,i,t)})},updateElement:function(t,n,i){for(var a=this,o=a.chart,r=a.getDataset(),l=o.options,s=l.animation,u=o.scale,d=e.getValueAtIndexOrDefault,c=o.data.labels,h=a.calculateCircumference(r.data[n]),f=u.xCenter,g=u.yCenter,p=0,m=a.getMeta(),v=0;v<n;++v)isNaN(r.data[v])||m.data[v].hidden||++p;var b=l.startAngle,x=t.hidden?0:u.getDistanceFromCenterForValue(r.data[n]),y=b+h*p,k=y+(t.hidden?0:h),w=s.animateScale?0:u.getDistanceFromCenterForValue(r.data[n]);e.extend(t,{_datasetIndex:a.index,_index:n,_scale:u,_model:{x:f,y:g,innerRadius:0,outerRadius:i?w:x,startAngle:i&&s.animateRotate?b:y,endAngle:i&&s.animateRotate?b:k,label:d(c,n,c[n])}}),a.removeHoverStyle(t),t.pivot()},removeHoverStyle:function(e){t.DatasetController.prototype.removeHoverStyle.call(this,e,this.chart.options.elements.arc)},countVisibleElements:function(){var t=this.getDataset(),n=this.getMeta(),i=0;return e.each(n.data,function(e,n){isNaN(t.data[n])||e.hidden||i++}),i},calculateCircumference:function(t){var e=this.getMeta().count;return e>0&&!isNaN(t)?2*Math.PI/e:0}})}},{}],20:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.radar={aspectRatio:1,scale:{type:"radialLinear"},elements:{line:{tension:0}}},t.controllers.radar=t.DatasetController.extend({datasetElementType:t.elements.Line,dataElementType:t.elements.Point,linkScales:e.noop,update:function(t){var n=this,i=n.getMeta(),a=i.dataset,o=i.data,r=a.custom||{},l=n.getDataset(),s=n.chart.options.elements.line,u=n.chart.scale;void 0!==l.tension&&void 0===l.lineTension&&(l.lineTension=l.tension),e.extend(i.dataset,{_datasetIndex:n.index,_scale:u,_children:o,_loop:!0,_model:{tension:r.tension?r.tension:e.getValueOrDefault(l.lineTension,s.tension),backgroundColor:r.backgroundColor?r.backgroundColor:l.backgroundColor||s.backgroundColor,borderWidth:r.borderWidth?r.borderWidth:l.borderWidth||s.borderWidth,borderColor:r.borderColor?r.borderColor:l.borderColor||s.borderColor,fill:r.fill?r.fill:void 0!==l.fill?l.fill:s.fill,borderCapStyle:r.borderCapStyle?r.borderCapStyle:l.borderCapStyle||s.borderCapStyle,borderDash:r.borderDash?r.borderDash:l.borderDash||s.borderDash,borderDashOffset:r.borderDashOffset?r.borderDashOffset:l.borderDashOffset||s.borderDashOffset,borderJoinStyle:r.borderJoinStyle?r.borderJoinStyle:l.borderJoinStyle||s.borderJoinStyle}}),i.dataset.pivot(),e.each(o,function(e,i){n.updateElement(e,i,t)},n),n.updateBezierControlPoints()},updateElement:function(t,n,i){var a=this,o=t.custom||{},r=a.getDataset(),l=a.chart.scale,s=a.chart.options.elements.point,u=l.getPointPositionForValue(n,r.data[n]);void 0!==r.radius&&void 0===r.pointRadius&&(r.pointRadius=r.radius),void 0!==r.hitRadius&&void 0===r.pointHitRadius&&(r.pointHitRadius=r.hitRadius),e.extend(t,{_datasetIndex:a.index,_index:n,_scale:l,_model:{x:i?l.xCenter:u.x,y:i?l.yCenter:u.y,tension:o.tension?o.tension:e.getValueOrDefault(r.lineTension,a.chart.options.elements.line.tension),radius:o.radius?o.radius:e.getValueAtIndexOrDefault(r.pointRadius,n,s.radius),backgroundColor:o.backgroundColor?o.backgroundColor:e.getValueAtIndexOrDefault(r.pointBackgroundColor,n,s.backgroundColor),borderColor:o.borderColor?o.borderColor:e.getValueAtIndexOrDefault(r.pointBorderColor,n,s.borderColor),borderWidth:o.borderWidth?o.borderWidth:e.getValueAtIndexOrDefault(r.pointBorderWidth,n,s.borderWidth),pointStyle:o.pointStyle?o.pointStyle:e.getValueAtIndexOrDefault(r.pointStyle,n,s.pointStyle),hitRadius:o.hitRadius?o.hitRadius:e.getValueAtIndexOrDefault(r.pointHitRadius,n,s.hitRadius)}}),t._model.skip=o.skip?o.skip:isNaN(t._model.x)||isNaN(t._model.y)},updateBezierControlPoints:function(){var t=this.chart.chartArea,n=this.getMeta();e.each(n.data,function(i,a){var o=i._model,r=e.splineCurve(e.previousItem(n.data,a,!0)._model,o,e.nextItem(n.data,a,!0)._model,o.tension);o.controlPointPreviousX=Math.max(Math.min(r.previous.x,t.right),t.left),o.controlPointPreviousY=Math.max(Math.min(r.previous.y,t.bottom),t.top),o.controlPointNextX=Math.max(Math.min(r.next.x,t.right),t.left),o.controlPointNextY=Math.max(Math.min(r.next.y,t.bottom),t.top),i.pivot()})},setHoverStyle:function(t){var n=this.chart.data.datasets[t._datasetIndex],i=t.custom||{},a=t._index,o=t._model;o.radius=i.hoverRadius?i.hoverRadius:e.getValueAtIndexOrDefault(n.pointHoverRadius,a,this.chart.options.elements.point.hoverRadius),o.backgroundColor=i.hoverBackgroundColor?i.hoverBackgroundColor:e.getValueAtIndexOrDefault(n.pointHoverBackgroundColor,a,e.getHoverColor(o.backgroundColor)),o.borderColor=i.hoverBorderColor?i.hoverBorderColor:e.getValueAtIndexOrDefault(n.pointHoverBorderColor,a,e.getHoverColor(o.borderColor)),o.borderWidth=i.hoverBorderWidth?i.hoverBorderWidth:e.getValueAtIndexOrDefault(n.pointHoverBorderWidth,a,o.borderWidth)},removeHoverStyle:function(t){var n=this.chart.data.datasets[t._datasetIndex],i=t.custom||{},a=t._index,o=t._model,r=this.chart.options.elements.point;o.radius=i.radius?i.radius:e.getValueAtIndexOrDefault(n.pointRadius,a,r.radius),o.backgroundColor=i.backgroundColor?i.backgroundColor:e.getValueAtIndexOrDefault(n.pointBackgroundColor,a,r.backgroundColor),o.borderColor=i.borderColor?i.borderColor:e.getValueAtIndexOrDefault(n.pointBorderColor,a,r.borderColor),o.borderWidth=i.borderWidth?i.borderWidth:e.getValueAtIndexOrDefault(n.pointBorderWidth,a,r.borderWidth)}})}},{}],21:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.global.animation={duration:1e3,easing:"easeOutQuart",onProgress:e.noop,onComplete:e.noop},t.Animation=t.Element.extend({chart:null,currentStep:0,numSteps:60,easing:"",render:null,onAnimationProgress:null,onAnimationComplete:null}),t.animationService={frameDuration:17,animations:[],dropFrames:0,request:null,addAnimation:function(t,e,n,i){var a,o,r=this.animations;for(e.chart=t,i||(t.animating=!0),a=0,o=r.length;a<o;++a)if(r[a].chart===t)return void(r[a]=e);r.push(e),1===r.length&&this.requestAnimationFrame()},cancelAnimation:function(t){var n=e.findIndex(this.animations,function(e){return e.chart===t});-1!==n&&(this.animations.splice(n,1),t.animating=!1)},requestAnimationFrame:function(){var t=this;null===t.request&&(t.request=e.requestAnimFrame.call(window,function(){t.request=null,t.startDigest()}))},startDigest:function(){var t=this,e=Date.now(),n=0;t.dropFrames>1&&(n=Math.floor(t.dropFrames),t.dropFrames=t.dropFrames%1),t.advance(1+n);var i=Date.now();t.dropFrames+=(i-e)/t.frameDuration,t.animations.length>0&&t.requestAnimationFrame()},advance:function(t){for(var n,i,a=this.animations,o=0;o<a.length;)n=a[o],i=n.chart,n.currentStep=(n.currentStep||0)+t,n.currentStep=Math.min(n.currentStep,n.numSteps),e.callback(n.render,[i,n],i),e.callback(n.onAnimationProgress,[n],i),n.currentStep>=n.numSteps?(e.callback(n.onAnimationComplete,[n],i),i.animating=!1,a.splice(o,1)):++o}},Object.defineProperty(t.Animation.prototype,"animationObject",{get:function(){return this}}),Object.defineProperty(t.Animation.prototype,"chartInstance",{get:function(){return this.chart},set:function(t){this.chart=t}})}},{}],22:[function(t,e,n){"use strict";e.exports=function(t){var e=t.canvasHelpers={};e.drawPoint=function(e,n,i,a,o){var r,l,s,u,d,c;if("object"!=typeof n||"[object HTMLImageElement]"!==(r=n.toString())&&"[object HTMLCanvasElement]"!==r){if(!(isNaN(i)||i<=0)){switch(n){default:e.beginPath(),e.arc(a,o,i,0,2*Math.PI),e.closePath(),e.fill();break;case"triangle":e.beginPath(),d=(l=3*i/Math.sqrt(3))*Math.sqrt(3)/2,e.moveTo(a-l/2,o+d/3),e.lineTo(a+l/2,o+d/3),e.lineTo(a,o-2*d/3),e.closePath(),e.fill();break;case"rect":c=1/Math.SQRT2*i,e.beginPath(),e.fillRect(a-c,o-c,2*c,2*c),e.strokeRect(a-c,o-c,2*c,2*c);break;case"rectRounded":var h=i/Math.SQRT2,f=a-h,g=o-h,p=Math.SQRT2*i;t.helpers.drawRoundedRectangle(e,f,g,p,p,i/2),e.fill();break;case"rectRot":c=1/Math.SQRT2*i,e.beginPath(),e.moveTo(a-c,o),e.lineTo(a,o+c),e.lineTo(a+c,o),e.lineTo(a,o-c),e.closePath(),e.fill();break;case"cross":e.beginPath(),e.moveTo(a,o+i),e.lineTo(a,o-i),e.moveTo(a-i,o),e.lineTo(a+i,o),e.closePath();break;case"crossRot":e.beginPath(),s=Math.cos(Math.PI/4)*i,u=Math.sin(Math.PI/4)*i,e.moveTo(a-s,o-u),e.lineTo(a+s,o+u),e.moveTo(a-s,o+u),e.lineTo(a+s,o-u),e.closePath();break;case"star":e.beginPath(),e.moveTo(a,o+i),e.lineTo(a,o-i),e.moveTo(a-i,o),e.lineTo(a+i,o),s=Math.cos(Math.PI/4)*i,u=Math.sin(Math.PI/4)*i,e.moveTo(a-s,o-u),e.lineTo(a+s,o+u),e.moveTo(a-s,o+u),e.lineTo(a+s,o-u),e.closePath();break;case"line":e.beginPath(),e.moveTo(a-i,o),e.lineTo(a+i,o),e.closePath();break;case"dash":e.beginPath(),e.moveTo(a,o),e.lineTo(a+i,o),e.closePath()}e.stroke()}}else e.drawImage(n,a-n.width/2,o-n.height/2,n.width,n.height)},e.clipArea=function(t,e){t.save(),t.beginPath(),t.rect(e.left,e.top,e.right-e.left,e.bottom-e.top),t.clip()},e.unclipArea=function(t){t.restore()},e.lineTo=function(t,e,n,i){return n.steppedLine?("after"===n.steppedLine?t.lineTo(e.x,n.y):t.lineTo(n.x,e.y),void t.lineTo(n.x,n.y)):n.tension?void t.bezierCurveTo(i?e.controlPointPreviousX:e.controlPointNextX,i?e.controlPointPreviousY:e.controlPointNextY,i?n.controlPointNextX:n.controlPointPreviousX,i?n.controlPointNextY:n.controlPointPreviousY,n.x,n.y):void t.lineTo(n.x,n.y)},t.helpers.canvas=e}},{}],23:[function(t,e,n){"use strict";e.exports=function(t){function e(t){return"top"===t||"bottom"===t}var n=t.helpers,i=t.plugins,a=t.platform;t.types={},t.instances={},t.controllers={},n.extend(t.prototype,{construct:function(e,i){var o=this;i=function(e){var i=(e=e||{}).data=e.data||{};return i.datasets=i.datasets||[],i.labels=i.labels||[],e.options=n.configMerge(t.defaults.global,t.defaults[e.type],e.options||{}),e}(i);var r=a.acquireContext(e,i),l=r&&r.canvas,s=l&&l.height,u=l&&l.width;return o.id=n.uid(),o.ctx=r,o.canvas=l,o.config=i,o.width=u,o.height=s,o.aspectRatio=s?u/s:null,o.options=i.options,o._bufferedRender=!1,o.chart=o,o.controller=o,t.instances[o.id]=o,Object.defineProperty(o,"data",{get:function(){return o.config.data},set:function(t){o.config.data=t}}),r&&l?(o.initialize(),void o.update()):void console.error("Failed to create chart: can't acquire context from the given item")},initialize:function(){var t=this;return i.notify(t,"beforeInit"),n.retinaScale(t),t.bindEvents(),t.options.responsive&&t.resize(!0),t.ensureScalesHaveIDs(),t.buildScales(),t.initToolTip(),i.notify(t,"afterInit"),t},clear:function(){return n.clear(this),this},stop:function(){return t.animationService.cancelAnimation(this),this},resize:function(t){var e=this,a=e.options,o=e.canvas,r=a.maintainAspectRatio&&e.aspectRatio||null,l=Math.floor(n.getMaximumWidth(o)),s=Math.floor(r?l/r:n.getMaximumHeight(o));if((e.width!==l||e.height!==s)&&(o.width=e.width=l,o.height=e.height=s,o.style.width=l+"px",o.style.height=s+"px",n.retinaScale(e),!t)){var u={width:l,height:s};i.notify(e,"resize",[u]),e.options.onResize&&e.options.onResize(e,u),e.stop(),e.update(e.options.responsiveAnimationDuration)}},ensureScalesHaveIDs:function(){var t=this.options,e=t.scales||{},i=t.scale;n.each(e.xAxes,function(t,e){t.id=t.id||"x-axis-"+e}),n.each(e.yAxes,function(t,e){t.id=t.id||"y-axis-"+e}),i&&(i.id=i.id||"scale")},buildScales:function(){var i=this,a=i.options,o=i.scales={},r=[];a.scales&&(r=r.concat((a.scales.xAxes||[]).map(function(t){return{options:t,dtype:"category",dposition:"bottom"}}),(a.scales.yAxes||[]).map(function(t){return{options:t,dtype:"linear",dposition:"left"}}))),a.scale&&r.push({options:a.scale,dtype:"radialLinear",isDefault:!0,dposition:"chartArea"}),n.each(r,function(a){var r=a.options,l=n.getValueOrDefault(r.type,a.dtype),s=t.scaleService.getScaleConstructor(l);if(s){e(r.position)!==e(a.dposition)&&(r.position=a.dposition);var u=new s({id:r.id,options:r,ctx:i.ctx,chart:i});o[u.id]=u,a.isDefault&&(i.scale=u)}}),t.scaleService.addScalesToLayout(this)},buildOrUpdateControllers:function(){var e=this,i=[],a=[];if(n.each(e.data.datasets,function(n,o){var r=e.getDatasetMeta(o);if(r.type||(r.type=n.type||e.config.type),i.push(r.type),r.controller)r.controller.updateIndex(o);else{var l=t.controllers[r.type];if(void 0===l)throw new Error('"'+r.type+'" is not a chart type.');r.controller=new l(e,o),a.push(r.controller)}},e),i.length>1)for(var o=1;o<i.length;o++)if(i[o]!==i[o-1]){e.isCombo=!0;break}return a},resetElements:function(){var t=this;n.each(t.data.datasets,function(e,n){t.getDatasetMeta(n).controller.reset()},t)},reset:function(){this.resetElements(),this.tooltip.initialize()},update:function(t,e){var a=this;if(function(t){var e=t.options;e.scale?t.scale.options=e.scale:e.scales&&e.scales.xAxes.concat(e.scales.yAxes).forEach(function(e){t.scales[e.id].options=e}),t.tooltip._options=e.tooltips}(a),!1!==i.notify(a,"beforeUpdate")){a.tooltip._data=a.data;var o=a.buildOrUpdateControllers();n.each(a.data.datasets,function(t,e){a.getDatasetMeta(e).controller.buildOrUpdateElements()},a),a.updateLayout(),n.each(o,function(t){t.reset()}),a.updateDatasets(),i.notify(a,"afterUpdate"),a._bufferedRender?a._bufferedRequest={lazy:e,duration:t}:a.render(t,e)}},updateLayout:function(){var e=this;!1!==i.notify(e,"beforeLayout")&&(t.layoutService.update(this,this.width,this.height),i.notify(e,"afterScaleUpdate"),i.notify(e,"afterLayout"))},updateDatasets:function(){var t=this;if(!1!==i.notify(t,"beforeDatasetsUpdate")){for(var e=0,n=t.data.datasets.length;e<n;++e)t.updateDataset(e);i.notify(t,"afterDatasetsUpdate")}},updateDataset:function(t){var e=this,n=e.getDatasetMeta(t),a={meta:n,index:t};!1!==i.notify(e,"beforeDatasetUpdate",[a])&&(n.controller.update(),i.notify(e,"afterDatasetUpdate",[a]))},render:function(e,a){var o=this;if(!1!==i.notify(o,"beforeRender")){var r=o.options.animation,l=function(t){i.notify(o,"afterRender"),n.callback(r&&r.onComplete,[t],o)};if(r&&(void 0!==e&&0!==e||void 0===e&&0!==r.duration)){var s=new t.Animation({numSteps:(e||r.duration)/16.66,easing:r.easing,render:function(t,e){var i=n.easingEffects[e.easing],a=e.currentStep,o=a/e.numSteps;t.draw(i(o),o,a)},onAnimationProgress:r.onProgress,onAnimationComplete:l});t.animationService.addAnimation(o,s,e,a)}else o.draw(),l(new t.Animation({numSteps:0,chart:o}));return o}},draw:function(t){var e=this;e.clear(),void 0!==t&&null!==t||(t=1),e.transition(t),!1!==i.notify(e,"beforeDraw",[t])&&(n.each(e.boxes,function(t){t.draw(e.chartArea)},e),e.scale&&e.scale.draw(),e.drawDatasets(t),e.tooltip.draw(),i.notify(e,"afterDraw",[t]))},transition:function(t){for(var e=this,n=0,i=(e.data.datasets||[]).length;n<i;++n)e.isDatasetVisible(n)&&e.getDatasetMeta(n).controller.transition(t);e.tooltip.transition(t)},drawDatasets:function(t){var e=this;if(!1!==i.notify(e,"beforeDatasetsDraw",[t])){for(var n=(e.data.datasets||[]).length-1;n>=0;--n)e.isDatasetVisible(n)&&e.drawDataset(n,t);i.notify(e,"afterDatasetsDraw",[t])}},drawDataset:function(t,e){var n=this,a=n.getDatasetMeta(t),o={meta:a,index:t,easingValue:e};!1!==i.notify(n,"beforeDatasetDraw",[o])&&(a.controller.draw(e),i.notify(n,"afterDatasetDraw",[o]))},getElementAtEvent:function(e){return t.Interaction.modes.single(this,e)},getElementsAtEvent:function(e){return t.Interaction.modes.label(this,e,{intersect:!0})},getElementsAtXAxis:function(e){return t.Interaction.modes["x-axis"](this,e,{intersect:!0})},getElementsAtEventForMode:function(e,n,i){var a=t.Interaction.modes[n];return"function"==typeof a?a(this,e,i):[]},getDatasetAtEvent:function(e){return t.Interaction.modes.dataset(this,e,{intersect:!0})},getDatasetMeta:function(t){var e=this,n=e.data.datasets[t];n._meta||(n._meta={});var i=n._meta[e.id];return i||(i=n._meta[e.id]={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null}),i},getVisibleDatasetCount:function(){for(var t=0,e=0,n=this.data.datasets.length;e<n;++e)this.isDatasetVisible(e)&&t++;return t},isDatasetVisible:function(t){var e=this.getDatasetMeta(t);return"boolean"==typeof e.hidden?!e.hidden:!this.data.datasets[t].hidden},generateLegend:function(){return this.options.legendCallback(this)},destroy:function(){var e,o,r,l=this,s=l.canvas;for(l.stop(),o=0,r=l.data.datasets.length;o<r;++o)(e=l.getDatasetMeta(o)).controller&&(e.controller.destroy(),e.controller=null);s&&(l.unbindEvents(),n.clear(l),a.releaseContext(l.ctx),l.canvas=null,l.ctx=null),i.notify(l,"destroy"),delete t.instances[l.id]},toBase64Image:function(){return this.canvas.toDataURL.apply(this.canvas,arguments)},initToolTip:function(){var e=this;e.tooltip=new t.Tooltip({_chart:e,_chartInstance:e,_data:e.data,_options:e.options.tooltips},e),e.tooltip.initialize()},bindEvents:function(){var t=this,e=t._listeners={},i=function(){t.eventHandler.apply(t,arguments)};n.each(t.options.events,function(n){a.addEventListener(t,n,i),e[n]=i}),t.options.responsive&&(i=function(){t.resize()},a.addEventListener(t,"resize",i),e.resize=i)},unbindEvents:function(){var t=this,e=t._listeners;e&&(delete t._listeners,n.each(e,function(e,n){a.removeEventListener(t,n,e)}))},updateHoverStyle:function(t,e,n){var i,a,o,r=n?"setHoverStyle":"removeHoverStyle";for(a=0,o=t.length;a<o;++a)(i=t[a])&&this.getDatasetMeta(i._datasetIndex).controller[r](i)},eventHandler:function(t){var e=this,n=e.tooltip;if(!1!==i.notify(e,"beforeEvent",[t])){e._bufferedRender=!0,e._bufferedRequest=null;var a=e.handleEvent(t);a|=n&&n.handleEvent(t),i.notify(e,"afterEvent",[t]);var o=e._bufferedRequest;return o?e.render(o.duration,o.lazy):a&&!e.animating&&(e.stop(),e.render(e.options.hover.animationDuration,!0)),e._bufferedRender=!1,e._bufferedRequest=null,e}},handleEvent:function(t){var e=this,i=e.options||{},a=i.hover,o=!1;return e.lastActive=e.lastActive||[],"mouseout"===t.type?e.active=[]:e.active=e.getElementsAtEventForMode(t,a.mode,a),a.onHover&&a.onHover.call(e,t.native,e.active),"mouseup"!==t.type&&"click"!==t.type||i.onClick&&i.onClick.call(e,t.native,e.active),e.lastActive.length&&e.updateHoverStyle(e.lastActive,a.mode,!1),e.active.length&&a.mode&&e.updateHoverStyle(e.active,a.mode,!0),o=!n.arrayEquals(e.active,e.lastActive),e.lastActive=e.active,o}}),t.Controller=t}},{}],24:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){return t._chartjs?void t._chartjs.listeners.push(e):(Object.defineProperty(t,"_chartjs",{configurable:!0,enumerable:!1,value:{listeners:[e]}}),void a.forEach(function(e){var n="onData"+e.charAt(0).toUpperCase()+e.slice(1),a=t[e];Object.defineProperty(t,e,{configurable:!0,enumerable:!1,value:function(){var e=Array.prototype.slice.call(arguments),o=a.apply(this,e);return i.each(t._chartjs.listeners,function(t){"function"==typeof t[n]&&t[n].apply(t,e)}),o}})}))}function n(t,e){var n=t._chartjs;if(n){var i=n.listeners,o=i.indexOf(e);-1!==o&&i.splice(o,1),i.length>0||(a.forEach(function(e){delete t[e]}),delete t._chartjs)}}var i=t.helpers,a=["push","pop","shift","splice","unshift"];t.DatasetController=function(t,e){this.initialize(t,e)},i.extend(t.DatasetController.prototype,{datasetElementType:null,dataElementType:null,initialize:function(t,e){var n=this;n.chart=t,n.index=e,n.linkScales(),n.addElements()},updateIndex:function(t){this.index=t},linkScales:function(){var t=this,e=t.getMeta(),n=t.getDataset();null===e.xAxisID&&(e.xAxisID=n.xAxisID||t.chart.options.scales.xAxes[0].id),null===e.yAxisID&&(e.yAxisID=n.yAxisID||t.chart.options.scales.yAxes[0].id)},getDataset:function(){return this.chart.data.datasets[this.index]},getMeta:function(){return this.chart.getDatasetMeta(this.index)},getScaleForId:function(t){return this.chart.scales[t]},reset:function(){this.update(!0)},destroy:function(){this._data&&n(this._data,this)},createMetaDataset:function(){var t=this,e=t.datasetElementType;return e&&new e({_chart:t.chart,_datasetIndex:t.index})},createMetaData:function(t){var e=this,n=e.dataElementType;return n&&new n({_chart:e.chart,_datasetIndex:e.index,_index:t})},addElements:function(){var t,e,n=this,i=n.getMeta(),a=n.getDataset().data||[],o=i.data;for(t=0,e=a.length;t<e;++t)o[t]=o[t]||n.createMetaData(t);i.dataset=i.dataset||n.createMetaDataset()},addElementAndReset:function(t){var e=this.createMetaData(t);this.getMeta().data.splice(t,0,e),this.updateElement(e,t,!0)},buildOrUpdateElements:function(){var t=this,i=t.getDataset(),a=i.data||(i.data=[]);t._data!==a&&(t._data&&n(t._data,t),e(a,t),t._data=a),t.resyncElements()},update:i.noop,transition:function(t){for(var e=this.getMeta(),n=e.data||[],i=n.length,a=0;a<i;++a)n[a].transition(t);e.dataset&&e.dataset.transition(t)},draw:function(){var t=this.getMeta(),e=t.data||[],n=e.length,i=0;for(t.dataset&&t.dataset.draw();i<n;++i)e[i].draw()},removeHoverStyle:function(t,e){var n=this.chart.data.datasets[t._datasetIndex],a=t._index,o=t.custom||{},r=i.getValueAtIndexOrDefault,l=t._model;l.backgroundColor=o.backgroundColor?o.backgroundColor:r(n.backgroundColor,a,e.backgroundColor),l.borderColor=o.borderColor?o.borderColor:r(n.borderColor,a,e.borderColor),l.borderWidth=o.borderWidth?o.borderWidth:r(n.borderWidth,a,e.borderWidth)},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],n=t._index,a=t.custom||{},o=i.getValueAtIndexOrDefault,r=i.getHoverColor,l=t._model;l.backgroundColor=a.hoverBackgroundColor?a.hoverBackgroundColor:o(e.hoverBackgroundColor,n,r(l.backgroundColor)),l.borderColor=a.hoverBorderColor?a.hoverBorderColor:o(e.hoverBorderColor,n,r(l.borderColor)),l.borderWidth=a.hoverBorderWidth?a.hoverBorderWidth:o(e.hoverBorderWidth,n,l.borderWidth)},resyncElements:function(){var t=this,e=t.getMeta(),n=t.getDataset().data,i=e.data.length,a=n.length;a<i?e.data.splice(a,i-a):a>i&&t.insertElements(i,a-i)},insertElements:function(t,e){for(var n=0;n<e;++n)this.addElementAndReset(t+n)},onDataPush:function(){this.insertElements(this.getDataset().data.length-1,arguments.length)},onDataPop:function(){this.getMeta().data.pop()},onDataShift:function(){this.getMeta().data.shift()},onDataSplice:function(t,e){this.getMeta().data.splice(t,e),this.insertElements(t,arguments.length-2)},onDataUnshift:function(){this.insertElements(0,arguments.length)}}),t.DatasetController.extend=i.inherits}},{}],25:[function(t,e,n){"use strict";var i=t(3);e.exports=function(t){function e(t,e,n,a){var o,r,l,s,u,d,c,h,f,g=Object.keys(n);for(o=0,r=g.length;o<r;++o)if(l=g[o],d=n[l],e.hasOwnProperty(l)||(e[l]=d),(s=e[l])!==d&&"_"!==l[0]){if(t.hasOwnProperty(l)||(t[l]=s),u=t[l],(c=typeof d)===typeof u)if("string"===c){if((h=i(u)).valid&&(f=i(d)).valid){e[l]=f.mix(h,a).rgbString();continue}}else if("number"===c&&isFinite(u)&&isFinite(d)){e[l]=u+(d-u)*a;continue}e[l]=d}}var n=t.helpers;t.elements={},t.Element=function(t){n.extend(this,t),this.initialize.apply(this,arguments)},n.extend(t.Element.prototype,{initialize:function(){this.hidden=!1},pivot:function(){var t=this;return t._view||(t._view=n.clone(t._model)),t._start={},t},transition:function(t){var n=this,i=n._model,a=n._start,o=n._view;return i&&1!==t?(o||(o=n._view={}),a||(a=n._start={}),e(a,o,i,t),n):(n._view=i,n._start=null,n)},tooltipPosition:function(){return{x:this._model.x,y:this._model.y}},hasValue:function(){return n.isNumber(this._model.x)&&n.isNumber(this._model.y)}}),t.Element.extend=n.inherits}},{3:3}],26:[function(t,e,n){"use strict";var i=t(3);e.exports=function(t){function e(t,e,n){var i;return"string"==typeof t?(i=parseInt(t,10),-1!==t.indexOf("%")&&(i=i/100*e.parentNode[n])):i=t,i}function n(t){return void 0!==t&&null!==t&&"none"!==t}function a(t,i,a){var o=document.defaultView,r=t.parentNode,l=o.getComputedStyle(t)[i],s=o.getComputedStyle(r)[i],u=n(l),d=n(s),c=Number.POSITIVE_INFINITY;return u||d?Math.min(u?e(l,t,a):c,d?e(s,r,a):c):"none"}var o=t.helpers={};o.each=function(t,e,n,i){var a,r;if(o.isArray(t))if(r=t.length,i)for(a=r-1;a>=0;a--)e.call(n,t[a],a);else for(a=0;a<r;a++)e.call(n,t[a],a);else if("object"==typeof t){var l=Object.keys(t);for(r=l.length,a=0;a<r;a++)e.call(n,t[l[a]],l[a])}},o.clone=function(t){var e={};return o.each(t,function(t,n){o.isArray(t)?e[n]=t.slice(0):e[n]="object"==typeof t&&null!==t?o.clone(t):t}),e},o.extend=function(t){for(var e=function(e,n){t[n]=e},n=1,i=arguments.length;n<i;n++)o.each(arguments[n],e);return t},o.configMerge=function(e){var n=o.clone(e);return o.each(Array.prototype.slice.call(arguments,1),function(e){o.each(e,function(e,i){var a=n.hasOwnProperty(i),r=a?n[i]:{};"scales"===i?n[i]=o.scaleMerge(r,e):"scale"===i?n[i]=o.configMerge(r,t.scaleService.getScaleDefaults(e.type),e):!a||"object"!=typeof r||o.isArray(r)||null===r||"object"!=typeof e||o.isArray(e)?n[i]=e:n[i]=o.configMerge(r,e)})}),n},o.scaleMerge=function(e,n){var i=o.clone(e);return o.each(n,function(e,n){"xAxes"===n||"yAxes"===n?i.hasOwnProperty(n)?o.each(e,function(e,a){var r=o.getValueOrDefault(e.type,"xAxes"===n?"category":"linear"),l=t.scaleService.getScaleDefaults(r);a>=i[n].length||!i[n][a].type?i[n].push(o.configMerge(l,e)):e.type&&e.type!==i[n][a].type?i[n][a]=o.configMerge(i[n][a],l,e):i[n][a]=o.configMerge(i[n][a],e)}):(i[n]=[],o.each(e,function(e){var a=o.getValueOrDefault(e.type,"xAxes"===n?"category":"linear");i[n].push(o.configMerge(t.scaleService.getScaleDefaults(a),e))})):i.hasOwnProperty(n)&&"object"==typeof i[n]&&null!==i[n]&&"object"==typeof e?i[n]=o.configMerge(i[n],e):i[n]=e}),i},o.getValueAtIndexOrDefault=function(t,e,n){return void 0===t||null===t?n:o.isArray(t)?e<t.length?t[e]:n:t},o.getValueOrDefault=function(t,e){return void 0===t?e:t},o.indexOf=Array.prototype.indexOf?function(t,e){return t.indexOf(e)}:function(t,e){for(var n=0,i=t.length;n<i;++n)if(t[n]===e)return n;return-1},o.where=function(t,e){if(o.isArray(t)&&Array.prototype.filter)return t.filter(e);var n=[];return o.each(t,function(t){e(t)&&n.push(t)}),n},o.findIndex=Array.prototype.findIndex?function(t,e,n){return t.findIndex(e,n)}:function(t,e,n){n=void 0===n?t:n;for(var i=0,a=t.length;i<a;++i)if(e.call(n,t[i],i,t))return i;return-1},o.findNextWhere=function(t,e,n){void 0!==n&&null!==n||(n=-1);for(var i=n+1;i<t.length;i++){var a=t[i];if(e(a))return a}},o.findPreviousWhere=function(t,e,n){void 0!==n&&null!==n||(n=t.length);for(var i=n-1;i>=0;i--){var a=t[i];if(e(a))return a}},o.inherits=function(t){var e=this,n=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return e.apply(this,arguments)},i=function(){this.constructor=n};return i.prototype=e.prototype,n.prototype=new i,n.extend=o.inherits,t&&o.extend(n.prototype,t),n.__super__=e.prototype,n},o.noop=function(){},o.uid=function(){var t=0;return function(){return t++}}(),o.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},o.almostEquals=function(t,e,n){return Math.abs(t-e)<n},o.almostWhole=function(t,e){var n=Math.round(t);return n-e<t&&n+e>t},o.max=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.max(t,e)},Number.NEGATIVE_INFINITY)},o.min=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.min(t,e)},Number.POSITIVE_INFINITY)},o.sign=Math.sign?function(t){return Math.sign(t)}:function(t){return 0==(t=+t)||isNaN(t)?t:t>0?1:-1},o.log10=Math.log10?function(t){return Math.log10(t)}:function(t){return Math.log(t)/Math.LN10},o.toRadians=function(t){return t*(Math.PI/180)},o.toDegrees=function(t){return t*(180/Math.PI)},o.getAngleFromPoint=function(t,e){var n=e.x-t.x,i=e.y-t.y,a=Math.sqrt(n*n+i*i),o=Math.atan2(i,n);return o<-.5*Math.PI&&(o+=2*Math.PI),{angle:o,distance:a}},o.distanceBetweenPoints=function(t,e){return Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))},o.aliasPixel=function(t){return t%2==0?0:.5},o.splineCurve=function(t,e,n,i){var a=t.skip?e:t,o=e,r=n.skip?e:n,l=Math.sqrt(Math.pow(o.x-a.x,2)+Math.pow(o.y-a.y,2)),s=Math.sqrt(Math.pow(r.x-o.x,2)+Math.pow(r.y-o.y,2)),u=l/(l+s),d=s/(l+s),c=i*(u=isNaN(u)?0:u),h=i*(d=isNaN(d)?0:d);return{previous:{x:o.x-c*(r.x-a.x),y:o.y-c*(r.y-a.y)},next:{x:o.x+h*(r.x-a.x),y:o.y+h*(r.y-a.y)}}},o.EPSILON=Number.EPSILON||1e-14,o.splineCurveMonotone=function(t){var e,n,i,a,r=(t||[]).map(function(t){return{model:t._model,deltaK:0,mK:0}}),l=r.length;for(e=0;e<l;++e)if(!(i=r[e]).model.skip){if(n=e>0?r[e-1]:null,(a=e<l-1?r[e+1]:null)&&!a.model.skip){var s=a.model.x-i.model.x;i.deltaK=0!==s?(a.model.y-i.model.y)/s:0}!n||n.model.skip?i.mK=i.deltaK:!a||a.model.skip?i.mK=n.deltaK:this.sign(n.deltaK)!==this.sign(i.deltaK)?i.mK=0:i.mK=(n.deltaK+i.deltaK)/2}var u,d,c,h;for(e=0;e<l-1;++e)i=r[e],a=r[e+1],i.model.skip||a.model.skip||(o.almostEquals(i.deltaK,0,this.EPSILON)?i.mK=a.mK=0:(u=i.mK/i.deltaK,d=a.mK/i.deltaK,(h=Math.pow(u,2)+Math.pow(d,2))<=9||(c=3/Math.sqrt(h),i.mK=u*c*i.deltaK,a.mK=d*c*i.deltaK)));var f;for(e=0;e<l;++e)(i=r[e]).model.skip||(n=e>0?r[e-1]:null,a=e<l-1?r[e+1]:null,n&&!n.model.skip&&(f=(i.model.x-n.model.x)/3,i.model.controlPointPreviousX=i.model.x-f,i.model.controlPointPreviousY=i.model.y-f*i.mK),a&&!a.model.skip&&(f=(a.model.x-i.model.x)/3,i.model.controlPointNextX=i.model.x+f,i.model.controlPointNextY=i.model.y+f*i.mK))},o.nextItem=function(t,e,n){return n?e>=t.length-1?t[0]:t[e+1]:e>=t.length-1?t[t.length-1]:t[e+1]},o.previousItem=function(t,e,n){return n?e<=0?t[t.length-1]:t[e-1]:e<=0?t[0]:t[e-1]},o.niceNum=function(t,e){var n=Math.floor(o.log10(t)),i=t/Math.pow(10,n);return(e?i<1.5?1:i<3?2:i<7?5:10:i<=1?1:i<=2?2:i<=5?5:10)*Math.pow(10,n)};var r=o.easingEffects={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-1*t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return 1*((t=t/1-1)*t*t+1)},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-1*((t=t/1-1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return 1*(t/=1)*t*t*t*t},easeOutQuint:function(t){return 1*((t=t/1-1)*t*t*t*t+1)},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return-1*Math.cos(t/1*(Math.PI/2))+1},easeOutSine:function(t){return 1*Math.sin(t/1*(Math.PI/2))},easeInOutSine:function(t){return-.5*(Math.cos(Math.PI*t/1)-1)},easeInExpo:function(t){return 0===t?1:1*Math.pow(2,10*(t/1-1))},easeOutExpo:function(t){return 1===t?1:1*(1-Math.pow(2,-10*t/1))},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(2-Math.pow(2,-10*--t))},easeInCirc:function(t){return t>=1?t:-1*(Math.sqrt(1-(t/=1)*t)-1)},easeOutCirc:function(t){return 1*Math.sqrt(1-(t=t/1-1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:1==(t/=1)?1:(n||(n=.3),i<Math.abs(1)?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),-i*Math.pow(2,10*(t-=1))*Math.sin((1*t-e)*(2*Math.PI)/n))},easeOutElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:1==(t/=1)?1:(n||(n=.3),i<Math.abs(1)?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),i*Math.pow(2,-10*t)*Math.sin((1*t-e)*(2*Math.PI)/n)+1)},easeInOutElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:2==(t/=.5)?1:(n||(n=.3*1.5*1),i<Math.abs(1)?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),t<1?i*Math.pow(2,10*(t-=1))*Math.sin((1*t-e)*(2*Math.PI)/n)*-.5:i*Math.pow(2,-10*(t-=1))*Math.sin((1*t-e)*(2*Math.PI)/n)*.5+1)},easeInBack:function(t){var e=1.70158;return 1*(t/=1)*t*((e+1)*t-e)},easeOutBack:function(t){var e=1.70158;return 1*((t=t/1-1)*t*((e+1)*t+e)+1)},easeInOutBack:function(t){var e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},easeInBounce:function(t){return 1-r.easeOutBounce(1-t)},easeOutBounce:function(t){return(t/=1)<1/2.75?7.5625*t*t*1:t<2/2.75?1*(7.5625*(t-=1.5/2.75)*t+.75):t<2.5/2.75?1*(7.5625*(t-=2.25/2.75)*t+.9375):1*(7.5625*(t-=2.625/2.75)*t+.984375)},easeInOutBounce:function(t){return t<.5?.5*r.easeInBounce(2*t):.5*r.easeOutBounce(2*t-1)+.5}};o.requestAnimFrame="undefined"==typeof window?function(t){t()}:window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)},o.getRelativePosition=function(t,e){var n,i,a=t.originalEvent||t,r=t.currentTarget||t.srcElement,l=r.getBoundingClientRect(),s=a.touches;s&&s.length>0?(n=s[0].clientX,i=s[0].clientY):(n=a.clientX,i=a.clientY);var u=parseFloat(o.getStyle(r,"padding-left")),d=parseFloat(o.getStyle(r,"padding-top")),c=parseFloat(o.getStyle(r,"padding-right")),h=parseFloat(o.getStyle(r,"padding-bottom")),f=l.right-l.left-u-c,g=l.bottom-l.top-d-h;return n=Math.round((n-l.left-u)/f*r.width/e.currentDevicePixelRatio),i=Math.round((i-l.top-d)/g*r.height/e.currentDevicePixelRatio),{x:n,y:i}},o.addEvent=function(t,e,n){t.addEventListener?t.addEventListener(e,n):t.attachEvent?t.attachEvent("on"+e,n):t["on"+e]=n},o.removeEvent=function(t,e,n){t.removeEventListener?t.removeEventListener(e,n,!1):t.detachEvent?t.detachEvent("on"+e,n):t["on"+e]=o.noop},o.getConstraintWidth=function(t){return a(t,"max-width","clientWidth")},o.getConstraintHeight=function(t){return a(t,"max-height","clientHeight")},o.getMaximumWidth=function(t){var e=t.parentNode,n=parseInt(o.getStyle(e,"padding-left"),10),i=parseInt(o.getStyle(e,"padding-right"),10),a=e.clientWidth-n-i,r=o.getConstraintWidth(t);return isNaN(r)?a:Math.min(a,r)},o.getMaximumHeight=function(t){var e=t.parentNode,n=parseInt(o.getStyle(e,"padding-top"),10),i=parseInt(o.getStyle(e,"padding-bottom"),10),a=e.clientHeight-n-i,r=o.getConstraintHeight(t);return isNaN(r)?a:Math.min(a,r)},o.getStyle=function(t,e){return t.currentStyle?t.currentStyle[e]:document.defaultView.getComputedStyle(t,null).getPropertyValue(e)},o.retinaScale=function(t){var e=t.currentDevicePixelRatio=window.devicePixelRatio||1;if(1!==e){var n=t.canvas,i=t.height,a=t.width;n.height=i*e,n.width=a*e,t.ctx.scale(e,e),n.style.height=i+"px",n.style.width=a+"px"}},o.clear=function(t){t.ctx.clearRect(0,0,t.width,t.height)},o.fontString=function(t,e,n){return e+" "+t+"px "+n},o.longestText=function(t,e,n,i){var a=(i=i||{}).data=i.data||{},r=i.garbageCollect=i.garbageCollect||[];i.font!==e&&(a=i.data={},r=i.garbageCollect=[],i.font=e),t.font=e;var l=0;o.each(n,function(e){void 0!==e&&null!==e&&!0!==o.isArray(e)?l=o.measureText(t,a,r,l,e):o.isArray(e)&&o.each(e,function(e){void 0===e||null===e||o.isArray(e)||(l=o.measureText(t,a,r,l,e))})});var s=r.length/2;if(s>n.length){for(var u=0;u<s;u++)delete a[r[u]];r.splice(0,s)}return l},o.measureText=function(t,e,n,i,a){var o=e[a];return o||(o=e[a]=t.measureText(a).width,n.push(a)),o>i&&(i=o),i},o.numberOfLabelLines=function(t){var e=1;return o.each(t,function(t){o.isArray(t)&&t.length>e&&(e=t.length)}),e},o.drawRoundedRectangle=function(t,e,n,i,a,o){t.beginPath(),t.moveTo(e+o,n),t.lineTo(e+i-o,n),t.quadraticCurveTo(e+i,n,e+i,n+o),t.lineTo(e+i,n+a-o),t.quadraticCurveTo(e+i,n+a,e+i-o,n+a),t.lineTo(e+o,n+a),t.quadraticCurveTo(e,n+a,e,n+a-o),t.lineTo(e,n+o),t.quadraticCurveTo(e,n,e+o,n),t.closePath()},o.color=i?function(e){return e instanceof CanvasGradient&&(e=t.defaults.global.defaultColor),i(e)}:function(t){return console.error("Color.js not found!"),t},o.isArray=Array.isArray?function(t){return Array.isArray(t)}:function(t){return"[object Array]"===Object.prototype.toString.call(t)},o.arrayEquals=function(t,e){var n,i,a,r;if(!t||!e||t.length!==e.length)return!1;for(n=0,i=t.length;n<i;++n)if(a=t[n],r=e[n],a instanceof Array&&r instanceof Array){if(!o.arrayEquals(a,r))return!1}else if(a!==r)return!1;return!0},o.callback=function(t,e,n){t&&"function"==typeof t.call&&t.apply(n,e)},o.getHoverColor=function(t){return t instanceof CanvasPattern?t:o.color(t).saturate(.5).darken(.1).rgbString()},o.callCallback=o.callback}},{3:3}],27:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){return t.native?{x:t.x,y:t.y}:r.getRelativePosition(t,e)}function n(t,e){var n,i,a,o,r;for(i=0,o=t.data.datasets.length;i<o;++i)if(t.isDatasetVisible(i))for(n=t.getDatasetMeta(i),a=0,r=n.data.length;a<r;++a){var l=n.data[a];l._view.skip||e(l)}}function i(t,e){var i=[];return n(t,function(t){t.inRange(e.x,e.y)&&i.push(t)}),i}function a(t,e,i,a){var o=Number.POSITIVE_INFINITY,l=[];return a||(a=r.distanceBetweenPoints),n(t,function(t){if(!i||t.inRange(e.x,e.y)){var n=t.getCenterPoint(),r=a(e,n);r<o?(l=[t],o=r):r===o&&l.push(t)}}),l}function o(t,n,o){var r=e(n,t),l=o.intersect?i(t,r):a(t,r,!1,function(t,e){return Math.abs(t.x-e.x)}),s=[];return l.length?(t.data.datasets.forEach(function(e,n){if(t.isDatasetVisible(n)){var i=t.getDatasetMeta(n).data[l[0]._index];i&&!i._view.skip&&s.push(i)}}),s):[]}var r=t.helpers;t.Interaction={modes:{single:function(t,i){var a=e(i,t),o=[];return n(t,function(t){if(t.inRange(a.x,a.y))return o.push(t),o}),o.slice(0,1)},label:o,index:o,dataset:function(t,n,o){var r=e(n,t),l=o.intersect?i(t,r):a(t,r,!1);return l.length>0&&(l=t.getDatasetMeta(l[0]._datasetIndex).data),l},"x-axis":function(t,e){return o(t,e,!0)},point:function(t,n){return i(t,e(n,t))},nearest:function(t,n,i){var o=a(t,e(n,t),i.intersect);return o.length>1&&o.sort(function(t,e){var n=t.getArea()-e.getArea();return 0===n&&(n=t._datasetIndex-e._datasetIndex),n}),o.slice(0,1)},x:function(t,i,a){var o=e(i,t),r=[],l=!1;return n(t,function(t){t.inXRange(o.x)&&r.push(t),t.inRange(o.x,o.y)&&(l=!0)}),a.intersect&&!l&&(r=[]),r},y:function(t,i,a){var o=e(i,t),r=[],l=!1;return n(t,function(t){t.inYRange(o.y)&&r.push(t),t.inRange(o.x,o.y)&&(l=!0)}),a.intersect&&!l&&(r=[]),r}}}}},{}],28:[function(t,e,n){"use strict";e.exports=function(){var t=function(t,e){return this.construct(t,e),this};return t.defaults={global:{responsive:!0,responsiveAnimationDuration:0,maintainAspectRatio:!0,events:["mousemove","mouseout","click","touchstart","touchmove"],hover:{onHover:null,mode:"nearest",intersect:!0,animationDuration:400},onClick:null,defaultColor:"rgba(0,0,0,0.1)",defaultFontColor:"#666",defaultFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",defaultFontSize:12,defaultFontStyle:"normal",showLines:!0,elements:{},legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');for(var n=0;n<t.data.datasets.length;n++)e.push('<li><span style="background-color:'+t.data.datasets[n].backgroundColor+'"></span>'),t.data.datasets[n].label&&e.push(t.data.datasets[n].label),e.push("</li>");return e.push("</ul>"),e.join("")}}},t.Chart=t,t}},{}],29:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){return i.where(t,function(t){return t.position===e})}function n(t,e){t.forEach(function(t,e){return t._tmpIndex_=e,t}),t.sort(function(t,n){var i=e?n:t,a=e?t:n;return i.weight===a.weight?i._tmpIndex_-a._tmpIndex_:i.weight-a.weight}),t.forEach(function(t){delete t._tmpIndex_})}var i=t.helpers;t.layoutService={defaults:{},addBox:function(t,e){t.boxes||(t.boxes=[]),e.fullWidth=e.fullWidth||!1,e.position=e.position||"top",e.weight=e.weight||0,t.boxes.push(e)},removeBox:function(t,e){var n=t.boxes?t.boxes.indexOf(e):-1;-1!==n&&t.boxes.splice(n,1)},configure:function(t,e,n){for(var i,a=["fullWidth","position","weight"],o=a.length,r=0;r<o;++r)i=a[r],n.hasOwnProperty(i)&&(e[i]=n[i])},update:function(t,a,o){function r(t){var e=i.findNextWhere(D,function(e){return e.box===t});if(e)if(t.isHorizontal()){var n={left:Math.max(T,I),right:Math.max(F,A),top:0,bottom:0};t.update(t.fullWidth?x:S,y/2,n)}else t.update(e.minSize.width,C)}function l(t){t.isHorizontal()?(t.left=t.fullWidth?d:T,t.right=t.fullWidth?a-c:T+S,t.top=N,t.bottom=N+t.height,N=t.bottom):(t.left=W,t.right=W+t.width,t.top=R,t.bottom=R+C,W=t.right)}if(t){var s=t.options.layout,u=s?s.padding:null,d=0,c=0,h=0,f=0;isNaN(u)?(d=u.left||0,c=u.right||0,h=u.top||0,f=u.bottom||0):(d=u,c=u,h=u,f=u);var g=e(t.boxes,"left"),p=e(t.boxes,"right"),m=e(t.boxes,"top"),v=e(t.boxes,"bottom"),b=e(t.boxes,"chartArea");n(g,!0),n(p,!1),n(m,!0),n(v,!1);var x=a-d-c,y=o-h-f,k=y/2,w=(a-x/2)/(g.length+p.length),M=(o-k)/(m.length+v.length),S=x,C=y,D=[];i.each(g.concat(p,m,v),function(t){var e,n=t.isHorizontal();n?(e=t.update(t.fullWidth?x:S,M),C-=e.height):(e=t.update(w,k),S-=e.width),D.push({horizontal:n,minSize:e,box:t})});var I=0,A=0,P=0,_=0;i.each(m.concat(v),function(t){if(t.getPadding){var e=t.getPadding();I=Math.max(I,e.left),A=Math.max(A,e.right)}}),i.each(g.concat(p),function(t){if(t.getPadding){var e=t.getPadding();P=Math.max(P,e.top),_=Math.max(_,e.bottom)}});var T=d,F=c,R=h,L=f;i.each(g.concat(p),r),i.each(g,function(t){T+=t.width}),i.each(p,function(t){F+=t.width}),i.each(m.concat(v),r),i.each(m,function(t){R+=t.height}),i.each(v,function(t){L+=t.height}),i.each(g.concat(p),function(t){var e=i.findNextWhere(D,function(e){return e.box===t}),n={left:0,right:0,top:R,bottom:L};e&&t.update(e.minSize.width,C,n)}),T=d,F=c,R=h,L=f,i.each(g,function(t){T+=t.width}),i.each(p,function(t){F+=t.width}),i.each(m,function(t){R+=t.height}),i.each(v,function(t){L+=t.height});var V=Math.max(I-T,0);T+=V,F+=Math.max(A-F,0);var O=Math.max(P-R,0);R+=O,L+=Math.max(_-L,0);var z=o-R-L,B=a-T-F;B===S&&z===C||(i.each(g,function(t){t.height=z}),i.each(p,function(t){t.height=z}),i.each(m,function(t){t.fullWidth||(t.width=B)}),i.each(v,function(t){t.fullWidth||(t.width=B)}),C=z,S=B);var W=d+V,N=h+O;i.each(g.concat(m),l),W+=S,N+=C,i.each(p,l),i.each(v,l),t.chartArea={left:T,top:R,right:T+S,bottom:R+C},i.each(b,function(e){e.left=t.chartArea.left,e.top=t.chartArea.top,e.right=t.chartArea.right,e.bottom=t.chartArea.bottom,e.update(S,C)})}}}}},{}],30:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.global.plugins={},t.plugins={_plugins:[],_cacheId:0,register:function(t){var e=this._plugins;[].concat(t).forEach(function(t){-1===e.indexOf(t)&&e.push(t)}),this._cacheId++},unregister:function(t){var e=this._plugins;[].concat(t).forEach(function(t){var n=e.indexOf(t);-1!==n&&e.splice(n,1)}),this._cacheId++},clear:function(){this._plugins=[],this._cacheId++},count:function(){return this._plugins.length},getAll:function(){return this._plugins},notify:function(t,e,n){var i,a,o,r,l,s=this.descriptors(t),u=s.length;for(i=0;i<u;++i)if(a=s[i],o=a.plugin,"function"==typeof(l=o[e])&&((r=[t].concat(n||[])).push(a.options),!1===l.apply(o,r)))return!1;return!0},descriptors:function(n){var i=n._plugins||(n._plugins={});if(i.id===this._cacheId)return i.descriptors;var a=[],o=[],r=n&&n.config||{},l=t.defaults.global.plugins,s=r.options&&r.options.plugins||{};return this._plugins.concat(r.plugins||[]).forEach(function(t){if(-1===a.indexOf(t)){var n=t.id,i=s[n];!1!==i&&(!0===i&&(i=e.clone(l[n])),a.push(t),o.push({plugin:t,options:i||{}}))}}),i.descriptors=o,i.id=this._cacheId,o}},t.pluginService=t.plugins,t.PluginBase=t.Element.extend({})}},{}],31:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e,n){return i.isArray(e)?i.longestText(t,n,e):t.measureText(e).width}function n(e){var n=i.getValueOrDefault,a=t.defaults.global,o=n(e.fontSize,a.defaultFontSize),r=n(e.fontStyle,a.defaultFontStyle),l=n(e.fontFamily,a.defaultFontFamily);return{size:o,style:r,family:l,font:i.fontString(o,r,l)}}var i=t.helpers;t.defaults.scale={display:!0,position:"left",gridLines:{display:!0,color:"rgba(0, 0, 0, 0.1)",lineWidth:1,drawBorder:!0,drawOnChartArea:!0,drawTicks:!0,tickMarkLength:10,zeroLineWidth:1,zeroLineColor:"rgba(0,0,0,0.25)",zeroLineBorderDash:[],zeroLineBorderDashOffset:0,offsetGridLines:!1,borderDash:[],borderDashOffset:0},scaleLabel:{labelString:"",display:!1},ticks:{beginAtZero:!1,minRotation:0,maxRotation:50,mirror:!1,padding:0,reverse:!1,display:!0,autoSkip:!0,autoSkipPadding:0,labelOffset:0,callback:t.Ticks.formatters.values}},t.Scale=t.Element.extend({getPadding:function(){var t=this;return{left:t.paddingLeft||0,top:t.paddingTop||0,right:t.paddingRight||0,bottom:t.paddingBottom||0}},beforeUpdate:function(){i.callback(this.options.beforeUpdate,[this])},update:function(t,e,n){var a=this;return a.beforeUpdate(),a.maxWidth=t,a.maxHeight=e,a.margins=i.extend({left:0,right:0,top:0,bottom:0},n),a.longestTextCache=a.longestTextCache||{},a.beforeSetDimensions(),a.setDimensions(),a.afterSetDimensions(),a.beforeDataLimits(),a.determineDataLimits(),a.afterDataLimits(),a.beforeBuildTicks(),a.buildTicks(),a.afterBuildTicks(),a.beforeTickToLabelConversion(),a.convertTicksToLabels(),a.afterTickToLabelConversion(),a.beforeCalculateTickRotation(),a.calculateTickRotation(),a.afterCalculateTickRotation(),a.beforeFit(),a.fit(),a.afterFit(),a.afterUpdate(),a.minSize},afterUpdate:function(){i.callback(this.options.afterUpdate,[this])},beforeSetDimensions:function(){i.callback(this.options.beforeSetDimensions,[this])},setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0},afterSetDimensions:function(){i.callback(this.options.afterSetDimensions,[this])},beforeDataLimits:function(){i.callback(this.options.beforeDataLimits,[this])},determineDataLimits:i.noop,afterDataLimits:function(){i.callback(this.options.afterDataLimits,[this])},beforeBuildTicks:function(){i.callback(this.options.beforeBuildTicks,[this])},buildTicks:i.noop,afterBuildTicks:function(){i.callback(this.options.afterBuildTicks,[this])},beforeTickToLabelConversion:function(){i.callback(this.options.beforeTickToLabelConversion,[this])},convertTicksToLabels:function(){var t=this,e=t.options.ticks;t.ticks=t.ticks.map(e.userCallback||e.callback)},afterTickToLabelConversion:function(){i.callback(this.options.afterTickToLabelConversion,[this])},beforeCalculateTickRotation:function(){i.callback(this.options.beforeCalculateTickRotation,[this])},calculateTickRotation:function(){var t=this,e=t.ctx,a=t.options.ticks,o=n(a);e.font=o.font;var r=a.minRotation||0;if(t.options.display&&t.isHorizontal())for(var l,s=i.longestText(e,o.font,t.ticks,t.longestTextCache),u=s,d=t.getPixelForTick(1)-t.getPixelForTick(0)-6;u>d&&r<a.maxRotation;){var c=i.toRadians(r);if(l=Math.cos(c),Math.sin(c)*s>t.maxHeight){r--;break}r++,u=l*s}t.labelRotation=r},afterCalculateTickRotation:function(){i.callback(this.options.afterCalculateTickRotation,[this])},beforeFit:function(){i.callback(this.options.beforeFit,[this])},fit:function(){var t=this,a=t.minSize={width:0,height:0},o=t.options,r=o.ticks,l=o.scaleLabel,s=o.gridLines,u=o.display,d=t.isHorizontal(),c=n(r),h=1.5*n(l).size,f=o.gridLines.tickMarkLength;if(a.width=d?t.isFullWidth()?t.maxWidth-t.margins.left-t.margins.right:t.maxWidth:u&&s.drawTicks?f:0,a.height=d?u&&s.drawTicks?f:0:t.maxHeight,l.display&&u&&(d?a.height+=h:a.width+=h),r.display&&u){var g=i.longestText(t.ctx,c.font,t.ticks,t.longestTextCache),p=i.numberOfLabelLines(t.ticks),m=.5*c.size;if(d){t.longestLabelWidth=g;var v=i.toRadians(t.labelRotation),b=Math.cos(v),x=Math.sin(v)*g+c.size*p+m*p;a.height=Math.min(t.maxHeight,a.height+x),t.ctx.font=c.font;var y=t.ticks[0],k=e(t.ctx,y,c.font),w=t.ticks[t.ticks.length-1],M=e(t.ctx,w,c.font);0!==t.labelRotation?(t.paddingLeft="bottom"===o.position?b*k+3:b*m+3,t.paddingRight="bottom"===o.position?b*m+3:b*M+3):(t.paddingLeft=k/2+3,t.paddingRight=M/2+3)}else r.mirror?g=0:g+=t.options.ticks.padding,a.width=Math.min(t.maxWidth,a.width+g),t.paddingTop=c.size/2,t.paddingBottom=c.size/2}t.handleMargins(),t.width=a.width,t.height=a.height},handleMargins:function(){var t=this;t.margins&&(t.paddingLeft=Math.max(t.paddingLeft-t.margins.left,0),t.paddingTop=Math.max(t.paddingTop-t.margins.top,0),t.paddingRight=Math.max(t.paddingRight-t.margins.right,0),t.paddingBottom=Math.max(t.paddingBottom-t.margins.bottom,0))},afterFit:function(){i.callback(this.options.afterFit,[this])},isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},isFullWidth:function(){return this.options.fullWidth},getRightValue:function(t){return null===t||void 0===t?NaN:"number"!=typeof t||isFinite(t)?"object"==typeof t?t instanceof Date||t.isValid?t:this.getRightValue(this.isHorizontal()?t.x:t.y):t:NaN},getLabelForIndex:i.noop,getPixelForValue:i.noop,getValueForPixel:i.noop,getPixelForTick:function(t,e){var n=this;if(n.isHorizontal()){var i=(n.width-(n.paddingLeft+n.paddingRight))/Math.max(n.ticks.length-(n.options.gridLines.offsetGridLines?0:1),1),a=i*t+n.paddingLeft;e&&(a+=i/2);var o=n.left+Math.round(a);return o+=n.isFullWidth()?n.margins.left:0}var r=n.height-(n.paddingTop+n.paddingBottom);return n.top+t*(r/(n.ticks.length-1))},getPixelForDecimal:function(t){var e=this;if(e.isHorizontal()){var n=(e.width-(e.paddingLeft+e.paddingRight))*t+e.paddingLeft,i=e.left+Math.round(n);return i+=e.isFullWidth()?e.margins.left:0}return e.top+t*e.height},getBasePixel:function(){return this.getPixelForValue(this.getBaseValue())},getBaseValue:function(){var t=this,e=t.min,n=t.max;return t.beginAtZero?0:e<0&&n<0?n:e>0&&n>0?e:0},draw:function(e){var a=this,o=a.options;if(o.display){var r,l,s=a.ctx,u=t.defaults.global,d=o.ticks,c=o.gridLines,h=o.scaleLabel,f=0!==a.labelRotation,g=d.autoSkip,p=a.isHorizontal();d.maxTicksLimit&&(l=d.maxTicksLimit);var m=i.getValueOrDefault(d.fontColor,u.defaultFontColor),v=n(d),b=c.drawTicks?c.tickMarkLength:0,x=i.getValueOrDefault(h.fontColor,u.defaultFontColor),y=n(h),k=i.toRadians(a.labelRotation),w=Math.cos(k),M=a.longestLabelWidth*w;s.fillStyle=m;var S=[];if(p){if(r=!1,(M+d.autoSkipPadding)*a.ticks.length>a.width-(a.paddingLeft+a.paddingRight)&&(r=1+Math.floor((M+d.autoSkipPadding)*a.ticks.length/(a.width-(a.paddingLeft+a.paddingRight)))),l&&a.ticks.length>l)for(;!r||a.ticks.length/(r||1)>l;)r||(r=1),r+=1;g||(r=!1)}var C="right"===o.position?a.left:a.right-b,D="right"===o.position?a.left+b:a.right,I="bottom"===o.position?a.top:a.bottom-b,A="bottom"===o.position?a.top+b:a.bottom;if(i.each(a.ticks,function(t,n){if(void 0!==t&&null!==t){var l=a.ticks.length===n+1;if((!(r>1&&n%r>0||n%r==0&&n+r>=a.ticks.length)||l)&&void 0!==t&&null!==t){var s,h,g,m;n===(void 0!==a.zeroLineIndex?a.zeroLineIndex:0)?(s=c.zeroLineWidth,h=c.zeroLineColor,g=c.zeroLineBorderDash,m=c.zeroLineBorderDashOffset):(s=i.getValueAtIndexOrDefault(c.lineWidth,n),h=i.getValueAtIndexOrDefault(c.color,n),g=i.getValueOrDefault(c.borderDash,u.borderDash),m=i.getValueOrDefault(c.borderDashOffset,u.borderDashOffset));var v,x,y,w,M,P,_,T,F,R,L="middle",V="middle";if(p){"bottom"===o.position?(V=f?"middle":"top",L=f?"right":"center",R=a.top+b):(V=f?"middle":"bottom",L=f?"left":"center",R=a.bottom-b);var O=a.getPixelForTick(n)+i.aliasPixel(s);F=a.getPixelForTick(n,c.offsetGridLines)+d.labelOffset,v=y=M=_=O,x=I,w=A,P=e.top,T=e.bottom}else{var z,B="left"===o.position,W=d.padding;d.mirror?(L=B?"left":"right",z=W):(L=B?"right":"left",z=b+W),F=B?a.right-z:a.left+z;var N=a.getPixelForTick(n);N+=i.aliasPixel(s),R=a.getPixelForTick(n,c.offsetGridLines),v=C,y=D,M=e.left,_=e.right,x=w=P=T=N}S.push({tx1:v,ty1:x,tx2:y,ty2:w,x1:M,y1:P,x2:_,y2:T,labelX:F,labelY:R,glWidth:s,glColor:h,glBorderDash:g,glBorderDashOffset:m,rotation:-1*k,label:t,textBaseline:V,textAlign:L})}}}),i.each(S,function(t){if(c.display&&(s.save(),s.lineWidth=t.glWidth,s.strokeStyle=t.glColor,s.setLineDash&&(s.setLineDash(t.glBorderDash),s.lineDashOffset=t.glBorderDashOffset),s.beginPath(),c.drawTicks&&(s.moveTo(t.tx1,t.ty1),s.lineTo(t.tx2,t.ty2)),c.drawOnChartArea&&(s.moveTo(t.x1,t.y1),s.lineTo(t.x2,t.y2)),s.stroke(),s.restore()),d.display){s.save(),s.translate(t.labelX,t.labelY),s.rotate(t.rotation),s.font=v.font,s.textBaseline=t.textBaseline,s.textAlign=t.textAlign;var e=t.label;if(i.isArray(e))for(var n=0,a=0;n<e.length;++n)s.fillText(""+e[n],0,a),a+=1.5*v.size;else s.fillText(e,0,0);s.restore()}}),h.display){var P,_,T=0;if(p)P=a.left+(a.right-a.left)/2,_="bottom"===o.position?a.bottom-y.size/2:a.top+y.size/2;else{var F="left"===o.position;P=F?a.left+y.size/2:a.right-y.size/2,_=a.top+(a.bottom-a.top)/2,T=F?-.5*Math.PI:.5*Math.PI}s.save(),s.translate(P,_),s.rotate(T),s.textAlign="center",s.textBaseline="middle",s.fillStyle=x,s.font=y.font,s.fillText(h.labelString,0,0),s.restore()}if(c.drawBorder){s.lineWidth=i.getValueAtIndexOrDefault(c.lineWidth,0),s.strokeStyle=i.getValueAtIndexOrDefault(c.color,0);var R=a.left,L=a.right,V=a.top,O=a.bottom,z=i.aliasPixel(s.lineWidth);p?(V=O="top"===o.position?a.bottom:a.top,V+=z,O+=z):(R=L="left"===o.position?a.right:a.left,R+=z,L+=z),s.beginPath(),s.moveTo(R,V),s.lineTo(L,O),s.stroke()}}}})}},{}],32:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.scaleService={constructors:{},defaults:{},registerScaleType:function(t,n,i){this.constructors[t]=n,this.defaults[t]=e.clone(i)},getScaleConstructor:function(t){return this.constructors.hasOwnProperty(t)?this.constructors[t]:void 0},getScaleDefaults:function(n){return this.defaults.hasOwnProperty(n)?e.scaleMerge(t.defaults.scale,this.defaults[n]):{}},updateScaleDefaults:function(t,n){var i=this.defaults;i.hasOwnProperty(t)&&(i[t]=e.extend(i[t],n))},addScalesToLayout:function(n){e.each(n.scales,function(e){e.fullWidth=e.options.fullWidth,e.position=e.options.position,e.weight=e.options.weight,t.layoutService.addBox(n,e)})}}}},{}],33:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.Ticks={generators:{linear:function(t,n){var i,a=[];if(t.stepSize&&t.stepSize>0)i=t.stepSize;else{var o=e.niceNum(n.max-n.min,!1);i=e.niceNum(o/(t.maxTicks-1),!0)}var r=Math.floor(n.min/i)*i,l=Math.ceil(n.max/i)*i;t.min&&t.max&&t.stepSize&&e.almostWhole((t.max-t.min)/t.stepSize,i/1e3)&&(r=t.min,l=t.max);var s=(l-r)/i;s=e.almostEquals(s,Math.round(s),i/1e3)?Math.round(s):Math.ceil(s),a.push(void 0!==t.min?t.min:r);for(var u=1;u<s;++u)a.push(r+u*i);return a.push(void 0!==t.max?t.max:l),a},logarithmic:function(t,n){var i,a,o=[],r=e.getValueOrDefault,l=r(t.min,Math.pow(10,Math.floor(e.log10(n.min)))),s=Math.floor(e.log10(n.max)),u=Math.ceil(n.max/Math.pow(10,s));0===l?(i=Math.floor(e.log10(n.minNotZero)),a=Math.floor(n.minNotZero/Math.pow(10,i)),o.push(l),l=a*Math.pow(10,i)):(i=Math.floor(e.log10(l)),a=Math.floor(l/Math.pow(10,i)));do{o.push(l),10===++a&&(a=1,++i),l=a*Math.pow(10,i)}while(i<s||i===s&&a<u);var d=r(t.max,l);return o.push(d),o}},formatters:{values:function(t){return e.isArray(t)?t:""+t},linear:function(t,n,i){var a=i.length>3?i[2]-i[1]:i[1]-i[0];Math.abs(a)>1&&t!==Math.floor(t)&&(a=t-Math.floor(t));var o=e.log10(Math.abs(a)),r="";if(0!==t){var l=-1*Math.floor(o);l=Math.max(Math.min(l,20),0),r=t.toFixed(l)}else r="0";return r},logarithmic:function(t,n,i){var a=t/Math.pow(10,Math.floor(e.log10(t)));return 0===t?"0":1===a||2===a||5===a||0===n||n===i.length-1?t.toExponential():""}}}}},{}],34:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){var n=o.color(t);return n.alpha(e*n.alpha()).rgbaString()}function n(t,e){return e&&(o.isArray(e)?Array.prototype.push.apply(t,e):t.push(e)),t}function i(t){var e=t._xScale,n=t._yScale||t._scale,i=t._index,a=t._datasetIndex;return{xLabel:e?e.getLabelForIndex(i,a):"",yLabel:n?n.getLabelForIndex(i,a):"",index:i,datasetIndex:a,x:t._model.x,y:t._model.y}}function a(e){var n=t.defaults.global,i=o.getValueOrDefault;return{xPadding:e.xPadding,yPadding:e.yPadding,xAlign:e.xAlign,yAlign:e.yAlign,bodyFontColor:e.bodyFontColor,_bodyFontFamily:i(e.bodyFontFamily,n.defaultFontFamily),_bodyFontStyle:i(e.bodyFontStyle,n.defaultFontStyle),_bodyAlign:e.bodyAlign,bodyFontSize:i(e.bodyFontSize,n.defaultFontSize),bodySpacing:e.bodySpacing,titleFontColor:e.titleFontColor,_titleFontFamily:i(e.titleFontFamily,n.defaultFontFamily),_titleFontStyle:i(e.titleFontStyle,n.defaultFontStyle),titleFontSize:i(e.titleFontSize,n.defaultFontSize),_titleAlign:e.titleAlign,titleSpacing:e.titleSpacing,titleMarginBottom:e.titleMarginBottom,footerFontColor:e.footerFontColor,_footerFontFamily:i(e.footerFontFamily,n.defaultFontFamily),_footerFontStyle:i(e.footerFontStyle,n.defaultFontStyle),footerFontSize:i(e.footerFontSize,n.defaultFontSize),_footerAlign:e.footerAlign,footerSpacing:e.footerSpacing,footerMarginTop:e.footerMarginTop,caretSize:e.caretSize,cornerRadius:e.cornerRadius,backgroundColor:e.backgroundColor,opacity:0,legendColorBackground:e.multiKeyBackground,displayColors:e.displayColors,borderColor:e.borderColor,borderWidth:e.borderWidth}}var o=t.helpers;t.defaults.global.tooltips={enabled:!0,custom:null,mode:"nearest",position:"average",intersect:!0,backgroundColor:"rgba(0,0,0,0.8)",titleFontStyle:"bold",titleSpacing:2,titleMarginBottom:6,titleFontColor:"#fff",titleAlign:"left",bodySpacing:2,bodyFontColor:"#fff",bodyAlign:"left",footerFontStyle:"bold",footerSpacing:2,footerMarginTop:6,footerFontColor:"#fff",footerAlign:"left",yPadding:6,xPadding:6,caretPadding:2,caretSize:5,cornerRadius:6,multiKeyBackground:"#fff",displayColors:!0,borderColor:"rgba(0,0,0,0)",borderWidth:0,callbacks:{beforeTitle:o.noop,title:function(t,e){var n="",i=e.labels,a=i?i.length:0;if(t.length>0){var o=t[0];o.xLabel?n=o.xLabel:a>0&&o.index<a&&(n=i[o.index])}return n},afterTitle:o.noop,beforeBody:o.noop,beforeLabel:o.noop,label:function(t,e){var n=e.datasets[t.datasetIndex].label||"";return n&&(n+=": "),n+=t.yLabel},labelColor:function(t,e){var n=e.getDatasetMeta(t.datasetIndex).data[t.index]._view;return{borderColor:n.borderColor,backgroundColor:n.backgroundColor}},afterLabel:o.noop,afterBody:o.noop,beforeFooter:o.noop,footer:o.noop,afterFooter:o.noop}},t.Tooltip=t.Element.extend({initialize:function(){this._model=a(this._options)},getTitle:function(){var t=this,e=t._options.callbacks,i=e.beforeTitle.apply(t,arguments),a=e.title.apply(t,arguments),o=e.afterTitle.apply(t,arguments),r=[];return r=n(r,i),r=n(r,a),r=n(r,o)},getBeforeBody:function(){var t=this._options.callbacks.beforeBody.apply(this,arguments);return o.isArray(t)?t:void 0!==t?[t]:[]},getBody:function(t,e){var i=this,a=i._options.callbacks,r=[];return o.each(t,function(t){var o={before:[],lines:[],after:[]};n(o.before,a.beforeLabel.call(i,t,e)),n(o.lines,a.label.call(i,t,e)),n(o.after,a.afterLabel.call(i,t,e)),r.push(o)}),r},getAfterBody:function(){var t=this._options.callbacks.afterBody.apply(this,arguments);return o.isArray(t)?t:void 0!==t?[t]:[]},getFooter:function(){var t=this,e=t._options.callbacks,i=e.beforeFooter.apply(t,arguments),a=e.footer.apply(t,arguments),o=e.afterFooter.apply(t,arguments),r=[];return r=n(r,i),r=n(r,a),r=n(r,o)},update:function(e){var n,r,l=this,s=l._options,u=l._model,d=l._model=a(s),c=l._active,h=l._data,f={xAlign:u.xAlign,yAlign:u.yAlign},g={x:u.x,y:u.y},p={width:u.width,height:u.height},m={x:u.caretX,y:u.caretY};if(c.length){d.opacity=1;var v=[];m=t.Tooltip.positioners[s.position](c,l._eventPosition);var b=[];for(n=0,r=c.length;n<r;++n)b.push(i(c[n]));s.filter&&(b=b.filter(function(t){return s.filter(t,h)})),s.itemSort&&(b=b.sort(function(t,e){return s.itemSort(t,e,h)})),o.each(b,function(t){v.push(s.callbacks.labelColor.call(l,t,l._chart))}),d.title=l.getTitle(b,h),d.beforeBody=l.getBeforeBody(b,h),d.body=l.getBody(b,h),d.afterBody=l.getAfterBody(b,h),d.footer=l.getFooter(b,h),d.x=Math.round(m.x),d.y=Math.round(m.y),d.caretPadding=s.caretPadding,d.labelColors=v,d.dataPoints=b,p=function(t,e){var n=t._chart.ctx,i=2*e.yPadding,a=0,r=e.body,l=r.reduce(function(t,e){return t+e.before.length+e.lines.length+e.after.length},0);l+=e.beforeBody.length+e.afterBody.length;var s=e.title.length,u=e.footer.length,d=e.titleFontSize,c=e.bodyFontSize,h=e.footerFontSize;i+=s*d,i+=s?(s-1)*e.titleSpacing:0,i+=s?e.titleMarginBottom:0,i+=l*c,i+=l?(l-1)*e.bodySpacing:0,i+=u?e.footerMarginTop:0,i+=u*h,i+=u?(u-1)*e.footerSpacing:0;var f=0,g=function(t){a=Math.max(a,n.measureText(t).width+f)};return n.font=o.fontString(d,e._titleFontStyle,e._titleFontFamily),o.each(e.title,g),n.font=o.fontString(c,e._bodyFontStyle,e._bodyFontFamily),o.each(e.beforeBody.concat(e.afterBody),g),f=e.displayColors?c+2:0,o.each(r,function(t){o.each(t.before,g),o.each(t.lines,g),o.each(t.after,g)}),f=0,n.font=o.fontString(h,e._footerFontStyle,e._footerFontFamily),o.each(e.footer,g),a+=2*e.xPadding,{width:a,height:i}}(this,d),g=function(t,e,n){var i=t.x,a=t.y,o=t.caretSize,r=t.caretPadding,l=t.cornerRadius,s=n.xAlign,u=n.yAlign,d=o+r,c=l+r;return"right"===s?i-=e.width:"center"===s&&(i-=e.width/2),"top"===u?a+=d:a-="bottom"===u?e.height+d:e.height/2,"center"===u?"left"===s?i+=d:"right"===s&&(i-=d):"left"===s?i-=c:"right"===s&&(i+=c),{x:i,y:a}}(d,p,f=function(t,e){var n=t._model,i=t._chart,a=t._chart.chartArea,o="center",r="center";n.y<e.height?r="top":n.y>i.height-e.height&&(r="bottom");var l,s,u,d,c,h=(a.left+a.right)/2,f=(a.top+a.bottom)/2;"center"===r?(l=function(t){return t<=h},s=function(t){return t>h}):(l=function(t){return t<=e.width/2},s=function(t){return t>=i.width-e.width/2}),u=function(t){return t+e.width>i.width},d=function(t){return t-e.width<0},c=function(t){return t<=f?"top":"bottom"},l(n.x)?(o="left",u(n.x)&&(o="center",r=c(n.y))):s(n.x)&&(o="right",d(n.x)&&(o="center",r=c(n.y)));var g=t._options;return{xAlign:g.xAlign?g.xAlign:o,yAlign:g.yAlign?g.yAlign:r}}(this,p))}else d.opacity=0;return d.xAlign=f.xAlign,d.yAlign=f.yAlign,d.x=g.x,d.y=g.y,d.width=p.width,d.height=p.height,d.caretX=m.x,d.caretY=m.y,l._model=d,e&&s.custom&&s.custom.call(l,d),l},drawCaret:function(t,e){var n=this._chart.ctx,i=this._view,a=this.getCaretPosition(t,e,i);n.lineTo(a.x1,a.y1),n.lineTo(a.x2,a.y2),n.lineTo(a.x3,a.y3)},getCaretPosition:function(t,e,n){var i,a,o,r,l,s,u=n.caretSize,d=n.cornerRadius,c=n.xAlign,h=n.yAlign,f=t.x,g=t.y,p=e.width,m=e.height;if("center"===h)l=g+m/2,"left"===c?(i=f,a=i-u,o=i,r=l+u,s=l-u):(i=f+p,a=i+u,o=i,r=l-u,s=l+u);else if("left"===c?(a=f+d+u,i=a-u,o=a+u):"right"===c?(a=f+p-d-u,i=a-u,o=a+u):(a=f+p/2,i=a-u,o=a+u),"top"===h)r=g,l=r-u,s=r;else{l=(r=g+m)+u,s=r;var v=o;o=i,i=v}return{x1:i,x2:a,x3:o,y1:r,y2:l,y3:s}},drawTitle:function(t,n,i,a){var r=n.title;if(r.length){i.textAlign=n._titleAlign,i.textBaseline="top";var l=n.titleFontSize,s=n.titleSpacing;i.fillStyle=e(n.titleFontColor,a),i.font=o.fontString(l,n._titleFontStyle,n._titleFontFamily);var u,d;for(u=0,d=r.length;u<d;++u)i.fillText(r[u],t.x,t.y),t.y+=l+s,u+1===r.length&&(t.y+=n.titleMarginBottom-s)}},drawBody:function(t,n,i,a){var r=n.bodyFontSize,l=n.bodySpacing,s=n.body;i.textAlign=n._bodyAlign,i.textBaseline="top";var u=e(n.bodyFontColor,a);i.fillStyle=u,i.font=o.fontString(r,n._bodyFontStyle,n._bodyFontFamily);var d=0,c=function(e){i.fillText(e,t.x+d,t.y),t.y+=r+l};o.each(n.beforeBody,c);var h=n.displayColors;d=h?r+2:0,o.each(s,function(l,s){o.each(l.before,c),o.each(l.lines,function(o){h&&(i.fillStyle=e(n.legendColorBackground,a),i.fillRect(t.x,t.y,r,r),i.strokeStyle=e(n.labelColors[s].borderColor,a),i.strokeRect(t.x,t.y,r,r),i.fillStyle=e(n.labelColors[s].backgroundColor,a),i.fillRect(t.x+1,t.y+1,r-2,r-2),i.fillStyle=u),c(o)}),o.each(l.after,c)}),d=0,o.each(n.afterBody,c),t.y-=l},drawFooter:function(t,n,i,a){var r=n.footer;r.length&&(t.y+=n.footerMarginTop,i.textAlign=n._footerAlign,i.textBaseline="top",i.fillStyle=e(n.footerFontColor,a),i.font=o.fontString(n.footerFontSize,n._footerFontStyle,n._footerFontFamily),o.each(r,function(e){i.fillText(e,t.x,t.y),t.y+=n.footerFontSize+n.footerSpacing}))},drawBackground:function(t,n,i,a,o){i.fillStyle=e(n.backgroundColor,o),i.strokeStyle=e(n.borderColor,o),i.lineWidth=n.borderWidth;var r=n.xAlign,l=n.yAlign,s=t.x,u=t.y,d=a.width,c=a.height,h=n.cornerRadius;i.beginPath(),i.moveTo(s+h,u),"top"===l&&this.drawCaret(t,a),i.lineTo(s+d-h,u),i.quadraticCurveTo(s+d,u,s+d,u+h),"center"===l&&"right"===r&&this.drawCaret(t,a),i.lineTo(s+d,u+c-h),i.quadraticCurveTo(s+d,u+c,s+d-h,u+c),"bottom"===l&&this.drawCaret(t,a),i.lineTo(s+h,u+c),i.quadraticCurveTo(s,u+c,s,u+c-h),"center"===l&&"left"===r&&this.drawCaret(t,a),i.lineTo(s,u+h),i.quadraticCurveTo(s,u,s+h,u),i.closePath(),i.fill(),n.borderWidth>0&&i.stroke()},draw:function(){var t=this._chart.ctx,e=this._view;if(0!==e.opacity){var n={width:e.width,height:e.height},i={x:e.x,y:e.y},a=Math.abs(e.opacity<.001)?0:e.opacity,o=e.title.length||e.beforeBody.length||e.body.length||e.afterBody.length||e.footer.length;this._options.enabled&&o&&(this.drawBackground(i,e,t,n,a),i.x+=e.xPadding,i.y+=e.yPadding,this.drawTitle(i,e,t,a),this.drawBody(i,e,t,a),this.drawFooter(i,e,t,a))}},handleEvent:function(t){var e=this,n=e._options,i=!1;if(e._lastActive=e._lastActive||[],"mouseout"===t.type?e._active=[]:e._active=e._chart.getElementsAtEventForMode(t,n.mode,n),!(i=!o.arrayEquals(e._active,e._lastActive)))return!1;if(e._lastActive=e._active,n.enabled||n.custom){e._eventPosition={x:t.x,y:t.y};var a=e._model;e.update(!0),e.pivot(),i|=a.x!==e._model.x||a.y!==e._model.y}return i}}),t.Tooltip.positioners={average:function(t){if(!t.length)return!1;var e,n,i=0,a=0,o=0;for(e=0,n=t.length;e<n;++e){var r=t[e];if(r&&r.hasValue()){var l=r.tooltipPosition();i+=l.x,a+=l.y,++o}}return{x:Math.round(i/o),y:Math.round(a/o)}},nearest:function(t,e){var n,i,a,r=e.x,l=e.y,s=Number.POSITIVE_INFINITY;for(i=0,a=t.length;i<a;++i){var u=t[i];if(u&&u.hasValue()){var d=u.getCenterPoint(),c=o.distanceBetweenPoints(e,d);c<s&&(s=c,n=u)}}if(n){var h=n.tooltipPosition();r=h.x,l=h.y}return{x:r,y:l}}}}},{}],35:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=t.defaults.global;n.elements.arc={backgroundColor:n.defaultColor,borderColor:"#fff",borderWidth:2},t.elements.Arc=t.Element.extend({inLabelRange:function(t){var e=this._view;return!!e&&Math.pow(t-e.x,2)<Math.pow(e.radius+e.hoverRadius,2)},inRange:function(t,n){var i=this._view;if(i){for(var a=e.getAngleFromPoint(i,{x:t,y:n}),o=a.angle,r=a.distance,l=i.startAngle,s=i.endAngle;s<l;)s+=2*Math.PI;for(;o>s;)o-=2*Math.PI;for(;o<l;)o+=2*Math.PI;var u=o>=l&&o<=s,d=r>=i.innerRadius&&r<=i.outerRadius;return u&&d}return!1},getCenterPoint:function(){var t=this._view,e=(t.startAngle+t.endAngle)/2,n=(t.innerRadius+t.outerRadius)/2;return{x:t.x+Math.cos(e)*n,y:t.y+Math.sin(e)*n}},getArea:function(){var t=this._view;return Math.PI*((t.endAngle-t.startAngle)/(2*Math.PI))*(Math.pow(t.outerRadius,2)-Math.pow(t.innerRadius,2))},tooltipPosition:function(){var t=this._view,e=t.startAngle+(t.endAngle-t.startAngle)/2,n=(t.outerRadius-t.innerRadius)/2+t.innerRadius;return{x:t.x+Math.cos(e)*n,y:t.y+Math.sin(e)*n}},draw:function(){var t=this._chart.ctx,e=this._view,n=e.startAngle,i=e.endAngle;t.beginPath(),t.arc(e.x,e.y,e.outerRadius,n,i),t.arc(e.x,e.y,e.innerRadius,i,n,!0),t.closePath(),t.strokeStyle=e.borderColor,t.lineWidth=e.borderWidth,t.fillStyle=e.backgroundColor,t.fill(),t.lineJoin="bevel",e.borderWidth&&t.stroke()}})}},{}],36:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=t.defaults.global;t.defaults.global.elements.line={tension:.4,backgroundColor:n.defaultColor,borderWidth:3,borderColor:n.defaultColor,borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",capBezierPoints:!0,fill:!0},t.elements.Line=t.Element.extend({draw:function(){var t,i,a,o,r=this,l=r._view,s=r._chart.ctx,u=l.spanGaps,d=r._children.slice(),c=n.elements.line,h=-1;for(r._loop&&d.length&&d.push(d[0]),s.save(),s.lineCap=l.borderCapStyle||c.borderCapStyle,s.setLineDash&&s.setLineDash(l.borderDash||c.borderDash),s.lineDashOffset=l.borderDashOffset||c.borderDashOffset,s.lineJoin=l.borderJoinStyle||c.borderJoinStyle,s.lineWidth=l.borderWidth||c.borderWidth,s.strokeStyle=l.borderColor||n.defaultColor,s.beginPath(),h=-1,t=0;t<d.length;++t)i=d[t],a=e.previousItem(d,t),o=i._view,0===t?o.skip||(s.moveTo(o.x,o.y),h=t):(a=-1===h?a:d[h],o.skip||(h!==t-1&&!u||-1===h?s.moveTo(o.x,o.y):e.canvas.lineTo(s,a._view,i._view),h=t));s.stroke(),s.restore()}})}},{}],37:[function(t,e,n){"use strict";e.exports=function(t){function e(t){var e=this._view;return!!e&&Math.pow(t-e.x,2)<Math.pow(e.radius+e.hitRadius,2)}var n=t.helpers,i=t.defaults.global,a=i.defaultColor;i.elements.point={radius:3,pointStyle:"circle",backgroundColor:a,borderWidth:1,borderColor:a,hitRadius:1,hoverRadius:4,hoverBorderWidth:1},t.elements.Point=t.Element.extend({inRange:function(t,e){var n=this._view;return!!n&&Math.pow(t-n.x,2)+Math.pow(e-n.y,2)<Math.pow(n.hitRadius+n.radius,2)},inLabelRange:e,inXRange:e,inYRange:function(t){var e=this._view;return!!e&&Math.pow(t-e.y,2)<Math.pow(e.radius+e.hitRadius,2)},getCenterPoint:function(){var t=this._view;return{x:t.x,y:t.y}},getArea:function(){return Math.PI*Math.pow(this._view.radius,2)},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y,padding:t.radius+t.borderWidth}},draw:function(e){var o=this._view,r=this._model,l=this._chart.ctx,s=o.pointStyle,u=o.radius,d=o.x,c=o.y,h=t.helpers.color,f=1.01,g=0;o.skip||(l.strokeStyle=o.borderColor||a,l.lineWidth=n.getValueOrDefault(o.borderWidth,i.elements.point.borderWidth),l.fillStyle=o.backgroundColor||a,void 0!==e&&(r.x<e.left||e.right*f<r.x||r.y<e.top||e.bottom*f<r.y)&&(r.x<e.left?g=(d-r.x)/(e.left-r.x):e.right*f<r.x?g=(r.x-d)/(r.x-e.right):r.y<e.top?g=(c-r.y)/(e.top-r.y):e.bottom*f<r.y&&(g=(r.y-c)/(r.y-e.bottom)),g=Math.round(100*g)/100,l.strokeStyle=h(l.strokeStyle).alpha(g).rgbString(),l.fillStyle=h(l.fillStyle).alpha(g).rgbString()),t.canvasHelpers.drawPoint(l,s,u,d,c))}})}},{}],38:[function(t,e,n){"use strict";e.exports=function(t){function e(t){return void 0!==t._view.width}function n(t){var n,i,a,o,r=t._view;if(e(t)){var l=r.width/2;n=r.x-l,i=r.x+l,a=Math.min(r.y,r.base),o=Math.max(r.y,r.base)}else{var s=r.height/2;n=Math.min(r.x,r.base),i=Math.max(r.x,r.base),a=r.y-s,o=r.y+s}return{left:n,top:a,right:i,bottom:o}}var i=t.defaults.global;i.elements.rectangle={backgroundColor:i.defaultColor,borderWidth:0,borderColor:i.defaultColor,borderSkipped:"bottom"},t.elements.Rectangle=t.Element.extend({draw:function(){function t(t){return v[(b+t)%4]}var e,n,i,a,o,r,l,s=this._chart.ctx,u=this._view,d=u.borderWidth;if(u.horizontal?(e=u.base,n=u.x,i=u.y-u.height/2,a=u.y+u.height/2,o=n>e?1:-1,r=1,l=u.borderSkipped||"left"):(e=u.x-u.width/2,n=u.x+u.width/2,i=u.y,a=u.base,o=1,r=a>i?1:-1,l=u.borderSkipped||"bottom"),d){var c=Math.min(Math.abs(e-n),Math.abs(i-a)),h=(d=d>c?c:d)/2,f=e+("left"!==l?h*o:0),g=n+("right"!==l?-h*o:0),p=i+("top"!==l?h*r:0),m=a+("bottom"!==l?-h*r:0);f!==g&&(i=p,a=m),p!==m&&(e=f,n=g)}s.beginPath(),s.fillStyle=u.backgroundColor,s.strokeStyle=u.borderColor,s.lineWidth=d;var v=[[e,a],[e,i],[n,i],[n,a]],b=["bottom","left","top","right"].indexOf(l,0);-1===b&&(b=0);var x=t(0);s.moveTo(x[0],x[1]);for(var y=1;y<4;y++)x=t(y),s.lineTo(x[0],x[1]);s.fill(),d&&s.stroke()},height:function(){var t=this._view;return t.base-t.y},inRange:function(t,e){var i=!1;if(this._view){var a=n(this);i=t>=a.left&&t<=a.right&&e>=a.top&&e<=a.bottom}return i},inLabelRange:function(t,i){var a=this;if(!a._view)return!1;var o=n(a);return e(a)?t>=o.left&&t<=o.right:i>=o.top&&i<=o.bottom},inXRange:function(t){var e=n(this);return t>=e.left&&t<=e.right},inYRange:function(t){var e=n(this);return t>=e.top&&t<=e.bottom},getCenterPoint:function(){var t,n,i=this._view;return e(this)?(t=i.x,n=(i.y+i.base)/2):(t=(i.x+i.base)/2,n=i.y),{x:t,y:n}},getArea:function(){var t=this._view;return t.width*Math.abs(t.y-t.base)},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y}}})}},{}],39:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){var n=r.getStyle(t,e),i=n&&n.match(/^(\d+)(\.\d+)?px$/);return i?Number(i[1]):void 0}function n(t,n){var i=t.style,a=t.getAttribute("height"),o=t.getAttribute("width");if(t._chartjs={initial:{height:a,width:o,style:{display:i.display,height:i.height,width:i.width}}},i.display=i.display||"block",null===o||""===o){var r=e(t,"width");void 0!==r&&(t.width=r)}if(null===a||""===a)if(""===t.style.height)t.height=t.width/(n.options.aspectRatio||2);else{var l=e(t,"height");void 0!==r&&(t.height=l)}return t}function i(t,e,n,i,a){return{type:t,chart:e,native:a||null,x:void 0!==n?n:null,y:void 0!==i?i:null}}function a(t,e){var n=l[t.type]||t.type,a=r.getRelativePosition(t,e);return i(n,e,a.x,a.y,t)}function o(t,e,n){var a=t._chartjs={ticking:!1};a.resizer=function(t){var e=document.createElement("iframe");return e.className="chartjs-hidden-iframe",e.style.cssText="display:block;overflow:hidden;border:0;margin:0;top:0;left:0;bottom:0;right:0;height:100%;width:100%;position:absolute;pointer-events:none;z-index:-1;",e.tabIndex=-1,r.addEvent(e,"load",function(){r.addEvent(e.contentWindow||e,"resize",t),t()}),e}(function(){a.ticking||(a.ticking=!0,r.requestAnimFrame.call(window,function(){if(a.resizer)return a.ticking=!1,e(i("resize",n))}))}),t.insertBefore(a.resizer,t.firstChild)}var r=t.helpers,l={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"};return{acquireContext:function(t,e){"string"==typeof t?t=document.getElementById(t):t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas);var i=t&&t.getContext&&t.getContext("2d");return i&&i.canvas===t?(n(t,e),i):null},releaseContext:function(t){var e=t.canvas;if(e._chartjs){var n=e._chartjs.initial;["height","width"].forEach(function(t){var i=n[t];void 0===i||null===i?e.removeAttribute(t):e.setAttribute(t,i)}),r.each(n.style||{},function(t,n){e.style[n]=t}),e.width=e.width,delete e._chartjs}},addEventListener:function(t,e,n){var i=t.canvas;if("resize"!==e){var l=n._chartjs||(n._chartjs={}),s=(l.proxies||(l.proxies={}))[t.id+"_"+e]=function(e){n(a(e,t))};r.addEvent(i,e,s)}else o(i.parentNode,n,t)},removeEventListener:function(t,e,n){var i=t.canvas;if("resize"!==e){var a=((n._chartjs||{}).proxies||{})[t.id+"_"+e];a&&r.removeEvent(i,e,a)}else!function(t){if(t&&t._chartjs){var e=t._chartjs.resizer;e&&(e.parentNode.removeChild(e),t._chartjs.resizer=null),delete t._chartjs}}(i.parentNode)}}}},{}],40:[function(t,e,n){"use strict";var i=t(39);e.exports=function(t){t.platform={acquireContext:function(){},releaseContext:function(){},addEventListener:function(){},removeEventListener:function(){}},t.helpers.extend(t.platform,i(t))}},{39:39}],41:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e,n){var i,a=t._model||{},o=a.fill;if(void 0===o&&(o=!!a.backgroundColor),!1===o||null===o)return!1;if(!0===o)return"origin";if(i=parseFloat(o,10),isFinite(i)&&Math.floor(i)===i)return"-"!==o[0]&&"+"!==o[0]||(i=e+i),!(i===e||i<0||i>=n)&&i;switch(o){case"bottom":return"start";case"top":return"end";case"zero":return"origin";case"origin":case"start":case"end":return o;default:return!1}}function n(t){var e,n=t.el._model||{},i=t.el._scale||{},a=t.fill,o=null;if(isFinite(a))return null;if("start"===a?o=void 0===n.scaleBottom?i.bottom:n.scaleBottom:"end"===a?o=void 0===n.scaleTop?i.top:n.scaleTop:void 0!==n.scaleZero?o=n.scaleZero:i.getBasePosition?o=i.getBasePosition():i.getBasePixel&&(o=i.getBasePixel()),void 0!==o&&null!==o){if(void 0!==o.x&&void 0!==o.y)return o;if("number"==typeof o&&isFinite(o))return e=i.isHorizontal(),{x:e?o:null,y:e?null:o}}return null}function i(t,e,n){var i,a=t[e].fill,o=[e];if(!n)return a;for(;!1!==a&&-1===o.indexOf(a);){if(!isFinite(a))return a;if(!(i=t[a]))return!1;if(i.visible)return a;o.push(a),a=i.fill}return!1}function a(t){var e=t.fill,n="dataset";return!1===e?null:(isFinite(e)||(n="boundary"),d[n](t))}function o(t){return t&&!t.skip}function r(t,e,n,i,a){var o;if(i&&a){for(t.moveTo(e[0].x,e[0].y),o=1;o<i;++o)u.canvas.lineTo(t,e[o-1],e[o]);for(t.lineTo(n[a-1].x,n[a-1].y),o=a-1;o>0;--o)u.canvas.lineTo(t,n[o],n[o-1],!0)}}function l(t,e,n,i,a,l){var s,u,d,c,h,f,g,p=e.length,m=i.spanGaps,v=[],b=[],x=0,y=0;for(t.beginPath(),s=0,u=p+!!l;s<u;++s)d=s%p,c=e[d]._view,h=n(c,d,i),f=o(c),g=o(h),f&&g?(x=v.push(c),y=b.push(h)):x&&y&&(m?(f&&v.push(c),g&&b.push(h)):(r(t,v,b,x,y),x=y=0,v=[],b=[]));r(t,v,b,x,y),t.closePath(),t.fillStyle=a,t.fill()}t.defaults.global.plugins.filler={propagate:!0};var s=t.defaults,u=t.helpers,d={dataset:function(t){var e=t.fill,n=t.chart,i=n.getDatasetMeta(e),a=i&&n.isDatasetVisible(e)&&i.dataset._children||[];return a.length?function(t,e){return a[e]._view||null}:null},boundary:function(t){var e=t.boundary,n=e?e.x:null,i=e?e.y:null;return function(t){return{x:null===n?t.x:n,y:null===i?t.y:i}}}};return{id:"filler",afterDatasetsUpdate:function(o,r){var l,s,u,d,c=(o.data.datasets||[]).length,h=r.propagate,f=[];for(s=0;s<c;++s)l=o.getDatasetMeta(s),u=l.dataset,d=null,u&&u._model&&u instanceof t.elements.Line&&(d={visible:o.isDatasetVisible(s),fill:e(u,s,c),chart:o,el:u}),l.$filler=d,f.push(d);for(s=0;s<c;++s)(d=f[s])&&(d.fill=i(f,s,h),d.boundary=n(d),d.mapper=a(d))},beforeDatasetDraw:function(t,e){var n=e.meta.$filler;if(n){var i=n.el,a=i._view,o=i._children||[],r=n.mapper,u=a.backgroundColor||s.global.defaultColor;r&&u&&o.length&&l(t.ctx,o,r,a,u,i._loop)}}}}},{}],42:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){return t.usePointStyle?e*Math.SQRT2:t.boxWidth}function n(e,n){var i=new t.Legend({ctx:e.ctx,options:n,chart:e});a.configure(e,i,n),a.addBox(e,i),e.legend=i}var i=t.helpers,a=t.layoutService,o=i.noop;return t.defaults.global.legend={display:!0,position:"top",fullWidth:!0,reverse:!1,weight:1e3,onClick:function(t,e){var n=e.datasetIndex,i=this.chart,a=i.getDatasetMeta(n);a.hidden=null===a.hidden?!i.data.datasets[n].hidden:null,i.update()},onHover:null,labels:{boxWidth:40,padding:10,generateLabels:function(t){var e=t.data;return i.isArray(e.datasets)?e.datasets.map(function(e,n){return{text:e.label,fillStyle:i.isArray(e.backgroundColor)?e.backgroundColor[0]:e.backgroundColor,hidden:!t.isDatasetVisible(n),lineCap:e.borderCapStyle,lineDash:e.borderDash,lineDashOffset:e.borderDashOffset,lineJoin:e.borderJoinStyle,lineWidth:e.borderWidth,strokeStyle:e.borderColor,pointStyle:e.pointStyle,datasetIndex:n}},this):[]}}},t.Legend=t.Element.extend({initialize:function(t){i.extend(this,t),this.legendHitBoxes=[],this.doughnutMode=!1},beforeUpdate:o,update:function(t,e,n){var i=this;return i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i.margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate(),i.minSize},afterUpdate:o,beforeSetDimensions:o,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:o,beforeBuildLabels:o,buildLabels:function(){var t=this,e=t.options.labels,n=e.generateLabels.call(t,t.chart);e.filter&&(n=n.filter(function(n){return e.filter(n,t.chart.data)})),t.options.reverse&&n.reverse(),t.legendItems=n},afterBuildLabels:o,beforeFit:o,fit:function(){var n=this,a=n.options,o=a.labels,r=a.display,l=n.ctx,s=t.defaults.global,u=i.getValueOrDefault,d=u(o.fontSize,s.defaultFontSize),c=u(o.fontStyle,s.defaultFontStyle),h=u(o.fontFamily,s.defaultFontFamily),f=i.fontString(d,c,h),g=n.legendHitBoxes=[],p=n.minSize,m=n.isHorizontal();if(m?(p.width=n.maxWidth,p.height=r?10:0):(p.width=r?10:0,p.height=n.maxHeight),r)if(l.font=f,m){var v=n.lineWidths=[0],b=n.legendItems.length?d+o.padding:0;l.textAlign="left",l.textBaseline="top",i.each(n.legendItems,function(t,i){var a=e(o,d)+d/2+l.measureText(t.text).width;v[v.length-1]+a+o.padding>=n.width&&(b+=d+o.padding,v[v.length]=n.left),g[i]={left:0,top:0,width:a,height:d},v[v.length-1]+=a+o.padding}),p.height+=b}else{var x=o.padding,y=n.columnWidths=[],k=o.padding,w=0,M=0,S=d+x;i.each(n.legendItems,function(t,n){var i=e(o,d)+d/2+l.measureText(t.text).width;M+S>p.height&&(k+=w+o.padding,y.push(w),w=0,M=0),w=Math.max(w,i),M+=S,g[n]={left:0,top:0,width:i,height:d}}),k+=w,y.push(w),p.width+=k}n.width=p.width,n.height=p.height},afterFit:o,isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},draw:function(){var n=this,a=n.options,o=a.labels,r=t.defaults.global,l=r.elements.line,s=n.width,u=n.lineWidths;if(a.display){var d,c=n.ctx,h=i.getValueOrDefault,f=h(o.fontColor,r.defaultFontColor),g=h(o.fontSize,r.defaultFontSize),p=h(o.fontStyle,r.defaultFontStyle),m=h(o.fontFamily,r.defaultFontFamily),v=i.fontString(g,p,m);c.textAlign="left",c.textBaseline="top",c.lineWidth=.5,c.strokeStyle=f,c.fillStyle=f,c.font=v;var b=e(o,g),x=n.legendHitBoxes,y=function(e,n,i){if(!(isNaN(b)||b<=0)){c.save(),c.fillStyle=h(i.fillStyle,r.defaultColor),c.lineCap=h(i.lineCap,l.borderCapStyle),c.lineDashOffset=h(i.lineDashOffset,l.borderDashOffset),c.lineJoin=h(i.lineJoin,l.borderJoinStyle),c.lineWidth=h(i.lineWidth,l.borderWidth),c.strokeStyle=h(i.strokeStyle,r.defaultColor);var o=0===h(i.lineWidth,l.borderWidth);if(c.setLineDash&&c.setLineDash(h(i.lineDash,l.borderDash)),a.labels&&a.labels.usePointStyle){var s=g*Math.SQRT2/2,u=s/Math.SQRT2,d=e+u,f=n+u;t.canvasHelpers.drawPoint(c,i.pointStyle,s,d,f)}else o||c.strokeRect(e,n,b,g),c.fillRect(e,n,b,g);c.restore()}},k=n.isHorizontal();d=k?{x:n.left+(s-u[0])/2,y:n.top+o.padding,line:0}:{x:n.left+o.padding,y:n.top+o.padding,line:0};var w=g+o.padding;i.each(n.legendItems,function(t,e){var i=c.measureText(t.text).width,a=b+g/2+i,r=d.x,l=d.y;k?r+a>=s&&(l=d.y+=w,d.line++,r=d.x=n.left+(s-u[d.line])/2):l+w>n.bottom&&(r=d.x=r+n.columnWidths[d.line]+o.padding,l=d.y=n.top+o.padding,d.line++),y(r,l,t),x[e].left=r,x[e].top=l,function(t,e,n,i){c.fillText(n.text,b+g/2+t,e),n.hidden&&(c.beginPath(),c.lineWidth=2,c.moveTo(b+g/2+t,e+g/2),c.lineTo(b+g/2+t+i,e+g/2),c.stroke())}(r,l,t,i),k?d.x+=a+o.padding:d.y+=w})}},handleEvent:function(t){var e=this,n=e.options,i="mouseup"===t.type?"click":t.type,a=!1;if("mousemove"===i){if(!n.onHover)return}else{if("click"!==i)return;if(!n.onClick)return}var o=t.x,r=t.y;if(o>=e.left&&o<=e.right&&r>=e.top&&r<=e.bottom)for(var l=e.legendHitBoxes,s=0;s<l.length;++s){var u=l[s];if(o>=u.left&&o<=u.left+u.width&&r>=u.top&&r<=u.top+u.height){if("click"===i){n.onClick.call(e,t.native,e.legendItems[s]),a=!0;break}if("mousemove"===i){n.onHover.call(e,t.native,e.legendItems[s]),a=!0;break}}}return a}}),{id:"legend",beforeInit:function(t){var e=t.options.legend;e&&n(t,e)},beforeUpdate:function(e){var o=e.options.legend,r=e.legend;o?(o=i.configMerge(t.defaults.global.legend,o),r?(a.configure(e,r,o),r.options=o):n(e,o)):r&&(a.removeBox(e,r),delete e.legend)},afterEvent:function(t,e){var n=t.legend;n&&n.handleEvent(e)}}}},{}],43:[function(t,e,n){"use strict";e.exports=function(t){function e(e,n){var a=new t.Title({ctx:e.ctx,options:n,chart:e});i.configure(e,a,n),i.addBox(e,a),e.titleBlock=a}var n=t.helpers,i=t.layoutService,a=n.noop;return t.defaults.global.title={display:!1,position:"top",fullWidth:!0,weight:2e3,fontStyle:"bold",padding:10,text:""},t.Title=t.Element.extend({initialize:function(t){n.extend(this,t),this.legendHitBoxes=[]},beforeUpdate:a,update:function(t,e,n){var i=this;return i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i.margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate(),i.minSize},afterUpdate:a,beforeSetDimensions:a,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:a,beforeBuildLabels:a,buildLabels:a,afterBuildLabels:a,beforeFit:a,fit:function(){var e=this,i=n.getValueOrDefault,a=e.options,o=t.defaults.global,r=a.display,l=i(a.fontSize,o.defaultFontSize),s=e.minSize;e.isHorizontal()?(s.width=e.maxWidth,s.height=r?l+2*a.padding:0):(s.width=r?l+2*a.padding:0,s.height=e.maxHeight),e.width=s.width,e.height=s.height},afterFit:a,isHorizontal:function(){var t=this.options.position;return"top"===t||"bottom"===t},draw:function(){var e=this,i=e.ctx,a=n.getValueOrDefault,o=e.options,r=t.defaults.global;if(o.display){var l,s,u,d=a(o.fontSize,r.defaultFontSize),c=a(o.fontStyle,r.defaultFontStyle),h=a(o.fontFamily,r.defaultFontFamily),f=n.fontString(d,c,h),g=0,p=e.top,m=e.left,v=e.bottom,b=e.right;i.fillStyle=a(o.fontColor,r.defaultFontColor),i.font=f,e.isHorizontal()?(l=m+(b-m)/2,s=p+(v-p)/2,u=b-m):(l="left"===o.position?m+d/2:b-d/2,s=p+(v-p)/2,u=v-p,g=Math.PI*("left"===o.position?-.5:.5)),i.save(),i.translate(l,s),i.rotate(g),i.textAlign="center",i.textBaseline="middle",i.fillText(o.text,0,0,u),i.restore()}}}),{id:"title",beforeInit:function(t){var n=t.options.title;n&&e(t,n)},beforeUpdate:function(a){var o=a.options.title,r=a.titleBlock;o?(o=n.configMerge(t.defaults.global.title,o),r?(i.configure(a,r,o),r.options=o):e(a,o)):r&&(t.layoutService.removeBox(a,r),delete a.titleBlock)}}}},{}],44:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=t.Scale.extend({getLabels:function(){var t=this.chart.data;return(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels},determineDataLimits:function(){var t=this,n=t.getLabels();t.minIndex=0,t.maxIndex=n.length-1;var i;void 0!==t.options.ticks.min&&(i=e.indexOf(n,t.options.ticks.min),t.minIndex=-1!==i?i:t.minIndex),void 0!==t.options.ticks.max&&(i=e.indexOf(n,t.options.ticks.max),t.maxIndex=-1!==i?i:t.maxIndex),t.min=n[t.minIndex],t.max=n[t.maxIndex]},buildTicks:function(){var t=this,e=t.getLabels();t.ticks=0===t.minIndex&&t.maxIndex===e.length-1?e:e.slice(t.minIndex,t.maxIndex+1)},getLabelForIndex:function(t,e){var n=this,i=n.chart.data,a=n.isHorizontal();return i.yLabels&&!a?n.getRightValue(i.datasets[e].data[t]):n.ticks[t-n.minIndex]},getPixelForValue:function(t,e,n,i){var a,o=this,r=Math.max(o.maxIndex+1-o.minIndex-(o.options.gridLines.offsetGridLines?0:1),1);if(void 0!==t&&null!==t&&(a=o.isHorizontal()?t.x:t.y),void 0!==a||void 0!==t&&isNaN(e)){var l=o.getLabels();t=a||t;var s=l.indexOf(t);e=-1!==s?s:e}if(o.isHorizontal()){var u=o.width/r,d=u*(e-o.minIndex);return(o.options.gridLines.offsetGridLines&&i||o.maxIndex===o.minIndex&&i)&&(d+=u/2),o.left+Math.round(d)}var c=o.height/r,h=c*(e-o.minIndex);return o.options.gridLines.offsetGridLines&&i&&(h+=c/2),o.top+Math.round(h)},getPixelForTick:function(t,e){return this.getPixelForValue(this.ticks[t],t+this.minIndex,null,e)},getValueForPixel:function(t){var e=this,n=Math.max(e.ticks.length-(e.options.gridLines.offsetGridLines?0:1),1),i=e.isHorizontal(),a=(i?e.width:e.height)/n;return t-=i?e.left:e.top,e.options.gridLines.offsetGridLines&&(t-=a/2),t<=0?0:Math.round(t/a)},getBasePixel:function(){return this.bottom}});t.scaleService.registerScaleType("category",n,{position:"bottom"})}},{}],45:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n={position:"left",ticks:{callback:t.Ticks.formatters.linear}},i=t.LinearScaleBase.extend({determineDataLimits:function(){function t(t){return r?t.xAxisID===n.id:t.yAxisID===n.id}var n=this,i=n.options,a=n.chart,o=a.data.datasets,r=n.isHorizontal();n.min=null,n.max=null;var l=i.stacked;if(void 0===l&&e.each(o,function(e,n){if(!l){var i=a.getDatasetMeta(n);a.isDatasetVisible(n)&&t(i)&&void 0!==i.stack&&(l=!0)}}),i.stacked||l){var s={};e.each(o,function(o,r){var l=a.getDatasetMeta(r),u=[l.type,void 0===i.stacked&&void 0===l.stack?r:"",l.stack].join(".");void 0===s[u]&&(s[u]={positiveValues:[],negativeValues:[]});var d=s[u].positiveValues,c=s[u].negativeValues;a.isDatasetVisible(r)&&t(l)&&e.each(o.data,function(t,e){var a=+n.getRightValue(t);isNaN(a)||l.data[e].hidden||(d[e]=d[e]||0,c[e]=c[e]||0,i.relativePoints?d[e]=100:a<0?c[e]+=a:d[e]+=a)})}),e.each(s,function(t){var i=t.positiveValues.concat(t.negativeValues),a=e.min(i),o=e.max(i);n.min=null===n.min?a:Math.min(n.min,a),n.max=null===n.max?o:Math.max(n.max,o)})}else e.each(o,function(i,o){var r=a.getDatasetMeta(o);a.isDatasetVisible(o)&&t(r)&&e.each(i.data,function(t,e){var i=+n.getRightValue(t);isNaN(i)||r.data[e].hidden||(null===n.min?n.min=i:i<n.min&&(n.min=i),null===n.max?n.max=i:i>n.max&&(n.max=i))})});n.min=isFinite(n.min)?n.min:0,n.max=isFinite(n.max)?n.max:1,this.handleTickRangeOptions()},getTickLimit:function(){var n,i=this,a=i.options.ticks;if(i.isHorizontal())n=Math.min(a.maxTicksLimit?a.maxTicksLimit:11,Math.ceil(i.width/50));else{var o=e.getValueOrDefault(a.fontSize,t.defaults.global.defaultFontSize);n=Math.min(a.maxTicksLimit?a.maxTicksLimit:11,Math.ceil(i.height/(2*o)))}return n},handleDirectionalChanges:function(){this.isHorizontal()||this.ticks.reverse()},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForValue:function(t){var e,n=this,i=n.start,a=+n.getRightValue(t),o=n.end-i;return n.isHorizontal()?(e=n.left+n.width/o*(a-i),Math.round(e)):(e=n.bottom-n.height/o*(a-i),Math.round(e))},getValueForPixel:function(t){var e=this,n=e.isHorizontal(),i=n?e.width:e.height,a=(n?t-e.left:e.bottom-t)/i;return e.start+(e.end-e.start)*a},getPixelForTick:function(t){return this.getPixelForValue(this.ticksAsNumbers[t])}});t.scaleService.registerScaleType("linear",i,n)}},{}],46:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=e.noop;t.LinearScaleBase=t.Scale.extend({handleTickRangeOptions:function(){var t=this,n=t.options.ticks;if(n.beginAtZero){var i=e.sign(t.min),a=e.sign(t.max);i<0&&a<0?t.max=0:i>0&&a>0&&(t.min=0)}void 0!==n.min?t.min=n.min:void 0!==n.suggestedMin&&(null===t.min?t.min=n.suggestedMin:t.min=Math.min(t.min,n.suggestedMin)),void 0!==n.max?t.max=n.max:void 0!==n.suggestedMax&&(null===t.max?t.max=n.suggestedMax:t.max=Math.max(t.max,n.suggestedMax)),t.min===t.max&&(t.max++,n.beginAtZero||t.min--)},getTickLimit:n,handleDirectionalChanges:n,buildTicks:function(){var n=this,i=n.options.ticks,a=n.getTickLimit(),o={maxTicks:a=Math.max(2,a),min:i.min,max:i.max,stepSize:e.getValueOrDefault(i.fixedStepSize,i.stepSize)},r=n.ticks=t.Ticks.generators.linear(o,n);n.handleDirectionalChanges(),n.max=e.max(r),n.min=e.min(r),i.reverse?(r.reverse(),n.start=n.max,n.end=n.min):(n.start=n.min,n.end=n.max)},convertTicksToLabels:function(){var e=this;e.ticksAsNumbers=e.ticks.slice(),e.zeroLineIndex=e.ticks.indexOf(0),t.Scale.prototype.convertTicksToLabels.call(e)}})}},{}],47:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n={position:"left",ticks:{callback:t.Ticks.formatters.logarithmic}},i=t.Scale.extend({determineDataLimits:function(){function t(t){return s?t.xAxisID===n.id:t.yAxisID===n.id}var n=this,i=n.options,a=i.ticks,o=n.chart,r=o.data.datasets,l=e.getValueOrDefault,s=n.isHorizontal();n.min=null,n.max=null,n.minNotZero=null;var u=i.stacked;if(void 0===u&&e.each(r,function(e,n){if(!u){var i=o.getDatasetMeta(n);o.isDatasetVisible(n)&&t(i)&&void 0!==i.stack&&(u=!0)}}),i.stacked||u){var d={};e.each(r,function(a,r){var l=o.getDatasetMeta(r),s=[l.type,void 0===i.stacked&&void 0===l.stack?r:"",l.stack].join(".");o.isDatasetVisible(r)&&t(l)&&(void 0===d[s]&&(d[s]=[]),e.each(a.data,function(t,e){var a=d[s],o=+n.getRightValue(t);isNaN(o)||l.data[e].hidden||(a[e]=a[e]||0,i.relativePoints?a[e]=100:a[e]+=o)}))}),e.each(d,function(t){var i=e.min(t),a=e.max(t);n.min=null===n.min?i:Math.min(n.min,i),n.max=null===n.max?a:Math.max(n.max,a)})}else e.each(r,function(i,a){var r=o.getDatasetMeta(a);o.isDatasetVisible(a)&&t(r)&&e.each(i.data,function(t,e){var i=+n.getRightValue(t);isNaN(i)||r.data[e].hidden||(null===n.min?n.min=i:i<n.min&&(n.min=i),null===n.max?n.max=i:i>n.max&&(n.max=i),0!==i&&(null===n.minNotZero||i<n.minNotZero)&&(n.minNotZero=i))})});n.min=l(a.min,n.min),n.max=l(a.max,n.max),n.min===n.max&&(0!==n.min&&null!==n.min?(n.min=Math.pow(10,Math.floor(e.log10(n.min))-1),n.max=Math.pow(10,Math.floor(e.log10(n.max))+1)):(n.min=1,n.max=10))},buildTicks:function(){var n=this,i=n.options.ticks,a={min:i.min,max:i.max},o=n.ticks=t.Ticks.generators.logarithmic(a,n);n.isHorizontal()||o.reverse(),n.max=e.max(o),n.min=e.min(o),i.reverse?(o.reverse(),n.start=n.max,n.end=n.min):(n.start=n.min,n.end=n.max)},convertTicksToLabels:function(){this.tickValues=this.ticks.slice(),t.Scale.prototype.convertTicksToLabels.call(this)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForTick:function(t){return this.getPixelForValue(this.tickValues[t])},getPixelForValue:function(t){var n,i,a,o=this,r=o.start,l=+o.getRightValue(t),s=o.options.ticks;return o.isHorizontal()?(a=e.log10(o.end)-e.log10(r),0===l?i=o.left:(n=o.width,i=o.left+n/a*(e.log10(l)-e.log10(r)))):(n=o.height,0!==r||s.reverse?0===o.end&&s.reverse?(a=e.log10(o.start)-e.log10(o.minNotZero),i=l===o.end?o.top:l===o.minNotZero?o.top+.02*n:o.top+.02*n+.98*n/a*(e.log10(l)-e.log10(o.minNotZero))):0===l?i=s.reverse?o.top:o.bottom:(a=e.log10(o.end)-e.log10(r),n=o.height,i=o.bottom-n/a*(e.log10(l)-e.log10(r))):(a=e.log10(o.end)-e.log10(o.minNotZero),i=l===r?o.bottom:l===o.minNotZero?o.bottom-.02*n:o.bottom-.02*n-.98*n/a*(e.log10(l)-e.log10(o.minNotZero)))),i},getValueForPixel:function(t){var n,i,a=this,o=e.log10(a.end)-e.log10(a.start);return a.isHorizontal()?(i=a.width,n=a.start*Math.pow(10,(t-a.left)*o/i)):(i=a.height,n=Math.pow(10,(a.bottom-t)*o/i)/a.start),n}});t.scaleService.registerScaleType("logarithmic",i,n)}},{}],48:[function(t,e,n){"use strict";e.exports=function(t){function e(t){var e=t.options;return e.angleLines.display||e.pointLabels.display?t.chart.data.labels.length:0}function n(t){var e=t.options.pointLabels,n=c.getValueOrDefault(e.fontSize,h.defaultFontSize),i=c.getValueOrDefault(e.fontStyle,h.defaultFontStyle),a=c.getValueOrDefault(e.fontFamily,h.defaultFontFamily);return{size:n,style:i,family:a,font:c.fontString(n,i,a)}}function i(t,e,n){return c.isArray(n)?{w:c.longestText(t,t.font,n),h:n.length*e+1.5*(n.length-1)*e}:{w:t.measureText(n).width,h:e}}function a(t,e,n,i,a){return t===i||t===a?{start:e-n/2,end:e+n/2}:t<i||t>a?{start:e-n-5,end:e}:{start:e,end:e+n+5}}function o(t){return 0===t||180===t?"center":t<180?"left":"right"}function r(t,e,n,i){if(c.isArray(e))for(var a=n.y,o=1.5*i,r=0;r<e.length;++r)t.fillText(e[r],n.x,a),a+=o;else t.fillText(e,n.x,n.y)}function l(t,e,n){90===t||270===t?n.y-=e.h/2:(t>270||t<90)&&(n.y-=e.h)}function s(t){var i=t.ctx,a=c.getValueOrDefault,s=t.options,u=s.angleLines,d=s.pointLabels;i.lineWidth=u.lineWidth,i.strokeStyle=u.color;var f=t.getDistanceFromCenterForValue(s.reverse?t.min:t.max),g=n(t);i.textBaseline="top";for(var p=e(t)-1;p>=0;p--){if(u.display){var m=t.getPointPosition(p,f);i.beginPath(),i.moveTo(t.xCenter,t.yCenter),i.lineTo(m.x,m.y),i.stroke(),i.closePath()}if(d.display){var v=t.getPointPosition(p,f+5),b=a(d.fontColor,h.defaultFontColor);i.font=g.font,i.fillStyle=b;var x=t.getIndexAngle(p),y=c.toDegrees(x);i.textAlign=o(y),l(y,t._pointLabelSizes[p],v),r(i,t.pointLabels[p]||"",v,g.size)}}}function u(t,n,i,a){var o=t.ctx;if(o.strokeStyle=c.getValueAtIndexOrDefault(n.color,a-1),o.lineWidth=c.getValueAtIndexOrDefault(n.lineWidth,a-1),t.options.gridLines.circular)o.beginPath(),o.arc(t.xCenter,t.yCenter,i,0,2*Math.PI),o.closePath(),o.stroke();else{var r=e(t);if(0===r)return;o.beginPath();var l=t.getPointPosition(0,i);o.moveTo(l.x,l.y);for(var s=1;s<r;s++)l=t.getPointPosition(s,i),o.lineTo(l.x,l.y);o.closePath(),o.stroke()}}function d(t){return c.isNumber(t)?t:0}var c=t.helpers,h=t.defaults.global,f={display:!0,animate:!0,position:"chartArea",angleLines:{display:!0,color:"rgba(0, 0, 0, 0.1)",lineWidth:1},gridLines:{circular:!1},ticks:{showLabelBackdrop:!0,backdropColor:"rgba(255,255,255,0.75)",backdropPaddingY:2,backdropPaddingX:2,callback:t.Ticks.formatters.linear},pointLabels:{display:!0,fontSize:10,callback:function(t){return t}}},g=t.LinearScaleBase.extend({setDimensions:function(){var t=this,e=t.options,n=e.ticks;t.width=t.maxWidth,t.height=t.maxHeight,t.xCenter=Math.round(t.width/2),t.yCenter=Math.round(t.height/2);var i=c.min([t.height,t.width]),a=c.getValueOrDefault(n.fontSize,h.defaultFontSize);t.drawingArea=e.display?i/2-(a/2+n.backdropPaddingY):i/2},determineDataLimits:function(){var t=this,e=t.chart,n=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY;c.each(e.data.datasets,function(a,o){if(e.isDatasetVisible(o)){var r=e.getDatasetMeta(o);c.each(a.data,function(e,a){var o=+t.getRightValue(e);isNaN(o)||r.data[a].hidden||(n=Math.min(o,n),i=Math.max(o,i))})}}),t.min=n===Number.POSITIVE_INFINITY?0:n,t.max=i===Number.NEGATIVE_INFINITY?0:i,t.handleTickRangeOptions()},getTickLimit:function(){var t=this.options.ticks,e=c.getValueOrDefault(t.fontSize,h.defaultFontSize);return Math.min(t.maxTicksLimit?t.maxTicksLimit:11,Math.ceil(this.drawingArea/(1.5*e)))},convertTicksToLabels:function(){var e=this;t.LinearScaleBase.prototype.convertTicksToLabels.call(e),e.pointLabels=e.chart.data.labels.map(e.options.pointLabels.callback,e)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},fit:function(){this.options.pointLabels.display?function(t){var o,r,l,s=n(t),u=Math.min(t.height/2,t.width/2),d={r:t.width,l:0,t:t.height,b:0},h={};t.ctx.font=s.font,t._pointLabelSizes=[];var f=e(t);for(o=0;o<f;o++){l=t.getPointPosition(o,u),r=i(t.ctx,s.size,t.pointLabels[o]||""),t._pointLabelSizes[o]=r;var g=t.getIndexAngle(o),p=c.toDegrees(g)%360,m=a(p,l.x,r.w,0,180),v=a(p,l.y,r.h,90,270);m.start<d.l&&(d.l=m.start,h.l=g),m.end>d.r&&(d.r=m.end,h.r=g),v.start<d.t&&(d.t=v.start,h.t=g),v.end>d.b&&(d.b=v.end,h.b=g)}t.setReductions(u,d,h)}(this):function(t){var e=Math.min(t.height/2,t.width/2);t.drawingArea=Math.round(e),t.setCenterPoint(0,0,0,0)}(this)},setReductions:function(t,e,n){var i=this,a=e.l/Math.sin(n.l),o=Math.max(e.r-i.width,0)/Math.sin(n.r),r=-e.t/Math.cos(n.t),l=-Math.max(e.b-i.height,0)/Math.cos(n.b);a=d(a),o=d(o),r=d(r),l=d(l),i.drawingArea=Math.min(Math.round(t-(a+o)/2),Math.round(t-(r+l)/2)),i.setCenterPoint(a,o,r,l)},setCenterPoint:function(t,e,n,i){var a=this,o=a.width-e-a.drawingArea,r=t+a.drawingArea,l=n+a.drawingArea,s=a.height-i-a.drawingArea;a.xCenter=Math.round((r+o)/2+a.left),a.yCenter=Math.round((l+s)/2+a.top)},getIndexAngle:function(t){return t*(2*Math.PI/e(this))+(this.chart.options&&this.chart.options.startAngle?this.chart.options.startAngle:0)*Math.PI*2/360},getDistanceFromCenterForValue:function(t){var e=this;if(null===t)return 0;var n=e.drawingArea/(e.max-e.min);return e.options.reverse?(e.max-t)*n:(t-e.min)*n},getPointPosition:function(t,e){var n=this,i=n.getIndexAngle(t)-Math.PI/2;return{x:Math.round(Math.cos(i)*e)+n.xCenter,y:Math.round(Math.sin(i)*e)+n.yCenter}},getPointPositionForValue:function(t,e){return this.getPointPosition(t,this.getDistanceFromCenterForValue(e))},getBasePosition:function(){var t=this,e=t.min,n=t.max;return t.getPointPositionForValue(0,t.beginAtZero?0:e<0&&n<0?n:e>0&&n>0?e:0)},draw:function(){var t=this,e=t.options,n=e.gridLines,i=e.ticks,a=c.getValueOrDefault;if(e.display){var o=t.ctx,r=a(i.fontSize,h.defaultFontSize),l=a(i.fontStyle,h.defaultFontStyle),d=a(i.fontFamily,h.defaultFontFamily),f=c.fontString(r,l,d);c.each(t.ticks,function(l,s){if(s>0||e.reverse){var d=t.getDistanceFromCenterForValue(t.ticksAsNumbers[s]),c=t.yCenter-d;if(n.display&&0!==s&&u(t,n,d,s),i.display){var g=a(i.fontColor,h.defaultFontColor);if(o.font=f,i.showLabelBackdrop){var p=o.measureText(l).width;o.fillStyle=i.backdropColor,o.fillRect(t.xCenter-p/2-i.backdropPaddingX,c-r/2-i.backdropPaddingY,p+2*i.backdropPaddingX,r+2*i.backdropPaddingY)}o.textAlign="center",o.textBaseline="middle",o.fillStyle=g,o.fillText(l,t.xCenter,c)}}}),(e.angleLines.display||e.pointLabels.display)&&s(t)}}});t.scaleService.registerScaleType("radialLinear",g,f)}},{}],49:[function(t,e,n){"use strict";var i=t(1);i="function"==typeof i?i:window.moment,e.exports=function(t){function e(t,e){var n=t.options.time;if("string"==typeof n.parser)return i(e,n.parser);if("function"==typeof n.parser)return n.parser(e);if("function"==typeof e.getMonth||"number"==typeof e)return i(e);if(e.isValid&&e.isValid())return e;var a=n.format;return"string"!=typeof a&&a.call?(console.warn("options.time.format is deprecated and replaced by options.time.parser."),a(e)):i(e,a)}function n(t,e,n,i){for(var a,o=Object.keys(r),l=o.length,s=o.indexOf(t);s<l;s++){a=o[s];var u=r[a],d=u.steps&&u.steps[u.steps.length-1]||u.maxStep;if(void 0===d||Math.ceil((n-e)/(d*u.size))<=i)break}return a}function a(t,e,n,i){var a=r[n],o=a.size,l=Math.ceil((e-t)/o),s=1,u=e-t;if(a.steps)for(var d=a.steps.length,c=0;c<d&&l>i;c++)s=a.steps[c],l=Math.ceil(u/(o*s));else for(;l>i&&i>0;)++s,l=Math.ceil(u/(o*s));return s}var o=t.helpers,r={millisecond:{size:1,steps:[1,2,5,10,20,50,100,250,500]},second:{size:1e3,steps:[1,2,5,10,30]},minute:{size:6e4,steps:[1,2,5,10,30]},hour:{size:36e5,steps:[1,2,3,6,12]},day:{size:864e5,steps:[1,2,5]},week:{size:6048e5,maxStep:4},month:{size:2628e6,maxStep:3},quarter:{size:7884e6,maxStep:4},year:{size:3154e7,maxStep:!1}};t.Ticks.generators.time=function(t,e){var n,a,o=t.isoWeekday;return"week"===t.unit&&!1!==o?(n=i(e.min).startOf("isoWeek").isoWeekday(o).valueOf(),a=i(e.max).startOf("isoWeek").isoWeekday(o),e.max-a>0&&a.add(1,"week"),a=a.valueOf()):(n=i(e.min).startOf(t.unit).valueOf(),a=i(e.max).startOf(t.unit),e.max-a>0&&a.add(1,t.unit),a=a.valueOf()),function(t,e,n){var a=[];if(t.maxTicks){var o=t.stepSize;a.push(void 0!==t.min?t.min:n.min);for(var r=i(n.min);r.add(o,t.unit).valueOf()<n.max;)a.push(r.valueOf());var l=t.max||n.max;a[a.length-1]!==l&&a.push(l)}return a}(t,0,{min:n,max:a})};var l=t.Scale.extend({initialize:function(){if(!i)throw new Error("Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com");t.Scale.prototype.initialize.call(this)},determineDataLimits:function(){var t,n=this,i=n.options.time,a=Number.MAX_SAFE_INTEGER,r=Number.MIN_SAFE_INTEGER,l=n.chart.data,s={labels:[],datasets:[]};o.each(l.labels,function(o,l){var u=e(n,o);u.isValid()&&(i.round&&u.startOf(i.round),t=u.valueOf(),a=Math.min(t,a),r=Math.max(t,r),s.labels[l]=t)}),o.each(l.datasets,function(l,u){var d=[];"object"==typeof l.data[0]&&null!==l.data[0]&&n.chart.isDatasetVisible(u)?o.each(l.data,function(o,l){var s=e(n,n.getRightValue(o));s.isValid()&&(i.round&&s.startOf(i.round),t=s.valueOf(),a=Math.min(t,a),r=Math.max(t,r),d[l]=t)}):d=s.labels.slice(),s.datasets[u]=d}),n.dataMin=a,n.dataMax=r,n._parsedData=s},buildTicks:function(){var i,r,l=this,s=l.options.time,u=l.dataMin,d=l.dataMax;if(s.min){var c=e(l,s.min);s.round&&c.round(s.round),i=c.valueOf()}s.max&&(r=e(l,s.max).valueOf());var h=l.getLabelCapacity(i||u),f=s.unit||n(s.minUnit,i||u,r||d,h);l.displayFormat=s.displayFormats[f];var g=s.stepSize||a(i||u,r||d,f,h);l.ticks=t.Ticks.generators.time({maxTicks:h,min:i,max:r,stepSize:g,unit:f,isoWeekday:s.isoWeekday},{min:u,max:d}),l.max=o.max(l.ticks),l.min=o.min(l.ticks)},getLabelForIndex:function(t,n){var i=this,a=i.chart.data.labels&&t<i.chart.data.labels.length?i.chart.data.labels[t]:"",o=i.chart.data.datasets[n].data[t];return null!==o&&"object"==typeof o&&(a=i.getRightValue(o)),i.options.time.tooltipFormat&&(a=e(i,a).format(i.options.time.tooltipFormat)),a},tickFormatFunction:function(t,e,n){var i=t.format(this.displayFormat),a=this.options.ticks,r=o.getValueOrDefault(a.callback,a.userCallback);return r?r(i,e,n):i},convertTicksToLabels:function(){var t=this;t.ticksAsTimestamps=t.ticks,t.ticks=t.ticks.map(function(t){return i(t)}).map(t.tickFormatFunction,t)},getPixelForOffset:function(t){var e=this,n=e.max-e.min,i=n?(t-e.min)/n:0;if(e.isHorizontal()){var a=e.width*i;return e.left+Math.round(a)}var o=e.height*i;return e.top+Math.round(o)},getPixelForValue:function(t,n,i){var a=this,o=null;if(void 0!==n&&void 0!==i&&(o=a._parsedData.datasets[i][n]),null===o&&(t&&t.isValid||(t=e(a,a.getRightValue(t))),t&&t.isValid&&t.isValid()&&(o=t.valueOf())),null!==o)return a.getPixelForOffset(o)},getPixelForTick:function(t){return this.getPixelForOffset(this.ticksAsTimestamps[t])},getValueForPixel:function(t){var e=this,n=e.isHorizontal()?e.width:e.height,a=(t-(e.isHorizontal()?e.left:e.top))/n;return i(e.min+a*(e.max-e.min))},getLabelWidth:function(e){var n=this.options.ticks,i=this.ctx.measureText(e).width,a=Math.cos(o.toRadians(n.maxRotation)),r=Math.sin(o.toRadians(n.maxRotation));return i*a+o.getValueOrDefault(n.fontSize,t.defaults.global.defaultFontSize)*r},getLabelCapacity:function(t){var e=this;e.displayFormat=e.options.time.displayFormats.millisecond;var n=e.tickFormatFunction(i(t),0,[]),a=e.getLabelWidth(n);return(e.isHorizontal()?e.width:e.height)/a}});t.scaleService.registerScaleType("time",l,{position:"bottom",time:{parser:!1,format:!1,unit:!1,round:!1,displayFormat:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{millisecond:"h:mm:ss.SSS a",second:"h:mm:ss a",minute:"h:mm:ss a",hour:"MMM D, hA",day:"ll",week:"ll",month:"MMM YYYY",quarter:"[Q]Q - YYYY",year:"YYYY"}},ticks:{autoSkip:!1}})}},{1:1}]},{},[7])(7)});
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/include.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/include.min.js
new file mode 100755
index 0000000..54ef4aa
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/include.min.js
@@ -0,0 +1 @@
+window.include=function(n,e,t){e.indexOf(".html")<0&&(e+=".html");var i=new XMLHttpRequest;i.onload=function(){if(4==this.readyState){var e=this.responseText,i="string"==typeof n?document.getElementById(n):n;console.log(i),i&&(i.innerHTML=e),t&&t()}},i.open("GET",e+"?cache="+(new Date).getTime(),!0),i.send()},window.bindIncludeEvent=function(){document.querySelectorAll("[include]").forEach(function(n,e){window.include(n,n.getAttribute("include"))})},window.bindIncludeEvent(),document.addEventListener("openPage",function(){window.bindIncludeEvent()});
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/input.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/input.min.js
new file mode 100755
index 0000000..3e585b7
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/input.min.js
@@ -0,0 +1 @@
+!function e(){setTimeout(function(){var t=document.getElementsByTagName("input");for(i in t){var a=t[i].parentNode;a&&(a.className.indexOf("left")>=0||a.className.indexOf("right")>=0)&&a.parentNode.className.indexOf("item")>=0&&(a=a.parentNode),a&&a.className.indexOf("item")>=0&&a.className.indexOf("bind-input-event-click")<0&&(a.className+=" bind-input-event-click",a.addEventListener("click",function(){this.getElementsByTagName("input").length&&(this.getElementsByTagName("input")[0].focus(),"radio"!==this.getElementsByTagName("input")[0].type||this.getElementsByTagName("input")[0].disabled||(this.getElementsByTagName("input")[0].checked=!0))},!1))}var l=document.getElementsByClassName("label-float");for(i in l)l[i].className&&l[i].className.indexOf("bind-input-event-focus")<0&&l[i].querySelectorAll("input,textarea").length&&(l[i].className+=" bind-input-event-focus",l[i].querySelectorAll("input,textarea")[0].addEventListener("focus",function(){this.parentNode.getElementsByTagName("label").length&&this.parentNode.getElementsByTagName("label")[0].className.indexOf("focus")<0&&(this.parentNode.getElementsByTagName("label")[0].className+=" focus")},!1),l[i].querySelectorAll("input,textarea")[0].addEventListener("blur",function(){this.parentNode.getElementsByTagName("label").length&&this.parentNode.getElementsByTagName("label")[0].className&&!this.value.length&&(this.parentNode.getElementsByTagName("label")[0].className=this.parentNode.getElementsByTagName("label")[0].className.replace("focus",""))},!1),l[i].querySelectorAll("input,textarea")[0].value&&l[i].querySelectorAll("input,textarea")[0].value.length&&(l[i].querySelectorAll("input,textarea")[0].parentNode.getElementsByTagName("label")[0].className+=" focus"));e()},500)}();
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/jquery.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/jquery.min.js
new file mode 100755
index 0000000..6756324
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/jquery.min.js
@@ -0,0 +1 @@
+!function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t)}):e(t)}(this,function(t){var e=function(){function e(t){return null==t?String(t):B[U.call(t)]||"object"}function n(t){return"function"==e(t)}function r(t){return null!=t&&t==t.window}function i(t){return null!=t&&t.nodeType==t.DOCUMENT_NODE}function o(t){return"object"==e(t)}function a(t){return o(t)&&!r(t)&&Object.getPrototypeOf(t)==Object.prototype}function s(t){var e=!!t&&"length"in t&&t.length,n=j.type(t);return"function"!=n&&!r(t)&&("array"==n||0===e||"number"==typeof e&&e>0&&e-1 in t)}function u(t){return t.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()}function c(t){return t in L?L[t]:L[t]=new RegExp("(^|\\s)"+t+"(\\s|$)")}function l(t,e){return"number"!=typeof e||$[u(t)]?e:e+"px"}function f(t){return"children"in t?P.call(t.children):j.map(t.childNodes,function(t){if(1==t.nodeType)return t})}function h(t,e){var n,r=t?t.length:0;for(n=0;n<r;n++)this[n]=t[n];this.length=r,this.selector=e||""}function p(t,e,n){for(E in e)n&&(a(e[E])||Y(e[E]))?(a(e[E])&&!a(t[E])&&(t[E]={}),Y(e[E])&&!Y(t[E])&&(t[E]=[]),p(t[E],e[E],n)):e[E]!==b&&(t[E]=e[E])}function d(t,e){return null==e?j(t):j(t).filter(e)}function m(t,e,r,i){return n(e)?e.call(t,r,i):e}function v(t,e,n){null==n?t.removeAttribute(e):t.setAttribute(e,n)}function g(t,e){var n=t.className||"",r=n&&n.baseVal!==b;if(e===b)return r?n.baseVal:n;r?n.baseVal=e:t.className=e}function y(t){try{return t?"true"==t||"false"!=t&&("null"==t?null:+t+""==t?+t:/^[\[\{]/.test(t)?j.parseJSON(t):t):t}catch(e){return t}}function x(t,e){e(t);for(var n=0,r=t.childNodes.length;n<r;n++)x(t.childNodes[n],e)}var b,E,j,T,w,S,C=[],N=C.concat,O=C.filter,P=C.slice,A=t.document,D={},L={},$={"column-count":1,columns:1,"font-weight":1,"line-height":1,opacity:1,"z-index":1,zoom:1},F=/^\s*<(\w+|!)[^>]*>/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,M=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,R=/^(?:body|html)$/i,Z=/([A-Z])/g,z=["val","css","html","text","data","width","height","offset"],q=A.createElement("table"),H=A.createElement("tr"),I={tr:A.createElement("tbody"),tbody:q,thead:q,tfoot:q,td:H,th:H,"*":A.createElement("div")},V=/complete|loaded|interactive/,_=/^[\w-]*$/,B={},U=B.toString,X={},J=A.createElement("div"),W={tabindex:"tabIndex",readonly:"readOnly",for:"htmlFor",class:"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},Y=Array.isArray||function(t){return t instanceof Array};return X.matches=function(t,e){if(!e||!t||1!==t.nodeType)return!1;var n=t.matches||t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.matchesSelector;if(n)return n.call(t,e);var r,i=t.parentNode,o=!i;return o&&(i=J).appendChild(t),r=~X.qsa(i,e).indexOf(t),o&&J.removeChild(t),r},w=function(t){return t.replace(/-+(.)?/g,function(t,e){return e?e.toUpperCase():""})},S=function(t){return O.call(t,function(e,n){return t.indexOf(e)==n})},X.fragment=function(t,e,n){var r,i,o;return k.test(t)&&(r=j(A.createElement(RegExp.$1))),r||(t.replace&&(t=t.replace(M,"<$1></$2>")),e===b&&(e=F.test(t)&&RegExp.$1),e in I||(e="*"),(o=I[e]).innerHTML=""+t,r=j.each(P.call(o.childNodes),function(){o.removeChild(this)})),a(n)&&(i=j(r),j.each(n,function(t,e){z.indexOf(t)>-1?i[t](e):i.attr(t,e)})),r},X.Z=function(t,e){return new h(t,e)},X.isZ=function(t){return t instanceof X.Z},X.init=function(t,e){var r;if(!t)return X.Z();if("string"==typeof t)if("<"==(t=t.trim())[0]&&F.test(t))r=X.fragment(t,RegExp.$1,e),t=null;else{if(e!==b)return j(e).find(t);r=X.qsa(A,t)}else{if(n(t))return j(A).ready(t);if(X.isZ(t))return t;if(Y(t))r=function(t){return O.call(t,function(t){return null!=t})}(t);else if(o(t))r=[t],t=null;else if(F.test(t))r=X.fragment(t.trim(),RegExp.$1,e),t=null;else{if(e!==b)return j(e).find(t);r=X.qsa(A,t)}}return X.Z(r,t)},j=function(t,e){return X.init(t,e)},j.extend=function(t){var e,n=P.call(arguments,1);return"boolean"==typeof t&&(e=t,t=n.shift()),n.forEach(function(n){p(t,n,e)}),t},X.qsa=function(t,e){var n,r="#"==e[0],i=!r&&"."==e[0],o=r||i?e.slice(1):e,a=_.test(o);return t.getElementById&&a&&r?(n=t.getElementById(o))?[n]:[]:1!==t.nodeType&&9!==t.nodeType&&11!==t.nodeType?[]:P.call(a&&!r&&t.getElementsByClassName?i?t.getElementsByClassName(o):t.getElementsByTagName(e):t.querySelectorAll(e))},j.contains=A.documentElement.contains?function(t,e){return t!==e&&t.contains(e)}:function(t,e){for(;e&&(e=e.parentNode);)if(e===t)return!0;return!1},j.type=e,j.isFunction=n,j.isWindow=r,j.isArray=Y,j.isPlainObject=a,j.isEmptyObject=function(t){var e;for(e in t)return!1;return!0},j.isNumeric=function(t){var e=Number(t),n=typeof t;return null!=t&&"boolean"!=n&&("string"!=n||t.length)&&!isNaN(e)&&isFinite(e)||!1},j.inArray=function(t,e,n){return C.indexOf.call(e,t,n)},j.camelCase=w,j.trim=function(t){return null==t?"":String.prototype.trim.call(t)},j.uuid=0,j.support={},j.expr={},j.noop=function(){},j.map=function(t,e){var n,r,i,o=[];if(s(t))for(r=0;r<t.length;r++)null!=(n=e(t[r],r))&&o.push(n);else for(i in t)null!=(n=e(t[i],i))&&o.push(n);return function(t){return t.length>0?j.fn.concat.apply([],t):t}(o)},j.each=function(t,e){var n,r;if(s(t)){for(n=0;n<t.length;n++)if(!1===e.call(t[n],n,t[n]))return t}else for(r in t)if(!1===e.call(t[r],r,t[r]))return t;return t},j.grep=function(t,e){return O.call(t,e)},t.JSON&&(j.parseJSON=JSON.parse),j.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(t,e){B["[object "+e+"]"]=e.toLowerCase()}),j.fn={constructor:X.Z,length:0,forEach:C.forEach,reduce:C.reduce,push:C.push,sort:C.sort,splice:C.splice,indexOf:C.indexOf,concat:function(){var t,e,n=[];for(t=0;t<arguments.length;t++)e=arguments[t],n[t]=X.isZ(e)?e.toArray():e;return N.apply(X.isZ(this)?this.toArray():this,n)},map:function(t){return j(j.map(this,function(e,n){return t.call(e,n,e)}))},slice:function(){return j(P.apply(this,arguments))},ready:function(t){return V.test(A.readyState)&&A.body?t(j):A.addEventListener("DOMContentLoaded",function(){t(j)},!1),this},get:function(t){return t===b?P.call(this):this[t>=0?t:t+this.length]},toArray:function(){return this.get()},size:function(){return this.length},remove:function(){return this.each(function(){null!=this.parentNode&&this.parentNode.removeChild(this)})},each:function(t){return C.every.call(this,function(e,n){return!1!==t.call(e,n,e)}),this},filter:function(t){return n(t)?this.not(this.not(t)):j(O.call(this,function(e){return X.matches(e,t)}))},add:function(t,e){return j(S(this.concat(j(t,e))))},is:function(t){return this.length>0&&X.matches(this[0],t)},not:function(t){var e=[];if(n(t)&&t.call!==b)this.each(function(n){t.call(this,n)||e.push(this)});else{var r="string"==typeof t?this.filter(t):s(t)&&n(t.item)?P.call(t):j(t);this.forEach(function(t){r.indexOf(t)<0&&e.push(t)})}return j(e)},has:function(t){return this.filter(function(){return o(t)?j.contains(this,t):j(this).find(t).size()})},eq:function(t){return-1===t?this.slice(t):this.slice(t,+t+1)},first:function(){var t=this[0];return t&&!o(t)?t:j(t)},last:function(){var t=this[this.length-1];return t&&!o(t)?t:j(t)},find:function(t){var e=this;return t?"object"==typeof t?j(t).filter(function(){var t=this;return C.some.call(e,function(e){return j.contains(e,t)})}):1==this.length?j(X.qsa(this[0],t)):this.map(function(){return X.qsa(this,t)}):j()},closest:function(t,e){var n=[],r="object"==typeof t&&j(t);return this.each(function(o,a){for(;a&&!(r?r.indexOf(a)>=0:X.matches(a,t));)a=a!==e&&!i(a)&&a.parentNode;a&&n.indexOf(a)<0&&n.push(a)}),j(n)},parents:function(t){for(var e=[],n=this;n.length>0;)n=j.map(n,function(t){if((t=t.parentNode)&&!i(t)&&e.indexOf(t)<0)return e.push(t),t});return d(e,t)},parent:function(t){return d(S(this.pluck("parentNode")),t)},children:function(t){return d(this.map(function(){return f(this)}),t)},contents:function(){return this.map(function(){return this.contentDocument||P.call(this.childNodes)})},siblings:function(t){return d(this.map(function(t,e){return O.call(f(e.parentNode),function(t){return t!==e})}),t)},empty:function(){return this.each(function(){this.innerHTML=""})},pluck:function(t){return j.map(this,function(e){return e[t]})},show:function(){return this.each(function(){"none"==this.style.display&&(this.style.display=""),"none"==getComputedStyle(this,"").getPropertyValue("display")&&(this.style.display=function(t){var e,n;return D[t]||(e=A.createElement(t),A.body.appendChild(e),n=getComputedStyle(e,"").getPropertyValue("display"),e.parentNode.removeChild(e),"none"==n&&(n="block"),D[t]=n),D[t]}(this.nodeName))})},replaceWith:function(t){return this.before(t).remove()},wrap:function(t){var e=n(t);if(this[0]&&!e)var r=j(t).get(0),i=r.parentNode||this.length>1;return this.each(function(n){j(this).wrapAll(e?t.call(this,n):i?r.cloneNode(!0):r)})},wrapAll:function(t){if(this[0]){j(this[0]).before(t=j(t));for(var e;(e=t.children()).length;)t=e.first();j(t).append(this)}return this},wrapInner:function(t){var e=n(t);return this.each(function(n){var r=j(this),i=r.contents(),o=e?t.call(this,n):t;i.length?i.wrapAll(o):r.append(o)})},unwrap:function(){return this.parent().each(function(){j(this).replaceWith(j(this).children())}),this},clone:function(){return this.map(function(){return this.cloneNode(!0)})},hide:function(){return this.css("display","none")},toggle:function(t){return this.each(function(){var e=j(this);(t===b?"none"==e.css("display"):t)?e.show():e.hide()})},prev:function(t){return j(this.pluck("previousElementSibling")).filter(t||"*")},next:function(t){return j(this.pluck("nextElementSibling")).filter(t||"*")},html:function(t){return 0 in arguments?this.each(function(e){var n=this.innerHTML;j(this).empty().append(m(this,t,e,n))}):0 in this?this[0].innerHTML:null},text:function(t){return 0 in arguments?this.each(function(e){var n=m(this,t,e,this.textContent);this.textContent=null==n?"":""+n}):0 in this?this.pluck("textContent").join(""):null},attr:function(t,e){var n;return"string"!=typeof t||1 in arguments?this.each(function(n){if(1===this.nodeType)if(o(t))for(E in t)v(this,E,t[E]);else v(this,t,m(this,e,n,this.getAttribute(t)))}):0 in this&&1==this[0].nodeType&&null!=(n=this[0].getAttribute(t))?n:b},removeAttr:function(t){return this.each(function(){1===this.nodeType&&t.split(" ").forEach(function(t){v(this,t)},this)})},prop:function(t,e){return t=W[t]||t,1 in arguments?this.each(function(n){this[t]=m(this,e,n,this[t])}):this[0]&&this[0][t]},removeProp:function(t){return t=W[t]||t,this.each(function(){delete this[t]})},data:function(t,e){var n="data-"+t.replace(Z,"-$1").toLowerCase(),r=1 in arguments?this.attr(n,e):this.attr(n);return null!==r?y(r):b},val:function(t){return 0 in arguments?(null==t&&(t=""),this.each(function(e){this.value=m(this,t,e,this.value)})):this[0]&&(this[0].multiple?j(this[0]).find("option").filter(function(){return this.selected}).pluck("value"):this[0].value)},offset:function(e){if(e)return this.each(function(t){var n=j(this),r=m(this,e,t,n.offset()),i=n.offsetParent().offset(),o={top:r.top-i.top,left:r.left-i.left};"static"==n.css("position")&&(o.position="relative"),n.css(o)});if(!this.length)return null;if(A.documentElement!==this[0]&&!j.contains(A.documentElement,this[0]))return{top:0,left:0};var n=this[0].getBoundingClientRect();return{left:n.left+t.pageXOffset,top:n.top+t.pageYOffset,width:Math.round(n.width),height:Math.round(n.height)}},css:function(t,n){if(arguments.length<2){var r=this[0];if("string"==typeof t){if(!r)return;return r.style[w(t)]||getComputedStyle(r,"").getPropertyValue(t)}if(Y(t)){if(!r)return;var i={},o=getComputedStyle(r,"");return j.each(t,function(t,e){i[e]=r.style[w(e)]||o.getPropertyValue(e)}),i}}var a="";if("string"==e(t))n||0===n?a=u(t)+":"+l(t,n):this.each(function(){this.style.removeProperty(u(t))});else for(E in t)t[E]||0===t[E]?a+=u(E)+":"+l(E,t[E])+";":this.each(function(){this.style.removeProperty(u(E))});return this.each(function(){this.style.cssText+=";"+a})},index:function(t){return t?this.indexOf(j(t)[0]):this.parent().children().indexOf(this[0])},hasClass:function(t){return!!t&&C.some.call(this,function(t){return this.test(g(t))},c(t))},addClass:function(t){return t?this.each(function(e){if("className"in this){T=[];var n=g(this);m(this,t,e,n).split(/\s+/g).forEach(function(t){j(this).hasClass(t)||T.push(t)},this),T.length&&g(this,n+(n?" ":"")+T.join(" "))}}):this},removeClass:function(t){return this.each(function(e){if("className"in this){if(t===b)return g(this,"");T=g(this),m(this,t,e,T).split(/\s+/g).forEach(function(t){T=T.replace(c(t)," ")}),g(this,T.trim())}})},toggleClass:function(t,e){return t?this.each(function(n){var r=j(this);m(this,t,n,g(this)).split(/\s+/g).forEach(function(t){(e===b?!r.hasClass(t):e)?r.addClass(t):r.removeClass(t)})}):this},scrollTop:function(t){if(this.length){var e="scrollTop"in this[0];return t===b?e?this[0].scrollTop:this[0].pageYOffset:this.each(e?function(){this.scrollTop=t}:function(){this.scrollTo(this.scrollX,t)})}},scrollLeft:function(t){if(this.length){var e="scrollLeft"in this[0];return t===b?e?this[0].scrollLeft:this[0].pageXOffset:this.each(e?function(){this.scrollLeft=t}:function(){this.scrollTo(t,this.scrollY)})}},position:function(){if(this.length){var t=this[0],e=this.offsetParent(),n=this.offset(),r=R.test(e[0].nodeName)?{top:0,left:0}:e.offset();return n.top-=parseFloat(j(t).css("margin-top"))||0,n.left-=parseFloat(j(t).css("margin-left"))||0,r.top+=parseFloat(j(e[0]).css("border-top-width"))||0,r.left+=parseFloat(j(e[0]).css("border-left-width"))||0,{top:n.top-r.top,left:n.left-r.left}}},offsetParent:function(){return this.map(function(){for(var t=this.offsetParent||A.body;t&&!R.test(t.nodeName)&&"static"==j(t).css("position");)t=t.offsetParent;return t})}},j.fn.detach=j.fn.remove,["width","height"].forEach(function(t){var e=t.replace(/./,function(t){return t[0].toUpperCase()});j.fn[t]=function(n){var o,a=this[0];return n===b?r(a)?a["inner"+e]:i(a)?a.documentElement["scroll"+e]:(o=this.offset())&&o[t]:this.each(function(e){(a=j(this)).css(t,m(this,n,e,a[t]()))})}}),["after","prepend","before","append"].forEach(function(n,r){var i=r%2;j.fn[n]=function(){var n,o,a=j.map(arguments,function(t){var r=[];return"array"==(n=e(t))?(t.forEach(function(t){return t.nodeType!==b?r.push(t):j.zepto.isZ(t)?r=r.concat(t.get()):void(r=r.concat(X.fragment(t)))}),r):"object"==n||null==t?t:X.fragment(t)}),s=this.length>1;return a.length<1?this:this.each(function(e,n){o=i?n:n.parentNode,n=0==r?n.nextSibling:1==r?n.firstChild:2==r?n:null;var u=j.contains(A.documentElement,o);a.forEach(function(e){if(s)e=e.cloneNode(!0);else if(!o)return j(e).remove();o.insertBefore(e,n),u&&x(e,function(e){if(!(null==e.nodeName||"SCRIPT"!==e.nodeName.toUpperCase()||e.type&&"text/javascript"!==e.type||e.src)){var n=e.ownerDocument?e.ownerDocument.defaultView:t;n.eval.call(n,e.innerHTML)}})})})},j.fn[i?n+"To":"insert"+(r?"Before":"After")]=function(t){return j(t)[n](this),this}}),X.Z.prototype=h.prototype=j.fn,X.uniq=S,X.deserializeValue=y,j.zepto=X,j}();return t.Zepto=e,void 0===t.$&&(t.$=e),function(e){function n(t){return t._zid||(t._zid=h++)}function r(t,e,r,o){if((e=i(e)).ns)var a=function(t){return new RegExp("(?:^| )"+t.replace(" "," .* ?")+"(?: |$)")}(e.ns);return(v[n(t)]||[]).filter(function(t){return t&&(!e.e||t.e==e.e)&&(!e.ns||a.test(t.ns))&&(!r||n(t.fn)===n(r))&&(!o||t.sel==o)})}function i(t){var e=(""+t).split(".");return{e:e[0],ns:e.slice(1).sort().join(" ")}}function o(t,e){return t.del&&!y&&t.e in x||!!e}function a(t){return b[t]||y&&x[t]||t}function s(t,r,s,u,l,h,p){var d=n(t),m=v[d]||(v[d]=[]);r.split(/\s/).forEach(function(n){if("ready"==n)return e(document).ready(s);var r=i(n);r.fn=s,r.sel=l,r.e in b&&(s=function(t){var n=t.relatedTarget;if(!n||n!==this&&!e.contains(this,n))return r.fn.apply(this,arguments)}),r.del=h;var d=h||s;r.proxy=function(e){if(!(e=c(e)).isImmediatePropagationStopped()){e.data=u;var n=d.apply(t,e._args==f?[e]:[e].concat(e._args));return!1===n&&(e.preventDefault(),e.stopPropagation()),n}},r.i=m.length,m.push(r),"addEventListener"in t&&t.addEventListener(a(r.e),r.proxy,o(r,p))})}function u(t,e,i,s,u){var c=n(t);(e||"").split(/\s/).forEach(function(e){r(t,e,i,s).forEach(function(e){delete v[c][e.i],"removeEventListener"in t&&t.removeEventListener(a(e.e),e.proxy,o(e,u))})})}function c(t,n){return!n&&t.isDefaultPrevented||(n||(n=t),e.each(w,function(e,r){var i=n[e];t[e]=function(){return this[r]=E,i&&i.apply(n,arguments)},t[r]=j}),t.timeStamp||(t.timeStamp=Date.now()),(n.defaultPrevented!==f?n.defaultPrevented:"returnValue"in n?!1===n.returnValue:n.getPreventDefault&&n.getPreventDefault())&&(t.isDefaultPrevented=E)),t}function l(t){var e,n={originalEvent:t};for(e in t)T.test(e)||t[e]===f||(n[e]=t[e]);return c(n,t)}var f,h=1,p=Array.prototype.slice,d=e.isFunction,m=function(t){return"string"==typeof t},v={},g={},y="onfocusin"in t,x={focus:"focusin",blur:"focusout"},b={mouseenter:"mouseover",mouseleave:"mouseout"};g.click=g.mousedown=g.mouseup=g.mousemove="MouseEvents",e.event={add:s,remove:u},e.proxy=function(t,r){var i=2 in arguments&&p.call(arguments,2);if(d(t)){var o=function(){return t.apply(r,i?i.concat(p.call(arguments)):arguments)};return o._zid=n(t),o}if(m(r))return i?(i.unshift(t[r],t),e.proxy.apply(null,i)):e.proxy(t[r],t);throw new TypeError("expected function")},e.fn.bind=function(t,e,n){return this.on(t,e,n)},e.fn.unbind=function(t,e){return this.off(t,e)},e.fn.one=function(t,e,n,r){return this.on(t,e,n,r,1)};var E=function(){return!0},j=function(){return!1},T=/^([A-Z]|returnValue$|layer[XY]$|webkitMovement[XY]$)/,w={preventDefault:"isDefaultPrevented",stopImmediatePropagation:"isImmediatePropagationStopped",stopPropagation:"isPropagationStopped"};e.fn.delegate=function(t,e,n){return this.on(e,t,n)},e.fn.undelegate=function(t,e,n){return this.off(e,t,n)},e.fn.live=function(t,n){return e(document.body).delegate(this.selector,t,n),this},e.fn.die=function(t,n){return e(document.body).undelegate(this.selector,t,n),this},e.fn.on=function(t,n,r,i,o){var a,c,h=this;return t&&!m(t)?(e.each(t,function(t,e){h.on(t,n,r,e,o)}),h):(m(n)||d(i)||!1===i||(i=r,r=n,n=f),i!==f&&!1!==r||(i=r,r=f),!1===i&&(i=j),h.each(function(f,h){o&&(a=function(t){return u(h,t.type,i),i.apply(this,arguments)}),n&&(c=function(t){var r,o=e(t.target).closest(n,h).get(0);if(o&&o!==h)return r=e.extend(l(t),{currentTarget:o,liveFired:h}),(a||i).apply(o,[r].concat(p.call(arguments,1)))}),s(h,t,i,r,n,c||a)}))},e.fn.off=function(t,n,r){var i=this;return t&&!m(t)?(e.each(t,function(t,e){i.off(t,n,e)}),i):(m(n)||d(r)||!1===r||(r=n,n=f),!1===r&&(r=j),i.each(function(){u(this,t,r,n)}))},e.fn.trigger=function(t,n){return t=m(t)||e.isPlainObject(t)?e.Event(t):c(t),t._args=n,this.each(function(){t.type in x&&"function"==typeof this[t.type]?this[t.type]():"dispatchEvent"in this?this.dispatchEvent(t):e(this).triggerHandler(t,n)})},e.fn.triggerHandler=function(t,n){var i,o;return this.each(function(a,s){(i=l(m(t)?e.Event(t):t))._args=n,i.target=s,e.each(r(s,t.type||t),function(t,e){if(o=e.proxy(i),i.isImmediatePropagationStopped())return!1})}),o},"focusin focusout focus blur load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error".split(" ").forEach(function(t){e.fn[t]=function(e){return 0 in arguments?this.bind(t,e):this.trigger(t)}}),e.Event=function(t,e){m(t)||(e=t,t=e.type);var n=document.createEvent(g[t]||"Events"),r=!0;if(e)for(var i in e)"bubbles"==i?r=!!e[i]:n[i]=e[i];return n.initEvent(t,r,!0),c(n)}}(e),function(e){function n(t,n,r,i){if(t.global)return function(t,n,r){var i=e.Event(n);return e(t).trigger(i,r),!i.isDefaultPrevented()}(n||d,r,i)}function r(t,e){var r=e.context;if(!1===e.beforeSend.call(r,t,e)||!1===n(e,r,"ajaxBeforeSend",[t,e]))return!1;n(e,r,"ajaxSend",[t,e])}function i(t,e,r,i){var o=r.context;r.success.call(o,t,"success",e),i&&i.resolveWith(o,[t,"success",e]),n(r,o,"ajaxSuccess",[e,r,t]),a("success",e,r)}function o(t,e,r,i,o){var s=i.context;i.error.call(s,r,e,t),o&&o.rejectWith(s,[r,e,t]),n(i,s,"ajaxError",[r,i,t||e]),a(e,r,i)}function a(t,r,i){var o=i.context;i.complete.call(o,r,t),n(i,o,"ajaxComplete",[r,i]),function(t){t.global&&!--e.active&&n(t,null,"ajaxStop")}(i)}function s(){}function u(t,e){return""==e?t:(t+"&"+e).replace(/[&?]{1,2}/,"?")}function c(t,n,r,i){return e.isFunction(n)&&(i=r,r=n,n=void 0),e.isFunction(r)||(i=r,r=void 0),{url:t,data:n,success:r,dataType:i}}function l(t,n,r,i){var o,a=e.isArray(n),s=e.isPlainObject(n);e.each(n,function(n,u){o=e.type(u),i&&(n=r?i:i+"["+(s||"object"==o||"array"==o?n:"")+"]"),!i&&a?t.add(u.name,u.value):"array"==o||!r&&"object"==o?l(t,u,r,n):t.add(n,u)})}var f,h,p=+new Date,d=t.document,m=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,v=/^(?:text|application)\/javascript/i,g=/^(?:text|application)\/xml/i,y="application/json",x="text/html",b=/^\s*$/,E=d.createElement("a");E.href=t.location.href,e.active=0,e.ajaxJSONP=function(n,a){if(!("type"in n))return e.ajax(n);var s,u,c=n.jsonpCallback,l=(e.isFunction(c)?c():c)||"Zepto"+p++,f=d.createElement("script"),h=t[l],m=function(t){e(f).triggerHandler("error",t||"abort")},v={abort:m};return a&&a.promise(v),e(f).on("load error",function(r,c){clearTimeout(u),e(f).off().remove(),"error"!=r.type&&s?i(s[0],v,n,a):o(null,c||"error",v,n,a),t[l]=h,s&&e.isFunction(h)&&h(s[0]),h=s=void 0}),!1===r(v,n)?(m("abort"),v):(t[l]=function(){s=arguments},f.src=n.url.replace(/\?(.+)=\?/,"?$1="+l),d.head.appendChild(f),n.timeout>0&&(u=setTimeout(function(){m("timeout")},n.timeout)),v)},e.ajaxSettings={type:"GET",beforeSend:s,success:s,error:s,complete:s,context:null,global:!0,xhr:function(){return new t.XMLHttpRequest},accepts:{script:"text/javascript, application/javascript, application/x-javascript",json:y,xml:"application/xml, text/xml",html:x,text:"text/plain"},crossDomain:!1,timeout:0,processData:!0,cache:!0,dataFilter:s},e.ajax=function(a){var c,l,p=e.extend({},a||{}),m=e.Deferred&&e.Deferred();for(f in e.ajaxSettings)void 0===p[f]&&(p[f]=e.ajaxSettings[f]);!function(t){t.global&&0==e.active++&&n(t,null,"ajaxStart")}(p),p.crossDomain||((c=d.createElement("a")).href=p.url,c.href=c.href,p.crossDomain=E.protocol+"//"+E.host!=c.protocol+"//"+c.host),p.url||(p.url=t.location.toString()),(l=p.url.indexOf("#"))>-1&&(p.url=p.url.slice(0,l)),function(t){t.processData&&t.data&&"string"!=e.type(t.data)&&(t.data=e.param(t.data,t.traditional)),!t.data||t.type&&"GET"!=t.type.toUpperCase()&&"jsonp"!=t.dataType||(t.url=u(t.url,t.data),t.data=void 0)}(p);var j=p.dataType,T=/\?.+=\?/.test(p.url);if(T&&(j="jsonp"),!1!==p.cache&&(a&&!0===a.cache||"script"!=j&&"jsonp"!=j)||(p.url=u(p.url,"_="+Date.now())),"jsonp"==j)return T||(p.url=u(p.url,p.jsonp?p.jsonp+"=?":!1===p.jsonp?"":"callback=?")),e.ajaxJSONP(p,m);var w,S=p.accepts[j],C={},N=function(t,e){C[t.toLowerCase()]=[t,e]},O=/^([\w-]+:)\/\//.test(p.url)?RegExp.$1:t.location.protocol,P=p.xhr(),A=P.setRequestHeader;if(m&&m.promise(P),p.crossDomain||N("X-Requested-With","XMLHttpRequest"),N("Accept",S||"*/*"),(S=p.mimeType||S)&&(S.indexOf(",")>-1&&(S=S.split(",",2)[0]),P.overrideMimeType&&P.overrideMimeType(S)),(p.contentType||!1!==p.contentType&&p.data&&"GET"!=p.type.toUpperCase())&&N("Content-Type",p.contentType||"application/x-www-form-urlencoded"),p.headers)for(h in p.headers)N(h,p.headers[h]);if(P.setRequestHeader=N,P.onreadystatechange=function(){if(4==P.readyState){P.onreadystatechange=s,clearTimeout(w);var t,n=!1;if(P.status>=200&&P.status<300||304==P.status||0==P.status&&"file:"==O){if(j=j||function(t){return t&&(t=t.split(";",2)[0]),t&&(t==x?"html":t==y?"json":v.test(t)?"script":g.test(t)&&"xml")||"text"}(p.mimeType||P.getResponseHeader("content-type")),"arraybuffer"==P.responseType||"blob"==P.responseType)t=P.response;else{t=P.responseText;try{t=function(t,e,n){if(n.dataFilter==s)return t;var r=n.context;return n.dataFilter.call(r,t,e)}(t,j,p),"script"==j?(0,eval)(t):"xml"==j?t=P.responseXML:"json"==j&&(t=b.test(t)?null:e.parseJSON(t))}catch(t){n=t}if(n)return o(n,"parsererror",P,p,m)}i(t,P,p,m)}else o(P.statusText||null,P.status?"error":"abort",P,p,m)}},!1===r(P,p))return P.abort(),o(null,"abort",P,p,m),P;var D=!("async"in p)||p.async;if(P.open(p.type,p.url,D,p.username,p.password),p.xhrFields)for(h in p.xhrFields)P[h]=p.xhrFields[h];for(h in C)A.apply(P,C[h]);return p.timeout>0&&(w=setTimeout(function(){P.onreadystatechange=s,P.abort(),o(null,"timeout",P,p,m)},p.timeout)),P.send(p.data?p.data:null),P},e.get=function(){return e.ajax(c.apply(null,arguments))},e.post=function(){var t=c.apply(null,arguments);return t.type="POST",e.ajax(t)},e.getJSON=function(){var t=c.apply(null,arguments);return t.dataType="json",e.ajax(t)},e.fn.load=function(t,n,r){if(!this.length)return this;var i,o=this,a=t.split(/\s/),s=c(t,n,r),u=s.success;return a.length>1&&(s.url=a[0],i=a[1]),s.success=function(t){o.html(i?e("<div>").html(t.replace(m,"")).find(i):t),u&&u.apply(o,arguments)},e.ajax(s),this};var j=encodeURIComponent;e.param=function(t,n){var r=[];return r.add=function(t,n){e.isFunction(n)&&(n=n()),null==n&&(n=""),this.push(j(t)+"="+j(n))},l(r,t,n),r.join("&").replace(/%20/g,"+")}}(e),function(t){t.fn.serializeArray=function(){var e,n,r=[],i=function(t){if(t.forEach)return t.forEach(i);r.push({name:e,value:t})};return this[0]&&t.each(this[0].elements,function(r,o){n=o.type,(e=o.name)&&"fieldset"!=o.nodeName.toLowerCase()&&!o.disabled&&"submit"!=n&&"reset"!=n&&"button"!=n&&"file"!=n&&("radio"!=n&&"checkbox"!=n||o.checked)&&i(t(o).val())}),r},t.fn.serialize=function(){var t=[];return this.serializeArray().forEach(function(e){t.push(encodeURIComponent(e.name)+"="+encodeURIComponent(e.value))}),t.join("&")},t.fn.submit=function(e){if(0 in arguments)this.bind("submit",e);else if(this.length){var n=t.Event("submit");this.eq(0).trigger(n),n.isDefaultPrevented()||this.get(0).submit()}return this}}(e),function(){try{getComputedStyle(void 0)}catch(n){var e=getComputedStyle;t.getComputedStyle=function(t,n){try{return e(t,n)}catch(t){return null}}}}(),e});
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/loading.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/loading.min.js
new file mode 100755
index 0000000..c230eb0
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/loading.min.js
@@ -0,0 +1 @@
+window.loading=function(e){var c={};"object"==typeof e?c=e:c.message=e,c.id||(c.id="LOADING"+(new Date).getTime());var t=document.getElementsByTagName("body")[0];event&&event.target&&event.target.parentNode&&event.target.parentNode.className.indexOf("body")>=0&&(t=event.target.parentNode);var d=document.createElement("div");d.className="backdrop show backdrop-alert",d.id=c.id+"_BACKDROP",t.appendChild(d);var a=document.createElement("div");a.className="alert-mobileui alert-loading",a.id=c.id,d.parentNode.appendChild(a);var l=document.createElement("div");c.class="white",l.className="alert "+c.class,window.SO&&2===SO.code?l.innerHTML='<div class="loading-circle"><svg xmlns="http://www.w3.org/2000/svg" width="37" height="37" viewBox="0 0 27 27"><path d="M18.696,10.5c-0.275-0.479-0.113-1.09,0.365-1.367l4.759-2.751c0.482-0.273,1.095-0.11,1.37,0.368 c0.276,0.479,0.115,1.092-0.364,1.364l-4.764,2.751C19.583,11.141,18.973,10.977,18.696,10.5z"/><path d="M16.133,6.938l2.75-4.765c0.276-0.478,0.889-0.643,1.367-0.366c0.479,0.276,0.641,0.886,0.365,1.366l-2.748,4.762 C17.591,8.415,16.979,8.58,16.5,8.303C16.021,8.027,15.856,7.414,16.133,6.938z"/><path d="M13.499,7.5c-0.552,0-1-0.448-1-1.001V1c0-0.554,0.448-1,1-1c0.554,0,1.003,0.447,1.003,1v5.499 C14.5,7.053,14.053,7.5,13.499,7.5z"/><path d="M8.303,10.5c-0.277,0.477-0.888,0.641-1.365,0.365L2.175,8.114C1.697,7.842,1.532,7.229,1.808,6.75 c0.277-0.479,0.89-0.642,1.367-0.368l4.762,2.751C8.416,9.41,8.58,10.021,8.303,10.5z"/><path d="M9.133,7.937l-2.75-4.763c-0.276-0.48-0.111-1.09,0.365-1.366c0.479-0.277,1.09-0.114,1.367,0.366l2.75,4.765 c0.274,0.476,0.112,1.088-0.367,1.364C10.021,8.581,9.409,8.415,9.133,7.937z"/><path d="M6.499,14.5H1c-0.554,0-1-0.448-1-1c0-0.554,0.447-1.001,1-1.001h5.499c0.552,0,1.001,0.448,1.001,1.001 C7.5,14.052,7.052,14.5,6.499,14.5z"/><path d="M8.303,16.502c0.277,0.478,0.113,1.088-0.365,1.366l-4.762,2.749c-0.478,0.273-1.091,0.112-1.368-0.366 c-0.276-0.479-0.111-1.089,0.367-1.368l4.762-2.748C7.415,15.856,8.026,16.021,8.303,16.502z"/><path d="M10.866,20.062l-2.75,4.767c-0.277,0.475-0.89,0.639-1.367,0.362c-0.477-0.277-0.642-0.886-0.365-1.365l2.75-4.764 c0.277-0.477,0.888-0.638,1.366-0.365C10.978,18.974,11.141,19.585,10.866,20.062z"/><path d="M13.499,19.502c0.554,0,1.003,0.448,1.003,1.002v5.498c0,0.55-0.448,0.999-1.003,0.999c-0.552,0-1-0.447-1-0.999v-5.498 C12.499,19.95,12.946,19.502,13.499,19.502z"/><path d="M17.867,19.062l2.748,4.764c0.275,0.479,0.113,1.088-0.365,1.365c-0.479,0.276-1.091,0.112-1.367-0.362l-2.75-4.767 c-0.276-0.477-0.111-1.088,0.367-1.365C16.979,18.424,17.591,18.585,17.867,19.062z"/><path d="M18.696,16.502c0.276-0.48,0.887-0.646,1.365-0.367l4.765,2.748c0.479,0.279,0.64,0.889,0.364,1.368 c-0.275,0.479-0.888,0.64-1.37,0.366l-4.759-2.749C18.583,17.59,18.421,16.979,18.696,16.502z"/><path d="M25.998,12.499h-5.501c-0.552,0-1.001,0.448-1.001,1.001c0,0.552,0.447,1,1.001,1h5.501c0.554,0,1.002-0.448,1.002-1 C27,12.946,26.552,12.499,25.998,12.499z"/></svg></div>':l.innerHTML='<svg class="loading-circle" width="40" height="40" version="1.1" xmlns="http://www.w3.org/2000/svg"><circle cx="20" cy="20" r="15"></svg>',c.message&&(l.innerHTML+="<p>"+c.message+"</p>"),a.appendChild(l)},window.loadingElement=function(e,c,t,d){"object"!=typeof e&&(e=document.getElementById(e));var a=c?"with-message":"";d=d?"":"white-loading",t||(t="");document.createElement("div");var l="";l=window.SO&&2===SO.code?'<svg class="loading-circle loading-element '+d+" "+a+" "+t+'" xmlns="http://www.w3.org/2000/svg" width="37" height="37" viewBox="0 0 27 27"><path d="M18.696,10.5c-0.275-0.479-0.113-1.09,0.365-1.367l4.759-2.751c0.482-0.273,1.095-0.11,1.37,0.368 c0.276,0.479,0.115,1.092-0.364,1.364l-4.764,2.751C19.583,11.141,18.973,10.977,18.696,10.5z"/><path d="M16.133,6.938l2.75-4.765c0.276-0.478,0.889-0.643,1.367-0.366c0.479,0.276,0.641,0.886,0.365,1.366l-2.748,4.762 C17.591,8.415,16.979,8.58,16.5,8.303C16.021,8.027,15.856,7.414,16.133,6.938z"/><path d="M13.499,7.5c-0.552,0-1-0.448-1-1.001V1c0-0.554,0.448-1,1-1c0.554,0,1.003,0.447,1.003,1v5.499 C14.5,7.053,14.053,7.5,13.499,7.5z"/><path d="M8.303,10.5c-0.277,0.477-0.888,0.641-1.365,0.365L2.175,8.114C1.697,7.842,1.532,7.229,1.808,6.75 c0.277-0.479,0.89-0.642,1.367-0.368l4.762,2.751C8.416,9.41,8.58,10.021,8.303,10.5z"/><path d="M9.133,7.937l-2.75-4.763c-0.276-0.48-0.111-1.09,0.365-1.366c0.479-0.277,1.09-0.114,1.367,0.366l2.75,4.765 c0.274,0.476,0.112,1.088-0.367,1.364C10.021,8.581,9.409,8.415,9.133,7.937z"/><path d="M6.499,14.5H1c-0.554,0-1-0.448-1-1c0-0.554,0.447-1.001,1-1.001h5.499c0.552,0,1.001,0.448,1.001,1.001 C7.5,14.052,7.052,14.5,6.499,14.5z"/><path d="M8.303,16.502c0.277,0.478,0.113,1.088-0.365,1.366l-4.762,2.749c-0.478,0.273-1.091,0.112-1.368-0.366 c-0.276-0.479-0.111-1.089,0.367-1.368l4.762-2.748C7.415,15.856,8.026,16.021,8.303,16.502z"/><path d="M10.866,20.062l-2.75,4.767c-0.277,0.475-0.89,0.639-1.367,0.362c-0.477-0.277-0.642-0.886-0.365-1.365l2.75-4.764 c0.277-0.477,0.888-0.638,1.366-0.365C10.978,18.974,11.141,19.585,10.866,20.062z"/><path d="M13.499,19.502c0.554,0,1.003,0.448,1.003,1.002v5.498c0,0.55-0.448,0.999-1.003,0.999c-0.552,0-1-0.447-1-0.999v-5.498 C12.499,19.95,12.946,19.502,13.499,19.502z"/><path d="M17.867,19.062l2.748,4.764c0.275,0.479,0.113,1.088-0.365,1.365c-0.479,0.276-1.091,0.112-1.367-0.362l-2.75-4.767 c-0.276-0.477-0.111-1.088,0.367-1.365C16.979,18.424,17.591,18.585,17.867,19.062z"/><path d="M18.696,16.502c0.276-0.48,0.887-0.646,1.365-0.367l4.765,2.748c0.479,0.279,0.64,0.889,0.364,1.368 c-0.275,0.479-0.888,0.64-1.37,0.366l-4.759-2.749C18.583,17.59,18.421,16.979,18.696,16.502z"/><path d="M25.998,12.499h-5.501c-0.552,0-1.001,0.448-1.001,1.001c0,0.552,0.447,1,1.001,1h5.501c0.554,0,1.002-0.448,1.002-1 C27,12.946,26.552,12.499,25.998,12.499z"/></svg>':'<svg class="loading-circle loading-element '+d+" "+a+" "+t+'" width="40" height="40" version="1.1" xmlns="http://www.w3.org/2000/svg"><circle cx="20" cy="20" r="15"></svg>',e.oldValue=e.innerHTML,e.innerHTML=l,e.disabled=!0,c&&(e.innerHTML+=c)},window.closeLoading=function(e){if(e)"object"!=typeof e&&(e=document.getElementById(e)),e.innerHTML=e.oldValue,e.disabled=!1;else{var c=document.getElementsByClassName("alert-mobileui")[0],t=c.id;(c=document.getElementById(t)).parentNode.removeChild(c);var d=document.getElementById(t+"_BACKDROP");d.parentNode.removeChild(d)}};
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/menu.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/menu.min.js
new file mode 100755
index 0000000..46cf212
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/menu.min.js
@@ -0,0 +1 @@
+window.menu={},window.openMenu=function(e){var n=e;if((e=document.getElementById(e)).className.indexOf("menu")>=0&&e.className.indexOf("open")<0){var o=document.createElement("div");if(o.className="backdrop backdrop-menu",e.parentNode.appendChild(o),setTimeout(function(){o.className+=" show"}),o.addEventListener("click",function(e){window.closeMenu(n)},!1),2===SO.code){e.style.height=window.innerHeight+"px";var d=" side-menu";if(window.menu.position="left",e.className.indexOf("menu-right")>=0){d=" side-menu-right",window.menu.position="right";var a=document.getElementsByClassName("header");if(a.length)for(i in a)a[i].className&&a[i].className.indexOf("side-menu-right")<0&&(a[i].className+=" side-menu-right")}e.parentNode.className.indexOf("body")>=0?e.parentNode.className+=d:document.getElementsByTagName("body")[0].className+=d}e.className+=" open";var t=new CustomEvent("openMenu",{detail:{menu:n}});document.dispatchEvent(t),window.menu.openFired=!0,document.addEventListener("firedCloseMenu",function(e){window.closeMenu(n)},!1)}},window.closeMenu=function(e){var n=e;if((e=document.getElementById(e)).className.indexOf("open")<0)return!1;var o=new CustomEvent("closeMenu",{detail:{menu:n}});document.dispatchEvent(o),window.menu.openFired=!1,e.className=e.className.replace("open","");var d=document.getElementsByClassName("header");if(d.length)for(i in d)d[i].className&&d[i].className.indexOf("side-menu-right")>=0&&(d[i].className=d[i].className.replace(" side-menu-right",""));var a=e.parentNode.getElementsByClassName("backdrop-menu");a&&a.length&&((a=a[0]).className=a.className.replace("show",""),setTimeout(function(){a&&a.parentNode&&a.parentNode.removeChild(a)},500)),1!==SO.code&&(e.parentNode.className.indexOf("body")>=0?e.parentNode.className=e.parentNode.className.replace("side-menu",""):document.getElementsByTagName("body")[0].className=document.getElementsByTagName("body")[0].className.replace("side-menu",""))},document.querySelector("body").addEventListener("touchstart",function(e){window.menu.xDown=e.touches[0].clientX,window.menu.yDown=e.touches[0].clientY},!1),window.menu.handleTouchMove=function(e,n){if(window.menu.xDown&&window.menu.yDown){var o=e.touches[0].clientX,i=e.touches[0].clientY;if(window.menu.xDiff=window.menu.xDown-o,window.menu.yDiff=window.menu.yDown-i,Math.abs(window.menu.xDiff)>Math.abs(window.menu.yDiff)){var d=-1!==document.getElementById(n).classList.value.indexOf("menu-right");window.menu.xDiff>0?d&&!window.menu.openFired?window.openMenu(n):!d&&window.menu.openFired&&window.closeMenu(n):d||window.menu.openFired?d&&window.menu.openFired&&window.closeMenu(n):window.openMenu(n)}window.menu.xDown=null,window.menu.yDown=null}},window.menu.enableSwiper=function(e){document.querySelector("body").addEventListener("touchmove",function(n){window.menu.handleTouchMove(n,e)},!1)};
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/mobileui-colors.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/mobileui-colors.min.js
new file mode 100755
index 0000000..cbae6e3
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/mobileui-colors.min.js
@@ -0,0 +1 @@
+window.colorsMobileUI=[],window.colorsMobileUI.red="rgb(244, 67, 54)",window.colorsMobileUI["red-50"]="rgb(255, 235, 238)",window.colorsMobileUI["red-100"]="rgb(255, 205, 210)",window.colorsMobileUI["red-200"]="rgb(239, 154, 154)",window.colorsMobileUI["red-300"]="rgb(229, 115, 115)",window.colorsMobileUI["red-400"]="rgb(239, 83, 80)",window.colorsMobileUI["red-500"]="rgb(244, 67, 54)",window.colorsMobileUI["red-600"]="rgb(229, 57, 53)",window.colorsMobileUI["red-700"]="rgb(211, 47, 47)",window.colorsMobileUI["red-800"]="rgb(198, 40, 40)",window.colorsMobileUI["red-900"]="rgb(183, 28, 28)",window.colorsMobileUI.pink="rgb(233, 30, 99)",window.colorsMobileUI["pink-50"]="rgb(252, 228, 236)",window.colorsMobileUI["pink-100"]="rgb(248, 187, 208)",window.colorsMobileUI["pink-200"]="rgb(244, 143, 177)",window.colorsMobileUI["Pink-300"]="rgb(240, 98, 146)",window.colorsMobileUI["pink-400"]="rgb(236, 64, 122)",window.colorsMobileUI["pink-500"]="rgb(233, 30, 99)",window.colorsMobileUI["pink-600"]="rgb(216, 27, 96)",window.colorsMobileUI["pink-700"]="rgb(194, 24, 91)",window.colorsMobileUI["pink-800"]="rgb(173, 20, 87)",window.colorsMobileUI["pink-900"]="rgb(136, 14, 79)",window.colorsMobileUI.purple="rgb(156, 39, 176)",window.colorsMobileUI["purple-50"]="rgb(243, 229, 245)",window.colorsMobileUI["purple-100"]="rgb(225, 190, 231)",window.colorsMobileUI["purple-200"]="rgb(206, 147, 216)",window.colorsMobileUI["Purple-300"]="rgb(186, 104, 200)",window.colorsMobileUI["Purple-400"]="rgb(171, 71, 188)",window.colorsMobileUI["purple-500"]="rgb(156, 39, 176)",window.colorsMobileUI["purple-600"]="rgb(142, 36, 170)",window.colorsMobileUI["purple-700"]="rgb(123, 31, 162)",window.colorsMobileUI["purple-800"]="rgb(106, 27, 154)",window.colorsMobileUI["purple-900"]="rgb(74, 20, 140)",window.colorsMobileUI["deep-purple"]="rgb(103, 58, 183)",window.colorsMobileUI["deep-purple-50"]="rgb(237, 231, 246)",window.colorsMobileUI["deep-purple-100"]="rgb(209, 196, 233)",window.colorsMobileUI["deep-purple-200"]="rgb(179, 157, 219)",window.colorsMobileUI["deep-purple-300"]="rgb(149, 117, 205)",window.colorsMobileUI["deep-purple-400"]="rgb(126, 87, 194)",window.colorsMobileUI["deep-purple-500"]="rgb(103, 58, 183)",window.colorsMobileUI["deep-purple-600"]="rgb(94, 53, 177)",window.colorsMobileUI["deep-purple-700"]="rgb(81, 45, 168)",window.colorsMobileUI["deep-purple-800"]="rgb(69, 39, 160)",window.colorsMobileUI["deep-purple-900"]="rgb(49, 27, 146)",window.colorsMobileUI.indigo="rgb(63, 81, 181)",window.colorsMobileUI["indigo-50"]="rgb(232, 234, 246)",window.colorsMobileUI["indigo-100"]="rgb(197, 202, 233)",window.colorsMobileUI["indigo-200"]="rgb(159, 168, 218)",window.colorsMobileUI["indigo-300"]="rgb(121, 134, 203)",window.colorsMobileUI["indigo-400"]="rgb(92, 107, 192)",window.colorsMobileUI["indigo-500"]="rgb(63, 81, 181)",window.colorsMobileUI["indigo-600"]="rgb(57, 73, 171)",window.colorsMobileUI["indigo-700"]="rgb(48, 63, 159)",window.colorsMobileUI["indigo-800"]="rgb(40, 53, 147)",window.colorsMobileUI["indigo-900"]="rgb(26, 35, 126)",window.colorsMobileUI.blue="rgb(33, 150, 243)",window.colorsMobileUI["blue-50"]="rgb(227, 242, 253)",window.colorsMobileUI["blue-100"]="rgb(187, 222, 251)",window.colorsMobileUI["blue-200"]="rgb(144, 202, 249)",window.colorsMobileUI["blue-300"]="rgb(100, 181, 246)",window.colorsMobileUI["blue-400"]="rgb(66, 165, 245)",window.colorsMobileUI["blue-500"]="rgb(33, 150, 243)",window.colorsMobileUI["blue-600"]="rgb(30, 136, 229)",window.colorsMobileUI["blue-700"]="rgb(25, 118, 210)",window.colorsMobileUI["blue-800"]="rgb(21, 101, 192)",window.colorsMobileUI["blue-900"]="rgb(13, 71, 161)",window.colorsMobileUI["light-blue"]="rgb(3, 169, 244)",window.colorsMobileUI["light-blue-50"]="rgb(225, 245, 254)",window.colorsMobileUI["light-blue-100"]="rgb(179, 229, 252)",window.colorsMobileUI["light-blue-200"]="rgb(129, 212, 250)",window.colorsMobileUI["light-blue-300"]="rgb(79, 195, 247)",window.colorsMobileUI["light-blue-400"]="rgb(41, 182, 246)",window.colorsMobileUI["light-blue-500"]="rgb(3, 169, 244)",window.colorsMobileUI["light-blue-600"]="rgb(3, 155, 229)",window.colorsMobileUI["light-blue-700"]="rgb(2, 136, 209)",window.colorsMobileUI["light-blue-800"]="rgb(2, 119, 189)",window.colorsMobileUI["light-blue-900"]="rgb(1, 87, 155)",window.colorsMobileUI.cyan="rgb(0, 188, 212)",window.colorsMobileUI["cyan-50"]="rgb(224, 247, 250)",window.colorsMobileUI["cyan-100"]="rgb(178, 235, 242)",window.colorsMobileUI["cyan-200"]="rgb(128, 222, 234)",window.colorsMobileUI["cyan-300"]="rgb(77, 208, 225)",window.colorsMobileUI["cyan-400"]="rgb(38, 198, 218)",window.colorsMobileUI["cyan-500"]="rgb(0, 188, 212)",window.colorsMobileUI["cyan-600"]="rgb(0, 172, 193)",window.colorsMobileUI["cyan-700"]="rgb(0, 151, 167)",window.colorsMobileUI["cyan-800"]="rgb(0, 131, 143)",window.colorsMobileUI["cyan-900"]="rgb(0, 96, 100)",window.colorsMobileUI.teal="rgb(0, 150, 136)",window.colorsMobileUI["teal-50"]="rgb(224, 242, 241)",window.colorsMobileUI["teal-100"]="rgb(178, 223, 219)",window.colorsMobileUI["teal-200"]="rgb(128, 203, 196)",window.colorsMobileUI["teal-300"]="rgb(77, 182, 172)",window.colorsMobileUI["teal-400"]="rgb(38, 166, 154)",window.colorsMobileUI["teal-500"]="rgb(0, 150, 136)",window.colorsMobileUI["teal-600"]="rgb(0, 137, 123)",window.colorsMobileUI["teal-700"]="rgb(0, 121, 107)",window.colorsMobileUI["teal-800"]="rgb(0, 105, 92)",window.colorsMobileUI["teal-900"]="rgb(0, 77, 64)",window.colorsMobileUI.green="rgb(76, 175, 80)",window.colorsMobileUI["green-50"]="rgb(232, 245, 233)",window.colorsMobileUI["green-100"]="rgb(200, 230, 201)",window.colorsMobileUI["green-200"]="rgb(165, 214, 167)",window.colorsMobileUI["green-300"]="rgb(129, 199, 132)",window.colorsMobileUI["green-400"]="rgb(102, 187, 106)",window.colorsMobileUI["green-500"]="rgb(76, 175, 80)",window.colorsMobileUI["green-600"]="rgb(67, 160, 71)",window.colorsMobileUI["green-700"]="rgb(56, 142, 60)",window.colorsMobileUI["green-800"]="rgb(46, 125, 50)",window.colorsMobileUI["green-900"]="rgb(27, 94, 32)",window.colorsMobileUI["light-green"]="rgb(139, 195, 74)",window.colorsMobileUI["light-green-50"]="rgb(241, 248, 233)",window.colorsMobileUI["light-green-100"]="rgb(220, 237, 200)",window.colorsMobileUI["light-green-200"]="rgb(197, 225, 165)",window.colorsMobileUI["light-green-300"]="rgb(174, 213, 129)",window.colorsMobileUI["light-green-400"]="rgb(156, 204, 101)",window.colorsMobileUI["light-green-500"]="rgb(139, 195, 74)",window.colorsMobileUI["light-green-600"]="rgb(124, 179, 66)",window.colorsMobileUI["light-green-700"]="rgb(104, 159, 56)",window.colorsMobileUI["light-green-800"]="rgb(85, 139, 47)",window.colorsMobileUI["light-green-900"]="rgb(51, 105, 30)",window.colorsMobileUI.lime="rgb(205, 220, 57)",window.colorsMobileUI["lime-50"]="rgb(249, 251, 231)",window.colorsMobileUI["lime-100"]="rgb(240, 244, 195)",window.colorsMobileUI["lime-200"]="rgb(230, 238, 156)",window.colorsMobileUI["lime-300"]="rgb(220, 231, 117)",window.colorsMobileUI["lime-400"]="rgb(212, 225, 87)",window.colorsMobileUI["lime-500"]="rgb(205, 220, 57)",window.colorsMobileUI["lime-600"]="rgb(192, 202, 51)",window.colorsMobileUI["lime-700"]="rgb(175, 180, 43)",window.colorsMobileUI["lime-800"]="rgb(158, 157, 36)",window.colorsMobileUI["lime-900"]="rgb(130, 119, 23)",window.colorsMobileUI.yellow="rgb(255, 235, 59)",window.colorsMobileUI["yellow-50"]="rgb(255, 253, 231)",window.colorsMobileUI["yellow-100"]="rgb(255, 249, 196)",window.colorsMobileUI["yellow-200"]="rgb(255, 245, 157)",window.colorsMobileUI["yellow-300"]="rgb(255, 241, 118)",window.colorsMobileUI["yellow-400"]="rgb(255, 238, 88)",window.colorsMobileUI["yellow-500"]="rgb(255, 235, 59)",window.colorsMobileUI["yellow-600"]="rgb(253, 216, 53)",window.colorsMobileUI["yellow-700"]="rgb(251, 192, 45)",window.colorsMobileUI["yellow-800"]="rgb(249, 168, 37)",window.colorsMobileUI["yellow-900"]="rgb(245, 127, 23)",window.colorsMobileUI.amber="rgb(255, 193, 7)",window.colorsMobileUI["amber-50"]="rgb(255, 248, 225)",window.colorsMobileUI["amber-100"]="rgb(255, 236, 179)",window.colorsMobileUI["amber-200"]="rgb(255, 224, 130)",window.colorsMobileUI["amber-300"]="rgb(255, 213, 79)",window.colorsMobileUI["amber-400"]="rgb(255, 202, 40)",window.colorsMobileUI["amber-500"]="rgb(255, 193, 7)",window.colorsMobileUI["amber-600"]="rgb(255, 179, 0)",window.colorsMobileUI["amber-700"]="rgb(255, 160, 0)",window.colorsMobileUI["amber-800"]="rgb(255, 143, 0)",window.colorsMobileUI["amber-900"]="rgb(255, 111, 0)",window.colorsMobileUI.orange="rgb(255, 152, 0)",window.colorsMobileUI["orange-50"]="rgb(255, 243, 224)",window.colorsMobileUI["orange-100"]="rgb(255, 224, 178)",window.colorsMobileUI["orange-200"]="rgb(255, 204, 128)",window.colorsMobileUI["orange-300"]="rgb(255, 183, 77)",window.colorsMobileUI["orange-400"]="rgb(255, 167, 38)",window.colorsMobileUI["orange-500"]="rgb(255, 152, 0)",window.colorsMobileUI["orange-600"]="rgb(251, 140, 0)",window.colorsMobileUI["orange-700"]="rgb(245, 124, 0)",window.colorsMobileUI["orange-800"]="rgb(239, 108, 0)",window.colorsMobileUI["orange-900"]="rgb(230, 81, 0)",window.colorsMobileUI["deep-orange"]="rgb(255, 87, 34)",window.colorsMobileUI["deep-orange-50"]="rgb(251, 233, 231)",window.colorsMobileUI["deep-orange-100"]="rgb(255, 204, 188)",window.colorsMobileUI["deep-orange-200"]="rgb(255, 171, 145)",window.colorsMobileUI["deep-orange-300"]="rgb(255, 138, 101)",window.colorsMobileUI["deep-orange-400"]="rgb(255, 112, 67)",window.colorsMobileUI["deep-orange-500"]="rgb(255, 87, 34)",window.colorsMobileUI["deep-orange-600"]="rgb(244, 81, 30)",window.colorsMobileUI["deep-orange-700"]="rgb(230, 74, 25)",window.colorsMobileUI["deep-orange-800"]="rgb(216, 67, 21)",window.colorsMobileUI["deep-orange-900"]="rgb(191, 54, 12)",window.colorsMobileUI.brown="rgb(121, 85, 72)",window.colorsMobileUI["brown-50"]="rgb(239, 235, 233)",window.colorsMobileUI["brown-100"]="rgb(215, 204, 200)",window.colorsMobileUI["brown-200"]="rgb(188, 170, 164)",window.colorsMobileUI["brown-300"]="rgb(161, 136, 127)",window.colorsMobileUI["brown-400"]="rgb(141, 110, 99)",window.colorsMobileUI["brown-500"]="rgb(121, 85, 72)",window.colorsMobileUI["brown-600"]="rgb(109, 76, 65)",window.colorsMobileUI["brown-700"]="rgb(93, 64, 55)",window.colorsMobileUI["brown-800"]="rgb(78, 52, 46)",window.colorsMobileUI["brown-900"]="rgb(62, 39, 35)",window.colorsMobileUI.grey="rgb(158, 158, 158)",window.colorsMobileUI["grey-50"]="rgb(250, 250, 250)",window.colorsMobileUI["grey-100"]="rgb(245, 245, 245)",window.colorsMobileUI["grey-200"]="rgb(238, 238, 238)",window.colorsMobileUI["grey-300"]="rgb(224, 224, 224)",window.colorsMobileUI["grey-400"]="rgb(189, 189, 189)",window.colorsMobileUI["grey-500"]="rgb(158, 158, 158)",window.colorsMobileUI["grey-600"]="rgb(117, 117, 117)",window.colorsMobileUI["grey-700"]="rgb(97, 97, 97)",window.colorsMobileUI["grey-800"]="rgb(66, 66, 66)",window.colorsMobileUI["grey-900"]="rgb(33, 33, 33)",window.colorsMobileUI["blue-grey"]="rgb(96, 125, 139)",window.colorsMobileUI["blue-grey-50"]="rgb(236, 239, 241)",window.colorsMobileUI["blue-grey-100"]="rgb(207, 216, 220)",window.colorsMobileUI["blue-grey-200"]="rgb(176, 190, 197)",window.colorsMobileUI["blue-grey-300"]="rgb(144, 164, 174)",window.colorsMobileUI["blue-grey-400"]="rgb(120, 144, 156)",window.colorsMobileUI["blue-grey-500"]="rgb(96, 125, 139)",window.colorsMobileUI["blue-grey-600"]="rgb(84, 110, 122)",window.colorsMobileUI["blue-grey-700"]="rgb(69, 90, 100)",window.colorsMobileUI["blue-grey-800"]="rgb(55, 71, 79)",window.colorsMobileUI["blue-grey-900"]="rgb(38, 50, 56)",window.colorsMobileUI.black="rgb(0, 0, 0)",window.colorsMobileUI.white="rgb(255, 255, 255)",window.colorsMobileUI["black-opacity-90"]="rgba(0, 0, 0, 0.9)",window.colorsMobileUI["white-opacity-90"]="rgba(255, 255, 255, 0.9)",window.colorsMobileUI["black-opacity-70"]="rgba(0, 0, 0, 0.8)",window.colorsMobileUI["white-opacity-70"]="rgba(255, 255, 255, 0.7)",window.colorsMobileUI["black-opacity-50"]="rgba(0, 0, 0, 0.7)",window.colorsMobileUI["white-opacity-50"]="rgba(255, 255, 255, 0.5)",window.colorsMobileUI["black-opacity-30"]="rgba(0, 0, 0, 0.6)",window.colorsMobileUI["white-opacity-30"]="rgba(255, 255, 255, 0.3)",window.colorsMobileUI["black-opacity-10"]="rgba(0, 0, 0, 0.5)",window.colorsMobileUI["white-opacity-10"]="rgba(255, 255, 255, 0.1)";
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/mobileuijs.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/mobileuijs.min.js
new file mode 100755
index 0000000..4a7e1b6
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/mobileuijs.min.js
@@ -0,0 +1 @@
+!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).superagent=t()}}(function(){return function t(e,r,n){function i(s,a){if(!r[s]){if(!e[s]){var u="function"==typeof require&&require;if(!a&&u)return u(s,!0);if(o)return o(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var h=r[s]={exports:{}};e[s][0].call(h.exports,function(t){return i(e[s][1][t]||t)},h,h.exports,t,e,r,n)}return r[s].exports}for(var o="function"==typeof require&&require,s=0;s<n.length;s++)i(n[s]);return i}({1:[function(t,e,r){var n=t("./is-object");e.exports=function(t){return"[object Function]"===(n(t)?Object.prototype.toString.call(t):"")}},{"./is-object":2}],2:[function(t,e,r){e.exports=function(t){return null!==t&&"object"==typeof t}},{}],3:[function(t,e,r){function n(t){if(t)return function(t){for(var e in n.prototype)t[e]=n.prototype[e];return t}(t)}var i=t("./is-object");e.exports=n,n.prototype.clearTimeout=function(){return clearTimeout(this._timer),clearTimeout(this._responseTimeoutTimer),delete this._timer,delete this._responseTimeoutTimer,this},n.prototype.parse=function(t){return this._parser=t,this},n.prototype.responseType=function(t){return this._responseType=t,this},n.prototype.serialize=function(t){return this._serializer=t,this},n.prototype.timeout=function(t){if(!t||"object"!=typeof t)return this._timeout=t,this._responseTimeout=0,this;for(var e in t)switch(e){case"deadline":this._timeout=t.deadline;break;case"response":this._responseTimeout=t.response;break;default:console.warn("Unknown timeout option",e)}return this},n.prototype.retry=function(t){return 0!==arguments.length&&!0!==t||(t=1),t<=0&&(t=0),this._maxRetries=t,this._retries=0,this},n.prototype._retry=function(){return this.clearTimeout(),this.req&&(this.req=null,this.req=this.request()),this._aborted=!1,this.timedout=!1,this._end()},n.prototype.then=function(t,e){if(!this._fullfilledPromise){var r=this;this._endCalled&&console.warn("Warning: superagent request was sent twice, because both .end() and .then() were called. Never call .end() if you use promises"),this._fullfilledPromise=new Promise(function(t,e){r.end(function(r,n){r?e(r):t(n)})})}return this._fullfilledPromise.then(t,e)},n.prototype.catch=function(t){return this.then(void 0,t)},n.prototype.use=function(t){return t(this),this},n.prototype.ok=function(t){if("function"!=typeof t)throw Error("Callback required");return this._okCallback=t,this},n.prototype._isResponseOK=function(t){return!!t&&(this._okCallback?this._okCallback(t):t.status>=200&&t.status<300)},n.prototype.get=function(t){return this._header[t.toLowerCase()]},n.prototype.getHeader=n.prototype.get,n.prototype.set=function(t,e){if(i(t)){for(var r in t)this.set(r,t[r]);return this}return this._header[t.toLowerCase()]=e,this.header[t]=e,this},n.prototype.unset=function(t){return delete this._header[t.toLowerCase()],delete this.header[t],this},n.prototype.field=function(t,e){if(null===t||void 0===t)throw new Error(".field(name, val) name can not be empty");if(this._data&&console.error(".field() can't be used if .send() is used. Please use only .send() or only .field() & .attach()"),i(t)){for(var r in t)this.field(r,t[r]);return this}if(Array.isArray(e)){for(var n in e)this.field(t,e[n]);return this}if(null===e||void 0===e)throw new Error(".field(name, val) val can not be empty");return"boolean"==typeof e&&(e=""+e),this._getFormData().append(t,e),this},n.prototype.abort=function(){return this._aborted?this:(this._aborted=!0,this.xhr&&this.xhr.abort(),this.req&&this.req.abort(),this.clearTimeout(),this.emit("abort"),this)},n.prototype.withCredentials=function(t){return void 0==t&&(t=!0),this._withCredentials=t,this},n.prototype.redirects=function(t){return this._maxRedirects=t,this},n.prototype.toJSON=function(){return{method:this.method,url:this.url,data:this._data,headers:this._header}},n.prototype.send=function(t){var e=i(t),r=this._header["content-type"];if(this._formData&&console.error(".send() can't be used if .attach() or .field() is used. Please use only .send() or only .field() & .attach()"),e&&!this._data)Array.isArray(t)?this._data=[]:this._isHost(t)||(this._data={});else if(t&&this._data&&this._isHost(this._data))throw Error("Can't merge these send calls");if(e&&i(this._data))for(var n in t)this._data[n]=t[n];else"string"==typeof t?(r||this.type("form"),r=this._header["content-type"],this._data="application/x-www-form-urlencoded"==r?this._data?this._data+"&"+t:t:(this._data||"")+t):this._data=t;return!e||this._isHost(t)?this:(r||this.type("json"),this)},n.prototype.sortQuery=function(t){return this._sort=void 0===t||t,this},n.prototype._timeoutError=function(t,e,r){if(!this._aborted){var n=new Error(t+e+"ms exceeded");n.timeout=e,n.code="ECONNABORTED",n.errno=r,this.timedout=!0,this.abort(),this.callback(n)}},n.prototype._setTimeouts=function(){var t=this;this._timeout&&!this._timer&&(this._timer=setTimeout(function(){t._timeoutError("Timeout of ",t._timeout,"ETIME")},this._timeout)),this._responseTimeout&&!this._responseTimeoutTimer&&(this._responseTimeoutTimer=setTimeout(function(){t._timeoutError("Response timeout of ",t._responseTimeout,"ETIMEDOUT")},this._responseTimeout))}},{"./is-object":2}],4:[function(t,e,r){function n(t){if(t)return function(t){for(var e in n.prototype)t[e]=n.prototype[e];return t}(t)}var i=t("./utils");e.exports=n,n.prototype.get=function(t){return this.header[t.toLowerCase()]},n.prototype._setHeaderProperties=function(t){var e=t["content-type"]||"";this.type=i.type(e);var r=i.params(e);for(var n in r)this[n]=r[n];this.links={};try{t.link&&(this.links=i.parseLinks(t.link))}catch(t){}},n.prototype._setStatusProperties=function(t){var e=t/100|0;this.status=this.statusCode=t,this.statusType=e,this.info=1==e,this.ok=2==e,this.redirect=3==e,this.clientError=4==e,this.serverError=5==e,this.error=(4==e||5==e)&&this.toError(),this.accepted=202==t,this.noContent=204==t,this.badRequest=400==t,this.unauthorized=401==t,this.notAcceptable=406==t,this.forbidden=403==t,this.notFound=404==t}},{"./utils":6}],5:[function(t,e,r){var n=["ECONNRESET","ETIMEDOUT","EADDRINFO","ESOCKETTIMEDOUT"];e.exports=function(t,e){return!!(t&&t.code&&~n.indexOf(t.code)||e&&e.status&&e.status>=500||t&&"timeout"in t&&"ECONNABORTED"==t.code||t&&"crossDomain"in t)}},{}],6:[function(t,e,r){r.type=function(t){return t.split(/ *; */).shift()},r.params=function(t){return t.split(/ *; */).reduce(function(t,e){var r=e.split(/ *= */),n=r.shift(),i=r.shift();return n&&i&&(t[n]=i),t},{})},r.parseLinks=function(t){return t.split(/ *, */).reduce(function(t,e){var r=e.split(/ *; */),n=r[0].slice(1,-1);return t[r[1].split(/ *= */)[1].slice(1,-1)]=n,t},{})},r.cleanHeader=function(t,e){return delete t["content-type"],delete t["content-length"],delete t["transfer-encoding"],delete t.host,e&&delete t.cookie,t}},{}],7:[function(t,e,r){function n(t){if(t)return function(t){for(var e in n.prototype)t[e]=n.prototype[e];return t}(t)}void 0!==e&&(e.exports=n),n.prototype.on=n.prototype.addEventListener=function(t,e){return this._callbacks=this._callbacks||{},(this._callbacks["$"+t]=this._callbacks["$"+t]||[]).push(e),this},n.prototype.once=function(t,e){function r(){this.off(t,r),e.apply(this,arguments)}return r.fn=e,this.on(t,r),this},n.prototype.off=n.prototype.removeListener=n.prototype.removeAllListeners=n.prototype.removeEventListener=function(t,e){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var r=this._callbacks["$"+t];if(!r)return this;if(1==arguments.length)return delete this._callbacks["$"+t],this;for(var n,i=0;i<r.length;i++)if((n=r[i])===e||n.fn===e){r.splice(i,1);break}return this},n.prototype.emit=function(t){this._callbacks=this._callbacks||{};var e=[].slice.call(arguments,1),r=this._callbacks["$"+t];if(r)for(var n=0,i=(r=r.slice(0)).length;n<i;++n)r[n].apply(this,e);return this},n.prototype.listeners=function(t){return this._callbacks=this._callbacks||{},this._callbacks["$"+t]||[]},n.prototype.hasListeners=function(t){return!!this.listeners(t).length}},{}],8:[function(t,e,r){function n(t){if(!p(t))return t;var e=[];for(var r in t)i(e,r,t[r]);return e.join("&")}function i(t,e,r){if(null!=r)if(Array.isArray(r))r.forEach(function(r){i(t,e,r)});else if(p(r))for(var n in r)i(t,e+"["+n+"]",r[n]);else t.push(encodeURIComponent(e)+"="+encodeURIComponent(r));else null===r&&t.push(encodeURIComponent(e))}function o(t){for(var e,r,n={},i=t.split("&"),o=0,s=i.length;o<s;++o)e=i[o],-1==(r=e.indexOf("="))?n[decodeURIComponent(e)]="":n[decodeURIComponent(e.slice(0,r))]=decodeURIComponent(e.slice(r+1));return n}function s(t){return/[\/+]json\b/.test(t)}function a(t){this.req=t,this.xhr=this.req.xhr,this.text="HEAD"!=this.req.method&&(""===this.xhr.responseType||"text"===this.xhr.responseType)||void 0===this.xhr.responseType?this.xhr.responseText:null,this.statusText=this.req.xhr.statusText;var e=this.xhr.status;1223===e&&(e=204),this._setStatusProperties(e),this.header=this.headers=function(t){var e,r,n,i,o=t.split(/\r?\n/),s={};o.pop();for(var a=0,u=o.length;a<u;++a)r=o[a],e=r.indexOf(":"),n=r.slice(0,e).toLowerCase(),i=v(r.slice(e+1)),s[n]=i;return s}(this.xhr.getAllResponseHeaders()),this.header["content-type"]=this.xhr.getResponseHeader("content-type"),this._setHeaderProperties(this.header),null===this.text&&t._responseType?this.body=this.xhr.response:this.body="HEAD"!=this.req.method?this._parseBody(this.text?this.text:this.xhr.response):null}function u(t,e){var r=this;this._query=this._query||[],this.method=t,this.url=e,this.header={},this._header={},this.on("end",function(){var t=null,e=null;try{e=new a(r)}catch(e){return t=new Error("Parser is unable to parse the response"),t.parse=!0,t.original=e,r.xhr?(t.rawResponse=void 0===r.xhr.responseType?r.xhr.responseText:r.xhr.response,t.status=r.xhr.status?r.xhr.status:null,t.statusCode=t.status):(t.rawResponse=null,t.status=null),r.callback(t)}r.emit("response",e);var n;try{r._isResponseOK(e)||(n=new Error(e.statusText||"Unsuccessful HTTP response"),n.original=t,n.response=e,n.status=e.status)}catch(t){n=t}n?r.callback(n,e):r.callback(null,e)})}function c(t,e,r){var n=b("DELETE",t);return"function"==typeof e&&(r=e,e=null),e&&n.send(e),r&&n.end(r),n}var h;"undefined"!=typeof window?h=window:"undefined"!=typeof self?h=self:(console.warn("Using browser-only version of superagent in non-browser environment"),h=this);var l=t("component-emitter"),d=t("./request-base"),p=t("./is-object"),f=t("./is-function"),y=t("./response-base"),m=t("./should-retry"),b=r=e.exports=function(t,e){return"function"==typeof e?new r.Request("GET",t).end(e):1==arguments.length?new r.Request("GET",t):new r.Request(t,e)};r.Request=u,b.getXHR=function(){if(!(!h.XMLHttpRequest||h.location&&"file:"==h.location.protocol&&h.ActiveXObject))return new XMLHttpRequest;try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(t){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(t){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(t){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(t){}throw Error("Browser-only verison of superagent could not find XHR")};var v="".trim?function(t){return t.trim()}:function(t){return t.replace(/(^\s*|\s*$)/g,"")};b.serializeObject=n,b.parseString=o,b.types={html:"text/html",json:"application/json",xml:"application/xml",urlencoded:"application/x-www-form-urlencoded",form:"application/x-www-form-urlencoded","form-data":"application/x-www-form-urlencoded"},b.serialize={"application/x-www-form-urlencoded":n,"application/json":JSON.stringify},b.parse={"application/x-www-form-urlencoded":o,"application/json":JSON.parse},y(a.prototype),a.prototype._parseBody=function(t){var e=b.parse[this.type];return this.req._parser?this.req._parser(this,t):(!e&&s(this.type)&&(e=b.parse["application/json"]),e&&t&&(t.length||t instanceof Object)?e(t):null)},a.prototype.toError=function(){var t=this.req,e=t.method,r=t.url,n="cannot "+e+" "+r+" ("+this.status+")",i=new Error(n);return i.status=this.status,i.method=e,i.url=r,i},b.Response=a,l(u.prototype),d(u.prototype),u.prototype.type=function(t){return this.set("Content-Type",b.types[t]||t),this},u.prototype.accept=function(t){return this.set("Accept",b.types[t]||t),this},u.prototype.auth=function(t,e,r){switch("object"==typeof e&&null!==e&&(r=e),r||(r={type:"function"==typeof btoa?"basic":"auto"}),r.type){case"basic":this.set("Authorization","Basic "+btoa(t+":"+e));break;case"auto":this.username=t,this.password=e;break;case"bearer":this.set("Authorization","Bearer "+t)}return this},u.prototype.query=function(t){return"string"!=typeof t&&(t=n(t)),t&&this._query.push(t),this},u.prototype.attach=function(t,e,r){if(e){if(this._data)throw Error("superagent can't mix .send() and .attach()");this._getFormData().append(t,e,r||e.name)}return this},u.prototype._getFormData=function(){return this._formData||(this._formData=new h.FormData),this._formData},u.prototype.callback=function(t,e){if(this._maxRetries&&this._retries++<this._maxRetries&&m(t,e))return this._retry();var r=this._callback;this.clearTimeout(),t&&(this._maxRetries&&(t.retries=this._retries-1),this.emit("error",t)),r(t,e)},u.prototype.crossDomainError=function(){var t=new Error("Request has been terminated\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.");t.crossDomain=!0,t.status=this.status,t.method=this.method,t.url=this.url,this.callback(t)},u.prototype.buffer=u.prototype.ca=u.prototype.agent=function(){return console.warn("This is not supported in browser version of superagent"),this},u.prototype.pipe=u.prototype.write=function(){throw Error("Streaming is not supported in browser version of superagent")},u.prototype._appendQueryString=function(){var t=this._query.join("&");if(t&&(this.url+=(this.url.indexOf("?")>=0?"&":"?")+t),this._sort){var e=this.url.indexOf("?");if(e>=0){var r=this.url.substring(e+1).split("&");f(this._sort)?r.sort(this._sort):r.sort(),this.url=this.url.substring(0,e)+"?"+r.join("&")}}},u.prototype._isHost=function(t){return t&&"object"==typeof t&&!Array.isArray(t)&&"[object Object]"!==Object.prototype.toString.call(t)},u.prototype.end=function(t){return this._endCalled&&console.warn("Warning: .end() was called twice. This is not supported in superagent"),this._endCalled=!0,this._callback=t||function(){},this._appendQueryString(),this._end()},u.prototype._end=function(){var t=this,e=this.xhr=b.getXHR(),r=this._formData||this._data;this._setTimeouts(),e.onreadystatechange=function(){var r=e.readyState;if(r>=2&&t._responseTimeoutTimer&&clearTimeout(t._responseTimeoutTimer),4==r){var n;try{n=e.status}catch(t){n=0}if(!n){if(t.timedout||t._aborted)return;return t.crossDomainError()}t.emit("end")}};var n=function(e,r){r.total>0&&(r.percent=r.loaded/r.total*100),r.direction=e,t.emit("progress",r)};if(this.hasListeners("progress"))try{e.onprogress=n.bind(null,"download"),e.upload&&(e.upload.onprogress=n.bind(null,"upload"))}catch(t){}try{this.username&&this.password?e.open(this.method,this.url,!0,this.username,this.password):e.open(this.method,this.url,!0)}catch(t){return this.callback(t)}if(this._withCredentials&&(e.withCredentials=!0),!this._formData&&"GET"!=this.method&&"HEAD"!=this.method&&"string"!=typeof r&&!this._isHost(r)){var i=this._header["content-type"],o=this._serializer||b.serialize[i?i.split(";")[0]:""];!o&&s(i)&&(o=b.serialize["application/json"]),o&&(r=o(r))}for(var a in this.header)null!=this.header[a]&&this.header.hasOwnProperty(a)&&e.setRequestHeader(a,this.header[a]);return this._responseType&&(e.responseType=this._responseType),this.emit("request",this),e.send(void 0!==r?r:null),this},b.get=function(t,e,r){var n=b("GET",t);return"function"==typeof e&&(r=e,e=null),e&&n.query(e),r&&n.end(r),n},b.head=function(t,e,r){var n=b("HEAD",t);return"function"==typeof e&&(r=e,e=null),e&&n.send(e),r&&n.end(r),n},b.options=function(t,e,r){var n=b("OPTIONS",t);return"function"==typeof e&&(r=e,e=null),e&&n.send(e),r&&n.end(r),n},b.del=c,b.delete=c,b.patch=function(t,e,r){var n=b("PATCH",t);return"function"==typeof e&&(r=e,e=null),e&&n.send(e),r&&n.end(r),n},b.post=function(t,e,r){var n=b("POST",t);return"function"==typeof e&&(r=e,e=null),e&&n.send(e),r&&n.end(r),n},b.put=function(t,e,r){var n=b("PUT",t);return"function"==typeof e&&(r=e,e=null),e&&n.send(e),r&&n.end(r),n}},{"./is-function":1,"./is-object":2,"./request-base":3,"./response-base":4,"./should-retry":5,"component-emitter":7}]},{},[8])(8)}),function(){var observerWatchers=[],tokenObserver=0,dataBind=function(){for(var t=document.querySelectorAll("[data]"),e=0;e<t.length;e++)if(t[e].getAttribute("data")&&!t[e].getAttribute("data-binded")){var r=t[e].getAttribute("data");(r=fetchFromObject(window,r))&&(writeElement(t[e],r),t[e].setAttribute("data-binded","mobileui"),dataObserver(t[e].getAttribute("data"),tokenObserver++))}eventLoopBind()};eventLoopBind=function(){setTimeout(function(){dataBind()},100)},reDataBind=function(t){for(var e=fetchFromObject(window,t.dataKey),r=document.querySelectorAll("[data-binded]"),n=0;n<r.length;n++)r[n].getAttribute("data-binded")===t.dataKey&&r[n].parentNode.removeChild(r[n]);r=document.querySelectorAll("[data][data-binded]");for(n=0;n<r.length;n++)r[n].getAttribute("data")===t.dataKey&&writeElement(r[n],e);t.dataValue=copyObj(e)},writeElement=function(elm,data){var bindWriteElement=function(dataObj,index){for(var html=elm.outerHTML,exp=/\${/g;match=exp.exec(html);){var prop=html.slice(match.index+2,html.length).split("}")[0],value=fetchFromObject(dataObj,prop);html=html.replace("${"+prop+"}",value)}index&&(html=html.replace(new RegExp("\\$\\$index","g"),index));for(var functionBind=html.split("$$"),i=1;i<functionBind.length;i++){var prop=functionBind[i].split("{")[1].split(",")[0].split("}")[0],value=fetchFromObject(dataObj,prop),functionName=functionBind[i].split("{")[0],functionReplace=functionBind[i].split("}")[0]+"}",functionInvoke="window.MobileUI."+functionBind[i].split("}")[0].replace(prop,"'"+value+"'").replace("{","(")+")",valueBind=eval(functionInvoke);html=html.replace(new RegExp("\\$\\$"+functionReplace,"g"),valueBind)}var divBind=document.createElement("div");elm.parentNode.insertBefore(divBind,elm),html=html.replace("data=","data-binded="),divBind.outerHTML=html};if(data.constructor===Array)for(var id in data)bindWriteElement(data[id],id);else bindWriteElement(data)},fetchFromObject=function(t,e){if(void 0===t)return console.error("Object for property ",e," is undefined!"),"";var r=e.indexOf(".");return r>-1?fetchFromObject(t[e.substring(0,r)],e.substr(r+1)):t.constructor===String||t.constructor===Number||t.constructor===Boolean||t.constructor===Date?t||"":t[e]?t[e]:""},dispatchEventObserver=function(t){var e=new CustomEvent("dataUpdated",{detail:{dataKey:t.dataKey,dataValue:t.dataValue}});document.dispatchEvent(e)},dataObserver=function(t,e){observerWatchers[e]||(observerWatchers[e]={dataKey:t,dataValue:copyObj(fetchFromObject(window,t))});var r=fetchFromObject(window,observerWatchers[e].dataKey);observerWatchers[e].dataValue.constructor===Array&&observerWatchers[e].dataValue.length!==r.length?(reDataBind(observerWatchers[e]),dispatchEventObserver(observerWatchers[e])):observerWatchers[e].dataValue.constructor===Array&&observerWatchers[e].dataValue.toString()!==r.toString()?(reDataBind(observerWatchers[e]),dispatchEventObserver(observerWatchers[e])):JSON.stringify(observerWatchers[e].dataValue)!==JSON.stringify(r)&&(reDataBind(observerWatchers[e]),dispatchEventObserver(observerWatchers[e])),setTimeout(function(){dataObserver(t,e)},100)},copyObj=function(t){return JSON.parse(JSON.stringify(t))},dataBind(),window.MobileUI={bind:function(){dataBind()},objectByForm:function(t){for(var e=document.getElementById(t),r={},n=e.querySelectorAll("input,textarea,select"),i=0;i<n.length;i++)if(n[i].id&&"checkbox"===n[i].type)r[n[i].id]=n[i].checked;else if(n[i].name&&"radio"===n[i].type){var o=e.querySelector('input[name="'+n[i].name+'"]:checked').value;o&&(r[n[i].name]=o)}else n[i].id&&(r[n[i].id]=n[i].value);return r},disable:function(t){for(var e=document.getElementById(t).querySelectorAll("input,textarea,select,button,a"),r=0;r<e.length;r++)e[r].setAttribute("disabled","disabled")},enable:function(t){for(var e=document.getElementById(t).querySelectorAll("input,textarea,select,button,a"),r=0;r<e.length;r++)e[r].removeAttribute("disabled")},formByObject:function(t,e){for(var r=document.getElementById(t),n=r.querySelectorAll("input,textarea,select"),i=0;i<n.length;i++)if(n[i].id&&"checkbox"===n[i].type)n[i].checked=e[n[i].id];else if(n[i].name&&"radio"===n[i].type){var o=r.querySelector('input[name="'+n[i].name+'"][value="'+e[n[i].name]+'"]');o&&(o.checked=!0)}else n[i].id&&e[n[i].id]&&(n[i].value=e[n[i].id])},clearForm:function(t){for(var e=document.getElementById(t),r=e.querySelectorAll("input,textarea,select"),n=0;n<r.length;n++)if(r[n].id&&r[n].type.indexOf("select")>=0){for(var i=r[n].options,o=0;o<i.length;o++)i[o].defaultSelected&&(r[n].selectedIndex=o,r[n].found=!0);r[n].found||(r[n].selectedIndex=0)}else r[n].id&&"checkbox"===r[n].type?r[n].checked=null!==r[n].getAttribute("checked"):r[n].name&&"radio"===r[n].type?e.querySelector('input[name="'+r[n].name+'"][checked]').checked=!0:r[n].id&&(r[n].value="")},show:function(t){document.getElementById(t).style.display="block"},hide:function(t){document.getElementById(t).style.display="none"},showHide:function(t){null===document.getElementById(t).offsetParent?this.show(t):this.hide(t)},focus:function(t){document.getElementById(t).focus()},formatMoney:function(t,e,r,n){var e=isNaN(e=Math.abs(e))?2:e,r=void 0==r?".":r,n=void 0==n?",":n,i=t<0?"-":"",o=String(parseInt(t=Math.abs(Number(t)||0).toFixed(e))),s=(s=o.length)>3?s%3:0;return i+(s?o.substr(0,s)+n:"")+o.substr(s).replace(/(\d{3})(?=\d)/g,"$1"+n)+(e?r+Math.abs(t-o).toFixed(e).slice(2):"")},ajax:superagent}}();
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/momentjs.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/momentjs.min.js
new file mode 100755
index 0000000..a2734f4
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/momentjs.min.js
@@ -0,0 +1 @@
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.moment=t()}(this,function(){"use strict";function e(){return Xe.apply(null,arguments)}function t(e){return e instanceof Array||"[object Array]"===Object.prototype.toString.call(e)}function n(e){return null!=e&&"[object Object]"===Object.prototype.toString.call(e)}function s(e){return void 0===e}function i(e){return"number"==typeof e||"[object Number]"===Object.prototype.toString.call(e)}function r(e){return e instanceof Date||"[object Date]"===Object.prototype.toString.call(e)}function a(e,t){var n,s=[];for(n=0;n<e.length;++n)s.push(t(e[n],n));return s}function o(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function u(e,t){for(var n in t)o(t,n)&&(e[n]=t[n]);return o(t,"toString")&&(e.toString=t.toString),o(t,"valueOf")&&(e.valueOf=t.valueOf),e}function l(e,t,n,s){return we(e,t,n,s,!0).utc()}function d(e){return null==e._pf&&(e._pf={empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],meridiem:null,rfc2822:!1,weekdayMismatch:!1}),e._pf}function h(e){if(null==e._isValid){var t=d(e),n=Ke.call(t.parsedDateParts,function(e){return null!=e}),s=!isNaN(e._d.getTime())&&t.overflow<0&&!t.empty&&!t.invalidMonth&&!t.invalidWeekday&&!t.weekdayMismatch&&!t.nullInput&&!t.invalidFormat&&!t.userInvalidated&&(!t.meridiem||t.meridiem&&n);if(e._strict&&(s=s&&0===t.charsLeftOver&&0===t.unusedTokens.length&&void 0===t.bigHour),null!=Object.isFrozen&&Object.isFrozen(e))return s;e._isValid=s}return e._isValid}function c(e){var t=l(NaN);return null!=e?u(d(t),e):d(t).userInvalidated=!0,t}function f(e,t){var n,i,r;if(s(t._isAMomentObject)||(e._isAMomentObject=t._isAMomentObject),s(t._i)||(e._i=t._i),s(t._f)||(e._f=t._f),s(t._l)||(e._l=t._l),s(t._strict)||(e._strict=t._strict),s(t._tzm)||(e._tzm=t._tzm),s(t._isUTC)||(e._isUTC=t._isUTC),s(t._offset)||(e._offset=t._offset),s(t._pf)||(e._pf=d(t)),s(t._locale)||(e._locale=t._locale),et.length>0)for(n=0;n<et.length;n++)s(r=t[i=et[n]])||(e[i]=r);return e}function m(t){f(this,t),this._d=new Date(null!=t._d?t._d.getTime():NaN),this.isValid()||(this._d=new Date(NaN)),!1===tt&&(tt=!0,e.updateOffset(this),tt=!1)}function _(e){return e instanceof m||null!=e&&null!=e._isAMomentObject}function y(e){return e<0?Math.ceil(e)||0:Math.floor(e)}function g(e){var t=+e,n=0;return 0!==t&&isFinite(t)&&(n=y(t)),n}function p(e,t,n){var s,i=Math.min(e.length,t.length),r=Math.abs(e.length-t.length),a=0;for(s=0;s<i;s++)(n&&e[s]!==t[s]||!n&&g(e[s])!==g(t[s]))&&a++;return a+r}function w(t){!1===e.suppressDeprecationWarnings&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+t)}function v(t,n){var s=!0;return u(function(){if(null!=e.deprecationHandler&&e.deprecationHandler(null,t),s){for(var i,r=[],a=0;a<arguments.length;a++){if(i="","object"==typeof arguments[a]){i+="\n["+a+"] ";for(var o in arguments[0])i+=o+": "+arguments[0][o]+", ";i=i.slice(0,-2)}else i=arguments[a];r.push(i)}w(t+"\nArguments: "+Array.prototype.slice.call(r).join("")+"\n"+(new Error).stack),s=!1}return n.apply(this,arguments)},n)}function M(t,n){null!=e.deprecationHandler&&e.deprecationHandler(t,n),nt[t]||(w(n),nt[t]=!0)}function k(e){return e instanceof Function||"[object Function]"===Object.prototype.toString.call(e)}function S(e,t){var s,i=u({},e);for(s in t)o(t,s)&&(n(e[s])&&n(t[s])?(i[s]={},u(i[s],e[s]),u(i[s],t[s])):null!=t[s]?i[s]=t[s]:delete i[s]);for(s in e)o(e,s)&&!o(t,s)&&n(e[s])&&(i[s]=u({},i[s]));return i}function D(e){null!=e&&this.set(e)}function Y(e,t){var n=e.toLowerCase();it[n]=it[n+"s"]=it[t]=e}function O(e){return"string"==typeof e?it[e]||it[e.toLowerCase()]:void 0}function x(e){var t,n,s={};for(n in e)o(e,n)&&(t=O(n))&&(s[t]=e[n]);return s}function T(e,t){rt[e]=t}function b(e,t,n){var s=""+Math.abs(e),i=t-s.length;return(e>=0?n?"+":"":"-")+Math.pow(10,Math.max(0,i)).toString().substr(1)+s}function P(e,t,n,s){var i=s;"string"==typeof s&&(i=function(){return this[s]()}),e&&(lt[e]=i),t&&(lt[t[0]]=function(){return b(i.apply(this,arguments),t[1],t[2])}),n&&(lt[n]=function(){return this.localeData().ordinal(i.apply(this,arguments),e)})}function W(e){return e.match(/\[[\s\S]/)?e.replace(/^\[|\]$/g,""):e.replace(/\\/g,"")}function R(e,t){return e.isValid()?(t=C(t,e.localeData()),ut[t]=ut[t]||function(e){var t,n,s=e.match(at);for(t=0,n=s.length;t<n;t++)lt[s[t]]?s[t]=lt[s[t]]:s[t]=W(s[t]);return function(t){var i,r="";for(i=0;i<n;i++)r+=k(s[i])?s[i].call(t,e):s[i];return r}}(t),ut[t](e)):e.localeData().invalidDate()}function C(e,t){var n=5;for(ot.lastIndex=0;n>=0&&ot.test(e);)e=e.replace(ot,function(e){return t.longDateFormat(e)||e}),ot.lastIndex=0,n-=1;return e}function F(e,t,n){Ot[e]=k(t)?t:function(e,s){return e&&n?n:t}}function U(e,t){return o(Ot,e)?Ot[e](t._strict,t._locale):new RegExp(function(e){return N(e.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(e,t,n,s,i){return t||n||s||i}))}(e))}function N(e){return e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function H(e,t){var n,s=t;for("string"==typeof e&&(e=[e]),i(t)&&(s=function(e,n){n[t]=g(e)}),n=0;n<e.length;n++)xt[e[n]]=s}function L(e,t){H(e,function(e,n,s,i){s._w=s._w||{},t(e,s._w,s,i)})}function G(e,t,n){null!=t&&o(xt,e)&&xt[e](t,n._a,n,e)}function V(e){return j(e)?366:365}function j(e){return e%4==0&&e%100!=0||e%400==0}function I(t,n){return function(s){return null!=s?(A(this,t,s),e.updateOffset(this,n),this):E(this,t)}}function E(e,t){return e.isValid()?e._d["get"+(e._isUTC?"UTC":"")+t]():NaN}function A(e,t,n){e.isValid()&&!isNaN(n)&&("FullYear"===t&&j(e.year())?e._d["set"+(e._isUTC?"UTC":"")+t](n,e.month(),z(n,e.month())):e._d["set"+(e._isUTC?"UTC":"")+t](n))}function z(e,t){if(isNaN(e)||isNaN(t))return NaN;var n=function(e,t){return(e%t+t)%t}(t,12);return e+=(t-n)/12,1===n?j(e)?29:28:31-n%7%2}function Z(e,t){var n;if(!e.isValid())return e;if("string"==typeof t)if(/^\d+$/.test(t))t=g(t);else if(t=e.localeData().monthsParse(t),!i(t))return e;return n=Math.min(e.date(),z(e.year(),t)),e._d["set"+(e._isUTC?"UTC":"")+"Month"](t,n),e}function $(t){return null!=t?(Z(this,t),e.updateOffset(this,!0),this):E(this,"Month")}function q(){function e(e,t){return t.length-e.length}var t,n,s=[],i=[],r=[];for(t=0;t<12;t++)n=l([2e3,t]),s.push(this.monthsShort(n,"")),i.push(this.months(n,"")),r.push(this.months(n,"")),r.push(this.monthsShort(n,""));for(s.sort(e),i.sort(e),r.sort(e),t=0;t<12;t++)s[t]=N(s[t]),i[t]=N(i[t]);for(t=0;t<24;t++)r[t]=N(r[t]);this._monthsRegex=new RegExp("^("+r.join("|")+")","i"),this._monthsShortRegex=this._monthsRegex,this._monthsStrictRegex=new RegExp("^("+i.join("|")+")","i"),this._monthsShortStrictRegex=new RegExp("^("+s.join("|")+")","i")}function J(e){var t=new Date(Date.UTC.apply(null,arguments));return e<100&&e>=0&&isFinite(t.getUTCFullYear())&&t.setUTCFullYear(e),t}function B(e,t,n){var s=7+t-n;return-(7+J(e,0,s).getUTCDay()-t)%7+s-1}function Q(e,t,n,s,i){var r,a,o=1+7*(t-1)+(7+n-s)%7+B(e,s,i);return o<=0?a=V(r=e-1)+o:o>V(e)?(r=e+1,a=o-V(e)):(r=e,a=o),{year:r,dayOfYear:a}}function X(e,t,n){var s,i,r=B(e.year(),t,n),a=Math.floor((e.dayOfYear()-r-1)/7)+1;return a<1?s=a+K(i=e.year()-1,t,n):a>K(e.year(),t,n)?(s=a-K(e.year(),t,n),i=e.year()+1):(i=e.year(),s=a),{week:s,year:i}}function K(e,t,n){var s=B(e,t,n),i=B(e+1,t,n);return(V(e)-s+i)/7}function ee(){function e(e,t){return t.length-e.length}var t,n,s,i,r,a=[],o=[],u=[],d=[];for(t=0;t<7;t++)n=l([2e3,1]).day(t),s=this.weekdaysMin(n,""),i=this.weekdaysShort(n,""),r=this.weekdays(n,""),a.push(s),o.push(i),u.push(r),d.push(s),d.push(i),d.push(r);for(a.sort(e),o.sort(e),u.sort(e),d.sort(e),t=0;t<7;t++)o[t]=N(o[t]),u[t]=N(u[t]),d[t]=N(d[t]);this._weekdaysRegex=new RegExp("^("+d.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+u.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+o.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+a.join("|")+")","i")}function te(){return this.hours()%12||12}function ne(e,t){P(e,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),t)})}function se(e,t){return t._meridiemParse}function ie(e){return e?e.toLowerCase().replace("_","-"):e}function re(e){var t=null;if(!Kt[e]&&"undefined"!=typeof module&&module&&module.exports){t=Bt._abbr;try{require("moment/locale/"+e)}catch(t){try{require("./locale/"+e)}catch(e){}}ae(t)}return Kt[e]}function ae(e,t){var n;return e&&(n=s(t)?ue(e):oe(e,t))&&(Bt=n),Bt._abbr}function oe(e,t){if(null!==t){var n=Xt;if(t.abbr=e,null!=Kt[e])M("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),n=Kt[e]._config;else if(null!=t.parentLocale){if(null==Kt[t.parentLocale])return en[t.parentLocale]||(en[t.parentLocale]=[]),en[t.parentLocale].push({name:e,config:t}),null;n=Kt[t.parentLocale]._config}return Kt[e]=new D(S(n,t)),en[e]&&en[e].forEach(function(e){oe(e.name,e.config)}),ae(e),Kt[e]}return delete Kt[e],null}function ue(e){var n;if(e&&e._locale&&e._locale._abbr&&(e=e._locale._abbr),!e)return Bt;if(!t(e)){if(n=re(e))return n;e=[e]}return function(e){for(var t,n,s,i,r=0;r<e.length;){for(t=(i=ie(e[r]).split("-")).length,n=(n=ie(e[r+1]))?n.split("-"):null;t>0;){if(s=re(i.slice(0,t).join("-")))return s;if(n&&n.length>=t&&p(i,n,!0)>=t-1)break;t--}r++}return null}(e)}function le(e){var t,n=e._a;return n&&-2===d(e).overflow&&(t=n[bt]<0||n[bt]>11?bt:n[Pt]<1||n[Pt]>z(n[Tt],n[bt])?Pt:n[Wt]<0||n[Wt]>24||24===n[Wt]&&(0!==n[Rt]||0!==n[Ct]||0!==n[Ft])?Wt:n[Rt]<0||n[Rt]>59?Rt:n[Ct]<0||n[Ct]>59?Ct:n[Ft]<0||n[Ft]>999?Ft:-1,d(e)._overflowDayOfYear&&(t<Tt||t>Pt)&&(t=Pt),d(e)._overflowWeeks&&-1===t&&(t=Ut),d(e)._overflowWeekday&&-1===t&&(t=Nt),d(e).overflow=t),e}function de(e,t,n){return null!=e?e:null!=t?t:n}function he(t){var n=new Date(e.now());return t._useUTC?[n.getUTCFullYear(),n.getUTCMonth(),n.getUTCDate()]:[n.getFullYear(),n.getMonth(),n.getDate()]}function ce(e){var t,n,s,i,r=[];if(!e._d){for(s=he(e),e._w&&null==e._a[Pt]&&null==e._a[bt]&&function(e){var t,n,s,i,r,a,o,u;if(null!=(t=e._w).GG||null!=t.W||null!=t.E)r=1,a=4,n=de(t.GG,e._a[Tt],X(ve(),1,4).year),s=de(t.W,1),((i=de(t.E,1))<1||i>7)&&(u=!0);else{r=e._locale._week.dow,a=e._locale._week.doy;var l=X(ve(),r,a);n=de(t.gg,e._a[Tt],l.year),s=de(t.w,l.week),null!=t.d?((i=t.d)<0||i>6)&&(u=!0):null!=t.e?(i=t.e+r,(t.e<0||t.e>6)&&(u=!0)):i=r}s<1||s>K(n,r,a)?d(e)._overflowWeeks=!0:null!=u?d(e)._overflowWeekday=!0:(o=Q(n,s,i,r,a),e._a[Tt]=o.year,e._dayOfYear=o.dayOfYear)}(e),null!=e._dayOfYear&&(i=de(e._a[Tt],s[Tt]),(e._dayOfYear>V(i)||0===e._dayOfYear)&&(d(e)._overflowDayOfYear=!0),n=J(i,0,e._dayOfYear),e._a[bt]=n.getUTCMonth(),e._a[Pt]=n.getUTCDate()),t=0;t<3&&null==e._a[t];++t)e._a[t]=r[t]=s[t];for(;t<7;t++)e._a[t]=r[t]=null==e._a[t]?2===t?1:0:e._a[t];24===e._a[Wt]&&0===e._a[Rt]&&0===e._a[Ct]&&0===e._a[Ft]&&(e._nextDay=!0,e._a[Wt]=0),e._d=(e._useUTC?J:function(e,t,n,s,i,r,a){var o=new Date(e,t,n,s,i,r,a);return e<100&&e>=0&&isFinite(o.getFullYear())&&o.setFullYear(e),o}).apply(null,r),null!=e._tzm&&e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),e._nextDay&&(e._a[Wt]=24),e._w&&void 0!==e._w.d&&e._w.d!==e._d.getDay()&&(d(e).weekdayMismatch=!0)}}function fe(e){var t,n,s,i,r,a,o=e._i,u=tn.exec(o)||nn.exec(o);if(u){for(d(e).iso=!0,t=0,n=rn.length;t<n;t++)if(rn[t][1].exec(u[1])){i=rn[t][0],s=!1!==rn[t][2];break}if(null==i)return void(e._isValid=!1);if(u[3]){for(t=0,n=an.length;t<n;t++)if(an[t][1].exec(u[3])){r=(u[2]||" ")+an[t][0];break}if(null==r)return void(e._isValid=!1)}if(!s&&null!=r)return void(e._isValid=!1);if(u[4]){if(!sn.exec(u[4]))return void(e._isValid=!1);a="Z"}e._f=i+(r||"")+(a||""),ye(e)}else e._isValid=!1}function me(e,t,n,s,i,r){var a=[function(e){var t=parseInt(e,10);return t<=49?2e3+t:t<=999?1900+t:t}(e),jt.indexOf(t),parseInt(n,10),parseInt(s,10),parseInt(i,10)];return r&&a.push(parseInt(r,10)),a}function _e(e){var t=un.exec(function(e){return e.replace(/\([^)]*\)|[\n\t]/g," ").replace(/(\s\s+)/g," ").trim()}(e._i));if(t){var n=me(t[4],t[3],t[2],t[5],t[6],t[7]);if(!function(e,t,n){return!e||zt.indexOf(e)===new Date(t[0],t[1],t[2]).getDay()||(d(n).weekdayMismatch=!0,n._isValid=!1,!1)}(t[1],n,e))return;e._a=n,e._tzm=function(e,t,n){if(e)return ln[e];if(t)return 0;var s=parseInt(n,10),i=s%100;return(s-i)/100*60+i}(t[8],t[9],t[10]),e._d=J.apply(null,e._a),e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),d(e).rfc2822=!0}else e._isValid=!1}function ye(t){if(t._f!==e.ISO_8601)if(t._f!==e.RFC_2822){t._a=[],d(t).empty=!0;var n,s,i,r,a,o=""+t._i,u=o.length,l=0;for(i=C(t._f,t._locale).match(at)||[],n=0;n<i.length;n++)r=i[n],(s=(o.match(U(r,t))||[])[0])&&((a=o.substr(0,o.indexOf(s))).length>0&&d(t).unusedInput.push(a),o=o.slice(o.indexOf(s)+s.length),l+=s.length),lt[r]?(s?d(t).empty=!1:d(t).unusedTokens.push(r),G(r,s,t)):t._strict&&!s&&d(t).unusedTokens.push(r);d(t).charsLeftOver=u-l,o.length>0&&d(t).unusedInput.push(o),t._a[Wt]<=12&&!0===d(t).bigHour&&t._a[Wt]>0&&(d(t).bigHour=void 0),d(t).parsedDateParts=t._a.slice(0),d(t).meridiem=t._meridiem,t._a[Wt]=function(e,t,n){var s;return null==n?t:null!=e.meridiemHour?e.meridiemHour(t,n):null!=e.isPM?((s=e.isPM(n))&&t<12&&(t+=12),s||12!==t||(t=0),t):t}(t._locale,t._a[Wt],t._meridiem),ce(t),le(t)}else _e(t);else fe(t)}function ge(e){var n=e._i,s=e._f;return e._locale=e._locale||ue(e._l),null===n||void 0===s&&""===n?c({nullInput:!0}):("string"==typeof n&&(e._i=n=e._locale.preparse(n)),_(n)?new m(le(n)):(r(n)?e._d=n:t(s)?function(e){var t,n,s,i,r;if(0===e._f.length)return d(e).invalidFormat=!0,void(e._d=new Date(NaN));for(i=0;i<e._f.length;i++)r=0,t=f({},e),null!=e._useUTC&&(t._useUTC=e._useUTC),t._f=e._f[i],ye(t),h(t)&&(r+=d(t).charsLeftOver,r+=10*d(t).unusedTokens.length,d(t).score=r,(null==s||r<s)&&(s=r,n=t));u(e,n||t)}(e):s?ye(e):pe(e),h(e)||(e._d=null),e))}function pe(o){var u=o._i;s(u)?o._d=new Date(e.now()):r(u)?o._d=new Date(u.valueOf()):"string"==typeof u?function(t){var n=on.exec(t._i);null===n?(fe(t),!1===t._isValid&&(delete t._isValid,_e(t),!1===t._isValid&&(delete t._isValid,e.createFromInputFallback(t)))):t._d=new Date(+n[1])}(o):t(u)?(o._a=a(u.slice(0),function(e){return parseInt(e,10)}),ce(o)):n(u)?function(e){if(!e._d){var t=x(e._i);e._a=a([t.year,t.month,t.day||t.date,t.hour,t.minute,t.second,t.millisecond],function(e){return e&&parseInt(e,10)}),ce(e)}}(o):i(u)?o._d=new Date(u):e.createFromInputFallback(o)}function we(e,s,i,r,a){var o={};return!0!==i&&!1!==i||(r=i,i=void 0),(n(e)&&function(e){if(Object.getOwnPropertyNames)return 0===Object.getOwnPropertyNames(e).length;var t;for(t in e)if(e.hasOwnProperty(t))return!1;return!0}(e)||t(e)&&0===e.length)&&(e=void 0),o._isAMomentObject=!0,o._useUTC=o._isUTC=a,o._l=i,o._i=e,o._f=s,o._strict=r,function(e){var t=new m(le(ge(e)));return t._nextDay&&(t.add(1,"d"),t._nextDay=void 0),t}(o)}function ve(e,t,n,s){return we(e,t,n,s,!1)}function Me(e,n){var s,i;if(1===n.length&&t(n[0])&&(n=n[0]),!n.length)return ve();for(s=n[0],i=1;i<n.length;++i)n[i].isValid()&&!n[i][e](s)||(s=n[i]);return s}function ke(e){var t=x(e),n=t.year||0,s=t.quarter||0,i=t.month||0,r=t.week||0,a=t.day||0,o=t.hour||0,u=t.minute||0,l=t.second||0,d=t.millisecond||0;this._isValid=function(e){for(var t in e)if(-1===Ht.call(cn,t)||null!=e[t]&&isNaN(e[t]))return!1;for(var n=!1,s=0;s<cn.length;++s)if(e[cn[s]]){if(n)return!1;parseFloat(e[cn[s]])!==g(e[cn[s]])&&(n=!0)}return!0}(t),this._milliseconds=+d+1e3*l+6e4*u+1e3*o*60*60,this._days=+a+7*r,this._months=+i+3*s+12*n,this._data={},this._locale=ue(),this._bubble()}function Se(e){return e instanceof ke}function De(e){return e<0?-1*Math.round(-1*e):Math.round(e)}function Ye(e,t){P(e,0,0,function(){var e=this.utcOffset(),n="+";return e<0&&(e=-e,n="-"),n+b(~~(e/60),2)+t+b(~~e%60,2)})}function Oe(e,t){var n=(t||"").match(e);if(null===n)return null;var s=((n[n.length-1]||[])+"").match(fn)||["-",0,0],i=60*s[1]+g(s[2]);return 0===i?0:"+"===s[0]?i:-i}function xe(t,n){var s,i;return n._isUTC?(s=n.clone(),i=(_(t)||r(t)?t.valueOf():ve(t).valueOf())-s.valueOf(),s._d.setTime(s._d.valueOf()+i),e.updateOffset(s,!1),s):ve(t).local()}function Te(e){return 15*-Math.round(e._d.getTimezoneOffset()/15)}function be(){return!!this.isValid()&&this._isUTC&&0===this._offset}function Pe(e,t){var n,s,r,a=e,u=null;return Se(e)?a={ms:e._milliseconds,d:e._days,M:e._months}:i(e)?(a={},t?a[t]=e:a.milliseconds=e):(u=mn.exec(e))?(n="-"===u[1]?-1:1,a={y:0,d:g(u[Pt])*n,h:g(u[Wt])*n,m:g(u[Rt])*n,s:g(u[Ct])*n,ms:g(De(1e3*u[Ft]))*n}):(u=_n.exec(e))?(n="-"===u[1]?-1:(u[1],1),a={y:We(u[2],n),M:We(u[3],n),w:We(u[4],n),d:We(u[5],n),h:We(u[6],n),m:We(u[7],n),s:We(u[8],n)}):null==a?a={}:"object"==typeof a&&("from"in a||"to"in a)&&(r=function(e,t){var n;return e.isValid()&&t.isValid()?(t=xe(t,e),e.isBefore(t)?n=Re(e,t):((n=Re(t,e)).milliseconds=-n.milliseconds,n.months=-n.months),n):{milliseconds:0,months:0}}(ve(a.from),ve(a.to)),(a={}).ms=r.milliseconds,a.M=r.months),s=new ke(a),Se(e)&&o(e,"_locale")&&(s._locale=e._locale),s}function We(e,t){var n=e&&parseFloat(e.replace(",","."));return(isNaN(n)?0:n)*t}function Re(e,t){var n={milliseconds:0,months:0};return n.months=t.month()-e.month()+12*(t.year()-e.year()),e.clone().add(n.months,"M").isAfter(t)&&--n.months,n.milliseconds=+t-+e.clone().add(n.months,"M"),n}function Ce(e,t){return function(n,s){var i,r;return null===s||isNaN(+s)||(M(t,"moment()."+t+"(period, number) is deprecated. Please use moment()."+t+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),r=n,n=s,s=r),n="string"==typeof n?+n:n,i=Pe(n,s),Fe(this,i,e),this}}function Fe(t,n,s,i){var r=n._milliseconds,a=De(n._days),o=De(n._months);t.isValid()&&(i=null==i||i,o&&Z(t,E(t,"Month")+o*s),a&&A(t,"Date",E(t,"Date")+a*s),r&&t._d.setTime(t._d.valueOf()+r*s),i&&e.updateOffset(t,a||o))}function Ue(e,t){var n,s=12*(t.year()-e.year())+(t.month()-e.month()),i=e.clone().add(s,"months");return n=t-i<0?(t-i)/(i-e.clone().add(s-1,"months")):(t-i)/(e.clone().add(s+1,"months")-i),-(s+n)||0}function Ne(e){var t;return void 0===e?this._locale._abbr:(null!=(t=ue(e))&&(this._locale=t),this)}function He(){return this._locale}function Le(e,t){P(0,[e,e.length],0,t)}function Ge(e,t,n,s,i){var r;return null==e?X(this,s,i).year:(r=K(e,s,i),t>r&&(t=r),function(e,t,n,s,i){var r=Q(e,t,n,s,i),a=J(r.year,0,r.dayOfYear);return this.year(a.getUTCFullYear()),this.month(a.getUTCMonth()),this.date(a.getUTCDate()),this}.call(this,e,t,n,s,i))}function Ve(e){return e}function je(e,t,n,s){var i=ue(),r=l().set(s,t);return i[n](r,e)}function Ie(e,t,n){if(i(e)&&(t=e,e=void 0),e=e||"",null!=t)return je(e,t,n,"month");var s,r=[];for(s=0;s<12;s++)r[s]=je(e,s,n,"month");return r}function Ee(e,t,n,s){"boolean"==typeof e?(i(t)&&(n=t,t=void 0),t=t||""):(n=t=e,e=!1,i(t)&&(n=t,t=void 0),t=t||"");var r=ue(),a=e?r._week.dow:0;if(null!=n)return je(t,(n+a)%7,s,"day");var o,u=[];for(o=0;o<7;o++)u[o]=je(t,(o+a)%7,s,"day");return u}function Ae(e,t,n,s){var i=Pe(t,n);return e._milliseconds+=s*i._milliseconds,e._days+=s*i._days,e._months+=s*i._months,e._bubble()}function ze(e){return e<0?Math.floor(e):Math.ceil(e)}function Ze(e){return 4800*e/146097}function $e(e){return 146097*e/4800}function qe(e){return function(){return this.as(e)}}function Je(e){return function(){return this.isValid()?this._data[e]:NaN}}function Be(e){return(e>0)-(e<0)||+e}function Qe(){if(!this.isValid())return this.localeData().invalidDate();var e,t,n,s=An(this._milliseconds)/1e3,i=An(this._days),r=An(this._months);t=y((e=y(s/60))/60),s%=60,e%=60;var a=n=y(r/12),o=r%=12,u=i,l=t,d=e,h=s?s.toFixed(3).replace(/\.?0+$/,""):"",c=this.asSeconds();if(!c)return"P0D";var f=c<0?"-":"",m=Be(this._months)!==Be(c)?"-":"",_=Be(this._days)!==Be(c)?"-":"",g=Be(this._milliseconds)!==Be(c)?"-":"";return f+"P"+(a?m+a+"Y":"")+(o?m+o+"M":"")+(u?_+u+"D":"")+(l||d||h?"T":"")+(l?g+l+"H":"")+(d?g+d+"M":"")+(h?g+h+"S":"")}var Xe,Ke;Ke=Array.prototype.some?Array.prototype.some:function(e){for(var t=Object(this),n=t.length>>>0,s=0;s<n;s++)if(s in t&&e.call(this,t[s],s,t))return!0;return!1};var et=e.momentProperties=[],tt=!1,nt={};e.suppressDeprecationWarnings=!1,e.deprecationHandler=null;var st;st=Object.keys?Object.keys:function(e){var t,n=[];for(t in e)o(e,t)&&n.push(t);return n};var it={},rt={},at=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,ot=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,ut={},lt={},dt=/\d/,ht=/\d\d/,ct=/\d{3}/,ft=/\d{4}/,mt=/[+-]?\d{6}/,_t=/\d\d?/,yt=/\d\d\d\d?/,gt=/\d\d\d\d\d\d?/,pt=/\d{1,3}/,wt=/\d{1,4}/,vt=/[+-]?\d{1,6}/,Mt=/\d+/,kt=/[+-]?\d+/,St=/Z|[+-]\d\d:?\d\d/gi,Dt=/Z|[+-]\d\d(?::?\d\d)?/gi,Yt=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Ot={},xt={},Tt=0,bt=1,Pt=2,Wt=3,Rt=4,Ct=5,Ft=6,Ut=7,Nt=8;P("Y",0,0,function(){var e=this.year();return e<=9999?""+e:"+"+e}),P(0,["YY",2],0,function(){return this.year()%100}),P(0,["YYYY",4],0,"year"),P(0,["YYYYY",5],0,"year"),P(0,["YYYYYY",6,!0],0,"year"),Y("year","y"),T("year",1),F("Y",kt),F("YY",_t,ht),F("YYYY",wt,ft),F("YYYYY",vt,mt),F("YYYYYY",vt,mt),H(["YYYYY","YYYYYY"],Tt),H("YYYY",function(t,n){n[Tt]=2===t.length?e.parseTwoDigitYear(t):g(t)}),H("YY",function(t,n){n[Tt]=e.parseTwoDigitYear(t)}),H("Y",function(e,t){t[Tt]=parseInt(e,10)}),e.parseTwoDigitYear=function(e){return g(e)+(g(e)>68?1900:2e3)};var Ht,Lt=I("FullYear",!0);Ht=Array.prototype.indexOf?Array.prototype.indexOf:function(e){var t;for(t=0;t<this.length;++t)if(this[t]===e)return t;return-1},P("M",["MM",2],"Mo",function(){return this.month()+1}),P("MMM",0,0,function(e){return this.localeData().monthsShort(this,e)}),P("MMMM",0,0,function(e){return this.localeData().months(this,e)}),Y("month","M"),T("month",8),F("M",_t),F("MM",_t,ht),F("MMM",function(e,t){return t.monthsShortRegex(e)}),F("MMMM",function(e,t){return t.monthsRegex(e)}),H(["M","MM"],function(e,t){t[bt]=g(e)-1}),H(["MMM","MMMM"],function(e,t,n,s){var i=n._locale.monthsParse(e,s,n._strict);null!=i?t[bt]=i:d(n).invalidMonth=e});var Gt=/D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/,Vt="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),jt="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),It=Yt,Et=Yt;P("w",["ww",2],"wo","week"),P("W",["WW",2],"Wo","isoWeek"),Y("week","w"),Y("isoWeek","W"),T("week",5),T("isoWeek",5),F("w",_t),F("ww",_t,ht),F("W",_t),F("WW",_t,ht),L(["w","ww","W","WW"],function(e,t,n,s){t[s.substr(0,1)]=g(e)});P("d",0,"do","day"),P("dd",0,0,function(e){return this.localeData().weekdaysMin(this,e)}),P("ddd",0,0,function(e){return this.localeData().weekdaysShort(this,e)}),P("dddd",0,0,function(e){return this.localeData().weekdays(this,e)}),P("e",0,0,"weekday"),P("E",0,0,"isoWeekday"),Y("day","d"),Y("weekday","e"),Y("isoWeekday","E"),T("day",11),T("weekday",11),T("isoWeekday",11),F("d",_t),F("e",_t),F("E",_t),F("dd",function(e,t){return t.weekdaysMinRegex(e)}),F("ddd",function(e,t){return t.weekdaysShortRegex(e)}),F("dddd",function(e,t){return t.weekdaysRegex(e)}),L(["dd","ddd","dddd"],function(e,t,n,s){var i=n._locale.weekdaysParse(e,s,n._strict);null!=i?t.d=i:d(n).invalidWeekday=e}),L(["d","e","E"],function(e,t,n,s){t[s]=g(e)});var At="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),zt="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Zt="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),$t=Yt,qt=Yt,Jt=Yt;P("H",["HH",2],0,"hour"),P("h",["hh",2],0,te),P("k",["kk",2],0,function(){return this.hours()||24}),P("hmm",0,0,function(){return""+te.apply(this)+b(this.minutes(),2)}),P("hmmss",0,0,function(){return""+te.apply(this)+b(this.minutes(),2)+b(this.seconds(),2)}),P("Hmm",0,0,function(){return""+this.hours()+b(this.minutes(),2)}),P("Hmmss",0,0,function(){return""+this.hours()+b(this.minutes(),2)+b(this.seconds(),2)}),ne("a",!0),ne("A",!1),Y("hour","h"),T("hour",13),F("a",se),F("A",se),F("H",_t),F("h",_t),F("k",_t),F("HH",_t,ht),F("hh",_t,ht),F("kk",_t,ht),F("hmm",yt),F("hmmss",gt),F("Hmm",yt),F("Hmmss",gt),H(["H","HH"],Wt),H(["k","kk"],function(e,t,n){var s=g(e);t[Wt]=24===s?0:s}),H(["a","A"],function(e,t,n){n._isPm=n._locale.isPM(e),n._meridiem=e}),H(["h","hh"],function(e,t,n){t[Wt]=g(e),d(n).bigHour=!0}),H("hmm",function(e,t,n){var s=e.length-2;t[Wt]=g(e.substr(0,s)),t[Rt]=g(e.substr(s)),d(n).bigHour=!0}),H("hmmss",function(e,t,n){var s=e.length-4,i=e.length-2;t[Wt]=g(e.substr(0,s)),t[Rt]=g(e.substr(s,2)),t[Ct]=g(e.substr(i)),d(n).bigHour=!0}),H("Hmm",function(e,t,n){var s=e.length-2;t[Wt]=g(e.substr(0,s)),t[Rt]=g(e.substr(s))}),H("Hmmss",function(e,t,n){var s=e.length-4,i=e.length-2;t[Wt]=g(e.substr(0,s)),t[Rt]=g(e.substr(s,2)),t[Ct]=g(e.substr(i))});var Bt,Qt=I("Hours",!0),Xt={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:Vt,monthsShort:jt,week:{dow:0,doy:6},weekdays:At,weekdaysMin:Zt,weekdaysShort:zt,meridiemParse:/[ap]\.?m?\.?/i},Kt={},en={},tn=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,nn=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,sn=/Z|[+-]\d\d(?::?\d\d)?/,rn=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],an=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],on=/^\/?Date\((\-?\d+)/i,un=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,ln={UT:0,GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};e.createFromInputFallback=v("value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.",function(e){e._d=new Date(e._i+(e._useUTC?" UTC":""))}),e.ISO_8601=function(){},e.RFC_2822=function(){};var dn=v("moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var e=ve.apply(null,arguments);return this.isValid()&&e.isValid()?e<this?this:e:c()}),hn=v("moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var e=ve.apply(null,arguments);return this.isValid()&&e.isValid()?e>this?this:e:c()}),cn=["year","quarter","month","week","day","hour","minute","second","millisecond"];Ye("Z",":"),Ye("ZZ",""),F("Z",Dt),F("ZZ",Dt),H(["Z","ZZ"],function(e,t,n){n._useUTC=!0,n._tzm=Oe(Dt,e)});var fn=/([\+\-]|\d\d)/gi;e.updateOffset=function(){};var mn=/^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/,_n=/^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;Pe.fn=ke.prototype,Pe.invalid=function(){return Pe(NaN)};var yn=Ce(1,"add"),gn=Ce(-1,"subtract");e.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",e.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var pn=v("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(e){return void 0===e?this.localeData():this.locale(e)});P(0,["gg",2],0,function(){return this.weekYear()%100}),P(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Le("gggg","weekYear"),Le("ggggg","weekYear"),Le("GGGG","isoWeekYear"),Le("GGGGG","isoWeekYear"),Y("weekYear","gg"),Y("isoWeekYear","GG"),T("weekYear",1),T("isoWeekYear",1),F("G",kt),F("g",kt),F("GG",_t,ht),F("gg",_t,ht),F("GGGG",wt,ft),F("gggg",wt,ft),F("GGGGG",vt,mt),F("ggggg",vt,mt),L(["gggg","ggggg","GGGG","GGGGG"],function(e,t,n,s){t[s.substr(0,2)]=g(e)}),L(["gg","GG"],function(t,n,s,i){n[i]=e.parseTwoDigitYear(t)}),P("Q",0,"Qo","quarter"),Y("quarter","Q"),T("quarter",7),F("Q",dt),H("Q",function(e,t){t[bt]=3*(g(e)-1)}),P("D",["DD",2],"Do","date"),Y("date","D"),T("date",9),F("D",_t),F("DD",_t,ht),F("Do",function(e,t){return e?t._dayOfMonthOrdinalParse||t._ordinalParse:t._dayOfMonthOrdinalParseLenient}),H(["D","DD"],Pt),H("Do",function(e,t){t[Pt]=g(e.match(_t)[0])});var wn=I("Date",!0);P("DDD",["DDDD",3],"DDDo","dayOfYear"),Y("dayOfYear","DDD"),T("dayOfYear",4),F("DDD",pt),F("DDDD",ct),H(["DDD","DDDD"],function(e,t,n){n._dayOfYear=g(e)}),P("m",["mm",2],0,"minute"),Y("minute","m"),T("minute",14),F("m",_t),F("mm",_t,ht),H(["m","mm"],Rt);var vn=I("Minutes",!1);P("s",["ss",2],0,"second"),Y("second","s"),T("second",15),F("s",_t),F("ss",_t,ht),H(["s","ss"],Ct);var Mn=I("Seconds",!1);P("S",0,0,function(){return~~(this.millisecond()/100)}),P(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),P(0,["SSS",3],0,"millisecond"),P(0,["SSSS",4],0,function(){return 10*this.millisecond()}),P(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),P(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),P(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),P(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),P(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),Y("millisecond","ms"),T("millisecond",16),F("S",pt,dt),F("SS",pt,ht),F("SSS",pt,ct);var kn;for(kn="SSSS";kn.length<=9;kn+="S")F(kn,Mt);for(kn="S";kn.length<=9;kn+="S")H(kn,function(e,t){t[Ft]=g(1e3*("0."+e))});var Sn=I("Milliseconds",!1);P("z",0,0,"zoneAbbr"),P("zz",0,0,"zoneName");var Dn=m.prototype;Dn.add=yn,Dn.calendar=function(t,n){var s=t||ve(),i=xe(s,this).startOf("day"),r=e.calendarFormat(this,i)||"sameElse",a=n&&(k(n[r])?n[r].call(this,s):n[r]);return this.format(a||this.localeData().calendar(r,this,ve(s)))},Dn.clone=function(){return new m(this)},Dn.diff=function(e,t,n){var s,i,r;if(!this.isValid())return NaN;if(!(s=xe(e,this)).isValid())return NaN;switch(i=6e4*(s.utcOffset()-this.utcOffset()),t=O(t)){case"year":r=Ue(this,s)/12;break;case"month":r=Ue(this,s);break;case"quarter":r=Ue(this,s)/3;break;case"second":r=(this-s)/1e3;break;case"minute":r=(this-s)/6e4;break;case"hour":r=(this-s)/36e5;break;case"day":r=(this-s-i)/864e5;break;case"week":r=(this-s-i)/6048e5;break;default:r=this-s}return n?r:y(r)},Dn.endOf=function(e){return void 0===(e=O(e))||"millisecond"===e?this:("date"===e&&(e="day"),this.startOf(e).add(1,"isoWeek"===e?"week":e).subtract(1,"ms"))},Dn.format=function(t){t||(t=this.isUtc()?e.defaultFormatUtc:e.defaultFormat);var n=R(this,t);return this.localeData().postformat(n)},Dn.from=function(e,t){return this.isValid()&&(_(e)&&e.isValid()||ve(e).isValid())?Pe({to:this,from:e}).locale(this.locale()).humanize(!t):this.localeData().invalidDate()},Dn.fromNow=function(e){return this.from(ve(),e)},Dn.to=function(e,t){return this.isValid()&&(_(e)&&e.isValid()||ve(e).isValid())?Pe({from:this,to:e}).locale(this.locale()).humanize(!t):this.localeData().invalidDate()},Dn.toNow=function(e){return this.to(ve(),e)},Dn.get=function(e){return e=O(e),k(this[e])?this[e]():this},Dn.invalidAt=function(){return d(this).overflow},Dn.isAfter=function(e,t){var n=_(e)?e:ve(e);return!(!this.isValid()||!n.isValid())&&("millisecond"===(t=O(s(t)?"millisecond":t))?this.valueOf()>n.valueOf():n.valueOf()<this.clone().startOf(t).valueOf())},Dn.isBefore=function(e,t){var n=_(e)?e:ve(e);return!(!this.isValid()||!n.isValid())&&("millisecond"===(t=O(s(t)?"millisecond":t))?this.valueOf()<n.valueOf():this.clone().endOf(t).valueOf()<n.valueOf())},Dn.isBetween=function(e,t,n,s){return("("===(s=s||"()")[0]?this.isAfter(e,n):!this.isBefore(e,n))&&(")"===s[1]?this.isBefore(t,n):!this.isAfter(t,n))},Dn.isSame=function(e,t){var n,s=_(e)?e:ve(e);return!(!this.isValid()||!s.isValid())&&("millisecond"===(t=O(t||"millisecond"))?this.valueOf()===s.valueOf():(n=s.valueOf(),this.clone().startOf(t).valueOf()<=n&&n<=this.clone().endOf(t).valueOf()))},Dn.isSameOrAfter=function(e,t){return this.isSame(e,t)||this.isAfter(e,t)},Dn.isSameOrBefore=function(e,t){return this.isSame(e,t)||this.isBefore(e,t)},Dn.isValid=function(){return h(this)},Dn.lang=pn,Dn.locale=Ne,Dn.localeData=He,Dn.max=hn,Dn.min=dn,Dn.parsingFlags=function(){return u({},d(this))},Dn.set=function(e,t){if("object"==typeof e)for(var n=function(e){var t=[];for(var n in e)t.push({unit:n,priority:rt[n]});return t.sort(function(e,t){return e.priority-t.priority}),t}(e=x(e)),s=0;s<n.length;s++)this[n[s].unit](e[n[s].unit]);else if(e=O(e),k(this[e]))return this[e](t);return this},Dn.startOf=function(e){switch(e=O(e)){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":case"date":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===e&&this.weekday(0),"isoWeek"===e&&this.isoWeekday(1),"quarter"===e&&this.month(3*Math.floor(this.month()/3)),this},Dn.subtract=gn,Dn.toArray=function(){var e=this;return[e.year(),e.month(),e.date(),e.hour(),e.minute(),e.second(),e.millisecond()]},Dn.toObject=function(){var e=this;return{years:e.year(),months:e.month(),date:e.date(),hours:e.hours(),minutes:e.minutes(),seconds:e.seconds(),milliseconds:e.milliseconds()}},Dn.toDate=function(){return new Date(this.valueOf())},Dn.toISOString=function(){if(!this.isValid())return null;var e=this.clone().utc();return e.year()<0||e.year()>9999?R(e,"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]"):k(Date.prototype.toISOString)?this.toDate().toISOString():R(e,"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]")},Dn.inspect=function(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var e="moment",t="";this.isLocal()||(e=0===this.utcOffset()?"moment.utc":"moment.parseZone",t="Z");var n="["+e+'("]',s=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",i=t+'[")]';return this.format(n+s+"-MM-DD[T]HH:mm:ss.SSS"+i)},Dn.toJSON=function(){return this.isValid()?this.toISOString():null},Dn.toString=function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},Dn.unix=function(){return Math.floor(this.valueOf()/1e3)},Dn.valueOf=function(){return this._d.valueOf()-6e4*(this._offset||0)},Dn.creationData=function(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},Dn.year=Lt,Dn.isLeapYear=function(){return j(this.year())},Dn.weekYear=function(e){return Ge.call(this,e,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)},Dn.isoWeekYear=function(e){return Ge.call(this,e,this.isoWeek(),this.isoWeekday(),1,4)},Dn.quarter=Dn.quarters=function(e){return null==e?Math.ceil((this.month()+1)/3):this.month(3*(e-1)+this.month()%3)},Dn.month=$,Dn.daysInMonth=function(){return z(this.year(),this.month())},Dn.week=Dn.weeks=function(e){var t=this.localeData().week(this);return null==e?t:this.add(7*(e-t),"d")},Dn.isoWeek=Dn.isoWeeks=function(e){var t=X(this,1,4).week;return null==e?t:this.add(7*(e-t),"d")},Dn.weeksInYear=function(){var e=this.localeData()._week;return K(this.year(),e.dow,e.doy)},Dn.isoWeeksInYear=function(){return K(this.year(),1,4)},Dn.date=wn,Dn.day=Dn.days=function(e){if(!this.isValid())return null!=e?this:NaN;var t=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=e?(e=function(e,t){return"string"!=typeof e?e:isNaN(e)?"number"==typeof(e=t.weekdaysParse(e))?e:null:parseInt(e,10)}(e,this.localeData()),this.add(e-t,"d")):t},Dn.weekday=function(e){if(!this.isValid())return null!=e?this:NaN;var t=(this.day()+7-this.localeData()._week.dow)%7;return null==e?t:this.add(e-t,"d")},Dn.isoWeekday=function(e){if(!this.isValid())return null!=e?this:NaN;if(null!=e){var t=function(e,t){return"string"==typeof e?t.weekdaysParse(e)%7||7:isNaN(e)?null:e}(e,this.localeData());return this.day(this.day()%7?t:t-7)}return this.day()||7},Dn.dayOfYear=function(e){var t=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==e?t:this.add(e-t,"d")},Dn.hour=Dn.hours=Qt,Dn.minute=Dn.minutes=vn,Dn.second=Dn.seconds=Mn,Dn.millisecond=Dn.milliseconds=Sn,Dn.utcOffset=function(t,n,s){var i,r=this._offset||0;if(!this.isValid())return null!=t?this:NaN;if(null!=t){if("string"==typeof t){if(null===(t=Oe(Dt,t)))return this}else Math.abs(t)<16&&!s&&(t*=60);return!this._isUTC&&n&&(i=Te(this)),this._offset=t,this._isUTC=!0,null!=i&&this.add(i,"m"),r!==t&&(!n||this._changeInProgress?Fe(this,Pe(t-r,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,e.updateOffset(this,!0),this._changeInProgress=null)),this}return this._isUTC?r:Te(this)},Dn.utc=function(e){return this.utcOffset(0,e)},Dn.local=function(e){return this._isUTC&&(this.utcOffset(0,e),this._isUTC=!1,e&&this.subtract(Te(this),"m")),this},Dn.parseZone=function(){if(null!=this._tzm)this.utcOffset(this._tzm,!1,!0);else if("string"==typeof this._i){var e=Oe(St,this._i);null!=e?this.utcOffset(e):this.utcOffset(0,!0)}return this},Dn.hasAlignedHourOffset=function(e){return!!this.isValid()&&(e=e?ve(e).utcOffset():0,(this.utcOffset()-e)%60==0)},Dn.isDST=function(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},Dn.isLocal=function(){return!!this.isValid()&&!this._isUTC},Dn.isUtcOffset=function(){return!!this.isValid()&&this._isUTC},Dn.isUtc=be,Dn.isUTC=be,Dn.zoneAbbr=function(){return this._isUTC?"UTC":""},Dn.zoneName=function(){return this._isUTC?"Coordinated Universal Time":""},Dn.dates=v("dates accessor is deprecated. Use date instead.",wn),Dn.months=v("months accessor is deprecated. Use month instead",$),Dn.years=v("years accessor is deprecated. Use year instead",Lt),Dn.zone=v("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",function(e,t){return null!=e?("string"!=typeof e&&(e=-e),this.utcOffset(e,t),this):-this.utcOffset()}),Dn.isDSTShifted=v("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",function(){if(!s(this._isDSTShifted))return this._isDSTShifted;var e={};if(f(e,this),(e=ge(e))._a){var t=e._isUTC?l(e._a):ve(e._a);this._isDSTShifted=this.isValid()&&p(e._a,t.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted});var Yn=D.prototype;Yn.calendar=function(e,t,n){var s=this._calendar[e]||this._calendar.sameElse;return k(s)?s.call(t,n):s},Yn.longDateFormat=function(e){var t=this._longDateFormat[e],n=this._longDateFormat[e.toUpperCase()];return t||!n?t:(this._longDateFormat[e]=n.replace(/MMMM|MM|DD|dddd/g,function(e){return e.slice(1)}),this._longDateFormat[e])},Yn.invalidDate=function(){return this._invalidDate},Yn.ordinal=function(e){return this._ordinal.replace("%d",e)},Yn.preparse=Ve,Yn.postformat=Ve,Yn.relativeTime=function(e,t,n,s){var i=this._relativeTime[n];return k(i)?i(e,t,n,s):i.replace(/%d/i,e)},Yn.pastFuture=function(e,t){var n=this._relativeTime[e>0?"future":"past"];return k(n)?n(t):n.replace(/%s/i,t)},Yn.set=function(e){var t,n;for(n in e)k(t=e[n])?this[n]=t:this["_"+n]=t;this._config=e,this._dayOfMonthOrdinalParseLenient=new RegExp((this._dayOfMonthOrdinalParse.source||this._ordinalParse.source)+"|"+/\d{1,2}/.source)},Yn.months=function(e,n){return e?t(this._months)?this._months[e.month()]:this._months[(this._months.isFormat||Gt).test(n)?"format":"standalone"][e.month()]:t(this._months)?this._months:this._months.standalone},Yn.monthsShort=function(e,n){return e?t(this._monthsShort)?this._monthsShort[e.month()]:this._monthsShort[Gt.test(n)?"format":"standalone"][e.month()]:t(this._monthsShort)?this._monthsShort:this._monthsShort.standalone},Yn.monthsParse=function(e,t,n){var s,i,r;if(this._monthsParseExact)return function(e,t,n){var s,i,r,a=e.toLocaleLowerCase();if(!this._monthsParse)for(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[],s=0;s<12;++s)r=l([2e3,s]),this._shortMonthsParse[s]=this.monthsShort(r,"").toLocaleLowerCase(),this._longMonthsParse[s]=this.months(r,"").toLocaleLowerCase();return n?"MMM"===t?-1!==(i=Ht.call(this._shortMonthsParse,a))?i:null:-1!==(i=Ht.call(this._longMonthsParse,a))?i:null:"MMM"===t?-1!==(i=Ht.call(this._shortMonthsParse,a))?i:-1!==(i=Ht.call(this._longMonthsParse,a))?i:null:-1!==(i=Ht.call(this._longMonthsParse,a))?i:-1!==(i=Ht.call(this._shortMonthsParse,a))?i:null}.call(this,e,t,n);for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),s=0;s<12;s++){if(i=l([2e3,s]),n&&!this._longMonthsParse[s]&&(this._longMonthsParse[s]=new RegExp("^"+this.months(i,"").replace(".","")+"$","i"),this._shortMonthsParse[s]=new RegExp("^"+this.monthsShort(i,"").replace(".","")+"$","i")),n||this._monthsParse[s]||(r="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[s]=new RegExp(r.replace(".",""),"i")),n&&"MMMM"===t&&this._longMonthsParse[s].test(e))return s;if(n&&"MMM"===t&&this._shortMonthsParse[s].test(e))return s;if(!n&&this._monthsParse[s].test(e))return s}},Yn.monthsRegex=function(e){return this._monthsParseExact?(o(this,"_monthsRegex")||q.call(this),e?this._monthsStrictRegex:this._monthsRegex):(o(this,"_monthsRegex")||(this._monthsRegex=Et),this._monthsStrictRegex&&e?this._monthsStrictRegex:this._monthsRegex)},Yn.monthsShortRegex=function(e){return this._monthsParseExact?(o(this,"_monthsRegex")||q.call(this),e?this._monthsShortStrictRegex:this._monthsShortRegex):(o(this,"_monthsShortRegex")||(this._monthsShortRegex=It),this._monthsShortStrictRegex&&e?this._monthsShortStrictRegex:this._monthsShortRegex)},Yn.week=function(e){return X(e,this._week.dow,this._week.doy).week},Yn.firstDayOfYear=function(){return this._week.doy},Yn.firstDayOfWeek=function(){return this._week.dow},Yn.weekdays=function(e,n){return e?t(this._weekdays)?this._weekdays[e.day()]:this._weekdays[this._weekdays.isFormat.test(n)?"format":"standalone"][e.day()]:t(this._weekdays)?this._weekdays:this._weekdays.standalone},Yn.weekdaysMin=function(e){return e?this._weekdaysMin[e.day()]:this._weekdaysMin},Yn.weekdaysShort=function(e){return e?this._weekdaysShort[e.day()]:this._weekdaysShort},Yn.weekdaysParse=function(e,t,n){var s,i,r;if(this._weekdaysParseExact)return function(e,t,n){var s,i,r,a=e.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],s=0;s<7;++s)r=l([2e3,1]).day(s),this._minWeekdaysParse[s]=this.weekdaysMin(r,"").toLocaleLowerCase(),this._shortWeekdaysParse[s]=this.weekdaysShort(r,"").toLocaleLowerCase(),this._weekdaysParse[s]=this.weekdays(r,"").toLocaleLowerCase();return n?"dddd"===t?-1!==(i=Ht.call(this._weekdaysParse,a))?i:null:"ddd"===t?-1!==(i=Ht.call(this._shortWeekdaysParse,a))?i:null:-1!==(i=Ht.call(this._minWeekdaysParse,a))?i:null:"dddd"===t?-1!==(i=Ht.call(this._weekdaysParse,a))?i:-1!==(i=Ht.call(this._shortWeekdaysParse,a))?i:-1!==(i=Ht.call(this._minWeekdaysParse,a))?i:null:"ddd"===t?-1!==(i=Ht.call(this._shortWeekdaysParse,a))?i:-1!==(i=Ht.call(this._weekdaysParse,a))?i:-1!==(i=Ht.call(this._minWeekdaysParse,a))?i:null:-1!==(i=Ht.call(this._minWeekdaysParse,a))?i:-1!==(i=Ht.call(this._weekdaysParse,a))?i:-1!==(i=Ht.call(this._shortWeekdaysParse,a))?i:null}.call(this,e,t,n);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),s=0;s<7;s++){if(i=l([2e3,1]).day(s),n&&!this._fullWeekdaysParse[s]&&(this._fullWeekdaysParse[s]=new RegExp("^"+this.weekdays(i,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[s]=new RegExp("^"+this.weekdaysShort(i,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[s]=new RegExp("^"+this.weekdaysMin(i,"").replace(".",".?")+"$","i")),this._weekdaysParse[s]||(r="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[s]=new RegExp(r.replace(".",""),"i")),n&&"dddd"===t&&this._fullWeekdaysParse[s].test(e))return s;if(n&&"ddd"===t&&this._shortWeekdaysParse[s].test(e))return s;if(n&&"dd"===t&&this._minWeekdaysParse[s].test(e))return s;if(!n&&this._weekdaysParse[s].test(e))return s}},Yn.weekdaysRegex=function(e){return this._weekdaysParseExact?(o(this,"_weekdaysRegex")||ee.call(this),e?this._weekdaysStrictRegex:this._weekdaysRegex):(o(this,"_weekdaysRegex")||(this._weekdaysRegex=$t),this._weekdaysStrictRegex&&e?this._weekdaysStrictRegex:this._weekdaysRegex)},Yn.weekdaysShortRegex=function(e){return this._weekdaysParseExact?(o(this,"_weekdaysRegex")||ee.call(this),e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(o(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=qt),this._weekdaysShortStrictRegex&&e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)},Yn.weekdaysMinRegex=function(e){return this._weekdaysParseExact?(o(this,"_weekdaysRegex")||ee.call(this),e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(o(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=Jt),this._weekdaysMinStrictRegex&&e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)},Yn.isPM=function(e){return"p"===(e+"").toLowerCase().charAt(0)},Yn.meridiem=function(e,t,n){return e>11?n?"pm":"PM":n?"am":"AM"},ae("en",{dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var t=e%10;return e+(1===g(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")}}),e.lang=v("moment.lang is deprecated. Use moment.locale instead.",ae),e.langData=v("moment.langData is deprecated. Use moment.localeData instead.",ue);var On=Math.abs,xn=qe("ms"),Tn=qe("s"),bn=qe("m"),Pn=qe("h"),Wn=qe("d"),Rn=qe("w"),Cn=qe("M"),Fn=qe("y"),Un=Je("milliseconds"),Nn=Je("seconds"),Hn=Je("minutes"),Ln=Je("hours"),Gn=Je("days"),Vn=Je("months"),jn=Je("years"),In=Math.round,En={ss:44,s:45,m:45,h:22,d:26,M:11},An=Math.abs,zn=ke.prototype;return zn.isValid=function(){return this._isValid},zn.abs=function(){var e=this._data;return this._milliseconds=On(this._milliseconds),this._days=On(this._days),this._months=On(this._months),e.milliseconds=On(e.milliseconds),e.seconds=On(e.seconds),e.minutes=On(e.minutes),e.hours=On(e.hours),e.months=On(e.months),e.years=On(e.years),this},zn.add=function(e,t){return Ae(this,e,t,1)},zn.subtract=function(e,t){return Ae(this,e,t,-1)},zn.as=function(e){if(!this.isValid())return NaN;var t,n,s=this._milliseconds;if("month"===(e=O(e))||"year"===e)return t=this._days+s/864e5,n=this._months+Ze(t),"month"===e?n:n/12;switch(t=this._days+Math.round($e(this._months)),e){case"week":return t/7+s/6048e5;case"day":return t+s/864e5;case"hour":return 24*t+s/36e5;case"minute":return 1440*t+s/6e4;case"second":return 86400*t+s/1e3;case"millisecond":return Math.floor(864e5*t)+s;default:throw new Error("Unknown unit "+e)}},zn.asMilliseconds=xn,zn.asSeconds=Tn,zn.asMinutes=bn,zn.asHours=Pn,zn.asDays=Wn,zn.asWeeks=Rn,zn.asMonths=Cn,zn.asYears=Fn,zn.valueOf=function(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*g(this._months/12):NaN},zn._bubble=function(){var e,t,n,s,i,r=this._milliseconds,a=this._days,o=this._months,u=this._data;return r>=0&&a>=0&&o>=0||r<=0&&a<=0&&o<=0||(r+=864e5*ze($e(o)+a),a=0,o=0),u.milliseconds=r%1e3,e=y(r/1e3),u.seconds=e%60,t=y(e/60),u.minutes=t%60,n=y(t/60),u.hours=n%24,a+=y(n/24),i=y(Ze(a)),o+=i,a-=ze($e(i)),s=y(o/12),o%=12,u.days=a,u.months=o,u.years=s,this},zn.clone=function(){return Pe(this)},zn.get=function(e){return e=O(e),this.isValid()?this[e+"s"]():NaN},zn.milliseconds=Un,zn.seconds=Nn,zn.minutes=Hn,zn.hours=Ln,zn.days=Gn,zn.weeks=function(){return y(this.days()/7)},zn.months=Vn,zn.years=jn,zn.humanize=function(e){if(!this.isValid())return this.localeData().invalidDate();var t=this.localeData(),n=function(e,t,n){var s=Pe(e).abs(),i=In(s.as("s")),r=In(s.as("m")),a=In(s.as("h")),o=In(s.as("d")),u=In(s.as("M")),l=In(s.as("y")),d=i<=En.ss&&["s",i]||i<En.s&&["ss",i]||r<=1&&["m"]||r<En.m&&["mm",r]||a<=1&&["h"]||a<En.h&&["hh",a]||o<=1&&["d"]||o<En.d&&["dd",o]||u<=1&&["M"]||u<En.M&&["MM",u]||l<=1&&["y"]||["yy",l];return d[2]=t,d[3]=+e>0,d[4]=n,function(e,t,n,s,i){return i.relativeTime(t||1,!!n,e,s)}.apply(null,d)}(this,!e,t);return e&&(n=t.pastFuture(+this,n)),t.postformat(n)},zn.toISOString=Qe,zn.toString=Qe,zn.toJSON=Qe,zn.locale=Ne,zn.localeData=He,zn.toIsoString=v("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",Qe),zn.lang=pn,P("X",0,0,"unix"),P("x",0,0,"valueOf"),F("x",kt),F("X",/[+-]?\d+(\.\d{1,3})?/),H("X",function(e,t,n){n._d=new Date(1e3*parseFloat(e,10))}),H("x",function(e,t,n){n._d=new Date(g(e))}),e.version="2.19.0",Xe=ve,e.fn=Dn,e.min=function(){return Me("isBefore",[].slice.call(arguments,0))},e.max=function(){return Me("isAfter",[].slice.call(arguments,0))},e.now=function(){return Date.now?Date.now():+new Date},e.utc=l,e.unix=function(e){return ve(1e3*e)},e.months=function(e,t){return Ie(e,t,"months")},e.isDate=r,e.locale=ae,e.invalid=c,e.duration=Pe,e.isMoment=_,e.weekdays=function(e,t,n){return Ee(e,t,n,"weekdays")},e.parseZone=function(){return ve.apply(null,arguments).parseZone()},e.localeData=ue,e.isDuration=Se,e.monthsShort=function(e,t){return Ie(e,t,"monthsShort")},e.weekdaysMin=function(e,t,n){return Ee(e,t,n,"weekdaysMin")},e.defineLocale=oe,e.updateLocale=function(e,t){if(null!=t){var n,s=Xt;null!=Kt[e]&&(s=Kt[e]._config),(n=new D(t=S(s,t))).parentLocale=Kt[e],Kt[e]=n,ae(e)}else null!=Kt[e]&&(null!=Kt[e].parentLocale?Kt[e]=Kt[e].parentLocale:null!=Kt[e]&&delete Kt[e]);return Kt[e]},e.locales=function(){return st(Kt)},e.weekdaysShort=function(e,t,n){return Ee(e,t,n,"weekdaysShort")},e.normalizeUnits=O,e.relativeTimeRounding=function(e){return void 0===e?In:"function"==typeof e&&(In=e,!0)},e.relativeTimeThreshold=function(e,t){return void 0!==En[e]&&(void 0===t?En[e]:(En[e]=t,"s"===e&&(En.ss=t-1),!0))},e.calendarFormat=function(e,t){var n=e.diff(t,"days",!0);return n<-6?"sameElse":n<-1?"lastWeek":n<0?"lastDay":n<1?"sameDay":n<2?"nextDay":n<7?"nextWeek":"sameElse"},e.prototype=Dn,e});
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/page.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/page.min.js
new file mode 100755
index 0000000..57bdd94
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/page.min.js
@@ -0,0 +1 @@
+window.PAGE={handePage:100},document.addEventListener("deviceready",function(){document.addEventListener("backbutton",function(e){if(window.disabledBackButton)return e.preventDefault();var t=document.getElementsByClassName("box-block");t.length?(e.preventDefault(),window.backPage(t[t.length-1].id)):navigator.app.exitApp()},!1)},!1),window.dispatch=function(e,t){return(e="function"==typeof e?e:window[e]).apply(this,t||[])},window.openPage=function(e,t,n){if(2===arguments.length&&(n=t),e.indexOf(".html")<0&&(e+=".html"),document.getElementById(e)){var a=document.getElementsByClassName("box-block");if(a[a.length-1].id===document.getElementById(e).id)return!1;document.getElementById(e).parentNode.removeChild(document.getElementById(e))}var s=new XMLHttpRequest;s.onload=function(){if(4==this.readyState){var a=this.responseText;a=a.replace("backPage()","backPage('"+e+"')");var s=document.getElementsByTagName("body")[0];document.getElementsByClassName("body").length&&(s=document.getElementsByClassName("body")[0]);var d=document.createElement("div");d.setAttribute("class","box-block"),d.setAttribute("id",e),d.innerHTML=a,s.appendChild(d),function(){window.PAGE.handePage++;var a="z-index:"+window.PAGE.handePage,s=";transform: translateY(0px);will-change: transform, -webkit-transform, opacity;transition-duration: 280ms;transition-timing-function: cubic-bezier(0.36,0.66,0.04,1);";2===SO.code&&(s=";transform: translateX(0px);transition-duration: 280ms;"),window.disabledOpenPageEffect&&(s=";opacity: 1;top: 0;");var d=document.getElementById(e).getElementsByClassName("page")[0].getAttribute("style");d?d+=" "+a+s:d=a+s,document.getElementById(e).getElementsByClassName("page")[0].setAttribute("style",d),n&&window.dispatch(n,[t]);var o=document.getElementById(e).getElementsByClassName("page")[0].getAttribute("class");o+=" show";var l=function(){setTimeout(function(){document.getElementById(e)&&document.getElementById(e).querySelectorAll(".page").length?i():l()},10)};l();var m=new CustomEvent("openPage",{detail:{page:e}});document.dispatchEvent(m);var i=function(){setTimeout(function(){document.getElementById(e).getElementsByClassName("page")[0].setAttribute("class",o),setTimeout(function(){var t=document.getElementById(e).getElementsByClassName("page")[0].getAttribute("style");t=t.replace(s,""),document.getElementById(e).getElementsByClassName("page")[0].setAttribute("style",t)},280)},100)}}()}},s.open("GET",e+"?cache="+(new Date).getTime(),!0),document.dispatchEvent(new Event("firedCloseMenu")),s.send()},window.backPage=function(e){if(!e){for(var t=document.querySelectorAll(".page.show"),n={zIndex:-1},a=0;a<t.length;a++){var s=Number(t[a].style.zIndex);n.zIndex<s&&(n.zIndex=s,n.element=t[a])}n.zIndex&&(e=n.element.parentElement.id)}document.getElementById(e).getElementsByClassName("page")[0];var d=";transform: translateY(0px);will-change: transform, -webkit-transform, opacity;transition-duration: 280ms;";window.disabledOpenPageEffect&&(d="");var o=document.getElementById(e).getElementsByClassName("page")[0].getAttribute("style");o?o+=" "+d:o=d,document.getElementById(e).getElementsByClassName("page")[0].setAttribute("style",o);var l=document.getElementById(e).getElementsByClassName("page")[0].getAttribute("class");l+=l.replace("show",""),document.getElementById(e).getElementsByClassName("page")[0].setAttribute("class",l);var m=new CustomEvent("backPage",{detail:{page:e}});document.dispatchEvent(m),setTimeout(function(){var t=document.getElementById(e);t.parentElement.removeChild(t)},window.disabledOpenPageEffect?0:280)};
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/popover.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/popover.min.js
new file mode 100755
index 0000000..35eca94
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/popover.min.js
@@ -0,0 +1 @@
+window.openPopover=function(e){var t=event.target.getBoundingClientRect(),o=e,e=document.getElementById(e),n=document.createElement("div");n.className="backdrop backdrop-popover",e.parentNode.appendChild(n),n.addEventListener("click",function(e){window.closePopover(o)}),e.addEventListener("click",function(e){window.closePopover(o)});var i=document.body.offsetWidth-t.left,r=document.body.offsetWidth-i;if(i-=t.width,e.style+=r>250?";top: 110%;right: "+i+"px;transform-origin: right top 0px;transform: scale(1);":";top: 110%;left: "+r+"px;transform-origin: right top 0px;transform: scale(1);",e.classList.add("show"),2===SO.code){e.style.top=t.top+t.height+"px";var s=document.createElement("div");s.classList.add("popover-arrow"),e.parentNode.appendChild(s),s.setAttribute("style","top:"+(t.top+t.height-5)+"px;left:"+(t.left+t.width/2-7)+"px")}else{var d=e.clientHeight,a=e.clientWidth;e.style.height=0,e.style.width=0,e.style.top=t.top+"px",setTimeout(function(){var t=e.getAttribute("style");t+=" ;-webkit-transition: all 200ms ease;transition: all 200ms ease;",e.setAttribute("style",t),e.style.height=d+"px",e.style.width=a+"px"})}var p=new CustomEvent("popoverOpened");document.dispatchEvent(p)},window.closePopover=function(e){var e=document.getElementById(e),t=0;2!==SO.code&&(e.style.opacity=0,t=200),setTimeout(function(){var t=document.getElementsByClassName("popover-arrow");t.length&&t[0].parentNode.removeChild(t[0]),e.classList.remove("show");var o=e.parentNode.getElementsByClassName("backdrop-popover");o&&o.length&&(o=o[0])&&o.parentNode&&o.parentNode.removeChild(o);var n=new CustomEvent("popoverClosed");document.dispatchEvent(n)},t)};
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/progress-circle.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/progress-circle.min.js
new file mode 100755
index 0000000..57ad8b6
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/progress-circle.min.js
@@ -0,0 +1 @@
+window.ProgressCircle={rebind:function(){for(var t=document.querySelectorAll(".progress-circle"),e=0;e<t.length;e++)t[e].classList.remove("binded"),t[e].innerHTML="";this.bind()},bind:function(){for(var t=document.querySelectorAll(".progress-circle:not(.binded)"),e=0;e<t.length;e++){var i={};i.value=Number(t[e].getAttribute("value")),i.maxValue=Number(t[e].getAttribute("maxValue"))||100,i.showValue="1"===t[e].getAttribute("showValue")||"true"===t[e].getAttribute("showValue")||!1,i.title=t[e].getAttribute("title")||"",i.subTitle=t[e].getAttribute("subTitle")||"",i.text=t[e].getAttribute("text")||"",i.color=t[e].getAttribute("color")||"blue",i.textColor=t[e].getAttribute("textColor")||"grey-800",i.textWeight=t[e].getAttribute("textWeight")||"normal",i.titleWeight=t[e].getAttribute("titleWeight")||"normal",i.subTitleWeight=t[e].getAttribute("subTitleWeight")||"normal",i.titleColor=t[e].getAttribute("titleColor")||"grey-500",i.subTitleColor=t[e].getAttribute("subTitleColor")||"grey-300",i.width=t[e].getAttribute("width")||"100%",i.height=t[e].getAttribute("height")||"300px",i.trailColor=t[e].getAttribute("trailColor")||"grey",i.strokeWidth=t[e].getAttribute("strokeWidth")||"1",i.trailWidth=t[e].getAttribute("trailWidth")||"1",i.textSize=t[e].getAttribute("textSize")||"16px",i.titleSize=t[e].getAttribute("titleSize")||"14px",i.subTitleSize=t[e].getAttribute("subTitleSize")||"12px",i.fill=t[e].getAttribute("fill")||"",i.padding=t[e].getAttribute("padding")||"0",i.durationAnimate=Number(t[e].getAttribute("duration")||"800"),this.create(t[e],i)}},create:function(t,e){t.classList.contains("binded")||(t.classList.add("binded"),t.classList.contains("progress-circle")||t.classList.add("progress-circle-js"),e.value=e.value||0,e.maxValue=e.maxValue||100,e.showValue=e.showValue||!1,e.title=e.title||"",e.subTitle=e.subTitle||"",e.text=e.text||"",e.color=e.color||"blue",e.textColor=e.textColor||"grey-800",e.textWeight=e.textWeight||"normal",e.titleWeight=e.titleWeight||"normal",e.subTitleWeight=e.subTitleWeight||"normal",e.titleColor=e.titleColor||"grey-500",e.subTitleColor=e.subTitleColor||"grey-300",e.width=e.width||"100%",e.height=e.height||"300px",e.trailColor=e.trailColor||"grey",e.strokeWidth=e.strokeWidth||"1",e.trailWidth=e.trailWidth||"1",e.textSize=e.textSize||"16px",e.titleSize=e.titleSize||"14px",e.subTitleSize=e.subTitleSize||"12px",e.fill=e.fill||"",e.padding=e.padding||"0",e.durationAnimate=e.durationAnimate||"800",t.style.width=e.width,t.style.height=e.height,t.progressCircle={},t.progressCircle.bar=new ProgressBar.Circle(t,{color:colorsMobileUI[e.color],trailColor:colorsMobileUI[e.trailColor],strokeWidth:e.strokeWidth,trailWidth:e.trailWidth,easing:"easeInOut",duration:e.durationAnimate,fill:e.fill,text:{autoStyleContainer:!0,style:{color:colorsMobileUI[e.textColor],position:"absolute",fontSize:e.textSize,fontWeight:e.textWeight,left:"50%",top:"50%",padding:0,margin:0,transform:{prefix:!0,value:"translate(-50%, -50%)"}}},svgStyle:{display:"block",width:e.width,height:e.height,padding:e.padding},from:{color:colorsMobileUI[e.color],width:e.strokeWidth},to:{color:colorsMobileUI[e.color],width:e.strokeWidth},step:function(t,i){i.path.setAttribute("stroke",t.color),i.path.setAttribute("stroke-width",t.width);var l=Math.round(i.value()*e.maxValue);e.showValue&&(l=e.value);var r="";if(e.title){o='style="';e.titleSize&&(o+=";font-size:"+e.titleSize),e.titleWeight&&(o+=";font-weight:"+e.titleWeight),e.titleColor&&(o+=";color:"+colorsMobileUI[e.titleColor]),r+="<div "+(o+='"')+' class="progress-circle-title">'+e.title+"</div>"}if(r+=l+e.text,e.subTitle){var o='style="';e.subTitleSize&&(o+=";font-size:"+e.subTitleSize),e.subTitleWeight&&(o+=";font-weight:"+e.subTitleWeight),e.subTitleColor&&(o+=";color:"+colorsMobileUI[e.subTitleColor]),r+="<div "+(o+='"')+' class="progress-circle-subtitle">'+e.subTitle+"</div>"}i.setText(r)}}),t.progressCircle.update=function(t){var i=0;t<=e.maxValue&&t>=0?i=t/e.maxValue:t<0?console.warn("Value for progress circle is too small. (Requested value is "+t+")"):(console.warn("Value for progress circle is too high. Maximum is "+e.maxValue+" and requested value is "+t+". (Value set to maximum for now.)"),i=1),this.bar.animate(i)},t.progressCircle.update(e.value))}};
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/progress-circular.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/progress-circular.min.js
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/progress-circular.min.js
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/progress-semicircle.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/progress-semicircle.min.js
new file mode 100755
index 0000000..70be9cf
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/progress-semicircle.min.js
@@ -0,0 +1 @@
+window.ProgressSemicircle={rebind:function(){for(var t=document.querySelectorAll(".progress-semicircle"),e=0;e<t.length;e++)t[e].classList.remove("binded"),t[e].innerHTML="";this.bind()},bind:function(){for(var t=document.querySelectorAll(".progress-semicircle:not(.binded)"),e=0;e<t.length;e++){var i={};i.value=Number(t[e].getAttribute("value")),i.maxValue=Number(t[e].getAttribute("maxValue"))||100,i.title=t[e].getAttribute("title")||"",i.subTitle=t[e].getAttribute("subTitle")||"",i.text=t[e].getAttribute("text")||"",i.color=t[e].getAttribute("color")||"blue",i.textColor=t[e].getAttribute("textColor")||"grey-800",i.textWeight=t[e].getAttribute("textWeight")||"normal",i.titleWeight=t[e].getAttribute("titleWeight")||"normal",i.titleLineHeight=t[e].getAttribute("titleLineHeight")||"normal",i.subTitleWeight=t[e].getAttribute("subTitleWeight")||"normal",i.titleColor=t[e].getAttribute("titleColor")||"grey-500",i.subTitleColor=t[e].getAttribute("subTitleColor")||"grey-300",i.width=t[e].getAttribute("width")||"100%",i.height=t[e].getAttribute("height")||"300px",i.trailColor=t[e].getAttribute("trailColor")||"grey",i.strokeWidth=t[e].getAttribute("strokeWidth")||"1",i.trailWidth=t[e].getAttribute("trailWidth")||"1",i.textSize=t[e].getAttribute("textSize")||"16px",i.titleSize=t[e].getAttribute("titleSize")||"14px",i.subTitleSize=t[e].getAttribute("subTitleSize")||"12px",i.fill=t[e].getAttribute("fill")||"",i.padding=t[e].getAttribute("padding")||"0",i.textMargin=t[e].getAttribute("textMargin")||"100px 0",i.durationAnimate=Number(t[e].getAttribute("duration")||"800"),this.create(t[e],i)}},create:function(t,e){t.classList.contains("binded")||(t.classList.add("binded"),t.classList.contains("progress-semicircle")||t.classList.add("progress-semicircle-js"),e.value=e.value||0,e.maxValue=e.maxValue||100,e.title=e.title||"",e.subTitle=e.subTitle||"",e.text=e.text||"",e.color=e.color||"blue",e.textColor=e.textColor||"grey-800",e.textWeight=e.textWeight||"normal",e.titleWeight=e.titleWeight||"normal",e.subTitleWeight=e.subTitleWeight||"normal",e.titleColor=e.titleColor||"grey-500",e.subTitleColor=e.subTitleColor||"grey-300",e.width=e.width||"100%",e.height=e.height||"300px",e.trailColor=e.trailColor||"grey",e.strokeWidth=e.strokeWidth||"1",e.trailWidth=e.trailWidth||"1",e.textSize=e.textSize||"16px",e.titleSize=e.titleSize||"14px",e.subTitleSize=e.subTitleSize||"12px",e.fill=e.fill||"",e.padding=e.padding||"0",e.durationAnimate=e.durationAnimate||"800",e.textMargin=e.textMargin||"100px 0",t.style.width=e.width,t.style.height=e.height,t.progressSemicircle={},t.progressSemicircle.bar=new ProgressBar.SemiCircle(t,{color:colorsMobileUI[e.color],trailColor:colorsMobileUI[e.trailColor],strokeWidth:e.strokeWidth,trailWidth:e.trailWidth,easing:"easeInOut",duration:e.durationAnimate,fill:e.fill,text:{alignToBottom:!1,style:{color:colorsMobileUI[e.textColor],position:"absolute",fontSize:e.textSize,fontWeight:e.textWeight,left:"50%",padding:0,margin:e.textMargin}},svgStyle:{display:"block",width:e.width,height:e.height,padding:e.padding},from:{color:colorsMobileUI[e.color],width:e.strokeWidth},to:{color:colorsMobileUI[e.color],width:e.strokeWidth},step:function(t,i){i.path.setAttribute("stroke",t.color),i.path.setAttribute("stroke-width",t.width);var l=Math.round(i.value()*e.maxValue),r="";if(e.title){o='style="';e.titleSize&&(o+=";font-size:"+e.titleSize),e.titleWeight&&(o+=";font-weight:"+e.titleWeight),e.titleLineHeight&&(o+=";line-height:"+e.titleLineHeight),e.titleColor&&(o+=";color:"+colorsMobileUI[e.titleColor]),r+="<div "+(o+='"')+' class="progress-semicircle-title">'+e.title+"</div>"}if(r+=l+e.text,e.subTitle){var o='style="';e.subTitleSize&&(o+=";font-size:"+e.subTitleSize),e.subTitleWeight&&(o+=";font-weight:"+e.subTitleWeight),e.subTitleColor&&(o+=";color:"+colorsMobileUI[e.subTitleColor]),r+="<div "+(o+='"')+' class="progress-semicircle-subtitle">'+e.subTitle+"</div>"}i.setText(r)}}),t.progressSemicircle.update=function(t){var i=0;t<=e.maxValue&&t>=0?i=t/e.maxValue:t<0?console.warn("Value for progress semicircle is too small. (Requested value is "+t+")"):(console.warn("Value for progress semicircle is too high. Maximum is "+e.maxValue+" and requested value is "+t+". (Value set to maximum for now.)"),i=1),this.bar.animate(i)},t.progressSemicircle.update(e.value))}};
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/progressbarjs.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/progressbarjs.min.js
new file mode 100755
index 0000000..24920e4
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/progressbarjs.min.js
@@ -0,0 +1 @@
+!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).ProgressBar=t()}}(function(){return function t(e,n,i){function r(s,a){if(!n[s]){if(!e[s]){var u="function"==typeof require&&require;if(!a&&u)return u(s,!0);if(o)return o(s,!0);var h=new Error("Cannot find module '"+s+"'");throw h.code="MODULE_NOT_FOUND",h}var c=n[s]={exports:{}};e[s][0].call(c.exports,function(t){var n=e[s][1][t];return r(n||t)},c,c.exports,t,e,n,i)}return n[s].exports}for(var o="function"==typeof require&&require,s=0;s<i.length;s++)r(i[s]);return r}({1:[function(t,e,n){(function(){var t=this||Function("return this")(),i=function(){"use strict";function i(){}function r(t,e){var n;for(n in t)Object.hasOwnProperty.call(t,n)&&e(n)}function o(t,e){return r(e,function(n){t[n]=e[n]}),t}function s(t,e){r(e,function(n){void 0===t[n]&&(t[n]=e[n])})}function a(t,e,n,i,r,o,s){var a,h,c,p=o>t?0:(t-o)/r;for(a in e)e.hasOwnProperty(a)&&(h=s[a],c="function"==typeof h?h:f[h],e[a]=u(n[a],i[a],c,p));return e}function u(t,e,n,i){return t+(e-t)*n(i)}function h(t,e){var n=l.prototype.filter,i=t._filterArgs;r(n,function(r){void 0!==n[r][e]&&n[r][e].apply(t,i)})}function c(t,e,n,i,r,o,s,u,c,p,l){m=e+n+i,v=Math.min(l||y(),m),S=v>=m,x=i-(m-v),t.isPlaying()&&(S?(c(s,t._attachment,x),t.stop(!0)):(t._scheduleId=p(t._timeoutHandler,g),h(t,"beforeTween"),e+n>v?a(1,r,o,s,1,1,u):a(v,r,o,s,i,e+n,u),h(t,"afterTween"),c(r,t._attachment,x)))}function p(t,e){var n={},i=typeof e;return"string"===i||"function"===i?r(t,function(t){n[t]=e}):r(t,function(t){n[t]||(n[t]=e[t]||d)}),n}function l(t,e){this._currentState=t||{},this._configured=!1,this._scheduleFunction=_,void 0!==e&&this.setConfig(e)}var f,_,d="linear",g=1e3/60,w=Date.now?Date.now:function(){return+new Date},y="undefined"!=typeof SHIFTY_DEBUG_NOW?SHIFTY_DEBUG_NOW:w;_="undefined"!=typeof window?window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||window.mozCancelRequestAnimationFrame&&window.mozRequestAnimationFrame||setTimeout:setTimeout;var m,v,S,x;return l.prototype.tween=function(t){return this._isTweening?this:(void 0===t&&this._configured||this.setConfig(t),this._timestamp=y(),this._start(this.get(),this._attachment),this.resume())},l.prototype.setConfig=function(t){t=t||{},this._configured=!0,this._attachment=t.attachment,this._pausedAtTime=null,this._scheduleId=null,this._delay=t.delay||0,this._start=t.start||i,this._step=t.step||i,this._finish=t.finish||i,this._duration=t.duration||500,this._currentState=o({},t.from)||this.get(),this._originalState=this.get(),this._targetState=o({},t.to)||this.get();var e=this;this._timeoutHandler=function(){c(e,e._timestamp,e._delay,e._duration,e._currentState,e._originalState,e._targetState,e._easing,e._step,e._scheduleFunction)};var n=this._currentState,r=this._targetState;return s(r,n),this._easing=p(n,t.easing||d),this._filterArgs=[n,this._originalState,r,this._easing],h(this,"tweenCreated"),this},l.prototype.get=function(){return o({},this._currentState)},l.prototype.set=function(t){this._currentState=t},l.prototype.pause=function(){return this._pausedAtTime=y(),this._isPaused=!0,this},l.prototype.resume=function(){return this._isPaused&&(this._timestamp+=y()-this._pausedAtTime),this._isPaused=!1,this._isTweening=!0,this._timeoutHandler(),this},l.prototype.seek=function(t){t=Math.max(t,0);var e=y();return this._timestamp+t===0?this:(this._timestamp=e-t,this.isPlaying()||(this._isTweening=!0,this._isPaused=!1,c(this,this._timestamp,this._delay,this._duration,this._currentState,this._originalState,this._targetState,this._easing,this._step,this._scheduleFunction,e),this.pause()),this)},l.prototype.stop=function(e){return this._isTweening=!1,this._isPaused=!1,this._timeoutHandler=i,(t.cancelAnimationFrame||t.webkitCancelAnimationFrame||t.oCancelAnimationFrame||t.msCancelAnimationFrame||t.mozCancelRequestAnimationFrame||t.clearTimeout)(this._scheduleId),e&&(h(this,"beforeTween"),a(1,this._currentState,this._originalState,this._targetState,1,0,this._easing),h(this,"afterTween"),h(this,"afterTweenEnd"),this._finish.call(this,this._currentState,this._attachment)),this},l.prototype.isPlaying=function(){return this._isTweening&&!this._isPaused},l.prototype.setScheduleFunction=function(t){this._scheduleFunction=t},l.prototype.dispose=function(){var t;for(t in this)this.hasOwnProperty(t)&&delete this[t]},l.prototype.filter={},l.prototype.formula={linear:function(t){return t}},f=l.prototype.formula,o(l,{now:y,each:r,tweenProps:a,tweenProp:u,applyFilter:h,shallowCopy:o,defaults:s,composeEasingObject:p}),"function"==typeof SHIFTY_DEBUG_NOW&&(t.timeoutHandler=c),"object"==typeof n?e.exports=l:void 0===t.Tweenable&&(t.Tweenable=l),l}();i.shallowCopy(i.prototype.formula,{easeInQuad:function(t){return Math.pow(t,2)},easeOutQuad:function(t){return-(Math.pow(t-1,2)-1)},easeInOutQuad:function(t){return(t/=.5)<1?.5*Math.pow(t,2):-.5*((t-=2)*t-2)},easeInCubic:function(t){return Math.pow(t,3)},easeOutCubic:function(t){return Math.pow(t-1,3)+1},easeInOutCubic:function(t){return(t/=.5)<1?.5*Math.pow(t,3):.5*(Math.pow(t-2,3)+2)},easeInQuart:function(t){return Math.pow(t,4)},easeOutQuart:function(t){return-(Math.pow(t-1,4)-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*Math.pow(t,4):-.5*((t-=2)*Math.pow(t,3)-2)},easeInQuint:function(t){return Math.pow(t,5)},easeOutQuint:function(t){return Math.pow(t-1,5)+1},easeInOutQuint:function(t){return(t/=.5)<1?.5*Math.pow(t,5):.5*(Math.pow(t-2,5)+2)},easeInSine:function(t){return 1-Math.cos(t*(Math.PI/2))},easeOutSine:function(t){return Math.sin(t*(Math.PI/2))},easeInOutSine:function(t){return-.5*(Math.cos(Math.PI*t)-1)},easeInExpo:function(t){return 0===t?0:Math.pow(2,10*(t-1))},easeOutExpo:function(t){return 1===t?1:1-Math.pow(2,-10*t)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(2-Math.pow(2,-10*--t))},easeInCirc:function(t){return-(Math.sqrt(1-t*t)-1)},easeOutCirc:function(t){return Math.sqrt(1-Math.pow(t-1,2))},easeInOutCirc:function(t){return(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeOutBounce:function(t){return 1/2.75>t?7.5625*t*t:2/2.75>t?7.5625*(t-=1.5/2.75)*t+.75:2.5/2.75>t?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375},easeInBack:function(t){var e=1.70158;return t*t*((e+1)*t-e)},easeOutBack:function(t){var e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},easeInOutBack:function(t){var e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},elastic:function(t){return-1*Math.pow(4,-8*t)*Math.sin((6*t-1)*(2*Math.PI)/2)+1},swingFromTo:function(t){var e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},swingFrom:function(t){var e=1.70158;return t*t*((e+1)*t-e)},swingTo:function(t){var e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},bounce:function(t){return 1/2.75>t?7.5625*t*t:2/2.75>t?7.5625*(t-=1.5/2.75)*t+.75:2.5/2.75>t?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375},bouncePast:function(t){return 1/2.75>t?7.5625*t*t:2/2.75>t?2-(7.5625*(t-=1.5/2.75)*t+.75):2.5/2.75>t?2-(7.5625*(t-=2.25/2.75)*t+.9375):2-(7.5625*(t-=2.625/2.75)*t+.984375)},easeFromTo:function(t){return(t/=.5)<1?.5*Math.pow(t,4):-.5*((t-=2)*Math.pow(t,3)-2)},easeFrom:function(t){return Math.pow(t,4)},easeTo:function(t){return Math.pow(t,.25)}}),function(){function t(t,e,n,i,r,o){function s(t){return((c*t+p)*t+l)*t}function a(t){return(3*c*t+2*p)*t+l}function u(t,e){return function(t){return((f*t+_)*t+d)*t}(function(t,e){var n,i,r,o,u,c;for(r=t,c=0;8>c;c++){if(o=s(r)-t,h(o)<e)return r;if(u=a(r),h(u)<1e-6)break;r-=o/u}if(n=0,i=1,r=t,n>r)return n;if(r>i)return i;for(;i>n;){if(o=s(r),h(o-t)<e)return r;t>o?n=r:i=r,r=.5*(i-n)+n}return r}(t,e))}function h(t){return t>=0?t:0-t}var c=0,p=0,l=0,f=0,_=0,d=0;return l=3*e,p=3*(i-e)-l,c=1-l-p,d=3*n,_=3*(r-n)-d,f=1-d-_,u(t,function(t){return 1/(200*t)}(o))}function e(e,n,i,r){return function(o){return t(o,e,n,i,r,1)}}i.setBezierFunction=function(t,n,r,o,s){var a=e(n,r,o,s);return a.displayName=t,a.x1=n,a.y1=r,a.x2=o,a.y2=s,i.prototype.formula[t]=a},i.unsetBezierFunction=function(t){delete i.prototype.formula[t]}}(),function(){var t=new i;t._filterArgs=[],i.interpolate=function(e,n,r,o,s){var a=i.shallowCopy({},e),u=s||0,h=i.composeEasingObject(e,o||"linear");t.set({});var c=t._filterArgs;c.length=0,c[0]=a,c[1]=e,c[2]=n,c[3]=h,i.applyFilter(t,"tweenCreated"),i.applyFilter(t,"beforeTween");var p=function(t,e,n,r,o,s){return i.tweenProps(r,e,t,n,1,s,o)}(e,a,n,r,h,u);return i.applyFilter(t,"afterTween"),p}}(),function(t){function e(e){t.each(e,function(t){var i=e[t];"string"==typeof i&&i.match(w)&&(e[t]=function(t){return r(w,t,n)}(i))})}function n(t){var e=function(t){return 3===(t=t.replace(/#/,"")).length&&(t=t.split(""),t=t[0]+t[0]+t[1]+t[1]+t[2]+t[2]),m[0]=i(t.substr(0,2)),m[1]=i(t.substr(2,2)),m[2]=i(t.substr(4,2)),m}(t);return"rgb("+e[0]+","+e[1]+","+e[2]+")"}function i(t){return parseInt(t,16)}function r(t,e,n){var i=e.match(t),r=e.replace(t,y);if(i)for(var o,s=i.length,a=0;s>a;a++)o=i.shift(),r=r.replace(y,n(o));return r}function o(t){for(var e=t.match(_),n=e.length,i=t.match(g)[0],r=0;n>r;r++)i+=parseInt(e[r],10)+",";return i=i.slice(0,-1)+")"}function s(e){var n={};return t.each(e,function(t){var i=e[t];if("string"==typeof i){var r=h(i);n[t]={formatString:function(t){var e=t.match(f);return e?(1===e.length||t[0].match(l))&&e.unshift(""):e=["",""],e.join(y)}(i),chunkNames:function(t,e){var n,i=[],r=t.length;for(n=0;r>n;n++)i.push("_"+e+"_"+n);return i}(r,t)}}}),n}function a(e,n){t.each(n,function(t){for(var i=h(e[t]),r=i.length,o=0;r>o;o++)e[n[t].chunkNames[o]]=+i[o];delete e[t]})}function u(e,n){t.each(n,function(t){var i=e[t],s=function(t,e){v.length=0;for(var n=e.length,i=0;n>i;i++)v.push(t[e[i]]);return v}(function(t,e){for(var n,i={},r=e.length,o=0;r>o;o++)n=e[o],i[n]=t[n],delete t[n];return i}(e,n[t].chunkNames),n[t].chunkNames);i=function(t,e){for(var n=t,i=e.length,r=0;i>r;r++)n=n.replace(y,+e[r].toFixed(4));return n}(n[t].formatString,s),e[t]=function(t){return r(d,t,o)}(i)})}function h(t){return t.match(_)}function c(e,n){t.each(n,function(t){var i,r=n[t].chunkNames,o=r.length,s=e[t];if("string"==typeof s){var a=s.split(" "),u=a[a.length-1];for(i=0;o>i;i++)e[r[i]]=a[i]||u}else for(i=0;o>i;i++)e[r[i]]=s;delete e[t]})}function p(e,n){t.each(n,function(t){var i=n[t].chunkNames,r=i.length,o=e[i[0]];if("string"===typeof o){for(var s="",a=0;r>a;a++)s+=" "+e[i[a]],delete e[i[a]];e[t]=s.substr(1)}else e[t]=o})}var l=/(\d|\-|\.)/,f=/([^\-0-9\.]+)/g,_=/[0-9.\-]+/g,d=new RegExp("rgb\\("+_.source+/,\s*/.source+_.source+/,\s*/.source+_.source+"\\)","g"),g=/^.*\(/,w=/#([0-9]|[a-f]){3,6}/gi,y="VAL",m=[],v=[];t.prototype.filter.token={tweenCreated:function(t,n,i,r){e(t),e(n),e(i),this._tokenData=s(t)},beforeTween:function(t,e,n,i){c(i,this._tokenData),a(t,this._tokenData),a(e,this._tokenData),a(n,this._tokenData)},afterTween:function(t,e,n,i){u(t,this._tokenData),u(e,this._tokenData),u(n,this._tokenData),p(i,this._tokenData)}}}(i)}).call(null)},{}],2:[function(t,e,n){var i=t("./shape"),r=t("./utils"),o=function(t,e){this._pathTemplate="M 50,50 m 0,-{radius} a {radius},{radius} 0 1 1 0,{2radius} a {radius},{radius} 0 1 1 0,-{2radius}",this.containerAspectRatio=1,i.apply(this,arguments)};(o.prototype=new i).constructor=o,o.prototype._pathString=function(t){var e=t.strokeWidth;t.trailWidth&&t.trailWidth>t.strokeWidth&&(e=t.trailWidth);var n=50-e/2;return r.render(this._pathTemplate,{radius:n,"2radius":2*n})},o.prototype._trailString=function(t){return this._pathString(t)},e.exports=o},{"./shape":7,"./utils":8}],3:[function(t,e,n){var i=t("./shape"),r=t("./utils"),o=function(t,e){this._pathTemplate="M 0,{center} L 100,{center}",i.apply(this,arguments)};(o.prototype=new i).constructor=o,o.prototype._initializeSvg=function(t,e){t.setAttribute("viewBox","0 0 100 "+e.strokeWidth),t.setAttribute("preserveAspectRatio","none")},o.prototype._pathString=function(t){return r.render(this._pathTemplate,{center:t.strokeWidth/2})},o.prototype._trailString=function(t){return this._pathString(t)},e.exports=o},{"./shape":7,"./utils":8}],4:[function(t,e,n){e.exports={Line:t("./line"),Circle:t("./circle"),SemiCircle:t("./semicircle"),Path:t("./path"),Shape:t("./shape"),utils:t("./utils")}},{"./circle":2,"./line":3,"./path":5,"./semicircle":6,"./shape":7,"./utils":8}],5:[function(t,e,n){var i=t("shifty"),r=t("./utils"),o={easeIn:"easeInCubic",easeOut:"easeOutCubic",easeInOut:"easeInOutCubic"},s=function t(e,n){if(!(this instanceof t))throw new Error("Constructor was called without new keyword");n=r.extend({duration:800,easing:"linear",from:{},to:{},step:function(){}},n);var i;i=r.isString(e)?document.querySelector(e):e,this.path=i,this._opts=n,this._tweenable=null;var o=this.path.getTotalLength();this.path.style.strokeDasharray=o+" "+o,this.set(0)};s.prototype.value=function(){var t=1-this._getComputedDashOffset()/this.path.getTotalLength();return parseFloat(t.toFixed(6),10)},s.prototype.set=function(t){this.stop(),this.path.style.strokeDashoffset=this._progressToOffset(t);var e=this._opts.step;if(r.isFunction(e)){var n=this._easing(this._opts.easing);e(this._calculateTo(t,n),this._opts.shape||this,this._opts.attachment)}},s.prototype.stop=function(){this._stopTween(),this.path.style.strokeDashoffset=this._getComputedDashOffset()},s.prototype.animate=function(t,e,n){e=e||{},r.isFunction(e)&&(n=e,e={});var o=r.extend({},e),s=r.extend({},this._opts);e=r.extend(s,e);var a=this._easing(e.easing),u=this._resolveFromAndTo(t,a,o);this.stop(),this.path.getBoundingClientRect();var h=this._getComputedDashOffset(),c=this._progressToOffset(t),p=this;this._tweenable=new i,this._tweenable.tween({from:r.extend({offset:h},u.from),to:r.extend({offset:c},u.to),duration:e.duration,easing:a,step:function(t){p.path.style.strokeDashoffset=t.offset;var n=e.shape||p;e.step(t,n,e.attachment)},finish:function(t){r.isFunction(n)&&n()}})},s.prototype._getComputedDashOffset=function(){var t=window.getComputedStyle(this.path,null);return parseFloat(t.getPropertyValue("stroke-dashoffset"),10)},s.prototype._progressToOffset=function(t){var e=this.path.getTotalLength();return e-t*e},s.prototype._resolveFromAndTo=function(t,e,n){return n.from&&n.to?{from:n.from,to:n.to}:{from:this._calculateFrom(e),to:this._calculateTo(t,e)}},s.prototype._calculateFrom=function(t){return i.interpolate(this._opts.from,this._opts.to,this.value(),t)},s.prototype._calculateTo=function(t,e){return i.interpolate(this._opts.from,this._opts.to,t,e)},s.prototype._stopTween=function(){null!==this._tweenable&&(this._tweenable.stop(),this._tweenable=null)},s.prototype._easing=function(t){return o.hasOwnProperty(t)?o[t]:t},e.exports=s},{"./utils":8,shifty:1}],6:[function(t,e,n){var i=t("./shape"),r=t("./circle"),o=t("./utils"),s=function(t,e){this._pathTemplate="M 50,50 m -{radius},0 a {radius},{radius} 0 1 1 {2radius},0",this.containerAspectRatio=2,i.apply(this,arguments)};(s.prototype=new i).constructor=s,s.prototype._initializeSvg=function(t,e){t.setAttribute("viewBox","0 0 100 50")},s.prototype._initializeTextContainer=function(t,e,n){t.text.style&&(n.style.top="auto",n.style.bottom="0",t.text.alignToBottom?o.setStyle(n,"transform","translate(-50%, 0)"):o.setStyle(n,"transform","translate(-50%, 50%)"))},s.prototype._pathString=r.prototype._pathString,s.prototype._trailString=r.prototype._trailString,e.exports=s},{"./circle":2,"./shape":7,"./utils":8}],7:[function(t,e,n){var i=t("./path"),r=t("./utils"),o="Object is destroyed",s=function t(e,n){if(!(this instanceof t))throw new Error("Constructor was called without new keyword");if(0!==arguments.length){this._opts=r.extend({color:"#555",strokeWidth:1,trailColor:null,trailWidth:null,fill:null,text:{style:{color:null,position:"absolute",left:"50%",top:"50%",padding:0,margin:0,transform:{prefix:!0,value:"translate(-50%, -50%)"}},autoStyleContainer:!0,alignToBottom:!0,value:null,className:"progressbar-text"},svgStyle:{display:"block",width:"100%"},warnings:!1},n,!0),r.isObject(n)&&void 0!==n.svgStyle&&(this._opts.svgStyle=n.svgStyle),r.isObject(n)&&r.isObject(n.text)&&void 0!==n.text.style&&(this._opts.text.style=n.text.style);var o,s=this._createSvgView(this._opts);if(!(o=r.isString(e)?document.querySelector(e):e))throw new Error("Container does not exist: "+e);this._container=o,this._container.appendChild(s.svg),this._opts.warnings&&this._warnContainerAspectRatio(this._container),this._opts.svgStyle&&r.setStyles(s.svg,this._opts.svgStyle),this.svg=s.svg,this.path=s.path,this.trail=s.trail,this.text=null;var a=r.extend({attachment:void 0,shape:this},this._opts);this._progressPath=new i(s.path,a),r.isObject(this._opts.text)&&null!==this._opts.text.value&&this.setText(this._opts.text.value)}};s.prototype.animate=function(t,e,n){if(null===this._progressPath)throw new Error(o);this._progressPath.animate(t,e,n)},s.prototype.stop=function(){if(null===this._progressPath)throw new Error(o);void 0!==this._progressPath&&this._progressPath.stop()},s.prototype.destroy=function(){if(null===this._progressPath)throw new Error(o);this.stop(),this.svg.parentNode.removeChild(this.svg),this.svg=null,this.path=null,this.trail=null,this._progressPath=null,null!==this.text&&(this.text.parentNode.removeChild(this.text),this.text=null)},s.prototype.set=function(t){if(null===this._progressPath)throw new Error(o);this._progressPath.set(t)},s.prototype.value=function(){if(null===this._progressPath)throw new Error(o);return void 0===this._progressPath?0:this._progressPath.value()},s.prototype.setText=function(t){if(null===this._progressPath)throw new Error(o);null===this.text&&(this.text=this._createTextContainer(this._opts,this._container),this._container.appendChild(this.text)),r.isObject(t)?(r.removeChildren(this.text),this.text.appendChild(t)):this.text.innerHTML=t},s.prototype._createSvgView=function(t){var e=document.createElementNS("http://www.w3.org/2000/svg","svg");this._initializeSvg(e,t);var n=null;(t.trailColor||t.trailWidth)&&(n=this._createTrail(t),e.appendChild(n));var i=this._createPath(t);return e.appendChild(i),{svg:e,path:i,trail:n}},s.prototype._initializeSvg=function(t,e){t.setAttribute("viewBox","0 0 100 100")},s.prototype._createPath=function(t){var e=this._pathString(t);return this._createPathElement(e,t)},s.prototype._createTrail=function(t){var e=this._trailString(t),n=r.extend({},t);return n.trailColor||(n.trailColor="#eee"),n.trailWidth||(n.trailWidth=n.strokeWidth),n.color=n.trailColor,n.strokeWidth=n.trailWidth,n.fill=null,this._createPathElement(e,n)},s.prototype._createPathElement=function(t,e){var n=document.createElementNS("http://www.w3.org/2000/svg","path");return n.setAttribute("d",t),n.setAttribute("stroke",e.color),n.setAttribute("stroke-width",e.strokeWidth),e.fill?n.setAttribute("fill",e.fill):n.setAttribute("fill-opacity","0"),n},s.prototype._createTextContainer=function(t,e){var n=document.createElement("div");n.className=t.text.className;var i=t.text.style;return i&&(t.text.autoStyleContainer&&(e.style.position="relative"),r.setStyles(n,i),i.color||(n.style.color=t.color)),this._initializeTextContainer(t,e,n),n},s.prototype._initializeTextContainer=function(t,e,n){},s.prototype._pathString=function(t){throw new Error("Override this function for each progress bar")},s.prototype._trailString=function(t){throw new Error("Override this function for each progress bar")},s.prototype._warnContainerAspectRatio=function(t){if(this.containerAspectRatio){var e=window.getComputedStyle(t,null),n=parseFloat(e.getPropertyValue("width"),10),i=parseFloat(e.getPropertyValue("height"),10);r.floatEquals(this.containerAspectRatio,n/i)||(console.warn("Incorrect aspect ratio of container","#"+t.id,"detected:",e.getPropertyValue("width")+"(width)","/",e.getPropertyValue("height")+"(height)","=",n/i),console.warn("Aspect ratio of should be",this.containerAspectRatio))}},e.exports=s},{"./path":5,"./utils":8}],8:[function(t,e,n){function i(t,e,n){t=t||{},e=e||{},n=n||!1;for(var r in e)if(e.hasOwnProperty(r)){var o=t[r],a=e[r];n&&s(o)&&s(a)?t[r]=i(o,a,n):t[r]=a}return t}function r(t,e,n){for(var i=t.style,r=0;r<u.length;++r){i[u[r]+o(e)]=n}i[e]=n}function o(t){return t.charAt(0).toUpperCase()+t.slice(1)}function s(t){if(function(t){return"[object Array]"===Object.prototype.toString.call(t)}(t))return!1;return"object"===typeof t&&!!t}function a(t,e){for(var n in t)if(t.hasOwnProperty(n)){e(t[n],n)}}var u="Webkit Moz O ms".split(" "),h=.001;e.exports={extend:i,render:function(t,e){var n=t;for(var i in e)if(e.hasOwnProperty(i)){var r=e[i],o="\\{"+i+"\\}",s=new RegExp(o,"g");n=n.replace(s,r)}return n},setStyle:r,setStyles:function(t,e){a(e,function(e,n){null!==e&&void 0!==e&&(s(e)&&!0===e.prefix?r(t,n,e.value):t.style[n]=e)})},capitalize:o,isString:function(t){return"string"==typeof t||t instanceof String},isFunction:function(t){return"function"==typeof t},isObject:s,forEachObject:a,floatEquals:function(t,e){return Math.abs(t-e)<h},removeChildren:function(t){for(;t.firstChild;)t.removeChild(t.firstChild)}}},{}]},{},[4])(4)});
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/pulltorefresh.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/pulltorefresh.min.js
new file mode 100755
index 0000000..5b273cd
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/pulltorefresh.min.js
@@ -0,0 +1 @@
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.PullToRefresh=t()}(this,function(){function e(){function e(e){var t=r.handlers.filter(function(t){return t.contains(e.target)})[0];r.enable=!!t,t&&"pending"===r.state&&(o=i.setupDOM(t),t.shouldPullToRefresh()&&(r.pullStartY=e.touches[0].screenY),clearTimeout(r.timeout),i.update(t))}function t(e){o&&o.ptrElement&&r.enable&&(r.pullStartY?r.pullMoveY=e.touches[0].screenY:o.shouldPullToRefresh()&&(r.pullStartY=e.touches[0].screenY),"refreshing"!==r.state?("pending"===r.state&&(o.ptrElement.classList.add(o.classPrefix+"pull"),r.state="pulling",i.update(o)),r.pullStartY&&r.pullMoveY&&(r.dist=r.pullMoveY-r.pullStartY),r.dist>0&&(e.preventDefault(),o.ptrElement.style[o.cssProp]=r.distResisted+"px",r.distResisted=o.resistanceFunction(r.dist/o.distThreshold)*Math.min(o.distMax,r.dist),"pulling"===r.state&&r.distResisted>o.distThreshold&&(o.ptrElement.classList.add(o.classPrefix+"release"),r.state="releasing",i.update(o)),"releasing"===r.state&&r.distResisted<o.distThreshold&&(o.ptrElement.classList.remove(o.classPrefix+"release"),r.state="pulling",i.update(o)))):o.shouldPullToRefresh()&&r.pullStartY<r.pullMoveY&&e.preventDefault())}function n(){if(o&&o.ptrElement&&r.enable){if("releasing"===r.state&&r.distResisted>o.distThreshold)r.state="refreshing",o.ptrElement.style[o.cssProp]=o.distReload+"px",o.ptrElement.classList.add(o.classPrefix+"refresh"),r.timeout=setTimeout(function(){var e=o.onRefresh(function(){return i.onReset(o)});e&&"function"==typeof e.then&&e.then(function(){return i.onReset(o)}),e||o.onRefresh.length||i.onReset(o)},o.refreshTimeout);else{if("refreshing"===r.state)return;o.ptrElement.style[o.cssProp]="0px",r.state="pending"}i.update(o),o.ptrElement.classList.remove(o.classPrefix+"release"),o.ptrElement.classList.remove(o.classPrefix+"pull"),r.pullStartY=r.pullMoveY=null,r.dist=r.distResisted=0}}function s(){o&&o.mainElement.classList.toggle(o.classPrefix+"top",o.shouldPullToRefresh())}var o,l=r.supportsPassive?{passive:r.passive||!1}:void 0;return window.addEventListener("touchend",n),window.addEventListener("touchstart",e),window.addEventListener("touchmove",t,l),window.addEventListener("scroll",s),{onTouchEnd:n,onTouchStart:e,onTouchMove:t,onScroll:s,destroy:function(){window.removeEventListener("touchstart",e),window.removeEventListener("touchend",n),window.removeEventListener("touchmove",t,l),window.removeEventListener("scroll",s)}}}function t(t){var i={};return Object.keys(n).forEach(function(e){i[e]=t[e]||n[e]}),i.refreshTimeout="number"==typeof t.refreshTimeout?t.refreshTimeout:n.refreshTimeout,s.forEach(function(e){"string"==typeof i[e]&&(i[e]=document.querySelector(i[e]))}),r.events||(r.events=e()),i.contains=function(e){return i.triggerElement.contains(e)},i.destroy=function(){clearTimeout(r.timeout),r.handlers.splice(i.offset,1)},i}var n={distThreshold:60,distMax:80,distReload:50,bodyOffset:20,mainElement:"body",triggerElement:"body",ptrElement:".ptr",classPrefix:"ptr--",cssProp:"min-height",iconArrow:"&#8675;",iconRefreshing:"&hellip;",instructionsPullToRefresh:"Pull down to refresh",instructionsReleaseToRefresh:"Release to refresh",instructionsRefreshing:"Refreshing",refreshTimeout:500,getMarkup:function(){return'\n<div class="__PREFIX__box">\n  <div class="__PREFIX__content">\n    <div class="__PREFIX__icon"></div>\n    <div class="__PREFIX__text"></div>\n  </div>\n</div>'},getStyles:function(){return".__PREFIX__ptr {\n  box-shadow: inset 0 -3px 5px rgba(0, 0, 0, 0.12);\n  pointer-events: none;\n  font-size: 0.85em;\n  font-weight: bold;\n  top: 0;\n  height: 0;\n  transition: height 0.3s, min-height 0.3s;\n  text-align: center;\n  width: 100%;\n  overflow: hidden;\n  display: flex;\n  align-items: flex-end;\n  align-content: stretch;\n}\n.__PREFIX__box {\n  padding: 10px;\n  flex-basis: 100%;\n}\n.__PREFIX__pull {\n  transition: none;\n}\n.__PREFIX__text {\n  margin-top: .33em;\n  color: rgba(0, 0, 0, 0.3);\n}\n.__PREFIX__icon {\n  color: rgba(0, 0, 0, 0.3);\n  transition: transform .3s;\n}\n.__PREFIX__top {\n  touch-action: pan-x pan-down pinch-zoom;\n}\n.__PREFIX__release .__PREFIX__icon {\n  transform: rotate(180deg);\n}\n"},onInit:function(){},onRefresh:function(){return location.reload()},resistanceFunction:function(e){return Math.min(1,e/2.5)},shouldPullToRefresh:function(){return!window.scrollY}},s=["mainElement","ptrElement","triggerElement"],r={pullStartY:null,pullMoveY:null,handlers:[],styleEl:null,events:null,dist:0,state:"pending",timeout:null,distResisted:0,supportsPassive:!1};try{window.addEventListener("test",null,{get passive(){r.supportsPassive=!0}})}catch(e){}var i={setupDOM:function(e){if(!e.ptrElement){var t=document.createElement("div");e.mainElement!==document.body?e.mainElement.parentNode.insertBefore(t,e.mainElement):document.body.insertBefore(t,document.body.firstChild),t.classList.add(e.classPrefix+"ptr"),t.innerHTML=e.getMarkup().replace(/__PREFIX__/g,e.classPrefix),e.ptrElement=t,"function"==typeof e.onInit&&e.onInit(e),r.styleEl||(r.styleEl=document.createElement("style"),r.styleEl.setAttribute("id","pull-to-refresh-js-style"),document.head.appendChild(r.styleEl)),r.styleEl.textContent=e.getStyles().replace(/__PREFIX__/g,e.classPrefix).replace(/\s+/g," ")}return e},onReset:function(e){e.ptrElement.classList.remove(e.classPrefix+"refresh"),e.ptrElement.style[e.cssProp]="0px",setTimeout(function(){e.ptrElement&&e.ptrElement.parentNode&&(e.ptrElement.parentNode.removeChild(e.ptrElement),e.ptrElement=null),r.state="pending"},e.refreshTimeout)},update:function(e){var t=e.ptrElement.querySelector("."+e.classPrefix+"icon"),n=e.ptrElement.querySelector("."+e.classPrefix+"text");t&&("refreshing"===r.state?t.innerHTML=e.iconRefreshing:t.innerHTML=e.iconArrow),n&&("releasing"===r.state&&(n.innerHTML=e.instructionsReleaseToRefresh),"pulling"!==r.state&&"pending"!==r.state||(n.innerHTML=e.instructionsPullToRefresh),"refreshing"===r.state&&(n.innerHTML=e.instructionsRefreshing))}};return{setPassiveMode:function(e){r.passive=e},destroyAll:function(){r.events&&(r.events.destroy(),r.events=null),r.handlers.forEach(function(e){e.destroy()})},init:function(e){void 0===e&&(e={});var n=t(e);return n.offset=r.handlers.push(n)-1,n},_:{setupHandler:t,setupEvents:e,setupDOM:i.setupDOM,onReset:i.onReset,update:i.update}}});
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/swiper.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/swiper.min.js
new file mode 100755
index 0000000..ae35ad5
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/swiper.min.js
@@ -0,0 +1 @@
+!function(){"use strict";var e,a=function(s,i){function r(e){return Math.floor(e)}function n(){var e=x.params.autoplay,a=x.slides.eq(x.activeIndex);a.attr("data-swiper-autoplay")&&(e=a.attr("data-swiper-autoplay")||x.params.autoplay),x.autoplayTimeoutId=setTimeout(function(){x.params.loop?(x.fixLoop(),x._slideNext(),x.emit("onAutoplay",x)):x.isEnd?i.autoplayStopOnLast?x.stopAutoplay():(x._slideTo(0),x.emit("onAutoplay",x)):(x._slideNext(),x.emit("onAutoplay",x))},e)}function o(a,t){var s=e(a.target);if(!s.is(t))if("string"==typeof t)s=s.parents(t);else if(t.nodeType){var i;return s.parents().each(function(e,a){a===t&&(i=t)}),i?t:void 0}if(0!==s.length)return s[0]}function l(e,a){a=a||{};var t=new(window.MutationObserver||window.WebkitMutationObserver)(function(e){e.forEach(function(e){x.onResize(!0),x.emit("onObserverUpdate",x,e)})});t.observe(e,{attributes:void 0===a.attributes||a.attributes,childList:void 0===a.childList||a.childList,characterData:void 0===a.characterData||a.characterData}),x.observers.push(t)}function p(e){e.originalEvent&&(e=e.originalEvent);var a=e.keyCode||e.charCode;if(!x.params.allowSwipeToNext&&(x.isHorizontal()&&39===a||!x.isHorizontal()&&40===a))return!1;if(!x.params.allowSwipeToPrev&&(x.isHorizontal()&&37===a||!x.isHorizontal()&&38===a))return!1;if(!(e.shiftKey||e.altKey||e.ctrlKey||e.metaKey||document.activeElement&&document.activeElement.nodeName&&("input"===document.activeElement.nodeName.toLowerCase()||"textarea"===document.activeElement.nodeName.toLowerCase()))){if(37===a||39===a||38===a||40===a){var t=!1;if(x.container.parents("."+x.params.slideClass).length>0&&0===x.container.parents("."+x.params.slideActiveClass).length)return;var s={left:window.pageXOffset,top:window.pageYOffset},i=window.innerWidth,r=window.innerHeight,n=x.container.offset();x.rtl&&(n.left=n.left-x.container[0].scrollLeft);for(var o=[[n.left,n.top],[n.left+x.width,n.top],[n.left,n.top+x.height],[n.left+x.width,n.top+x.height]],l=0;l<o.length;l++){var p=o[l];p[0]>=s.left&&p[0]<=s.left+i&&p[1]>=s.top&&p[1]<=s.top+r&&(t=!0)}if(!t)return}x.isHorizontal()?(37!==a&&39!==a||(e.preventDefault?e.preventDefault():e.returnValue=!1),(39===a&&!x.rtl||37===a&&x.rtl)&&x.slideNext(),(37===a&&!x.rtl||39===a&&x.rtl)&&x.slidePrev()):(38!==a&&40!==a||(e.preventDefault?e.preventDefault():e.returnValue=!1),40===a&&x.slideNext(),38===a&&x.slidePrev()),x.emit("onKeyPress",x,a)}}function d(e){e.originalEvent&&(e=e.originalEvent);var a=0,t=x.rtl?-1:1,s=function(e){var a=0,t=0,s=0,i=0;return"detail"in e&&(t=e.detail),"wheelDelta"in e&&(t=-e.wheelDelta/120),"wheelDeltaY"in e&&(t=-e.wheelDeltaY/120),"wheelDeltaX"in e&&(a=-e.wheelDeltaX/120),"axis"in e&&e.axis===e.HORIZONTAL_AXIS&&(a=t,t=0),s=10*a,i=10*t,"deltaY"in e&&(i=e.deltaY),"deltaX"in e&&(s=e.deltaX),(s||i)&&e.deltaMode&&(1===e.deltaMode?(s*=40,i*=40):(s*=800,i*=800)),s&&!a&&(a=s<1?-1:1),i&&!t&&(t=i<1?-1:1),{spinX:a,spinY:t,pixelX:s,pixelY:i}}(e);if(x.params.mousewheelForceToAxis)if(x.isHorizontal()){if(!(Math.abs(s.pixelX)>Math.abs(s.pixelY)))return;a=s.pixelX*t}else{if(!(Math.abs(s.pixelY)>Math.abs(s.pixelX)))return;a=s.pixelY}else a=Math.abs(s.pixelX)>Math.abs(s.pixelY)?-s.pixelX*t:-s.pixelY;if(0!==a){if(x.params.mousewheelInvert&&(a=-a),x.params.freeMode){var i=x.getWrapperTranslate()+a*x.params.mousewheelSensitivity,r=x.isBeginning,n=x.isEnd;if(i>=x.minTranslate()&&(i=x.minTranslate()),i<=x.maxTranslate()&&(i=x.maxTranslate()),x.setWrapperTransition(0),x.setWrapperTranslate(i),x.updateProgress(),x.updateActiveIndex(),(!r&&x.isBeginning||!n&&x.isEnd)&&x.updateClasses(),x.params.freeModeSticky?(clearTimeout(x.mousewheel.timeout),x.mousewheel.timeout=setTimeout(function(){x.slideReset()},300)):x.params.lazyLoading&&x.lazy&&x.lazy.load(),x.emit("onScroll",x,e),x.params.autoplay&&x.params.autoplayDisableOnInteraction&&x.stopAutoplay(),0===i||i===x.maxTranslate())return}else{if((new window.Date).getTime()-x.mousewheel.lastScrollTime>60)if(a<0)if(x.isEnd&&!x.params.loop||x.animating){if(x.params.mousewheelReleaseOnEdges)return!0}else x.slideNext(),x.emit("onScroll",x,e);else if(x.isBeginning&&!x.params.loop||x.animating){if(x.params.mousewheelReleaseOnEdges)return!0}else x.slidePrev(),x.emit("onScroll",x,e);x.mousewheel.lastScrollTime=(new window.Date).getTime()}return e.preventDefault?e.preventDefault():e.returnValue=!1,!1}}function u(a,t){a=e(a);var s,i,r,n=x.rtl?-1:1;s=a.attr("data-swiper-parallax")||"0",i=a.attr("data-swiper-parallax-x"),r=a.attr("data-swiper-parallax-y"),i||r?(i=i||"0",r=r||"0"):x.isHorizontal()?(i=s,r="0"):(r=s,i="0"),i=i.indexOf("%")>=0?parseInt(i,10)*t*n+"%":i*t*n+"px",r=r.indexOf("%")>=0?parseInt(r,10)*t+"%":r*t+"px",a.transform("translate3d("+i+", "+r+",0px)")}function c(e){return 0!==e.indexOf("on")&&(e=e[0]!==e[0].toUpperCase()?"on"+e[0].toUpperCase()+e.substring(1):"on"+e),e}if(!(this instanceof a))return new a(s,i);var m={direction:"horizontal",touchEventsTarget:"container",initialSlide:0,speed:300,autoplay:!1,autoplayDisableOnInteraction:!0,autoplayStopOnLast:!1,iOSEdgeSwipeDetection:!1,iOSEdgeSwipeThreshold:20,freeMode:!1,freeModeMomentum:!0,freeModeMomentumRatio:1,freeModeMomentumBounce:!0,freeModeMomentumBounceRatio:1,freeModeMomentumVelocityRatio:1,freeModeSticky:!1,freeModeMinimumVelocity:.02,autoHeight:!1,setWrapperSize:!1,virtualTranslate:!1,effect:"slide",coverflow:{rotate:50,stretch:0,depth:100,modifier:1,slideShadows:!0},flip:{slideShadows:!0,limitRotation:!0},cube:{slideShadows:!0,shadow:!0,shadowOffset:20,shadowScale:.94},fade:{crossFade:!1},parallax:!1,zoom:!1,zoomMax:3,zoomMin:1,zoomToggle:!0,scrollbar:null,scrollbarHide:!0,scrollbarDraggable:!1,scrollbarSnapOnRelease:!1,keyboardControl:!1,mousewheelControl:!1,mousewheelReleaseOnEdges:!1,mousewheelInvert:!1,mousewheelForceToAxis:!1,mousewheelSensitivity:1,mousewheelEventsTarged:"container",hashnav:!1,hashnavWatchState:!1,history:!1,replaceState:!1,breakpoints:void 0,spaceBetween:0,slidesPerView:1,slidesPerColumn:1,slidesPerColumnFill:"column",slidesPerGroup:1,centeredSlides:!1,slidesOffsetBefore:0,slidesOffsetAfter:0,roundLengths:!1,touchRatio:1,touchAngle:45,simulateTouch:!0,shortSwipes:!0,longSwipes:!0,longSwipesRatio:.5,longSwipesMs:300,followFinger:!0,onlyExternal:!1,threshold:0,touchMoveStopPropagation:!0,touchReleaseOnEdges:!1,uniqueNavElements:!0,pagination:null,paginationElement:"span",paginationClickable:!1,paginationHide:!1,paginationBulletRender:null,paginationProgressRender:null,paginationFractionRender:null,paginationCustomRender:null,paginationType:"bullets",resistance:!0,resistanceRatio:.85,nextButton:null,prevButton:null,watchSlidesProgress:!1,watchSlidesVisibility:!1,grabCursor:!1,preventClicks:!0,preventClicksPropagation:!0,slideToClickedSlide:!1,lazyLoading:!1,lazyLoadingInPrevNext:!1,lazyLoadingInPrevNextAmount:1,lazyLoadingOnTransitionStart:!1,preloadImages:!0,updateOnImagesReady:!0,loop:!1,loopAdditionalSlides:0,loopedSlides:null,control:void 0,controlInverse:!1,controlBy:"slide",normalizeSlideIndex:!0,allowSwipeToPrev:!0,allowSwipeToNext:!0,swipeHandler:null,noSwiping:!0,noSwipingClass:"swiper-no-swiping",passiveListeners:!0,containerModifierClass:"swiper-container-",slideClass:"swiper-slide",slideActiveClass:"swiper-slide-active",slideDuplicateActiveClass:"swiper-slide-duplicate-active",slideVisibleClass:"swiper-slide-visible",slideDuplicateClass:"swiper-slide-duplicate",slideNextClass:"swiper-slide-next",slideDuplicateNextClass:"swiper-slide-duplicate-next",slidePrevClass:"swiper-slide-prev",slideDuplicatePrevClass:"swiper-slide-duplicate-prev",wrapperClass:"swiper-wrapper",bulletClass:"swiper-pagination-bullet",bulletActiveClass:"swiper-pagination-bullet-active",buttonDisabledClass:"swiper-button-disabled",paginationCurrentClass:"swiper-pagination-current",paginationTotalClass:"swiper-pagination-total",paginationHiddenClass:"swiper-pagination-hidden",paginationProgressbarClass:"swiper-pagination-progressbar",paginationClickableClass:"swiper-pagination-clickable",paginationModifierClass:"swiper-pagination-",lazyLoadingClass:"swiper-lazy",lazyStatusLoadingClass:"swiper-lazy-loading",lazyStatusLoadedClass:"swiper-lazy-loaded",lazyPreloaderClass:"swiper-lazy-preloader",notificationClass:"swiper-notification",preloaderClass:"preloader",zoomContainerClass:"swiper-zoom-container",observer:!1,observeParents:!1,a11y:!1,prevSlideMessage:"Previous slide",nextSlideMessage:"Next slide",firstSlideMessage:"This is the first slide",lastSlideMessage:"This is the last slide",paginationBulletMessage:"Go to slide {{index}}",runCallbacksOnInit:!0},h=i&&i.virtualTranslate;i=i||{};var g={};for(var f in i)if("object"!=typeof i[f]||null===i[f]||(i[f].nodeType||i[f]===window||i[f]===document||void 0!==t&&i[f]instanceof t||"undefined"!=typeof jQuery&&i[f]instanceof jQuery))g[f]=i[f];else{g[f]={};for(var v in i[f])g[f][v]=i[f][v]}for(var w in m)if(void 0===i[w])i[w]=m[w];else if("object"==typeof i[w])for(var y in m[w])void 0===i[w][y]&&(i[w][y]=m[w][y]);var x=this;if(x.params=i,x.originalParams=g,x.classNames=[],void 0!==e&&void 0!==t&&(e=t),(void 0!==e||(e=void 0===t?window.Dom7||window.Zepto||window.jQuery:t))&&(x.$=e,x.currentBreakpoint=void 0,x.getActiveBreakpoint=function(){if(!x.params.breakpoints)return!1;var e,a=!1,t=[];for(e in x.params.breakpoints)x.params.breakpoints.hasOwnProperty(e)&&t.push(e);t.sort(function(e,a){return parseInt(e,10)>parseInt(a,10)});for(var s=0;s<t.length;s++)(e=t[s])>=window.innerWidth&&!a&&(a=e);return a||"max"},x.setBreakpoint=function(){var e=x.getActiveBreakpoint();if(e&&x.currentBreakpoint!==e){var a=e in x.params.breakpoints?x.params.breakpoints[e]:x.originalParams,t=x.params.loop&&a.slidesPerView!==x.params.slidesPerView;for(var s in a)x.params[s]=a[s];x.currentBreakpoint=e,t&&x.destroyLoop&&x.reLoop(!0)}},x.params.breakpoints&&x.setBreakpoint(),x.container=e(s),0!==x.container.length)){if(x.container.length>1){var T=[];return x.container.each(function(){T.push(new a(this,i))}),T}x.container[0].swiper=x,x.container.data("swiper",x),x.classNames.push(x.params.containerModifierClass+x.params.direction),x.params.freeMode&&x.classNames.push(x.params.containerModifierClass+"free-mode"),x.support.flexbox||(x.classNames.push(x.params.containerModifierClass+"no-flexbox"),x.params.slidesPerColumn=1),x.params.autoHeight&&x.classNames.push(x.params.containerModifierClass+"autoheight"),(x.params.parallax||x.params.watchSlidesVisibility)&&(x.params.watchSlidesProgress=!0),x.params.touchReleaseOnEdges&&(x.params.resistanceRatio=0),["cube","coverflow","flip"].indexOf(x.params.effect)>=0&&(x.support.transforms3d?(x.params.watchSlidesProgress=!0,x.classNames.push(x.params.containerModifierClass+"3d")):x.params.effect="slide"),"slide"!==x.params.effect&&x.classNames.push(x.params.containerModifierClass+x.params.effect),"cube"===x.params.effect&&(x.params.resistanceRatio=0,x.params.slidesPerView=1,x.params.slidesPerColumn=1,x.params.slidesPerGroup=1,x.params.centeredSlides=!1,x.params.spaceBetween=0,x.params.virtualTranslate=!0),"fade"!==x.params.effect&&"flip"!==x.params.effect||(x.params.slidesPerView=1,x.params.slidesPerColumn=1,x.params.slidesPerGroup=1,x.params.watchSlidesProgress=!0,x.params.spaceBetween=0,void 0===h&&(x.params.virtualTranslate=!0)),x.params.grabCursor&&x.support.touch&&(x.params.grabCursor=!1),x.wrapper=x.container.children("."+x.params.wrapperClass),x.params.pagination&&(x.paginationContainer=e(x.params.pagination),x.params.uniqueNavElements&&"string"==typeof x.params.pagination&&x.paginationContainer.length>1&&1===x.container.find(x.params.pagination).length&&(x.paginationContainer=x.container.find(x.params.pagination)),"bullets"===x.params.paginationType&&x.params.paginationClickable?x.paginationContainer.addClass(x.params.paginationModifierClass+"clickable"):x.params.paginationClickable=!1,x.paginationContainer.addClass(x.params.paginationModifierClass+x.params.paginationType)),(x.params.nextButton||x.params.prevButton)&&(x.params.nextButton&&(x.nextButton=e(x.params.nextButton),x.params.uniqueNavElements&&"string"==typeof x.params.nextButton&&x.nextButton.length>1&&1===x.container.find(x.params.nextButton).length&&(x.nextButton=x.container.find(x.params.nextButton))),x.params.prevButton&&(x.prevButton=e(x.params.prevButton),x.params.uniqueNavElements&&"string"==typeof x.params.prevButton&&x.prevButton.length>1&&1===x.container.find(x.params.prevButton).length&&(x.prevButton=x.container.find(x.params.prevButton)))),x.isHorizontal=function(){return"horizontal"===x.params.direction},x.rtl=x.isHorizontal()&&("rtl"===x.container[0].dir.toLowerCase()||"rtl"===x.container.css("direction")),x.rtl&&x.classNames.push(x.params.containerModifierClass+"rtl"),x.rtl&&(x.wrongRTL="-webkit-box"===x.wrapper.css("display")),x.params.slidesPerColumn>1&&x.classNames.push(x.params.containerModifierClass+"multirow"),x.device.android&&x.classNames.push(x.params.containerModifierClass+"android"),x.container.addClass(x.classNames.join(" ")),x.translate=0,x.progress=0,x.velocity=0,x.lockSwipeToNext=function(){x.params.allowSwipeToNext=!1,!1===x.params.allowSwipeToPrev&&x.params.grabCursor&&x.unsetGrabCursor()},x.lockSwipeToPrev=function(){x.params.allowSwipeToPrev=!1,!1===x.params.allowSwipeToNext&&x.params.grabCursor&&x.unsetGrabCursor()},x.lockSwipes=function(){x.params.allowSwipeToNext=x.params.allowSwipeToPrev=!1,x.params.grabCursor&&x.unsetGrabCursor()},x.unlockSwipeToNext=function(){x.params.allowSwipeToNext=!0,!0===x.params.allowSwipeToPrev&&x.params.grabCursor&&x.setGrabCursor()},x.unlockSwipeToPrev=function(){x.params.allowSwipeToPrev=!0,!0===x.params.allowSwipeToNext&&x.params.grabCursor&&x.setGrabCursor()},x.unlockSwipes=function(){x.params.allowSwipeToNext=x.params.allowSwipeToPrev=!0,x.params.grabCursor&&x.setGrabCursor()},x.setGrabCursor=function(e){x.container[0].style.cursor="move",x.container[0].style.cursor=e?"-webkit-grabbing":"-webkit-grab",x.container[0].style.cursor=e?"-moz-grabbin":"-moz-grab",x.container[0].style.cursor=e?"grabbing":"grab"},x.unsetGrabCursor=function(){x.container[0].style.cursor=""},x.params.grabCursor&&x.setGrabCursor(),x.imagesToLoad=[],x.imagesLoaded=0,x.loadImage=function(e,a,t,s,i,r){function n(){r&&r()}var o;e.complete&&i?n():a?((o=new window.Image).onload=n,o.onerror=n,s&&(o.sizes=s),t&&(o.srcset=t),a&&(o.src=a)):n()},x.preloadImages=function(){function e(){void 0!==x&&null!==x&&x&&(void 0!==x.imagesLoaded&&x.imagesLoaded++,x.imagesLoaded===x.imagesToLoad.length&&(x.params.updateOnImagesReady&&x.update(),x.emit("onImagesReady",x)))}x.imagesToLoad=x.container.find("img");for(var a=0;a<x.imagesToLoad.length;a++)x.loadImage(x.imagesToLoad[a],x.imagesToLoad[a].currentSrc||x.imagesToLoad[a].getAttribute("src"),x.imagesToLoad[a].srcset||x.imagesToLoad[a].getAttribute("srcset"),x.imagesToLoad[a].sizes||x.imagesToLoad[a].getAttribute("sizes"),!0,e)},x.autoplayTimeoutId=void 0,x.autoplaying=!1,x.autoplayPaused=!1,x.startAutoplay=function(){return void 0===x.autoplayTimeoutId&&(!!x.params.autoplay&&(!x.autoplaying&&(x.autoplaying=!0,x.emit("onAutoplayStart",x),void n())))},x.stopAutoplay=function(e){x.autoplayTimeoutId&&(x.autoplayTimeoutId&&clearTimeout(x.autoplayTimeoutId),x.autoplaying=!1,x.autoplayTimeoutId=void 0,x.emit("onAutoplayStop",x))},x.pauseAutoplay=function(e){x.autoplayPaused||(x.autoplayTimeoutId&&clearTimeout(x.autoplayTimeoutId),x.autoplayPaused=!0,0===e?(x.autoplayPaused=!1,n()):x.wrapper.transitionEnd(function(){x&&(x.autoplayPaused=!1,x.autoplaying?n():x.stopAutoplay())}))},x.minTranslate=function(){return-x.snapGrid[0]},x.maxTranslate=function(){return-x.snapGrid[x.snapGrid.length-1]},x.updateAutoHeight=function(){var e,a=[],t=0;if("auto"!==x.params.slidesPerView&&x.params.slidesPerView>1)for(e=0;e<Math.ceil(x.params.slidesPerView);e++){var s=x.activeIndex+e;if(s>x.slides.length)break;a.push(x.slides.eq(s)[0])}else a.push(x.slides.eq(x.activeIndex)[0]);for(e=0;e<a.length;e++)if(void 0!==a[e]){var i=a[e].offsetHeight;t=i>t?i:t}t&&x.wrapper.css("height",t+"px")},x.updateContainerSize=function(){var e,a;e=void 0!==x.params.width?x.params.width:x.container[0].clientWidth,a=void 0!==x.params.height?x.params.height:x.container[0].clientHeight,0===e&&x.isHorizontal()||0===a&&!x.isHorizontal()||(e=e-parseInt(x.container.css("padding-left"),10)-parseInt(x.container.css("padding-right"),10),a=a-parseInt(x.container.css("padding-top"),10)-parseInt(x.container.css("padding-bottom"),10),x.width=e,x.height=a,x.size=x.isHorizontal()?x.width:x.height)},x.updateSlidesSize=function(){x.slides=x.wrapper.children("."+x.params.slideClass),x.snapGrid=[],x.slidesGrid=[],x.slidesSizesGrid=[];var e,a=x.params.spaceBetween,t=-x.params.slidesOffsetBefore,s=0,i=0;if(void 0!==x.size){"string"==typeof a&&a.indexOf("%")>=0&&(a=parseFloat(a.replace("%",""))/100*x.size),x.virtualSize=-a,x.rtl?x.slides.css({marginLeft:"",marginTop:""}):x.slides.css({marginRight:"",marginBottom:""});var n;x.params.slidesPerColumn>1&&(n=Math.floor(x.slides.length/x.params.slidesPerColumn)===x.slides.length/x.params.slidesPerColumn?x.slides.length:Math.ceil(x.slides.length/x.params.slidesPerColumn)*x.params.slidesPerColumn,"auto"!==x.params.slidesPerView&&"row"===x.params.slidesPerColumnFill&&(n=Math.max(n,x.params.slidesPerView*x.params.slidesPerColumn)));var o,l=x.params.slidesPerColumn,p=n/l,d=p-(x.params.slidesPerColumn*p-x.slides.length);for(e=0;e<x.slides.length;e++){o=0;var u=x.slides.eq(e);if(x.params.slidesPerColumn>1){var c,m,h;"column"===x.params.slidesPerColumnFill?(h=e-(m=Math.floor(e/l))*l,(m>d||m===d&&h===l-1)&&++h>=l&&(h=0,m++),c=m+h*n/l,u.css({"-webkit-box-ordinal-group":c,"-moz-box-ordinal-group":c,"-ms-flex-order":c,"-webkit-order":c,order:c})):m=e-(h=Math.floor(e/p))*p,u.css("margin-"+(x.isHorizontal()?"top":"left"),0!==h&&x.params.spaceBetween&&x.params.spaceBetween+"px").attr("data-swiper-column",m).attr("data-swiper-row",h)}"none"!==u.css("display")&&("auto"===x.params.slidesPerView?(o=x.isHorizontal()?u.outerWidth(!0):u.outerHeight(!0),x.params.roundLengths&&(o=r(o))):(o=(x.size-(x.params.slidesPerView-1)*a)/x.params.slidesPerView,x.params.roundLengths&&(o=r(o)),x.isHorizontal()?x.slides[e].style.width=o+"px":x.slides[e].style.height=o+"px"),x.slides[e].swiperSlideSize=o,x.slidesSizesGrid.push(o),x.params.centeredSlides?(t=t+o/2+s/2+a,0===s&&0!==e&&(t=t-x.size/2-a),0===e&&(t=t-x.size/2-a),Math.abs(t)<.001&&(t=0),i%x.params.slidesPerGroup==0&&x.snapGrid.push(t),x.slidesGrid.push(t)):(i%x.params.slidesPerGroup==0&&x.snapGrid.push(t),x.slidesGrid.push(t),t=t+o+a),x.virtualSize+=o+a,s=o,i++)}x.virtualSize=Math.max(x.virtualSize,x.size)+x.params.slidesOffsetAfter;var g;if(x.rtl&&x.wrongRTL&&("slide"===x.params.effect||"coverflow"===x.params.effect)&&x.wrapper.css({width:x.virtualSize+x.params.spaceBetween+"px"}),x.support.flexbox&&!x.params.setWrapperSize||(x.isHorizontal()?x.wrapper.css({width:x.virtualSize+x.params.spaceBetween+"px"}):x.wrapper.css({height:x.virtualSize+x.params.spaceBetween+"px"})),x.params.slidesPerColumn>1&&(x.virtualSize=(o+x.params.spaceBetween)*n,x.virtualSize=Math.ceil(x.virtualSize/x.params.slidesPerColumn)-x.params.spaceBetween,x.isHorizontal()?x.wrapper.css({width:x.virtualSize+x.params.spaceBetween+"px"}):x.wrapper.css({height:x.virtualSize+x.params.spaceBetween+"px"}),x.params.centeredSlides)){for(g=[],e=0;e<x.snapGrid.length;e++)x.snapGrid[e]<x.virtualSize+x.snapGrid[0]&&g.push(x.snapGrid[e]);x.snapGrid=g}if(!x.params.centeredSlides){for(g=[],e=0;e<x.snapGrid.length;e++)x.snapGrid[e]<=x.virtualSize-x.size&&g.push(x.snapGrid[e]);x.snapGrid=g,Math.floor(x.virtualSize-x.size)-Math.floor(x.snapGrid[x.snapGrid.length-1])>1&&x.snapGrid.push(x.virtualSize-x.size)}0===x.snapGrid.length&&(x.snapGrid=[0]),0!==x.params.spaceBetween&&(x.isHorizontal()?x.rtl?x.slides.css({marginLeft:a+"px"}):x.slides.css({marginRight:a+"px"}):x.slides.css({marginBottom:a+"px"})),x.params.watchSlidesProgress&&x.updateSlidesOffset()}},x.updateSlidesOffset=function(){for(var e=0;e<x.slides.length;e++)x.slides[e].swiperSlideOffset=x.isHorizontal()?x.slides[e].offsetLeft:x.slides[e].offsetTop},x.currentSlidesPerView=function(){var e,a,t=1;if(x.params.centeredSlides){var s,i=x.slides[x.activeIndex].swiperSlideSize;for(e=x.activeIndex+1;e<x.slides.length;e++)x.slides[e]&&!s&&(t++,(i+=x.slides[e].swiperSlideSize)>x.size&&(s=!0));for(a=x.activeIndex-1;a>=0;a--)x.slides[a]&&!s&&(t++,(i+=x.slides[a].swiperSlideSize)>x.size&&(s=!0))}else for(e=x.activeIndex+1;e<x.slides.length;e++)x.slidesGrid[e]-x.slidesGrid[x.activeIndex]<x.size&&t++;return t},x.updateSlidesProgress=function(e){if(void 0===e&&(e=x.translate||0),0!==x.slides.length){void 0===x.slides[0].swiperSlideOffset&&x.updateSlidesOffset();var a=-e;x.rtl&&(a=e),x.slides.removeClass(x.params.slideVisibleClass);for(var t=0;t<x.slides.length;t++){var s=x.slides[t],i=(a+(x.params.centeredSlides?x.minTranslate():0)-s.swiperSlideOffset)/(s.swiperSlideSize+x.params.spaceBetween);if(x.params.watchSlidesVisibility){var r=-(a-s.swiperSlideOffset),n=r+x.slidesSizesGrid[t];(r>=0&&r<x.size||n>0&&n<=x.size||r<=0&&n>=x.size)&&x.slides.eq(t).addClass(x.params.slideVisibleClass)}s.progress=x.rtl?-i:i}}},x.updateProgress=function(e){void 0===e&&(e=x.translate||0);var a=x.maxTranslate()-x.minTranslate(),t=x.isBeginning,s=x.isEnd;0===a?(x.progress=0,x.isBeginning=x.isEnd=!0):(x.progress=(e-x.minTranslate())/a,x.isBeginning=x.progress<=0,x.isEnd=x.progress>=1),x.isBeginning&&!t&&x.emit("onReachBeginning",x),x.isEnd&&!s&&x.emit("onReachEnd",x),x.params.watchSlidesProgress&&x.updateSlidesProgress(e),x.emit("onProgress",x,x.progress)},x.updateActiveIndex=function(){var e,a,t,s=x.rtl?x.translate:-x.translate;for(a=0;a<x.slidesGrid.length;a++)void 0!==x.slidesGrid[a+1]?s>=x.slidesGrid[a]&&s<x.slidesGrid[a+1]-(x.slidesGrid[a+1]-x.slidesGrid[a])/2?e=a:s>=x.slidesGrid[a]&&s<x.slidesGrid[a+1]&&(e=a+1):s>=x.slidesGrid[a]&&(e=a);x.params.normalizeSlideIndex&&(e<0||void 0===e)&&(e=0),(t=Math.floor(e/x.params.slidesPerGroup))>=x.snapGrid.length&&(t=x.snapGrid.length-1),e!==x.activeIndex&&(x.snapIndex=t,x.previousIndex=x.activeIndex,x.activeIndex=e,x.updateClasses(),x.updateRealIndex())},x.updateRealIndex=function(){x.realIndex=parseInt(x.slides.eq(x.activeIndex).attr("data-swiper-slide-index")||x.activeIndex,10)},x.updateClasses=function(){x.slides.removeClass(x.params.slideActiveClass+" "+x.params.slideNextClass+" "+x.params.slidePrevClass+" "+x.params.slideDuplicateActiveClass+" "+x.params.slideDuplicateNextClass+" "+x.params.slideDuplicatePrevClass);var a=x.slides.eq(x.activeIndex);a.addClass(x.params.slideActiveClass),i.loop&&(a.hasClass(x.params.slideDuplicateClass)?x.wrapper.children("."+x.params.slideClass+":not(."+x.params.slideDuplicateClass+')[data-swiper-slide-index="'+x.realIndex+'"]').addClass(x.params.slideDuplicateActiveClass):x.wrapper.children("."+x.params.slideClass+"."+x.params.slideDuplicateClass+'[data-swiper-slide-index="'+x.realIndex+'"]').addClass(x.params.slideDuplicateActiveClass));var t=a.next("."+x.params.slideClass).addClass(x.params.slideNextClass);x.params.loop&&0===t.length&&(t=x.slides.eq(0)).addClass(x.params.slideNextClass);var s=a.prev("."+x.params.slideClass).addClass(x.params.slidePrevClass);if(x.params.loop&&0===s.length&&(s=x.slides.eq(-1)).addClass(x.params.slidePrevClass),i.loop&&(t.hasClass(x.params.slideDuplicateClass)?x.wrapper.children("."+x.params.slideClass+":not(."+x.params.slideDuplicateClass+')[data-swiper-slide-index="'+t.attr("data-swiper-slide-index")+'"]').addClass(x.params.slideDuplicateNextClass):x.wrapper.children("."+x.params.slideClass+"."+x.params.slideDuplicateClass+'[data-swiper-slide-index="'+t.attr("data-swiper-slide-index")+'"]').addClass(x.params.slideDuplicateNextClass),s.hasClass(x.params.slideDuplicateClass)?x.wrapper.children("."+x.params.slideClass+":not(."+x.params.slideDuplicateClass+')[data-swiper-slide-index="'+s.attr("data-swiper-slide-index")+'"]').addClass(x.params.slideDuplicatePrevClass):x.wrapper.children("."+x.params.slideClass+"."+x.params.slideDuplicateClass+'[data-swiper-slide-index="'+s.attr("data-swiper-slide-index")+'"]').addClass(x.params.slideDuplicatePrevClass)),x.paginationContainer&&x.paginationContainer.length>0){var r,n=x.params.loop?Math.ceil((x.slides.length-2*x.loopedSlides)/x.params.slidesPerGroup):x.snapGrid.length;if(x.params.loop?((r=Math.ceil((x.activeIndex-x.loopedSlides)/x.params.slidesPerGroup))>x.slides.length-1-2*x.loopedSlides&&(r-=x.slides.length-2*x.loopedSlides),r>n-1&&(r-=n),r<0&&"bullets"!==x.params.paginationType&&(r=n+r)):r=void 0!==x.snapIndex?x.snapIndex:x.activeIndex||0,"bullets"===x.params.paginationType&&x.bullets&&x.bullets.length>0&&(x.bullets.removeClass(x.params.bulletActiveClass),x.paginationContainer.length>1?x.bullets.each(function(){e(this).index()===r&&e(this).addClass(x.params.bulletActiveClass)}):x.bullets.eq(r).addClass(x.params.bulletActiveClass)),"fraction"===x.params.paginationType&&(x.paginationContainer.find("."+x.params.paginationCurrentClass).text(r+1),x.paginationContainer.find("."+x.params.paginationTotalClass).text(n)),"progress"===x.params.paginationType){var o=(r+1)/n,l=o,p=1;x.isHorizontal()||(p=o,l=1),x.paginationContainer.find("."+x.params.paginationProgressbarClass).transform("translate3d(0,0,0) scaleX("+l+") scaleY("+p+")").transition(x.params.speed)}"custom"===x.params.paginationType&&x.params.paginationCustomRender&&(x.paginationContainer.html(x.params.paginationCustomRender(x,r+1,n)),x.emit("onPaginationRendered",x,x.paginationContainer[0]))}x.params.loop||(x.params.prevButton&&x.prevButton&&x.prevButton.length>0&&(x.isBeginning?(x.prevButton.addClass(x.params.buttonDisabledClass),x.params.a11y&&x.a11y&&x.a11y.disable(x.prevButton)):(x.prevButton.removeClass(x.params.buttonDisabledClass),x.params.a11y&&x.a11y&&x.a11y.enable(x.prevButton))),x.params.nextButton&&x.nextButton&&x.nextButton.length>0&&(x.isEnd?(x.nextButton.addClass(x.params.buttonDisabledClass),x.params.a11y&&x.a11y&&x.a11y.disable(x.nextButton)):(x.nextButton.removeClass(x.params.buttonDisabledClass),x.params.a11y&&x.a11y&&x.a11y.enable(x.nextButton))))},x.updatePagination=function(){if(x.params.pagination&&x.paginationContainer&&x.paginationContainer.length>0){var e="";if("bullets"===x.params.paginationType){for(var a=x.params.loop?Math.ceil((x.slides.length-2*x.loopedSlides)/x.params.slidesPerGroup):x.snapGrid.length,t=0;t<a;t++)x.params.paginationBulletRender?e+=x.params.paginationBulletRender(x,t,x.params.bulletClass):e+="<"+x.params.paginationElement+' class="'+x.params.bulletClass+'"></'+x.params.paginationElement+">";x.paginationContainer.html(e),x.bullets=x.paginationContainer.find("."+x.params.bulletClass),x.params.paginationClickable&&x.params.a11y&&x.a11y&&x.a11y.initPagination()}"fraction"===x.params.paginationType&&(e=x.params.paginationFractionRender?x.params.paginationFractionRender(x,x.params.paginationCurrentClass,x.params.paginationTotalClass):'<span class="'+x.params.paginationCurrentClass+'"></span> / <span class="'+x.params.paginationTotalClass+'"></span>',x.paginationContainer.html(e)),"progress"===x.params.paginationType&&(e=x.params.paginationProgressRender?x.params.paginationProgressRender(x,x.params.paginationProgressbarClass):'<span class="'+x.params.paginationProgressbarClass+'"></span>',x.paginationContainer.html(e)),"custom"!==x.params.paginationType&&x.emit("onPaginationRendered",x,x.paginationContainer[0])}},x.update=function(e){function a(){x.rtl,x.translate;t=Math.min(Math.max(x.translate,x.maxTranslate()),x.minTranslate()),x.setWrapperTranslate(t),x.updateActiveIndex(),x.updateClasses()}if(x){x.updateContainerSize(),x.updateSlidesSize(),x.updateProgress(),x.updatePagination(),x.updateClasses(),x.params.scrollbar&&x.scrollbar&&x.scrollbar.set();var t;if(e){x.controller&&x.controller.spline&&(x.controller.spline=void 0),x.params.freeMode?(a(),x.params.autoHeight&&x.updateAutoHeight()):(("auto"===x.params.slidesPerView||x.params.slidesPerView>1)&&x.isEnd&&!x.params.centeredSlides?x.slideTo(x.slides.length-1,0,!1,!0):x.slideTo(x.activeIndex,0,!1,!0))||a()}else x.params.autoHeight&&x.updateAutoHeight()}},x.onResize=function(e){x.params.onBeforeResize&&x.params.onBeforeResize(x),x.params.breakpoints&&x.setBreakpoint();var a=x.params.allowSwipeToPrev,t=x.params.allowSwipeToNext;x.params.allowSwipeToPrev=x.params.allowSwipeToNext=!0,x.updateContainerSize(),x.updateSlidesSize(),("auto"===x.params.slidesPerView||x.params.freeMode||e)&&x.updatePagination(),x.params.scrollbar&&x.scrollbar&&x.scrollbar.set(),x.controller&&x.controller.spline&&(x.controller.spline=void 0);var s=!1;if(x.params.freeMode){var i=Math.min(Math.max(x.translate,x.maxTranslate()),x.minTranslate());x.setWrapperTranslate(i),x.updateActiveIndex(),x.updateClasses(),x.params.autoHeight&&x.updateAutoHeight()}else x.updateClasses(),s=("auto"===x.params.slidesPerView||x.params.slidesPerView>1)&&x.isEnd&&!x.params.centeredSlides?x.slideTo(x.slides.length-1,0,!1,!0):x.slideTo(x.activeIndex,0,!1,!0);x.params.lazyLoading&&!s&&x.lazy&&x.lazy.load(),x.params.allowSwipeToPrev=a,x.params.allowSwipeToNext=t,x.params.onAfterResize&&x.params.onAfterResize(x)},x.touchEventsDesktop={start:"mousedown",move:"mousemove",end:"mouseup"},window.navigator.pointerEnabled?x.touchEventsDesktop={start:"pointerdown",move:"pointermove",end:"pointerup"}:window.navigator.msPointerEnabled&&(x.touchEventsDesktop={start:"MSPointerDown",move:"MSPointerMove",end:"MSPointerUp"}),x.touchEvents={start:x.support.touch||!x.params.simulateTouch?"touchstart":x.touchEventsDesktop.start,move:x.support.touch||!x.params.simulateTouch?"touchmove":x.touchEventsDesktop.move,end:x.support.touch||!x.params.simulateTouch?"touchend":x.touchEventsDesktop.end},(window.navigator.pointerEnabled||window.navigator.msPointerEnabled)&&("container"===x.params.touchEventsTarget?x.container:x.wrapper).addClass("swiper-wp8-"+x.params.direction),x.initEvents=function(e){var a=e?"off":"on",t=e?"removeEventListener":"addEventListener",s="container"===x.params.touchEventsTarget?x.container[0]:x.wrapper[0],r=x.support.touch?s:document,n=!!x.params.nested;if(x.browser.ie)s[t](x.touchEvents.start,x.onTouchStart,!1),r[t](x.touchEvents.move,x.onTouchMove,n),r[t](x.touchEvents.end,x.onTouchEnd,!1);else{if(x.support.touch){var o=!("touchstart"!==x.touchEvents.start||!x.support.passiveListener||!x.params.passiveListeners)&&{passive:!0,capture:!1};s[t](x.touchEvents.start,x.onTouchStart,o),s[t](x.touchEvents.move,x.onTouchMove,n),s[t](x.touchEvents.end,x.onTouchEnd,o)}(i.simulateTouch&&!x.device.ios&&!x.device.android||i.simulateTouch&&!x.support.touch&&x.device.ios)&&(s[t]("mousedown",x.onTouchStart,!1),document[t]("mousemove",x.onTouchMove,n),document[t]("mouseup",x.onTouchEnd,!1))}window[t]("resize",x.onResize),x.params.nextButton&&x.nextButton&&x.nextButton.length>0&&(x.nextButton[a]("click",x.onClickNext),x.params.a11y&&x.a11y&&x.nextButton[a]("keydown",x.a11y.onEnterKey)),x.params.prevButton&&x.prevButton&&x.prevButton.length>0&&(x.prevButton[a]("click",x.onClickPrev),x.params.a11y&&x.a11y&&x.prevButton[a]("keydown",x.a11y.onEnterKey)),x.params.pagination&&x.params.paginationClickable&&(x.paginationContainer[a]("click","."+x.params.bulletClass,x.onClickIndex),x.params.a11y&&x.a11y&&x.paginationContainer[a]("keydown","."+x.params.bulletClass,x.a11y.onEnterKey)),(x.params.preventClicks||x.params.preventClicksPropagation)&&s[t]("click",x.preventClicks,!0)},x.attachEvents=function(){x.initEvents()},x.detachEvents=function(){x.initEvents(!0)},x.allowClick=!0,x.preventClicks=function(e){x.allowClick||(x.params.preventClicks&&e.preventDefault(),x.params.preventClicksPropagation&&x.animating&&(e.stopPropagation(),e.stopImmediatePropagation()))},x.onClickNext=function(e){e.preventDefault(),x.isEnd&&!x.params.loop||x.slideNext()},x.onClickPrev=function(e){e.preventDefault(),x.isBeginning&&!x.params.loop||x.slidePrev()},x.onClickIndex=function(a){a.preventDefault();var t=e(this).index()*x.params.slidesPerGroup;x.params.loop&&(t+=x.loopedSlides),x.slideTo(t)},x.updateClickedSlide=function(a){var t=o(a,"."+x.params.slideClass),s=!1;if(t)for(var i=0;i<x.slides.length;i++)x.slides[i]===t&&(s=!0);if(!t||!s)return x.clickedSlide=void 0,void(x.clickedIndex=void 0);if(x.clickedSlide=t,x.clickedIndex=e(t).index(),x.params.slideToClickedSlide&&void 0!==x.clickedIndex&&x.clickedIndex!==x.activeIndex){var r,n=x.clickedIndex,l="auto"===x.params.slidesPerView?x.currentSlidesPerView():x.params.slidesPerView;if(x.params.loop){if(x.animating)return;r=parseInt(e(x.clickedSlide).attr("data-swiper-slide-index"),10),x.params.centeredSlides?n<x.loopedSlides-l/2||n>x.slides.length-x.loopedSlides+l/2?(x.fixLoop(),n=x.wrapper.children("."+x.params.slideClass+'[data-swiper-slide-index="'+r+'"]:not(.'+x.params.slideDuplicateClass+")").eq(0).index(),setTimeout(function(){x.slideTo(n)},0)):x.slideTo(n):n>x.slides.length-l?(x.fixLoop(),n=x.wrapper.children("."+x.params.slideClass+'[data-swiper-slide-index="'+r+'"]:not(.'+x.params.slideDuplicateClass+")").eq(0).index(),setTimeout(function(){x.slideTo(n)},0)):x.slideTo(n)}else x.slideTo(n)}};var b,S,C,z,M,E,P,I,k,L,D="input, select, textarea, button, video",B=Date.now(),H=[];x.animating=!1,x.touches={startX:0,startY:0,currentX:0,currentY:0,diff:0};var G,X;x.onTouchStart=function(a){if(a.originalEvent&&(a=a.originalEvent),(G="touchstart"===a.type)||!("which"in a)||3!==a.which)if(x.params.noSwiping&&o(a,"."+x.params.noSwipingClass))x.allowClick=!0;else if(!x.params.swipeHandler||o(a,x.params.swipeHandler)){var t=x.touches.currentX="touchstart"===a.type?a.targetTouches[0].pageX:a.pageX,s=x.touches.currentY="touchstart"===a.type?a.targetTouches[0].pageY:a.pageY;if(!(x.device.ios&&x.params.iOSEdgeSwipeDetection&&t<=x.params.iOSEdgeSwipeThreshold)){if(b=!0,S=!1,C=!0,M=void 0,X=void 0,x.touches.startX=t,x.touches.startY=s,z=Date.now(),x.allowClick=!0,x.updateContainerSize(),x.swipeDirection=void 0,x.params.threshold>0&&(I=!1),"touchstart"!==a.type){var i=!0;e(a.target).is(D)&&(i=!1),document.activeElement&&e(document.activeElement).is(D)&&document.activeElement.blur(),i&&a.preventDefault()}x.emit("onTouchStart",x,a)}}},x.onTouchMove=function(a){if(a.originalEvent&&(a=a.originalEvent),!G||"mousemove"!==a.type){if(a.preventedByNestedSwiper)return x.touches.startX="touchmove"===a.type?a.targetTouches[0].pageX:a.pageX,void(x.touches.startY="touchmove"===a.type?a.targetTouches[0].pageY:a.pageY);if(x.params.onlyExternal)return x.allowClick=!1,void(b&&(x.touches.startX=x.touches.currentX="touchmove"===a.type?a.targetTouches[0].pageX:a.pageX,x.touches.startY=x.touches.currentY="touchmove"===a.type?a.targetTouches[0].pageY:a.pageY,z=Date.now()));if(G&&x.params.touchReleaseOnEdges&&!x.params.loop)if(x.isHorizontal()){if(x.touches.currentX<x.touches.startX&&x.translate<=x.maxTranslate()||x.touches.currentX>x.touches.startX&&x.translate>=x.minTranslate())return}else if(x.touches.currentY<x.touches.startY&&x.translate<=x.maxTranslate()||x.touches.currentY>x.touches.startY&&x.translate>=x.minTranslate())return;if(G&&document.activeElement&&a.target===document.activeElement&&e(a.target).is(D))return S=!0,void(x.allowClick=!1);if(C&&x.emit("onTouchMove",x,a),!(a.targetTouches&&a.targetTouches.length>1)){if(x.touches.currentX="touchmove"===a.type?a.targetTouches[0].pageX:a.pageX,x.touches.currentY="touchmove"===a.type?a.targetTouches[0].pageY:a.pageY,void 0===M){var t;x.isHorizontal()&&x.touches.currentY===x.touches.startY||!x.isHorizontal()&&x.touches.currentX===x.touches.startX?M=!1:(t=180*Math.atan2(Math.abs(x.touches.currentY-x.touches.startY),Math.abs(x.touches.currentX-x.touches.startX))/Math.PI,M=x.isHorizontal()?t>x.params.touchAngle:90-t>x.params.touchAngle)}if(M&&x.emit("onTouchMoveOpposite",x,a),void 0===X&&(x.touches.currentX===x.touches.startX&&x.touches.currentY===x.touches.startY||(X=!0)),b)if(M)b=!1;else if(X){x.allowClick=!1,x.emit("onSliderMove",x,a),a.preventDefault(),x.params.touchMoveStopPropagation&&!x.params.nested&&a.stopPropagation(),S||(i.loop&&x.fixLoop(),P=x.getWrapperTranslate(),x.setWrapperTransition(0),x.animating&&x.wrapper.trigger("webkitTransitionEnd transitionend oTransitionEnd MSTransitionEnd msTransitionEnd"),x.params.autoplay&&x.autoplaying&&(x.params.autoplayDisableOnInteraction?x.stopAutoplay():x.pauseAutoplay()),L=!1,!x.params.grabCursor||!0!==x.params.allowSwipeToNext&&!0!==x.params.allowSwipeToPrev||x.setGrabCursor(!0)),S=!0;var s=x.touches.diff=x.isHorizontal()?x.touches.currentX-x.touches.startX:x.touches.currentY-x.touches.startY;s*=x.params.touchRatio,x.rtl&&(s=-s),x.swipeDirection=s>0?"prev":"next",E=s+P;var r=!0;if(s>0&&E>x.minTranslate()?(r=!1,x.params.resistance&&(E=x.minTranslate()-1+Math.pow(-x.minTranslate()+P+s,x.params.resistanceRatio))):s<0&&E<x.maxTranslate()&&(r=!1,x.params.resistance&&(E=x.maxTranslate()+1-Math.pow(x.maxTranslate()-P-s,x.params.resistanceRatio))),r&&(a.preventedByNestedSwiper=!0),!x.params.allowSwipeToNext&&"next"===x.swipeDirection&&E<P&&(E=P),!x.params.allowSwipeToPrev&&"prev"===x.swipeDirection&&E>P&&(E=P),x.params.threshold>0){if(!(Math.abs(s)>x.params.threshold||I))return void(E=P);if(!I)return I=!0,x.touches.startX=x.touches.currentX,x.touches.startY=x.touches.currentY,E=P,void(x.touches.diff=x.isHorizontal()?x.touches.currentX-x.touches.startX:x.touches.currentY-x.touches.startY)}x.params.followFinger&&((x.params.freeMode||x.params.watchSlidesProgress)&&x.updateActiveIndex(),x.params.freeMode&&(0===H.length&&H.push({position:x.touches[x.isHorizontal()?"startX":"startY"],time:z}),H.push({position:x.touches[x.isHorizontal()?"currentX":"currentY"],time:(new window.Date).getTime()})),x.updateProgress(E),x.setWrapperTranslate(E))}}}},x.onTouchEnd=function(a){if(a.originalEvent&&(a=a.originalEvent),C&&x.emit("onTouchEnd",x,a),C=!1,b){x.params.grabCursor&&S&&b&&(!0===x.params.allowSwipeToNext||!0===x.params.allowSwipeToPrev)&&x.setGrabCursor(!1);var t=Date.now(),s=t-z;if(x.allowClick&&(x.updateClickedSlide(a),x.emit("onTap",x,a),s<300&&t-B>300&&(k&&clearTimeout(k),k=setTimeout(function(){x&&(x.params.paginationHide&&x.paginationContainer.length>0&&!e(a.target).hasClass(x.params.bulletClass)&&x.paginationContainer.toggleClass(x.params.paginationHiddenClass),x.emit("onClick",x,a))},300)),s<300&&t-B<300&&(k&&clearTimeout(k),x.emit("onDoubleTap",x,a))),B=Date.now(),setTimeout(function(){x&&(x.allowClick=!0)},0),b&&S&&x.swipeDirection&&0!==x.touches.diff&&E!==P){b=S=!1;var i;if(i=x.params.followFinger?x.rtl?x.translate:-x.translate:-E,x.params.freeMode){if(i<-x.minTranslate())return void x.slideTo(x.activeIndex);if(i>-x.maxTranslate())return void(x.slides.length<x.snapGrid.length?x.slideTo(x.snapGrid.length-1):x.slideTo(x.slides.length-1));if(x.params.freeModeMomentum){if(H.length>1){var r=H.pop(),n=H.pop(),o=r.position-n.position,l=r.time-n.time;x.velocity=o/l,x.velocity=x.velocity/2,Math.abs(x.velocity)<x.params.freeModeMinimumVelocity&&(x.velocity=0),(l>150||(new window.Date).getTime()-r.time>300)&&(x.velocity=0)}else x.velocity=0;x.velocity=x.velocity*x.params.freeModeMomentumVelocityRatio,H.length=0;var p=1e3*x.params.freeModeMomentumRatio,d=x.velocity*p,u=x.translate+d;x.rtl&&(u=-u);var c,m=!1,h=20*Math.abs(x.velocity)*x.params.freeModeMomentumBounceRatio;if(u<x.maxTranslate())x.params.freeModeMomentumBounce?(u+x.maxTranslate()<-h&&(u=x.maxTranslate()-h),c=x.maxTranslate(),m=!0,L=!0):u=x.maxTranslate();else if(u>x.minTranslate())x.params.freeModeMomentumBounce?(u-x.minTranslate()>h&&(u=x.minTranslate()+h),c=x.minTranslate(),m=!0,L=!0):u=x.minTranslate();else if(x.params.freeModeSticky){var g,f=0;for(f=0;f<x.snapGrid.length;f+=1)if(x.snapGrid[f]>-u){g=f;break}u=Math.abs(x.snapGrid[g]-u)<Math.abs(x.snapGrid[g-1]-u)||"next"===x.swipeDirection?x.snapGrid[g]:x.snapGrid[g-1],x.rtl||(u=-u)}if(0!==x.velocity)p=x.rtl?Math.abs((-u-x.translate)/x.velocity):Math.abs((u-x.translate)/x.velocity);else if(x.params.freeModeSticky)return void x.slideReset();x.params.freeModeMomentumBounce&&m?(x.updateProgress(c),x.setWrapperTransition(p),x.setWrapperTranslate(u),x.onTransitionStart(),x.animating=!0,x.wrapper.transitionEnd(function(){x&&L&&(x.emit("onMomentumBounce",x),x.setWrapperTransition(x.params.speed),x.setWrapperTranslate(c),x.wrapper.transitionEnd(function(){x&&x.onTransitionEnd()}))})):x.velocity?(x.updateProgress(u),x.setWrapperTransition(p),x.setWrapperTranslate(u),x.onTransitionStart(),x.animating||(x.animating=!0,x.wrapper.transitionEnd(function(){x&&x.onTransitionEnd()}))):x.updateProgress(u),x.updateActiveIndex()}(!x.params.freeModeMomentum||s>=x.params.longSwipesMs)&&(x.updateProgress(),x.updateActiveIndex())}else{var v,w=0,y=x.slidesSizesGrid[0];for(v=0;v<x.slidesGrid.length;v+=x.params.slidesPerGroup)void 0!==x.slidesGrid[v+x.params.slidesPerGroup]?i>=x.slidesGrid[v]&&i<x.slidesGrid[v+x.params.slidesPerGroup]&&(w=v,y=x.slidesGrid[v+x.params.slidesPerGroup]-x.slidesGrid[v]):i>=x.slidesGrid[v]&&(w=v,y=x.slidesGrid[x.slidesGrid.length-1]-x.slidesGrid[x.slidesGrid.length-2]);var T=(i-x.slidesGrid[w])/y;if(s>x.params.longSwipesMs){if(!x.params.longSwipes)return void x.slideTo(x.activeIndex);"next"===x.swipeDirection&&(T>=x.params.longSwipesRatio?x.slideTo(w+x.params.slidesPerGroup):x.slideTo(w)),"prev"===x.swipeDirection&&(T>1-x.params.longSwipesRatio?x.slideTo(w+x.params.slidesPerGroup):x.slideTo(w))}else{if(!x.params.shortSwipes)return void x.slideTo(x.activeIndex);"next"===x.swipeDirection&&x.slideTo(w+x.params.slidesPerGroup),"prev"===x.swipeDirection&&x.slideTo(w)}}}else b=S=!1}},x._slideTo=function(e,a){return x.slideTo(e,a,!0,!0)},x.slideTo=function(e,a,t,s){void 0===t&&(t=!0),void 0===e&&(e=0),e<0&&(e=0),x.snapIndex=Math.floor(e/x.params.slidesPerGroup),x.snapIndex>=x.snapGrid.length&&(x.snapIndex=x.snapGrid.length-1);var i=-x.snapGrid[x.snapIndex];if(x.params.autoplay&&x.autoplaying&&(s||!x.params.autoplayDisableOnInteraction?x.pauseAutoplay(a):x.stopAutoplay()),x.updateProgress(i),x.params.normalizeSlideIndex)for(var r=0;r<x.slidesGrid.length;r++)-Math.floor(100*i)>=Math.floor(100*x.slidesGrid[r])&&(e=r);return!(!x.params.allowSwipeToNext&&i<x.translate&&i<x.minTranslate())&&(!(!x.params.allowSwipeToPrev&&i>x.translate&&i>x.maxTranslate()&&(x.activeIndex||0)!==e)&&(void 0===a&&(a=x.params.speed),x.previousIndex=x.activeIndex||0,x.activeIndex=e,x.updateRealIndex(),x.rtl&&-i===x.translate||!x.rtl&&i===x.translate?(x.params.autoHeight&&x.updateAutoHeight(),x.updateClasses(),"slide"!==x.params.effect&&x.setWrapperTranslate(i),!1):(x.updateClasses(),x.onTransitionStart(t),0===a||x.browser.lteIE9?(x.setWrapperTranslate(i),x.setWrapperTransition(0),x.onTransitionEnd(t)):(x.setWrapperTranslate(i),x.setWrapperTransition(a),x.animating||(x.animating=!0,x.wrapper.transitionEnd(function(){x&&x.onTransitionEnd(t)}))),!0)))},x.onTransitionStart=function(e){void 0===e&&(e=!0),x.params.autoHeight&&x.updateAutoHeight(),x.lazy&&x.lazy.onTransitionStart(),e&&(x.emit("onTransitionStart",x),x.activeIndex!==x.previousIndex&&(x.emit("onSlideChangeStart",x),x.activeIndex>x.previousIndex?x.emit("onSlideNextStart",x):x.emit("onSlidePrevStart",x)))},x.onTransitionEnd=function(e){x.animating=!1,x.setWrapperTransition(0),void 0===e&&(e=!0),x.lazy&&x.lazy.onTransitionEnd(),e&&(x.emit("onTransitionEnd",x),x.activeIndex!==x.previousIndex&&(x.emit("onSlideChangeEnd",x),x.activeIndex>x.previousIndex?x.emit("onSlideNextEnd",x):x.emit("onSlidePrevEnd",x))),x.params.history&&x.history&&x.history.setHistory(x.params.history,x.activeIndex),x.params.hashnav&&x.hashnav&&x.hashnav.setHash()},x.slideNext=function(e,a,t){if(x.params.loop){if(x.animating)return!1;x.fixLoop();x.container[0].clientLeft;return x.slideTo(x.activeIndex+x.params.slidesPerGroup,a,e,t)}return x.slideTo(x.activeIndex+x.params.slidesPerGroup,a,e,t)},x._slideNext=function(e){return x.slideNext(!0,e,!0)},x.slidePrev=function(e,a,t){if(x.params.loop){if(x.animating)return!1;x.fixLoop();x.container[0].clientLeft;return x.slideTo(x.activeIndex-1,a,e,t)}return x.slideTo(x.activeIndex-1,a,e,t)},x._slidePrev=function(e){return x.slidePrev(!0,e,!0)},x.slideReset=function(e,a,t){return x.slideTo(x.activeIndex,a,e)},x.disableTouchControl=function(){return x.params.onlyExternal=!0,!0},x.enableTouchControl=function(){return x.params.onlyExternal=!1,!0},x.setWrapperTransition=function(e,a){x.wrapper.transition(e),"slide"!==x.params.effect&&x.effects[x.params.effect]&&x.effects[x.params.effect].setTransition(e),x.params.parallax&&x.parallax&&x.parallax.setTransition(e),x.params.scrollbar&&x.scrollbar&&x.scrollbar.setTransition(e),x.params.control&&x.controller&&x.controller.setTransition(e,a),x.emit("onSetTransition",x,e)},x.setWrapperTranslate=function(e,a,t){var s=0,i=0;x.isHorizontal()?s=x.rtl?-e:e:i=e,x.params.roundLengths&&(s=r(s),i=r(i)),x.params.virtualTranslate||(x.support.transforms3d?x.wrapper.transform("translate3d("+s+"px, "+i+"px, 0px)"):x.wrapper.transform("translate("+s+"px, "+i+"px)")),x.translate=x.isHorizontal()?s:i;var n=x.maxTranslate()-x.minTranslate();(0===n?0:(e-x.minTranslate())/n)!==x.progress&&x.updateProgress(e),a&&x.updateActiveIndex(),"slide"!==x.params.effect&&x.effects[x.params.effect]&&x.effects[x.params.effect].setTranslate(x.translate),x.params.parallax&&x.parallax&&x.parallax.setTranslate(x.translate),x.params.scrollbar&&x.scrollbar&&x.scrollbar.setTranslate(x.translate),x.params.control&&x.controller&&x.controller.setTranslate(x.translate,t),x.emit("onSetTranslate",x,x.translate)},x.getTranslate=function(e,a){var t,s,i,r;return void 0===a&&(a="x"),x.params.virtualTranslate?x.rtl?-x.translate:x.translate:(i=window.getComputedStyle(e,null),window.WebKitCSSMatrix?((s=i.transform||i.webkitTransform).split(",").length>6&&(s=s.split(", ").map(function(e){return e.replace(",",".")}).join(", ")),r=new window.WebKitCSSMatrix("none"===s?"":s)):t=(r=i.MozTransform||i.OTransform||i.MsTransform||i.msTransform||i.transform||i.getPropertyValue("transform").replace("translate(","matrix(1, 0, 0, 1,")).toString().split(","),"x"===a&&(s=window.WebKitCSSMatrix?r.m41:16===t.length?parseFloat(t[12]):parseFloat(t[4])),"y"===a&&(s=window.WebKitCSSMatrix?r.m42:16===t.length?parseFloat(t[13]):parseFloat(t[5])),x.rtl&&s&&(s=-s),s||0)},x.getWrapperTranslate=function(e){return void 0===e&&(e=x.isHorizontal()?"x":"y"),x.getTranslate(x.wrapper[0],e)},x.observers=[],x.initObservers=function(){if(x.params.observeParents)for(var e=x.container.parents(),a=0;a<e.length;a++)l(e[a]);l(x.container[0],{childList:!1}),l(x.wrapper[0],{attributes:!1})},x.disconnectObservers=function(){for(var e=0;e<x.observers.length;e++)x.observers[e].disconnect();x.observers=[]},x.createLoop=function(){x.wrapper.children("."+x.params.slideClass+"."+x.params.slideDuplicateClass).remove();var a=x.wrapper.children("."+x.params.slideClass);"auto"!==x.params.slidesPerView||x.params.loopedSlides||(x.params.loopedSlides=a.length),x.loopedSlides=parseInt(x.params.loopedSlides||x.params.slidesPerView,10),x.loopedSlides=x.loopedSlides+x.params.loopAdditionalSlides,x.loopedSlides>a.length&&(x.loopedSlides=a.length);var t,s=[],i=[];for(a.each(function(t,r){var n=e(this);t<x.loopedSlides&&i.push(r),t<a.length&&t>=a.length-x.loopedSlides&&s.push(r),n.attr("data-swiper-slide-index",t)}),t=0;t<i.length;t++)x.wrapper.append(e(i[t].cloneNode(!0)).addClass(x.params.slideDuplicateClass));for(t=s.length-1;t>=0;t--)x.wrapper.prepend(e(s[t].cloneNode(!0)).addClass(x.params.slideDuplicateClass))},x.destroyLoop=function(){x.wrapper.children("."+x.params.slideClass+"."+x.params.slideDuplicateClass).remove(),x.slides.removeAttr("data-swiper-slide-index")},x.reLoop=function(e){var a=x.activeIndex-x.loopedSlides;x.destroyLoop(),x.createLoop(),x.updateSlidesSize(),e&&x.slideTo(a+x.loopedSlides,0,!1)},x.fixLoop=function(){var e;x.activeIndex<x.loopedSlides?(e=x.slides.length-3*x.loopedSlides+x.activeIndex,e+=x.loopedSlides,x.slideTo(e,0,!1,!0)):("auto"===x.params.slidesPerView&&x.activeIndex>=2*x.loopedSlides||x.activeIndex>x.slides.length-2*x.params.slidesPerView)&&(e=-x.slides.length+x.activeIndex+x.loopedSlides,e+=x.loopedSlides,x.slideTo(e,0,!1,!0))},x.appendSlide=function(e){if(x.params.loop&&x.destroyLoop(),"object"==typeof e&&e.length)for(var a=0;a<e.length;a++)e[a]&&x.wrapper.append(e[a]);else x.wrapper.append(e);x.params.loop&&x.createLoop(),x.params.observer&&x.support.observer||x.update(!0)},x.prependSlide=function(e){x.params.loop&&x.destroyLoop();var a=x.activeIndex+1;if("object"==typeof e&&e.length){for(var t=0;t<e.length;t++)e[t]&&x.wrapper.prepend(e[t]);a=x.activeIndex+e.length}else x.wrapper.prepend(e);x.params.loop&&x.createLoop(),x.params.observer&&x.support.observer||x.update(!0),x.slideTo(a,0,!1)},x.removeSlide=function(e){x.params.loop&&(x.destroyLoop(),x.slides=x.wrapper.children("."+x.params.slideClass));var a,t=x.activeIndex;if("object"==typeof e&&e.length){for(var s=0;s<e.length;s++)a=e[s],x.slides[a]&&x.slides.eq(a).remove(),a<t&&t--;t=Math.max(t,0)}else a=e,x.slides[a]&&x.slides.eq(a).remove(),a<t&&t--,t=Math.max(t,0);x.params.loop&&x.createLoop(),x.params.observer&&x.support.observer||x.update(!0),x.params.loop?x.slideTo(t+x.loopedSlides,0,!1):x.slideTo(t,0,!1)},x.removeAllSlides=function(){for(var e=[],a=0;a<x.slides.length;a++)e.push(a);x.removeSlide(e)},x.effects={fade:{setTranslate:function(){for(var e=0;e<x.slides.length;e++){var a=x.slides.eq(e),t=-a[0].swiperSlideOffset;x.params.virtualTranslate||(t-=x.translate);var s=0;x.isHorizontal()||(s=t,t=0);var i=x.params.fade.crossFade?Math.max(1-Math.abs(a[0].progress),0):1+Math.min(Math.max(a[0].progress,-1),0);a.css({opacity:i}).transform("translate3d("+t+"px, "+s+"px, 0px)")}},setTransition:function(e){if(x.slides.transition(e),x.params.virtualTranslate&&0!==e){var a=!1;x.slides.transitionEnd(function(){if(!a&&x){a=!0,x.animating=!1;for(var e=["webkitTransitionEnd","transitionend","oTransitionEnd","MSTransitionEnd","msTransitionEnd"],t=0;t<e.length;t++)x.wrapper.trigger(e[t])}})}}},flip:{setTranslate:function(){for(var a=0;a<x.slides.length;a++){var t=x.slides.eq(a),s=t[0].progress;x.params.flip.limitRotation&&(s=Math.max(Math.min(t[0].progress,1),-1));var i=-180*s,r=0,n=-t[0].swiperSlideOffset,o=0;if(x.isHorizontal()?x.rtl&&(i=-i):(o=n,n=0,r=-i,i=0),t[0].style.zIndex=-Math.abs(Math.round(s))+x.slides.length,x.params.flip.slideShadows){var l=x.isHorizontal()?t.find(".swiper-slide-shadow-left"):t.find(".swiper-slide-shadow-top"),p=x.isHorizontal()?t.find(".swiper-slide-shadow-right"):t.find(".swiper-slide-shadow-bottom");0===l.length&&(l=e('<div class="swiper-slide-shadow-'+(x.isHorizontal()?"left":"top")+'"></div>'),t.append(l)),0===p.length&&(p=e('<div class="swiper-slide-shadow-'+(x.isHorizontal()?"right":"bottom")+'"></div>'),t.append(p)),l.length&&(l[0].style.opacity=Math.max(-s,0)),p.length&&(p[0].style.opacity=Math.max(s,0))}t.transform("translate3d("+n+"px, "+o+"px, 0px) rotateX("+r+"deg) rotateY("+i+"deg)")}},setTransition:function(a){if(x.slides.transition(a).find(".swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left").transition(a),x.params.virtualTranslate&&0!==a){var t=!1;x.slides.eq(x.activeIndex).transitionEnd(function(){if(!t&&x&&e(this).hasClass(x.params.slideActiveClass)){t=!0,x.animating=!1;for(var a=["webkitTransitionEnd","transitionend","oTransitionEnd","MSTransitionEnd","msTransitionEnd"],s=0;s<a.length;s++)x.wrapper.trigger(a[s])}})}}},cube:{setTranslate:function(){var a,t=0;x.params.cube.shadow&&(x.isHorizontal()?(0===(a=x.wrapper.find(".swiper-cube-shadow")).length&&(a=e('<div class="swiper-cube-shadow"></div>'),x.wrapper.append(a)),a.css({height:x.width+"px"})):0===(a=x.container.find(".swiper-cube-shadow")).length&&(a=e('<div class="swiper-cube-shadow"></div>'),x.container.append(a)));for(var s=0;s<x.slides.length;s++){var i=x.slides.eq(s),r=90*s,n=Math.floor(r/360);x.rtl&&(r=-r,n=Math.floor(-r/360));var o=Math.max(Math.min(i[0].progress,1),-1),l=0,p=0,d=0;s%4==0?(l=4*-n*x.size,d=0):(s-1)%4==0?(l=0,d=4*-n*x.size):(s-2)%4==0?(l=x.size+4*n*x.size,d=x.size):(s-3)%4==0&&(l=-x.size,d=3*x.size+4*x.size*n),x.rtl&&(l=-l),x.isHorizontal()||(p=l,l=0);var u="rotateX("+(x.isHorizontal()?0:-r)+"deg) rotateY("+(x.isHorizontal()?r:0)+"deg) translate3d("+l+"px, "+p+"px, "+d+"px)";if(o<=1&&o>-1&&(t=90*s+90*o,x.rtl&&(t=90*-s-90*o)),i.transform(u),x.params.cube.slideShadows){var c=x.isHorizontal()?i.find(".swiper-slide-shadow-left"):i.find(".swiper-slide-shadow-top"),m=x.isHorizontal()?i.find(".swiper-slide-shadow-right"):i.find(".swiper-slide-shadow-bottom");0===c.length&&(c=e('<div class="swiper-slide-shadow-'+(x.isHorizontal()?"left":"top")+'"></div>'),i.append(c)),0===m.length&&(m=e('<div class="swiper-slide-shadow-'+(x.isHorizontal()?"right":"bottom")+'"></div>'),i.append(m)),c.length&&(c[0].style.opacity=Math.max(-o,0)),m.length&&(m[0].style.opacity=Math.max(o,0))}}if(x.wrapper.css({"-webkit-transform-origin":"50% 50% -"+x.size/2+"px","-moz-transform-origin":"50% 50% -"+x.size/2+"px","-ms-transform-origin":"50% 50% -"+x.size/2+"px","transform-origin":"50% 50% -"+x.size/2+"px"}),x.params.cube.shadow)if(x.isHorizontal())a.transform("translate3d(0px, "+(x.width/2+x.params.cube.shadowOffset)+"px, "+-x.width/2+"px) rotateX(90deg) rotateZ(0deg) scale("+x.params.cube.shadowScale+")");else{var h=Math.abs(t)-90*Math.floor(Math.abs(t)/90),g=1.5-(Math.sin(2*h*Math.PI/360)/2+Math.cos(2*h*Math.PI/360)/2),f=x.params.cube.shadowScale,v=x.params.cube.shadowScale/g,w=x.params.cube.shadowOffset;a.transform("scale3d("+f+", 1, "+v+") translate3d(0px, "+(x.height/2+w)+"px, "+-x.height/2/v+"px) rotateX(-90deg)")}var y=x.isSafari||x.isUiWebView?-x.size/2:0;x.wrapper.transform("translate3d(0px,0,"+y+"px) rotateX("+(x.isHorizontal()?0:t)+"deg) rotateY("+(x.isHorizontal()?-t:0)+"deg)")},setTransition:function(e){x.slides.transition(e).find(".swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left").transition(e),x.params.cube.shadow&&!x.isHorizontal()&&x.container.find(".swiper-cube-shadow").transition(e)}},coverflow:{setTranslate:function(){for(var a=x.translate,t=x.isHorizontal()?-a+x.width/2:-a+x.height/2,s=x.isHorizontal()?x.params.coverflow.rotate:-x.params.coverflow.rotate,i=x.params.coverflow.depth,r=0,n=x.slides.length;r<n;r++){var o=x.slides.eq(r),l=x.slidesSizesGrid[r],p=(t-o[0].swiperSlideOffset-l/2)/l*x.params.coverflow.modifier,d=x.isHorizontal()?s*p:0,u=x.isHorizontal()?0:s*p,c=-i*Math.abs(p),m=x.isHorizontal()?0:x.params.coverflow.stretch*p,h=x.isHorizontal()?x.params.coverflow.stretch*p:0;Math.abs(h)<.001&&(h=0),Math.abs(m)<.001&&(m=0),Math.abs(c)<.001&&(c=0),Math.abs(d)<.001&&(d=0),Math.abs(u)<.001&&(u=0);var g="translate3d("+h+"px,"+m+"px,"+c+"px)  rotateX("+u+"deg) rotateY("+d+"deg)";if(o.transform(g),o[0].style.zIndex=1-Math.abs(Math.round(p)),x.params.coverflow.slideShadows){var f=x.isHorizontal()?o.find(".swiper-slide-shadow-left"):o.find(".swiper-slide-shadow-top"),v=x.isHorizontal()?o.find(".swiper-slide-shadow-right"):o.find(".swiper-slide-shadow-bottom");0===f.length&&(f=e('<div class="swiper-slide-shadow-'+(x.isHorizontal()?"left":"top")+'"></div>'),o.append(f)),0===v.length&&(v=e('<div class="swiper-slide-shadow-'+(x.isHorizontal()?"right":"bottom")+'"></div>'),o.append(v)),f.length&&(f[0].style.opacity=p>0?p:0),v.length&&(v[0].style.opacity=-p>0?-p:0)}}if(x.browser.ie){x.wrapper[0].style.perspectiveOrigin=t+"px 50%"}},setTransition:function(e){x.slides.transition(e).find(".swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left").transition(e)}}},x.lazy={initialImageLoaded:!1,loadImageInSlide:function(a,t){if(void 0!==a&&(void 0===t&&(t=!0),0!==x.slides.length)){var s=x.slides.eq(a),i=s.find("."+x.params.lazyLoadingClass+":not(."+x.params.lazyStatusLoadedClass+"):not(."+x.params.lazyStatusLoadingClass+")");!s.hasClass(x.params.lazyLoadingClass)||s.hasClass(x.params.lazyStatusLoadedClass)||s.hasClass(x.params.lazyStatusLoadingClass)||(i=i.add(s[0])),0!==i.length&&i.each(function(){var a=e(this);a.addClass(x.params.lazyStatusLoadingClass);var i=a.attr("data-background"),r=a.attr("data-src"),n=a.attr("data-srcset"),o=a.attr("data-sizes");x.loadImage(a[0],r||i,n,o,!1,function(){if(void 0!==x&&null!==x&&x){if(i?(a.css("background-image",'url("'+i+'")'),a.removeAttr("data-background")):(n&&(a.attr("srcset",n),a.removeAttr("data-srcset")),o&&(a.attr("sizes",o),a.removeAttr("data-sizes")),r&&(a.attr("src",r),a.removeAttr("data-src"))),a.addClass(x.params.lazyStatusLoadedClass).removeClass(x.params.lazyStatusLoadingClass),s.find("."+x.params.lazyPreloaderClass+", ."+x.params.preloaderClass).remove(),x.params.loop&&t){var e=s.attr("data-swiper-slide-index");if(s.hasClass(x.params.slideDuplicateClass)){var l=x.wrapper.children('[data-swiper-slide-index="'+e+'"]:not(.'+x.params.slideDuplicateClass+")");x.lazy.loadImageInSlide(l.index(),!1)}else{var p=x.wrapper.children("."+x.params.slideDuplicateClass+'[data-swiper-slide-index="'+e+'"]');x.lazy.loadImageInSlide(p.index(),!1)}}x.emit("onLazyImageReady",x,s[0],a[0])}}),x.emit("onLazyImageLoad",x,s[0],a[0])})}},load:function(){var a,t=x.params.slidesPerView;if("auto"===t&&(t=0),x.lazy.initialImageLoaded||(x.lazy.initialImageLoaded=!0),x.params.watchSlidesVisibility)x.wrapper.children("."+x.params.slideVisibleClass).each(function(){x.lazy.loadImageInSlide(e(this).index())});else if(t>1)for(a=x.activeIndex;a<x.activeIndex+t;a++)x.slides[a]&&x.lazy.loadImageInSlide(a);else x.lazy.loadImageInSlide(x.activeIndex);if(x.params.lazyLoadingInPrevNext)if(t>1||x.params.lazyLoadingInPrevNextAmount&&x.params.lazyLoadingInPrevNextAmount>1){var s=x.params.lazyLoadingInPrevNextAmount,i=t,r=Math.min(x.activeIndex+i+Math.max(s,i),x.slides.length),n=Math.max(x.activeIndex-Math.max(i,s),0);for(a=x.activeIndex+t;a<r;a++)x.slides[a]&&x.lazy.loadImageInSlide(a);for(a=n;a<x.activeIndex;a++)x.slides[a]&&x.lazy.loadImageInSlide(a)}else{var o=x.wrapper.children("."+x.params.slideNextClass);o.length>0&&x.lazy.loadImageInSlide(o.index());var l=x.wrapper.children("."+x.params.slidePrevClass);l.length>0&&x.lazy.loadImageInSlide(l.index())}},onTransitionStart:function(){x.params.lazyLoading&&(x.params.lazyLoadingOnTransitionStart||!x.params.lazyLoadingOnTransitionStart&&!x.lazy.initialImageLoaded)&&x.lazy.load()},onTransitionEnd:function(){x.params.lazyLoading&&!x.params.lazyLoadingOnTransitionStart&&x.lazy.load()}},x.scrollbar={isTouched:!1,setDragPosition:function(e){var a=x.scrollbar,t=(x.isHorizontal()?"touchstart"===e.type||"touchmove"===e.type?e.targetTouches[0].pageX:e.pageX||e.clientX:"touchstart"===e.type||"touchmove"===e.type?e.targetTouches[0].pageY:e.pageY||e.clientY)-a.track.offset()[x.isHorizontal()?"left":"top"]-a.dragSize/2,s=-x.minTranslate()*a.moveDivider,i=-x.maxTranslate()*a.moveDivider;t<s?t=s:t>i&&(t=i),t=-t/a.moveDivider,x.updateProgress(t),x.setWrapperTranslate(t,!0)},dragStart:function(e){var a=x.scrollbar;a.isTouched=!0,e.preventDefault(),e.stopPropagation(),a.setDragPosition(e),clearTimeout(a.dragTimeout),a.track.transition(0),x.params.scrollbarHide&&a.track.css("opacity",1),x.wrapper.transition(100),a.drag.transition(100),x.emit("onScrollbarDragStart",x)},dragMove:function(e){var a=x.scrollbar;a.isTouched&&(e.preventDefault?e.preventDefault():e.returnValue=!1,a.setDragPosition(e),x.wrapper.transition(0),a.track.transition(0),a.drag.transition(0),x.emit("onScrollbarDragMove",x))},dragEnd:function(e){var a=x.scrollbar;a.isTouched&&(a.isTouched=!1,x.params.scrollbarHide&&(clearTimeout(a.dragTimeout),a.dragTimeout=setTimeout(function(){a.track.css("opacity",0),a.track.transition(400)},1e3)),x.emit("onScrollbarDragEnd",x),x.params.scrollbarSnapOnRelease&&x.slideReset())},draggableEvents:!1!==x.params.simulateTouch||x.support.touch?x.touchEvents:x.touchEventsDesktop,enableDraggable:function(){var a=x.scrollbar,t=x.support.touch?a.track:document;e(a.track).on(a.draggableEvents.start,a.dragStart),e(t).on(a.draggableEvents.move,a.dragMove),e(t).on(a.draggableEvents.end,a.dragEnd)},disableDraggable:function(){var a=x.scrollbar,t=x.support.touch?a.track:document;e(a.track).off(a.draggableEvents.start,a.dragStart),e(t).off(a.draggableEvents.move,a.dragMove),e(t).off(a.draggableEvents.end,a.dragEnd)},set:function(){if(x.params.scrollbar){var a=x.scrollbar;a.track=e(x.params.scrollbar),x.params.uniqueNavElements&&"string"==typeof x.params.scrollbar&&a.track.length>1&&1===x.container.find(x.params.scrollbar).length&&(a.track=x.container.find(x.params.scrollbar)),a.drag=a.track.find(".swiper-scrollbar-drag"),0===a.drag.length&&(a.drag=e('<div class="swiper-scrollbar-drag"></div>'),a.track.append(a.drag)),a.drag[0].style.width="",a.drag[0].style.height="",a.trackSize=x.isHorizontal()?a.track[0].offsetWidth:a.track[0].offsetHeight,a.divider=x.size/x.virtualSize,a.moveDivider=a.divider*(a.trackSize/x.size),a.dragSize=a.trackSize*a.divider,x.isHorizontal()?a.drag[0].style.width=a.dragSize+"px":a.drag[0].style.height=a.dragSize+"px",a.divider>=1?a.track[0].style.display="none":a.track[0].style.display="",x.params.scrollbarHide&&(a.track[0].style.opacity=0)}},setTranslate:function(){if(x.params.scrollbar){var e,a=x.scrollbar,t=(x.translate,a.dragSize);e=(a.trackSize-a.dragSize)*x.progress,x.rtl&&x.isHorizontal()?(e=-e)>0?(t=a.dragSize-e,e=0):-e+a.dragSize>a.trackSize&&(t=a.trackSize+e):e<0?(t=a.dragSize+e,e=0):e+a.dragSize>a.trackSize&&(t=a.trackSize-e),x.isHorizontal()?(x.support.transforms3d?a.drag.transform("translate3d("+e+"px, 0, 0)"):a.drag.transform("translateX("+e+"px)"),a.drag[0].style.width=t+"px"):(x.support.transforms3d?a.drag.transform("translate3d(0px, "+e+"px, 0)"):a.drag.transform("translateY("+e+"px)"),a.drag[0].style.height=t+"px"),x.params.scrollbarHide&&(clearTimeout(a.timeout),a.track[0].style.opacity=1,a.timeout=setTimeout(function(){a.track[0].style.opacity=0,a.track.transition(400)},1e3))}},setTransition:function(e){x.params.scrollbar&&x.scrollbar.drag.transition(e)}},x.controller={LinearSpline:function(e,a){var t=function(){var e,a,t;return function(s,i){for(a=-1,e=s.length;e-a>1;)s[t=e+a>>1]<=i?a=t:e=t;return e}}();this.x=e,this.y=a,this.lastIndex=e.length-1;var s,i;this.x.length;this.interpolate=function(e){return e?(i=t(this.x,e),s=i-1,(e-this.x[s])*(this.y[i]-this.y[s])/(this.x[i]-this.x[s])+this.y[s]):0}},getInterpolateFunction:function(e){x.controller.spline||(x.controller.spline=x.params.loop?new x.controller.LinearSpline(x.slidesGrid,e.slidesGrid):new x.controller.LinearSpline(x.snapGrid,e.snapGrid))},setTranslate:function(e,t){function s(a){e=a.rtl&&"horizontal"===a.params.direction?-x.translate:x.translate,"slide"===x.params.controlBy&&(x.controller.getInterpolateFunction(a),r=-x.controller.spline.interpolate(-e)),r&&"container"!==x.params.controlBy||(i=(a.maxTranslate()-a.minTranslate())/(x.maxTranslate()-x.minTranslate()),r=(e-x.minTranslate())*i+a.minTranslate()),x.params.controlInverse&&(r=a.maxTranslate()-r),a.updateProgress(r),a.setWrapperTranslate(r,!1,x),a.updateActiveIndex()}var i,r,n=x.params.control;if(Array.isArray(n))for(var o=0;o<n.length;o++)n[o]!==t&&n[o]instanceof a&&s(n[o]);else n instanceof a&&t!==n&&s(n)},setTransition:function(e,t){function s(a){a.setWrapperTransition(e,x),0!==e&&(a.onTransitionStart(),a.wrapper.transitionEnd(function(){r&&(a.params.loop&&"slide"===x.params.controlBy&&a.fixLoop(),a.onTransitionEnd())}))}var i,r=x.params.control;if(Array.isArray(r))for(i=0;i<r.length;i++)r[i]!==t&&r[i]instanceof a&&s(r[i]);else r instanceof a&&t!==r&&s(r)}},x.hashnav={onHashCange:function(e,a){var t=document.location.hash.replace("#","");t!==x.slides.eq(x.activeIndex).attr("data-hash")&&x.slideTo(x.wrapper.children("."+x.params.slideClass+'[data-hash="'+t+'"]').index())},attachEvents:function(a){var t=a?"off":"on";e(window)[t]("hashchange",x.hashnav.onHashCange)},setHash:function(){if(x.hashnav.initialized&&x.params.hashnav)if(x.params.replaceState&&window.history&&window.history.replaceState)window.history.replaceState(null,null,"#"+x.slides.eq(x.activeIndex).attr("data-hash")||"");else{var e=x.slides.eq(x.activeIndex),a=e.attr("data-hash")||e.attr("data-history");document.location.hash=a||""}},init:function(){if(x.params.hashnav&&!x.params.history){x.hashnav.initialized=!0;var e=document.location.hash.replace("#","");if(e)for(var a=0,t=x.slides.length;a<t;a++){var s=x.slides.eq(a);if((s.attr("data-hash")||s.attr("data-history"))===e&&!s.hasClass(x.params.slideDuplicateClass)){var i=s.index();x.slideTo(i,0,x.params.runCallbacksOnInit,!0)}}x.params.hashnavWatchState&&x.hashnav.attachEvents()}},destroy:function(){x.params.hashnavWatchState&&x.hashnav.attachEvents(!0)}},x.history={init:function(){if(x.params.history){if(!window.history||!window.history.pushState)return x.params.history=!1,void(x.params.hashnav=!0);x.history.initialized=!0,this.paths=this.getPathValues(),(this.paths.key||this.paths.value)&&(this.scrollToSlide(0,this.paths.value,x.params.runCallbacksOnInit),x.params.replaceState||window.addEventListener("popstate",this.setHistoryPopState))}},setHistoryPopState:function(){x.history.paths=x.history.getPathValues(),x.history.scrollToSlide(x.params.speed,x.history.paths.value,!1)},getPathValues:function(){var e=window.location.pathname.slice(1).split("/"),a=e.length;return{key:e[a-2],value:e[a-1]}},setHistory:function(e,a){if(x.history.initialized&&x.params.history){var t=x.slides.eq(a),s=this.slugify(t.attr("data-history"));window.location.pathname.includes(e)||(s=e+"/"+s),x.params.replaceState?window.history.replaceState(null,null,s):window.history.pushState(null,null,s)}},slugify:function(e){return e.toString().toLowerCase().replace(/\s+/g,"-").replace(/[^\w\-]+/g,"").replace(/\-\-+/g,"-").replace(/^-+/,"").replace(/-+$/,"")},scrollToSlide:function(e,a,t){if(a)for(var s=0,i=x.slides.length;s<i;s++){var r=x.slides.eq(s);if(this.slugify(r.attr("data-history"))===a&&!r.hasClass(x.params.slideDuplicateClass)){var n=r.index();x.slideTo(n,e,t)}}else x.slideTo(0,e,t)}},x.disableKeyboardControl=function(){x.params.keyboardControl=!1,e(document).off("keydown",p)},x.enableKeyboardControl=function(){x.params.keyboardControl=!0,e(document).on("keydown",p)},x.mousewheel={event:!1,lastScrollTime:(new window.Date).getTime()},x.params.mousewheelControl&&(x.mousewheel.event=navigator.userAgent.indexOf("firefox")>-1?"DOMMouseScroll":function(){var e="onwheel"in document;if(!e){var a=document.createElement("div");a.setAttribute("onwheel","return;"),e="function"==typeof a.onwheel}return!e&&document.implementation&&document.implementation.hasFeature&&!0!==document.implementation.hasFeature("","")&&(e=document.implementation.hasFeature("Events.wheel","3.0")),e}()?"wheel":"mousewheel"),x.disableMousewheelControl=function(){if(!x.mousewheel.event)return!1;var a=x.container;return"container"!==x.params.mousewheelEventsTarged&&(a=e(x.params.mousewheelEventsTarged)),a.off(x.mousewheel.event,d),x.params.mousewheelControl=!1,!0},x.enableMousewheelControl=function(){if(!x.mousewheel.event)return!1;var a=x.container;return"container"!==x.params.mousewheelEventsTarged&&(a=e(x.params.mousewheelEventsTarged)),a.on(x.mousewheel.event,d),x.params.mousewheelControl=!0,!0},x.parallax={setTranslate:function(){x.container.children("[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]").each(function(){u(this,x.progress)}),x.slides.each(function(){var a=e(this);a.find("[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]").each(function(){u(this,Math.min(Math.max(a[0].progress,-1),1))})})},setTransition:function(a){void 0===a&&(a=x.params.speed),x.container.find("[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]").each(function(){var t=e(this),s=parseInt(t.attr("data-swiper-parallax-duration"),10)||a;0===a&&(s=0),t.transition(s)})}},x.zoom={scale:1,currentScale:1,isScaling:!1,gesture:{slide:void 0,slideWidth:void 0,slideHeight:void 0,image:void 0,imageWrap:void 0,zoomMax:x.params.zoomMax},image:{isTouched:void 0,isMoved:void 0,currentX:void 0,currentY:void 0,minX:void 0,minY:void 0,maxX:void 0,maxY:void 0,width:void 0,height:void 0,startX:void 0,startY:void 0,touchesStart:{},touchesCurrent:{}},velocity:{x:void 0,y:void 0,prevPositionX:void 0,prevPositionY:void 0,prevTime:void 0},getDistanceBetweenTouches:function(e){if(e.targetTouches.length<2)return 1;var a=e.targetTouches[0].pageX,t=e.targetTouches[0].pageY,s=e.targetTouches[1].pageX,i=e.targetTouches[1].pageY;return Math.sqrt(Math.pow(s-a,2)+Math.pow(i-t,2))},onGestureStart:function(a){var t=x.zoom;if(!x.support.gestures){if("touchstart"!==a.type||"touchstart"===a.type&&a.targetTouches.length<2)return;t.gesture.scaleStart=t.getDistanceBetweenTouches(a)}t.gesture.slide&&t.gesture.slide.length||(t.gesture.slide=e(this),0===t.gesture.slide.length&&(t.gesture.slide=x.slides.eq(x.activeIndex)),t.gesture.image=t.gesture.slide.find("img, svg, canvas"),t.gesture.imageWrap=t.gesture.image.parent("."+x.params.zoomContainerClass),t.gesture.zoomMax=t.gesture.imageWrap.attr("data-swiper-zoom")||x.params.zoomMax,0!==t.gesture.imageWrap.length)?(t.gesture.image.transition(0),t.isScaling=!0):t.gesture.image=void 0},onGestureChange:function(e){var a=x.zoom;if(!x.support.gestures){if("touchmove"!==e.type||"touchmove"===e.type&&e.targetTouches.length<2)return;a.gesture.scaleMove=a.getDistanceBetweenTouches(e)}a.gesture.image&&0!==a.gesture.image.length&&(x.support.gestures?a.scale=e.scale*a.currentScale:a.scale=a.gesture.scaleMove/a.gesture.scaleStart*a.currentScale,a.scale>a.gesture.zoomMax&&(a.scale=a.gesture.zoomMax-1+Math.pow(a.scale-a.gesture.zoomMax+1,.5)),a.scale<x.params.zoomMin&&(a.scale=x.params.zoomMin+1-Math.pow(x.params.zoomMin-a.scale+1,.5)),a.gesture.image.transform("translate3d(0,0,0) scale("+a.scale+")"))},onGestureEnd:function(e){var a=x.zoom;!x.support.gestures&&("touchend"!==e.type||"touchend"===e.type&&e.changedTouches.length<2)||a.gesture.image&&0!==a.gesture.image.length&&(a.scale=Math.max(Math.min(a.scale,a.gesture.zoomMax),x.params.zoomMin),a.gesture.image.transition(x.params.speed).transform("translate3d(0,0,0) scale("+a.scale+")"),a.currentScale=a.scale,a.isScaling=!1,1===a.scale&&(a.gesture.slide=void 0))},onTouchStart:function(e,a){var t=e.zoom;t.gesture.image&&0!==t.gesture.image.length&&(t.image.isTouched||("android"===e.device.os&&a.preventDefault(),t.image.isTouched=!0,t.image.touchesStart.x="touchstart"===a.type?a.targetTouches[0].pageX:a.pageX,t.image.touchesStart.y="touchstart"===a.type?a.targetTouches[0].pageY:a.pageY))},onTouchMove:function(e){var a=x.zoom;if(a.gesture.image&&0!==a.gesture.image.length&&(x.allowClick=!1,a.image.isTouched&&a.gesture.slide)){a.image.isMoved||(a.image.width=a.gesture.image[0].offsetWidth,a.image.height=a.gesture.image[0].offsetHeight,a.image.startX=x.getTranslate(a.gesture.imageWrap[0],"x")||0,a.image.startY=x.getTranslate(a.gesture.imageWrap[0],"y")||0,a.gesture.slideWidth=a.gesture.slide[0].offsetWidth,a.gesture.slideHeight=a.gesture.slide[0].offsetHeight,a.gesture.imageWrap.transition(0),x.rtl&&(a.image.startX=-a.image.startX),x.rtl&&(a.image.startY=-a.image.startY));var t=a.image.width*a.scale,s=a.image.height*a.scale;if(!(t<a.gesture.slideWidth&&s<a.gesture.slideHeight)){if(a.image.minX=Math.min(a.gesture.slideWidth/2-t/2,0),a.image.maxX=-a.image.minX,a.image.minY=Math.min(a.gesture.slideHeight/2-s/2,0),a.image.maxY=-a.image.minY,a.image.touchesCurrent.x="touchmove"===e.type?e.targetTouches[0].pageX:e.pageX,a.image.touchesCurrent.y="touchmove"===e.type?e.targetTouches[0].pageY:e.pageY,!a.image.isMoved&&!a.isScaling){if(x.isHorizontal()&&Math.floor(a.image.minX)===Math.floor(a.image.startX)&&a.image.touchesCurrent.x<a.image.touchesStart.x||Math.floor(a.image.maxX)===Math.floor(a.image.startX)&&a.image.touchesCurrent.x>a.image.touchesStart.x)return void(a.image.isTouched=!1);if(!x.isHorizontal()&&Math.floor(a.image.minY)===Math.floor(a.image.startY)&&a.image.touchesCurrent.y<a.image.touchesStart.y||Math.floor(a.image.maxY)===Math.floor(a.image.startY)&&a.image.touchesCurrent.y>a.image.touchesStart.y)return void(a.image.isTouched=!1)}e.preventDefault(),e.stopPropagation(),a.image.isMoved=!0,a.image.currentX=a.image.touchesCurrent.x-a.image.touchesStart.x+a.image.startX,a.image.currentY=a.image.touchesCurrent.y-a.image.touchesStart.y+a.image.startY,a.image.currentX<a.image.minX&&(a.image.currentX=a.image.minX+1-Math.pow(a.image.minX-a.image.currentX+1,.8)),a.image.currentX>a.image.maxX&&(a.image.currentX=a.image.maxX-1+Math.pow(a.image.currentX-a.image.maxX+1,.8)),a.image.currentY<a.image.minY&&(a.image.currentY=a.image.minY+1-Math.pow(a.image.minY-a.image.currentY+1,.8)),a.image.currentY>a.image.maxY&&(a.image.currentY=a.image.maxY-1+Math.pow(a.image.currentY-a.image.maxY+1,.8)),a.velocity.prevPositionX||(a.velocity.prevPositionX=a.image.touchesCurrent.x),a.velocity.prevPositionY||(a.velocity.prevPositionY=a.image.touchesCurrent.y),a.velocity.prevTime||(a.velocity.prevTime=Date.now()),a.velocity.x=(a.image.touchesCurrent.x-a.velocity.prevPositionX)/(Date.now()-a.velocity.prevTime)/2,a.velocity.y=(a.image.touchesCurrent.y-a.velocity.prevPositionY)/(Date.now()-a.velocity.prevTime)/2,Math.abs(a.image.touchesCurrent.x-a.velocity.prevPositionX)<2&&(a.velocity.x=0),Math.abs(a.image.touchesCurrent.y-a.velocity.prevPositionY)<2&&(a.velocity.y=0),a.velocity.prevPositionX=a.image.touchesCurrent.x,a.velocity.prevPositionY=a.image.touchesCurrent.y,a.velocity.prevTime=Date.now(),a.gesture.imageWrap.transform("translate3d("+a.image.currentX+"px, "+a.image.currentY+"px,0)")}}},onTouchEnd:function(e,a){var t=e.zoom;if(t.gesture.image&&0!==t.gesture.image.length){if(!t.image.isTouched||!t.image.isMoved)return t.image.isTouched=!1,void(t.image.isMoved=!1);t.image.isTouched=!1,t.image.isMoved=!1;var s=300,i=300,r=t.velocity.x*s,n=t.image.currentX+r,o=t.velocity.y*i,l=t.image.currentY+o;0!==t.velocity.x&&(s=Math.abs((n-t.image.currentX)/t.velocity.x)),0!==t.velocity.y&&(i=Math.abs((l-t.image.currentY)/t.velocity.y));var p=Math.max(s,i);t.image.currentX=n,t.image.currentY=l;var d=t.image.width*t.scale,u=t.image.height*t.scale;t.image.minX=Math.min(t.gesture.slideWidth/2-d/2,0),t.image.maxX=-t.image.minX,t.image.minY=Math.min(t.gesture.slideHeight/2-u/2,0),t.image.maxY=-t.image.minY,t.image.currentX=Math.max(Math.min(t.image.currentX,t.image.maxX),t.image.minX),t.image.currentY=Math.max(Math.min(t.image.currentY,t.image.maxY),t.image.minY),t.gesture.imageWrap.transition(p).transform("translate3d("+t.image.currentX+"px, "+t.image.currentY+"px,0)")}},onTransitionEnd:function(e){var a=e.zoom;a.gesture.slide&&e.previousIndex!==e.activeIndex&&(a.gesture.image.transform("translate3d(0,0,0) scale(1)"),a.gesture.imageWrap.transform("translate3d(0,0,0)"),a.gesture.slide=a.gesture.image=a.gesture.imageWrap=void 0,a.scale=a.currentScale=1)},toggleZoom:function(a,t){var s=a.zoom;if(s.gesture.slide||(s.gesture.slide=a.clickedSlide?e(a.clickedSlide):a.slides.eq(a.activeIndex),s.gesture.image=s.gesture.slide.find("img, svg, canvas"),s.gesture.imageWrap=s.gesture.image.parent("."+a.params.zoomContainerClass)),s.gesture.image&&0!==s.gesture.image.length){var i,r,n,o,l,p,d,u,c,m,h,g,f,v,w,y;void 0===s.image.touchesStart.x&&t?(i="touchend"===t.type?t.changedTouches[0].pageX:t.pageX,r="touchend"===t.type?t.changedTouches[0].pageY:t.pageY):(i=s.image.touchesStart.x,r=s.image.touchesStart.y),s.scale&&1!==s.scale?(s.scale=s.currentScale=1,s.gesture.imageWrap.transition(300).transform("translate3d(0,0,0)"),s.gesture.image.transition(300).transform("translate3d(0,0,0) scale(1)"),s.gesture.slide=void 0):(s.scale=s.currentScale=s.gesture.imageWrap.attr("data-swiper-zoom")||a.params.zoomMax,t?(w=s.gesture.slide[0].offsetWidth,y=s.gesture.slide[0].offsetHeight,n=s.gesture.slide.offset().left+w/2-i,o=s.gesture.slide.offset().top+y/2-r,d=s.gesture.image[0].offsetWidth,u=s.gesture.image[0].offsetHeight,c=d*s.scale,m=u*s.scale,f=-(h=Math.min(w/2-c/2,0)),v=-(g=Math.min(y/2-m/2,0)),l=n*s.scale,p=o*s.scale,l<h&&(l=h),l>f&&(l=f),p<g&&(p=g),p>v&&(p=v)):(l=0,p=0),s.gesture.imageWrap.transition(300).transform("translate3d("+l+"px, "+p+"px,0)"),s.gesture.image.transition(300).transform("translate3d(0,0,0) scale("+s.scale+")"))}},attachEvents:function(a){var t=a?"off":"on";if(x.params.zoom){x.slides;var s=!("touchstart"!==x.touchEvents.start||!x.support.passiveListener||!x.params.passiveListeners)&&{passive:!0,capture:!1};x.support.gestures?(x.slides[t]("gesturestart",x.zoom.onGestureStart,s),x.slides[t]("gesturechange",x.zoom.onGestureChange,s),x.slides[t]("gestureend",x.zoom.onGestureEnd,s)):"touchstart"===x.touchEvents.start&&(x.slides[t](x.touchEvents.start,x.zoom.onGestureStart,s),x.slides[t](x.touchEvents.move,x.zoom.onGestureChange,s),x.slides[t](x.touchEvents.end,x.zoom.onGestureEnd,s)),x[t]("touchStart",x.zoom.onTouchStart),x.slides.each(function(a,s){e(s).find("."+x.params.zoomContainerClass).length>0&&e(s)[t](x.touchEvents.move,x.zoom.onTouchMove)}),x[t]("touchEnd",x.zoom.onTouchEnd),x[t]("transitionEnd",x.zoom.onTransitionEnd),x.params.zoomToggle&&x.on("doubleTap",x.zoom.toggleZoom)}},init:function(){x.zoom.attachEvents()},destroy:function(){x.zoom.attachEvents(!0)}},x._plugins=[];for(var A in x.plugins){var Y=x.plugins[A](x,x.params[A]);Y&&x._plugins.push(Y)}return x.callPlugins=function(e){for(var a=0;a<x._plugins.length;a++)e in x._plugins[a]&&x._plugins[a][e](arguments[1],arguments[2],arguments[3],arguments[4],arguments[5])},x.emitterEventListeners={},x.emit=function(e){x.params[e]&&x.params[e](arguments[1],arguments[2],arguments[3],arguments[4],arguments[5]);var a;if(x.emitterEventListeners[e])for(a=0;a<x.emitterEventListeners[e].length;a++)x.emitterEventListeners[e][a](arguments[1],arguments[2],arguments[3],arguments[4],arguments[5]);x.callPlugins&&x.callPlugins(e,arguments[1],arguments[2],arguments[3],arguments[4],arguments[5])},x.on=function(e,a){return e=c(e),x.emitterEventListeners[e]||(x.emitterEventListeners[e]=[]),x.emitterEventListeners[e].push(a),x},x.off=function(e,a){var t;if(e=c(e),void 0===a)return x.emitterEventListeners[e]=[],x;if(x.emitterEventListeners[e]&&0!==x.emitterEventListeners[e].length){for(t=0;t<x.emitterEventListeners[e].length;t++)x.emitterEventListeners[e][t]===a&&x.emitterEventListeners[e].splice(t,1);return x}},x.once=function(e,a){e=c(e);var t=function(){a(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4]),x.off(e,t)};return x.on(e,t),x},x.a11y={makeFocusable:function(e){return e.attr("tabIndex","0"),e},addRole:function(e,a){return e.attr("role",a),e},addLabel:function(e,a){return e.attr("aria-label",a),e},disable:function(e){return e.attr("aria-disabled",!0),e},enable:function(e){return e.attr("aria-disabled",!1),e},onEnterKey:function(a){13===a.keyCode&&(e(a.target).is(x.params.nextButton)?(x.onClickNext(a),x.isEnd?x.a11y.notify(x.params.lastSlideMessage):x.a11y.notify(x.params.nextSlideMessage)):e(a.target).is(x.params.prevButton)&&(x.onClickPrev(a),x.isBeginning?x.a11y.notify(x.params.firstSlideMessage):x.a11y.notify(x.params.prevSlideMessage)),e(a.target).is("."+x.params.bulletClass)&&e(a.target)[0].click())},liveRegion:e('<span class="'+x.params.notificationClass+'" aria-live="assertive" aria-atomic="true"></span>'),notify:function(e){var a=x.a11y.liveRegion;0!==a.length&&(a.html(""),a.html(e))},init:function(){x.params.nextButton&&x.nextButton&&x.nextButton.length>0&&(x.a11y.makeFocusable(x.nextButton),x.a11y.addRole(x.nextButton,"button"),x.a11y.addLabel(x.nextButton,x.params.nextSlideMessage)),x.params.prevButton&&x.prevButton&&x.prevButton.length>0&&(x.a11y.makeFocusable(x.prevButton),x.a11y.addRole(x.prevButton,"button"),x.a11y.addLabel(x.prevButton,x.params.prevSlideMessage)),e(x.container).append(x.a11y.liveRegion)},initPagination:function(){x.params.pagination&&x.params.paginationClickable&&x.bullets&&x.bullets.length&&x.bullets.each(function(){var a=e(this);x.a11y.makeFocusable(a),x.a11y.addRole(a,"button"),x.a11y.addLabel(a,x.params.paginationBulletMessage.replace(/{{index}}/,a.index()+1))})},destroy:function(){x.a11y.liveRegion&&x.a11y.liveRegion.length>0&&x.a11y.liveRegion.remove()}},x.init=function(){x.params.loop&&x.createLoop(),x.updateContainerSize(),x.updateSlidesSize(),x.updatePagination(),x.params.scrollbar&&x.scrollbar&&(x.scrollbar.set(),x.params.scrollbarDraggable&&x.scrollbar.enableDraggable()),"slide"!==x.params.effect&&x.effects[x.params.effect]&&(x.params.loop||x.updateProgress(),x.effects[x.params.effect].setTranslate()),x.params.loop?x.slideTo(x.params.initialSlide+x.loopedSlides,0,x.params.runCallbacksOnInit):(x.slideTo(x.params.initialSlide,0,x.params.runCallbacksOnInit),0===x.params.initialSlide&&(x.parallax&&x.params.parallax&&x.parallax.setTranslate(),x.lazy&&x.params.lazyLoading&&(x.lazy.load(),x.lazy.initialImageLoaded=!0))),x.attachEvents(),x.params.observer&&x.support.observer&&x.initObservers(),x.params.preloadImages&&!x.params.lazyLoading&&x.preloadImages(),x.params.zoom&&x.zoom&&x.zoom.init(),x.params.autoplay&&x.startAutoplay(),x.params.keyboardControl&&x.enableKeyboardControl&&x.enableKeyboardControl(),x.params.mousewheelControl&&x.enableMousewheelControl&&x.enableMousewheelControl(),x.params.hashnavReplaceState&&(x.params.replaceState=x.params.hashnavReplaceState),x.params.history&&x.history&&x.history.init(),x.params.hashnav&&x.hashnav&&x.hashnav.init(),x.params.a11y&&x.a11y&&x.a11y.init(),x.emit("onInit",x)},x.cleanupStyles=function(){x.container.removeClass(x.classNames.join(" ")).removeAttr("style"),x.wrapper.removeAttr("style"),x.slides&&x.slides.length&&x.slides.removeClass([x.params.slideVisibleClass,x.params.slideActiveClass,x.params.slideNextClass,x.params.slidePrevClass].join(" ")).removeAttr("style").removeAttr("data-swiper-column").removeAttr("data-swiper-row"),x.paginationContainer&&x.paginationContainer.length&&x.paginationContainer.removeClass(x.params.paginationHiddenClass),x.bullets&&x.bullets.length&&x.bullets.removeClass(x.params.bulletActiveClass),x.params.prevButton&&e(x.params.prevButton).removeClass(x.params.buttonDisabledClass),x.params.nextButton&&e(x.params.nextButton).removeClass(x.params.buttonDisabledClass),x.params.scrollbar&&x.scrollbar&&(x.scrollbar.track&&x.scrollbar.track.length&&x.scrollbar.track.removeAttr("style"),x.scrollbar.drag&&x.scrollbar.drag.length&&x.scrollbar.drag.removeAttr("style"))},x.destroy=function(e,a){x.detachEvents(),x.stopAutoplay(),x.params.scrollbar&&x.scrollbar&&x.params.scrollbarDraggable&&x.scrollbar.disableDraggable(),x.params.loop&&x.destroyLoop(),a&&x.cleanupStyles(),x.disconnectObservers(),x.params.zoom&&x.zoom&&x.zoom.destroy(),x.params.keyboardControl&&x.disableKeyboardControl&&x.disableKeyboardControl(),x.params.mousewheelControl&&x.disableMousewheelControl&&x.disableMousewheelControl(),x.params.a11y&&x.a11y&&x.a11y.destroy(),x.params.history&&!x.params.replaceState&&window.removeEventListener("popstate",x.history.setHistoryPopState),x.params.hashnav&&x.hashnav&&x.hashnav.destroy(),x.emit("onDestroy"),!1!==e&&(x=null)},x.init(),x}};a.prototype={isSafari:function(){var e=window.navigator.userAgent.toLowerCase();return e.indexOf("safari")>=0&&e.indexOf("chrome")<0&&e.indexOf("android")<0}(),isUiWebView:/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(window.navigator.userAgent),isArray:function(e){return"[object Array]"===Object.prototype.toString.apply(e)},browser:{ie:window.navigator.pointerEnabled||window.navigator.msPointerEnabled,ieTouch:window.navigator.msPointerEnabled&&window.navigator.msMaxTouchPoints>1||window.navigator.pointerEnabled&&window.navigator.maxTouchPoints>1,lteIE9:function(){var e=document.createElement("div");return e.innerHTML="\x3c!--[if lte IE 9]><i></i><![endif]--\x3e",1===e.getElementsByTagName("i").length}()},device:function(){var e=window.navigator.userAgent,a=e.match(/(Android);?[\s\/]+([\d.]+)?/),t=e.match(/(iPad).*OS\s([\d_]+)/),s=e.match(/(iPod)(.*OS\s([\d_]+))?/),i=!t&&e.match(/(iPhone\sOS|iOS)\s([\d_]+)/);return{ios:t||i||s,android:a}}(),support:{touch:window.Modernizr&&!0===Modernizr.touch||!!("ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch),transforms3d:window.Modernizr&&!0===Modernizr.csstransforms3d||function(){var e=document.createElement("div").style;return"webkitPerspective"in e||"MozPerspective"in e||"OPerspective"in e||"MsPerspective"in e||"perspective"in e}(),flexbox:function(){for(var e=document.createElement("div").style,a="alignItems webkitAlignItems webkitBoxAlign msFlexAlign mozBoxAlign webkitFlexDirection msFlexDirection mozBoxDirection mozBoxOrient webkitBoxDirection webkitBoxOrient".split(" "),t=0;t<a.length;t++)if(a[t]in e)return!0}(),observer:"MutationObserver"in window||"WebkitMutationObserver"in window,passiveListener:function(){var e=!1;try{var a=Object.defineProperty({},"passive",{get:function(){e=!0}});window.addEventListener("testPassiveListener",null,a)}catch(e){}return e}(),gestures:"ongesturestart"in window},plugins:{}};for(var t=function(){var e=function(e){var a=0;for(a=0;a<e.length;a++)this[a]=e[a];return this.length=e.length,this},a=function(a,t){var s=[],i=0;if(a&&!t&&a instanceof e)return a;if(a)if("string"==typeof a){var r,n,o=a.trim();if(o.indexOf("<")>=0&&o.indexOf(">")>=0){var l="div";for(0===o.indexOf("<li")&&(l="ul"),0===o.indexOf("<tr")&&(l="tbody"),0!==o.indexOf("<td")&&0!==o.indexOf("<th")||(l="tr"),0===o.indexOf("<tbody")&&(l="table"),0===o.indexOf("<option")&&(l="select"),(n=document.createElement(l)).innerHTML=a,i=0;i<n.childNodes.length;i++)s.push(n.childNodes[i])}else for(r=t||"#"!==a[0]||a.match(/[ .<>:~]/)?(t||document).querySelectorAll(a):[document.getElementById(a.split("#")[1])],i=0;i<r.length;i++)r[i]&&s.push(r[i])}else if(a.nodeType||a===window||a===document)s.push(a);else if(a.length>0&&a[0].nodeType)for(i=0;i<a.length;i++)s.push(a[i]);return new e(s)};return e.prototype={addClass:function(e){if(void 0===e)return this;for(var a=e.split(" "),t=0;t<a.length;t++)for(var s=0;s<this.length;s++)this[s].classList.add(a[t]);return this},removeClass:function(e){for(var a=e.split(" "),t=0;t<a.length;t++)for(var s=0;s<this.length;s++)this[s].classList.remove(a[t]);return this},hasClass:function(e){return!!this[0]&&this[0].classList.contains(e)},toggleClass:function(e){for(var a=e.split(" "),t=0;t<a.length;t++)for(var s=0;s<this.length;s++)this[s].classList.toggle(a[t]);return this},attr:function(e,a){if(1===arguments.length&&"string"==typeof e)return this[0]?this[0].getAttribute(e):void 0;for(var t=0;t<this.length;t++)if(2===arguments.length)this[t].setAttribute(e,a);else for(var s in e)this[t][s]=e[s],this[t].setAttribute(s,e[s]);return this},removeAttr:function(e){for(var a=0;a<this.length;a++)this[a].removeAttribute(e);return this},data:function(e,a){if(void 0!==a){for(var t=0;t<this.length;t++){var s=this[t];s.dom7ElementDataStorage||(s.dom7ElementDataStorage={}),s.dom7ElementDataStorage[e]=a}return this}if(this[0]){var i=this[0].getAttribute("data-"+e);return i||(this[0].dom7ElementDataStorage&&e in this[0].dom7ElementDataStorage?this[0].dom7ElementDataStorage[e]:void 0)}},transform:function(e){for(var a=0;a<this.length;a++){var t=this[a].style;t.webkitTransform=t.MsTransform=t.msTransform=t.MozTransform=t.OTransform=t.transform=e}return this},transition:function(e){"string"!=typeof e&&(e+="ms");for(var a=0;a<this.length;a++){var t=this[a].style;t.webkitTransitionDuration=t.MsTransitionDuration=t.msTransitionDuration=t.MozTransitionDuration=t.OTransitionDuration=t.transitionDuration=e}return this},on:function(e,t,s,i){function r(e){var i=e.target;if(a(i).is(t))s.call(i,e);else for(var r=a(i).parents(),n=0;n<r.length;n++)a(r[n]).is(t)&&s.call(r[n],e)}var n,o,l=e.split(" ");for(n=0;n<this.length;n++)if("function"==typeof t||!1===t)for("function"==typeof t&&(s=arguments[1],i=arguments[2]||!1),o=0;o<l.length;o++)this[n].addEventListener(l[o],s,i);else for(o=0;o<l.length;o++)this[n].dom7LiveListeners||(this[n].dom7LiveListeners=[]),this[n].dom7LiveListeners.push({listener:s,liveListener:r}),this[n].addEventListener(l[o],r,i);return this},off:function(e,a,t,s){for(var i=e.split(" "),r=0;r<i.length;r++)for(var n=0;n<this.length;n++)if("function"==typeof a||!1===a)"function"==typeof a&&(t=arguments[1],s=arguments[2]||!1),this[n].removeEventListener(i[r],t,s);else if(this[n].dom7LiveListeners)for(var o=0;o<this[n].dom7LiveListeners.length;o++)this[n].dom7LiveListeners[o].listener===t&&this[n].removeEventListener(i[r],this[n].dom7LiveListeners[o].liveListener,s);return this},once:function(e,a,t,s){function i(n){t(n),r.off(e,a,i,s)}var r=this;"function"==typeof a&&(a=!1,t=arguments[1],s=arguments[2]),r.on(e,a,i,s)},trigger:function(e,a){for(var t=0;t<this.length;t++){var s;try{s=new window.CustomEvent(e,{detail:a,bubbles:!0,cancelable:!0})}catch(t){(s=document.createEvent("Event")).initEvent(e,!0,!0),s.detail=a}this[t].dispatchEvent(s)}return this},transitionEnd:function(e){function a(r){if(r.target===this)for(e.call(this,r),t=0;t<s.length;t++)i.off(s[t],a)}var t,s=["webkitTransitionEnd","transitionend","oTransitionEnd","MSTransitionEnd","msTransitionEnd"],i=this;if(e)for(t=0;t<s.length;t++)i.on(s[t],a);return this},width:function(){return this[0]===window?window.innerWidth:this.length>0?parseFloat(this.css("width")):null},outerWidth:function(e){return this.length>0?e?this[0].offsetWidth+parseFloat(this.css("margin-right"))+parseFloat(this.css("margin-left")):this[0].offsetWidth:null},height:function(){return this[0]===window?window.innerHeight:this.length>0?parseFloat(this.css("height")):null},outerHeight:function(e){return this.length>0?e?this[0].offsetHeight+parseFloat(this.css("margin-top"))+parseFloat(this.css("margin-bottom")):this[0].offsetHeight:null},offset:function(){if(this.length>0){var e=this[0],a=e.getBoundingClientRect(),t=document.body,s=e.clientTop||t.clientTop||0,i=e.clientLeft||t.clientLeft||0,r=window.pageYOffset||e.scrollTop,n=window.pageXOffset||e.scrollLeft;return{top:a.top+r-s,left:a.left+n-i}}return null},css:function(e,a){var t;if(1===arguments.length){if("string"!=typeof e){for(t=0;t<this.length;t++)for(var s in e)this[t].style[s]=e[s];return this}if(this[0])return window.getComputedStyle(this[0],null).getPropertyValue(e)}if(2===arguments.length&&"string"==typeof e){for(t=0;t<this.length;t++)this[t].style[e]=a;return this}return this},each:function(e){for(var a=0;a<this.length;a++)e.call(this[a],a,this[a]);return this},html:function(e){if(void 0===e)return this[0]?this[0].innerHTML:void 0;for(var a=0;a<this.length;a++)this[a].innerHTML=e;return this},text:function(e){if(void 0===e)return this[0]?this[0].textContent.trim():null;for(var a=0;a<this.length;a++)this[a].textContent=e;return this},is:function(t){if(!this[0])return!1;var s,i;if("string"==typeof t){var r=this[0];if(r===document)return t===document;if(r===window)return t===window;if(r.matches)return r.matches(t);if(r.webkitMatchesSelector)return r.webkitMatchesSelector(t);if(r.mozMatchesSelector)return r.mozMatchesSelector(t);if(r.msMatchesSelector)return r.msMatchesSelector(t);for(s=a(t),i=0;i<s.length;i++)if(s[i]===this[0])return!0;return!1}if(t===document)return this[0]===document;if(t===window)return this[0]===window;if(t.nodeType||t instanceof e){for(s=t.nodeType?[t]:t,i=0;i<s.length;i++)if(s[i]===this[0])return!0;return!1}return!1},index:function(){if(this[0]){for(var e=this[0],a=0;null!==(e=e.previousSibling);)1===e.nodeType&&a++;return a}},eq:function(a){if(void 0===a)return this;var t,s=this.length;return a>s-1?new e([]):a<0?(t=s+a,new e(t<0?[]:[this[t]])):new e([this[a]])},append:function(a){var t,s;for(t=0;t<this.length;t++)if("string"==typeof a){var i=document.createElement("div");for(i.innerHTML=a;i.firstChild;)this[t].appendChild(i.firstChild)}else if(a instanceof e)for(s=0;s<a.length;s++)this[t].appendChild(a[s]);else this[t].appendChild(a);return this},prepend:function(a){var t,s;for(t=0;t<this.length;t++)if("string"==typeof a){var i=document.createElement("div");for(i.innerHTML=a,s=i.childNodes.length-1;s>=0;s--)this[t].insertBefore(i.childNodes[s],this[t].childNodes[0])}else if(a instanceof e)for(s=0;s<a.length;s++)this[t].insertBefore(a[s],this[t].childNodes[0]);else this[t].insertBefore(a,this[t].childNodes[0]);return this},insertBefore:function(e){for(var t=a(e),s=0;s<this.length;s++)if(1===t.length)t[0].parentNode.insertBefore(this[s],t[0]);else if(t.length>1)for(var i=0;i<t.length;i++)t[i].parentNode.insertBefore(this[s].cloneNode(!0),t[i])},insertAfter:function(e){for(var t=a(e),s=0;s<this.length;s++)if(1===t.length)t[0].parentNode.insertBefore(this[s],t[0].nextSibling);else if(t.length>1)for(var i=0;i<t.length;i++)t[i].parentNode.insertBefore(this[s].cloneNode(!0),t[i].nextSibling)},next:function(t){return new e(this.length>0?t?this[0].nextElementSibling&&a(this[0].nextElementSibling).is(t)?[this[0].nextElementSibling]:[]:this[0].nextElementSibling?[this[0].nextElementSibling]:[]:[])},nextAll:function(t){var s=[],i=this[0];if(!i)return new e([]);for(;i.nextElementSibling;){var r=i.nextElementSibling;t?a(r).is(t)&&s.push(r):s.push(r),i=r}return new e(s)},prev:function(t){return new e(this.length>0?t?this[0].previousElementSibling&&a(this[0].previousElementSibling).is(t)?[this[0].previousElementSibling]:[]:this[0].previousElementSibling?[this[0].previousElementSibling]:[]:[])},prevAll:function(t){var s=[],i=this[0];if(!i)return new e([]);for(;i.previousElementSibling;){var r=i.previousElementSibling;t?a(r).is(t)&&s.push(r):s.push(r),i=r}return new e(s)},parent:function(e){for(var t=[],s=0;s<this.length;s++)e?a(this[s].parentNode).is(e)&&t.push(this[s].parentNode):t.push(this[s].parentNode);return a(a.unique(t))},parents:function(e){for(var t=[],s=0;s<this.length;s++)for(var i=this[s].parentNode;i;)e?a(i).is(e)&&t.push(i):t.push(i),i=i.parentNode;return a(a.unique(t))},find:function(a){for(var t=[],s=0;s<this.length;s++)for(var i=this[s].querySelectorAll(a),r=0;r<i.length;r++)t.push(i[r]);return new e(t)},children:function(t){for(var s=[],i=0;i<this.length;i++)for(var r=this[i].childNodes,n=0;n<r.length;n++)t?1===r[n].nodeType&&a(r[n]).is(t)&&s.push(r[n]):1===r[n].nodeType&&s.push(r[n]);return new e(a.unique(s))},remove:function(){for(var e=0;e<this.length;e++)this[e].parentNode&&this[e].parentNode.removeChild(this[e]);return this},add:function(){var e,t;for(e=0;e<arguments.length;e++){var s=a(arguments[e]);for(t=0;t<s.length;t++)this[this.length]=s[t],this.length++}return this}},a.fn=e.prototype,a.unique=function(e){for(var a=[],t=0;t<e.length;t++)-1===a.indexOf(e[t])&&a.push(e[t]);return a},a}(),s=["jQuery","Zepto","Dom7"],i=0;i<s.length;i++)window[s[i]]&&function(e){e.fn.swiper=function(t){var s;return e(this).each(function(){var e=new a(this,t);s||(s=e)}),s}}(window[s[i]]);var r;(r=void 0===t?window.Dom7||window.Zepto||window.jQuery:t)&&("transitionEnd"in r.fn||(r.fn.transitionEnd=function(e){function a(r){if(r.target===this)for(e.call(this,r),t=0;t<s.length;t++)i.off(s[t],a)}var t,s=["webkitTransitionEnd","transitionend","oTransitionEnd","MSTransitionEnd","msTransitionEnd"],i=this;if(e)for(t=0;t<s.length;t++)i.on(s[t],a);return this}),"transform"in r.fn||(r.fn.transform=function(e){for(var a=0;a<this.length;a++){var t=this[a].style;t.webkitTransform=t.MsTransform=t.msTransform=t.MozTransform=t.OTransform=t.transform=e}return this}),"transition"in r.fn||(r.fn.transition=function(e){"string"!=typeof e&&(e+="ms");for(var a=0;a<this.length;a++){var t=this[a].style;t.webkitTransitionDuration=t.MsTransitionDuration=t.msTransitionDuration=t.MozTransitionDuration=t.OTransitionDuration=t.transitionDuration=e}return this}),"outerWidth"in r.fn||(r.fn.outerWidth=function(e){return this.length>0?e?this[0].offsetWidth+parseFloat(this.css("margin-right"))+parseFloat(this.css("margin-left")):this[0].offsetWidth:null})),window.Swiper=a}(),"undefined"!=typeof module?module.exports=window.Swiper:"function"==typeof define&&define.amd&&define([],function(){"use strict";return window.Swiper});
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/tab.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/tab.min.js
new file mode 100755
index 0000000..94476aa
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/tab.min.js
@@ -0,0 +1 @@
+window.openTab=function(e){for(var t=event.target;!t.parentNode.classList.contains("tab");){if("BODY"==t.nodeName)return console.error("The component tab not found, please check your code."),!1;t=t.parentNode}for(var a=document.getElementById(e).parentNode.getElementsByClassName("tab-content"),s=t.parentNode.getElementsByClassName("active"),n=0;n<a.length;n++)a[n].setAttribute("class",a[n].getAttribute("class").replace("active",""));for(n=0;n<s.length;n++)s[n].setAttribute("class",s[n].getAttribute("class").replace("active",""));t.setAttribute("class",t.getAttribute("class")+" active"),document.getElementById(e).setAttribute("class",document.getElementById(e).getAttribute("class")+" active")};
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/js/toast.min.js b/platforms/android/app/src/main/assets/www/mobileui/js/toast.min.js
new file mode 100755
index 0000000..75db5f7
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/js/toast.min.js
@@ -0,0 +1 @@
+window.openToast=function(e){var t={class:"black radius padding shadow",duration:2e3,position:"bottom",onclick:window.closeToast};"string"==typeof e&&(t.message=e),"object"==typeof e&&e.message&&(t.message=e.message),"object"==typeof e&&e.class&&(t.class=e.class),"object"==typeof e&&e.duration&&(t.duration=e.duration),"object"==typeof e&&e.position&&(t.position="toast-"+e.position),"object"==typeof e&&e.onclick&&(t.onclick=e.onclick);var o=document.getElementsByTagName("body")[0];event&&event.target&&event.target.parentNode&&event.target.parentNode.className.indexOf("body")>=0&&(o=event.target.parentNode);var a=document.createElement("div");a.className="toast",a.classList.add(t.position);var n=document.createElement("div");n.className=t.class,n.innerHTML=t.message,n.onclick=t.onclick,a.appendChild(n),o.appendChild(a),setTimeout(function(){a.classList.add("show")},100),setTimeout(function(){if(!a)return!1;a.classList.remove("show"),setTimeout(function(){if(!a.parentNode)return!1;a.parentNode.removeChild(a)},400)},t.duration)},window.closeToast=function(e){e.target.parentNode.classList.remove("show"),setTimeout(function(){e.target.parentNode.parentNode.removeChild(e.target.parentNode)},400)};
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/mobileui/mobileui.js b/platforms/android/app/src/main/assets/www/mobileui/mobileui.js
new file mode 100644
index 0000000..4675be7
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/mobileui.js
@@ -0,0 +1,3 @@
+/*component-base*/var userAgent=navigator.userAgent||navigator.vendor||window.opera,SO={name:"unknown",code:0};/android/i.test(userAgent)&&(SO.name="Android",SO.class="platform-android",SO.code=1);/iPad|iPhone|iPod/.test(userAgent)&&!window.MSStream&&(SO.name="iOS",SO.class="platform-ios",SO.code=2);/windows phone/i.test(userAgent)&&(SO.name="Windows Phone",SO.class="platform-wp",SO.code=3);SO.class&&document.getElementsByTagName("body").length&&(document.getElementsByTagName("body")[0].className+=" "+SO.class);
+
+/*component-button*/document.addEventListener("click",function(e){if(1!==SO.code)return!1;var t=e.target;if("button"!==t.tagName.toLowerCase())return!1;var o=t.getBoundingClientRect(),s=t.querySelector(".ripple");s||((s=document.createElement("span")).className="ripple",s.style.height=s.style.width=Math.max(o.width,o.height)+"px",t.appendChild(s)),s.classList.remove("show");var a=e.pageY-o.top-s.offsetHeight/2-document.body.scrollTop,l=e.pageX-o.left-s.offsetWidth/2-document.body.scrollLeft;return s.style.top=a+"px",s.style.left=l+"px",s.classList.add("show"),!1},!1);
diff --git a/platforms/android/app/src/main/assets/www/mobileui/style.css b/platforms/android/app/src/main/assets/www/mobileui/style.css
new file mode 100644
index 0000000..d0433d2
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/mobileui/style.css
@@ -0,0 +1,34 @@
+.component-base{display:block}*{-webkit-tap-highlight-color:transparent;margin:0;padding:0;box-sizing:border-box;outline:0}body{-webkit-touch-callout:none;-webkit-text-size-adjust:none;-webkit-user-select:none;background-color:#fff;font-size:14px;height:100%;margin:0;padding:0;width:100%}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:400}*{box-sizing:border-box;outline:0}body{font-family:Roboto,"Helvetica Neue",sans-serif;-webkit-overflow-scrolling:touch;overflow:hidden;position:absolute}body.platform-ios{font-family:-apple-system,"Helvetica Neue",Roboto,sans-serif}a{cursor:pointer;color:#000;text-decoration:none}.content{position:absolute;width:100%;overflow:auto}.left{float:left}.right{float:right}.top{position:absolute;top:0;left:0}.bottom{position:absolute;bottom:0;left:0}.align-left{text-align:left}.align-center{text-align:center}.align-right{text-align:right}.border{border-width:1px;border-style:solid}.hidden{display:none}.opacity-90{opacity:.9}.opacity-80{opacity:.8}.opacity-70{opacity:.7}.opacity-60{opacity:.6}.opacity-50{opacity:.5}.opacity-40{opacity:.4}.opacity-30{opacity:.3}.opacity-20{opacity:.2}.opacity-10{opacity:.1}.line{width:100%;height:1px;display:block;clear:both}.icon{font-size:28px}img,video{max-width:100%}p{margin-top:5px;margin-bottom:5px}.padding{padding:10px}.padding-top{padding-top:10px}.margin{margin:10px}span.padding{padding:6px;padding-top:2px;padding-bottom:2px}.radius{border-radius:4px}.radius-big{border-radius:22px}.circle{border-radius:50%}.radius-left{border-top-left-radius:4px;border-bottom-left-radius:4px}.radius-right{border-top-right-radius:4px;border-bottom-right-radius:4px}.radius-top{border-top-left-radius:4px;border-top-right-radius:4px}.ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.shadow{box-shadow:1px 1px 3px rgba(0,0,0,.2)}.space{width:100%;height:20px}.space-big{width:100%;height:50px}.space-huge{width:100%;height:100px}.margin-bottom{margin-bottom:10px}.margin-top{margin-top:10px}.text-shadow{text-shadow:1px 1px 3px rgba(0,0,0,.2)}.text-small{font-size:14px}.text-small .icon,.text-small.icon{font-size:14px!important}.icon-small{font-size:14px!important}.icon-big{font-size:50px!important}.icon-huge{font-size:65px!important}.icon-extra-huge{font-size:120px!important}.text-big{font-size:22px}.text-big .icon,.text-big.icon{font-size:22px!important}.text-extra-huge{font-size:65px}.text-extra-huge .icon,.text-extra-huge.icon{font-size:65px!important}.text-huge{font-size:32px}.text-huge .icon,.text-huge.icon{font-size:32px!important}.text-light{font-weight:300}.text-bold{font-weight:700}.text-strong{font-weight:800}.float-bottom-right{position:fixed;right:15px;bottom:15px}.float-bottom-left{position:fixed;left:15px;bottom:15px}.float-bottom-center{position:fixed;margin:auto;left:0;bottom:15px}.icon-circle{width:40px;height:40px;border-radius:50%;text-align:center;display:flex;align-items:center;justify-content:center}.icon-circle-small{width:25px;height:25px;border-radius:50%;text-align:center;display:flex;align-items:center;justify-content:center}.icon-circle-small i{font-size:15px}.icon-circle-big{width:80px;height:80px;border-radius:50%;text-align:center;display:flex;align-items:center;justify-content:center}.icon-circle-big i{font-size:70px}.backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#000;opacity:.01;z-index:9999;transition-duration:280ms}.backdrop.show{opacity:0.3}.mark{border-left-width:8px!important}.red{color:rgba(255,255,255,.9);background-color:#f44336!important}.red-100,.red-200,.red-300,.red-50{color:rgba(0,0,0,.8)}.red-50,input[type=checkbox].red-50.switch::after{background-color:#ffebee!important}.red-100,input[type=checkbox].red-100.switch::after{background-color:#ffcdd2!important}.red-200,input[type=checkbox].red-200.switch::after{background-color:#ef9a9a!important}.red-300,input[type=checkbox].red-300.switch::after{background-color:#e57373!important}.pink,.red-400,.red-500,.red-600,.red-700,.red-800,.red-900{color:rgba(255,255,255,.9)}.red-400,input[type=checkbox].red-400.switch::after{background-color:#ef5350!important}.red-500,input[type=checkbox].red-500.switch::after{background-color:#f44336!important}.red-600,input[type=checkbox].red-600.switch::after{background-color:#e53935!important}.red-700,input[type=checkbox].red-700.switch::after{background-color:#d32f2f!important}.red-800,input[type=checkbox].red-800.switch::after{background-color:#c62828!important}.red-900,input[type=checkbox].red-900.switch::after{background-color:#b71c1c!important}.pink,input[type=checkbox].pink.switch::after{background-color:#e91e63!important}.pink-100,.pink-200,.pink-50{color:rgba(0,0,0,.8)}.pink-50,input[type=checkbox].pink-50.switch::after{background-color:#fce4ec!important}.pink-100,input[type=checkbox].pink-100.switch::after{background-color:#f8bbd0!important}.pink-200,input[type=checkbox].pink-200.switch::after{background-color:#f48fb1!important}.Pink-300,.pink-400,.pink-500,.pink-600,.pink-700,.pink-800,.pink-900,.purple{color:rgba(255,255,255,.9)}.Pink-300,input[type=checkbox].Pink-300.switch::after{background-color:#f06292!important}.pink-400,input[type=checkbox].pink-400.switch::after{background-color:#ec407a!important}.pink-500,input[type=checkbox].pink-500.switch::after{background-color:#e91e63!important}.pink-600,input[type=checkbox].pink-600.switch::after{background-color:#d81b60!important}.pink-700,input[type=checkbox].pink-700.switch::after{background-color:#c2185b!important}.pink-800,input[type=checkbox].pink-800.switch::after{background-color:#ad1457!important}.pink-900,input[type=checkbox].pink-900.switch::after{background-color:#880e4f!important}.purple,input[type=checkbox].purple.switch::after{background-color:#9c27b0!important}.purple-100,.purple-200,.purple-50{color:rgba(0,0,0,.8)}.purple-50,input[type=checkbox].purple-50.switch::after{background-color:#f3e5f5!important}.purple-100,input[type=checkbox].purple-100.switch::after{background-color:#e1bee7!important}.purple-200,input[type=checkbox].purple-200.switch::after{background-color:#ce93d8!important}.deep-purple,.purple-300,.purple-400,.purple-500,.purple-600,.purple-700,.purple-800,.purple-900{color:rgba(255,255,255,.9)}.purple-300,input[type=checkbox].purple-300.switch::after{background-color:#ba68c8!important}.purple-400,input[type=checkbox].purple-400.switch::after{background-color:#ab47bc!important}.purple-500,input[type=checkbox].purple-500.switch::after{background-color:#9c27b0!important}.purple-600,input[type=checkbox].purple-600.switch::after{background-color:#8e24aa!important}.purple-700,input[type=checkbox].purple-700.switch::after{background-color:#7b1fa2!important}.purple-800,input[type=checkbox].purple-800.switch::after{background-color:#6a1b9a!important}.purple-900,input[type=checkbox].purple-900.switch::after{background-color:#4a148c!important}.deep-purple,input[type=checkbox].deep-purple.switch::after{background-color:#673ab7!important}.deep-purple-50{color:rgba(0,0,0,.8);background-color:#ede7f6!important}.deep-purple-100{color:rgba(0,0,0,.8);background-color:#d1c4e9!important}.deep-purple-200{color:rgba(0,0,0,.8);background-color:#b39ddb!important}.deep-purple-300,.deep-purple-400,.deep-purple-500,.deep-purple-600,.deep-purple-700,.deep-purple-800,.deep-purple-900,.indigo{color:rgba(255,255,255,.9)}.deep-purple-300,input[type=checkbox].deep-purple-300.switch::after{background-color:#9575cd!important}.deep-purple-400,input[type=checkbox].deep-purple-400.switch::after{background-color:#7e57c2!important}.deep-purple-500,input[type=checkbox].deep-purple-500.switch::after{background-color:#673ab7!important}.deep-purple-600,input[type=checkbox].deep-purple-600.switch::after{background-color:#5e35b1!important}.deep-purple-700,input[type=checkbox].deep-purple-700.switch::after{background-color:#512da8!important}.deep-purple-800,input[type=checkbox].deep-purple-800.switch::after{background-color:#4527a0!important}.deep-purple-900,input[type=checkbox].deep-purple-900.switch::after{background-color:#311b92!important}.indigo,input[type=checkbox].indigo.switch::after{background-color:#3f51b5!important}.indigo-100,.indigo-200,.indigo-50{color:rgba(0,0,0,.8)}.indigo-50,input[type=checkbox].indigo-50.switch::after{background-color:#e8eaf6!important}.indigo-100,input[type=checkbox].indigo-100.switch::after{background-color:#c5cae9!important}.indigo-200,input[type=checkbox].indigo-200.switch::after{background-color:#9fa8da!important}.blue,.indigo-300,.indigo-400,.indigo-500,.indigo-600,.indigo-700,.indigo-800,.indigo-900{color:rgba(255,255,255,.9)}.indigo-300,input[type=checkbox].indigo-300.switch::after{background-color:#7986cb!important}.indigo-400,input[type=checkbox].indigo-400.switch::after{background-color:#5c6bc0!important}.indigo-500,input[type=checkbox].indigo-500.switch::after{background-color:#3f51b5!important}.indigo-600,input[type=checkbox].indigo-600.switch::after{background-color:#3949ab!important}.indigo-700,input[type=checkbox].indigo-700.switch::after{background-color:#303f9f!important}.indigo-800,input[type=checkbox].indigo-800.switch::after{background-color:#283593!important}.indigo-900,input[type=checkbox].indigo-900.switch::after{background-color:#1a237e!important}.blue,input[type=checkbox].blue.switch::after{background-color:#2196f3!important}.blue-100,.blue-200,.blue-300,.blue-400,.blue-50{color:rgba(0,0,0,.8)}.blue-50,input[type=checkbox].blue-50.switch::after{background-color:#e3f2fd!important}.blue-100,input[type=checkbox].blue-100.switch::after{background-color:#bbdefb!important}.blue-200,input[type=checkbox].blue-200.switch::after{background-color:#90caf9!important}.blue-300,input[type=checkbox].blue-300.switch::after{background-color:#64b5f6!important}.blue-400,input[type=checkbox].blue-400.switch::after{background-color:#42a5f5!important}.blue-500,.blue-600,.blue-700,.blue-800,.blue-900,.light-blue{color:rgba(255,255,255,.9)}.blue-500,input[type=checkbox].blue-500.switch::after{background-color:#2196f3!important}.blue-600,input[type=checkbox].blue-600.switch::after{background-color:#1e88e5!important}.blue-700,input[type=checkbox].blue-700.switch::after{background-color:#1976d2!important}.blue-800,input[type=checkbox].blue-800.switch::after{background-color:#1565c0!important}.blue-900,input[type=checkbox].blue-900.switch::after{background-color:#0d47a1!important}.light-blue,input[type=checkbox].light-blue.switch::after{background-color:#03a9f4!important}.light-blue-100,.light-blue-200,.light-blue-300,.light-blue-400,.light-blue-50,.light-blue-500{color:rgba(0,0,0,.8)}.light-blue-50,input[type=checkbox].light-blue-50.switch::after{background-color:#e1f5fe!important}.light-blue-100,input[type=checkbox].light-blue-100.switch::after{background-color:#b3e5fc!important}.light-blue-200,input[type=checkbox].light-blue-200.switch::after{background-color:#81d4fa!important}.light-blue-300,input[type=checkbox].light-blue-300.switch::after{background-color:#4fc3f7!important}.light-blue-400,input[type=checkbox].light-blue-400.switch::after{background-color:#29b6f6!important}.light-blue-500,input[type=checkbox].light-blue-500.switch::after{background-color:#03a9f4!important}.cyan,.light-blue-600,.light-blue-700,.light-blue-800,.light-blue-900{color:rgba(255,255,255,.9)}.light-blue-600,input[type=checkbox].light-blue-600.switch::after{background-color:#039be5!important}.light-blue-700,input[type=checkbox].light-blue-700.switch::after{background-color:#0288d1!important}.light-blue-800,input[type=checkbox].light-blue-800.switch::after{background-color:#0277bd!important}.light-blue-900,input[type=checkbox].light-blue-900.switch::after{background-color:#01579b!important}.cyan,input[type=checkbox].cyan.switch::after{background-color:#00bcd4!important}.cyan-100,.cyan-200,.cyan-300,.cyan-400,.cyan-50,.cyan-500,.cyan-600{color:rgba(0,0,0,.8)}.cyan-50,input[type=checkbox].cyan-50.switch::after{background-color:#e0f7fa!important}.cyan-100,input[type=checkbox].cyan-100.switch::after{background-color:#b2ebf2!important}.cyan-200,input[type=checkbox].cyan-200.switch::after{background-color:#80deea!important}.cyan-300,input[type=checkbox].cyan-300.switch::after{background-color:#4dd0e1!important}.cyan-400,input[type=checkbox].cyan-400.switch::after{background-color:#26c6da!important}.cyan-500,input[type=checkbox].cyan-500.switch::after{background-color:#00bcd4!important}.cyan-600,input[type=checkbox].cyan-600.switch::after{background-color:#00acc1!important}.cyan-700,.cyan-800,.cyan-900,.teal{color:rgba(255,255,255,.9)}.cyan-700,input[type=checkbox].cyan-700.switch::after{background-color:#0097a7!important}.cyan-800,input[type=checkbox].cyan-800.switch::after{background-color:#00838f!important}.cyan-900,input[type=checkbox].cyan-900.switch::after{background-color:#006064!important}.teal,input[type=checkbox].teal.switch::after{background-color:#009688!important}.teal-100,.teal-200,.teal-300,.teal-400,.teal-50{color:rgba(0,0,0,.8)}.teal-50,input[type=checkbox].teal-50.switch::after{background-color:#e0f2f1!important}.teal-100,input[type=checkbox].teal-100.switch::after{background-color:#b2dfdb!important}.teal-200,input[type=checkbox].teal-200.switch::after{background-color:#80cbc4!important}.teal-300,input[type=checkbox].teal-300.switch::after{background-color:#4db6ac!important}.teal-400,input[type=checkbox].teal-400.switch::after{background-color:#26a69a!important}.green,.teal-500,.teal-600,.teal-700,.teal-800,.teal-900{color:rgba(255,255,255,.9)}.teal-500,input[type=checkbox].teal-500.switch::after{background-color:#009688!important}.teal-600,input[type=checkbox].teal-600.switch::after{background-color:#00897b!important}.teal-700,input[type=checkbox].teal-700.switch::after{background-color:#00796b!important}.teal-800,input[type=checkbox].teal-800.switch::after{background-color:#00695c!important}.teal-900,input[type=checkbox].teal-900.switch::after{background-color:#004d40!important}.green,input[type=checkbox].green.switch::after{background-color:#4caf50!important}.green-100,.green-200,.green-300,.green-400,.green-50,.green-500{color:rgba(0,0,0,.8)}.green-50,input[type=checkbox].green-50.switch::after{background-color:#e8f5e9!important}.green-100,input[type=checkbox].green-100.switch::after{background-color:#c8e6c9!important}.green-200,input[type=checkbox].green-200.switch::after{background-color:#a5d6a7!important}.green-300,input[type=checkbox].green-300.switch::after{background-color:#81c784!important}.green-400,input[type=checkbox].green-400.switch::after{background-color:#66bb6a!important}.green-500,input[type=checkbox].green-500.switch::after{background-color:#4caf50!important}.green-600,.green-700,.green-800,.green-900,.light-green{color:rgba(255,255,255,.9)}.green-600,input[type=checkbox].green-600.switch::after{background-color:#43a047!important}.green-700,input[type=checkbox].green-700.switch::after{background-color:#388e3c!important}.green-800,input[type=checkbox].green-800.switch::after{background-color:#2e7d32!important}.green-900,input[type=checkbox].green-900.switch::after{background-color:#1b5e20!important}.light-green,input[type=checkbox].light-green.switch::after{background-color:#8bc34a!important}.light-green-100,.light-green-200,.light-green-300,.light-green-400,.light-green-50,.light-green-500,.light-green-600{color:rgba(0,0,0,.8)}.light-green-50,input[type=checkbox].light-green-50.switch::after{background-color:#f1f8e9!important}.light-green-100,input[type=checkbox].light-green-100.switch::after{background-color:#dcedc8!important}.light-green-200,input[type=checkbox].light-green-200.switch::after{background-color:#c5e1a5!important}.light-green-300,input[type=checkbox].light-green-300.switch::after{background-color:#aed581!important}.light-green-400,input[type=checkbox].light-green-400.switch::after{background-color:#9ccc65!important}.light-green-500,input[type=checkbox].light-green-500.switch::after{background-color:#8bc34a!important}.light-green-600,input[type=checkbox].light-green-600.switch::after{background-color:#7cb342!important}.light-green-700,.light-green-800,.light-green-900,.lime{color:rgba(255,255,255,.9)}.light-green-700,input[type=checkbox].light-green-700.switch::after{background-color:#689f38!important}.light-green-800,input[type=checkbox].light-green-800.switch::after{background-color:#558b2f!important}.light-green-900,input[type=checkbox].light-green-900.switch::after{background-color:#33691e!important}.lime,input[type=checkbox].lime.switch::after{background-color:#cddc39!important}.lime-100,.lime-200,.lime-300,.lime-400,.lime-50,.lime-500,.lime-600,.lime-700,.lime-800{color:rgba(0,0,0,.8)}.lime-50,input[type=checkbox].lime-50.switch::after{background-color:#f9fbe7!important}.lime-100,input[type=checkbox].lime-100.switch::after{background-color:#f0f4c3!important}.lime-200,input[type=checkbox].lime-200.switch::after{background-color:#e6ee9c!important}.lime-300,input[type=checkbox].lime-300.switch::after{background-color:#dce775!important}.lime-400,input[type=checkbox].lime-400.switch::after{background-color:#d4e157!important}.lime-500,input[type=checkbox].lime-500.switch::after{background-color:#cddc39!important}.lime-600,input[type=checkbox].lime-600.switch::after{background-color:#c0ca33!important}.lime-700,input[type=checkbox].lime-700.switch::after{background-color:#afb42b!important}.lime-800,input[type=checkbox].lime-800.switch::after{background-color:#9e9d24!important}.lime-900,.yellow{color:rgba(255,255,255,.9)}.lime-900,input[type=checkbox].lime-900.switch::after{background-color:#827717!important}.yellow,input[type=checkbox].yellow.switch::after{background-color:#ffeb3b!important}.yellow-100,.yellow-200,.yellow-300,.yellow-50,.yellow-500,.yellow-600,.yellow-700,.yellow-800,.yellow-900{color:rgba(0,0,0,.8)}.yellow-50,input[type=checkbox].yellow-50.switch::after{background-color:#fffde7!important}.yellow-100,input[type=checkbox].yellow-100.switch::after{background-color:#fff9c4!important}.yellow-200,input[type=checkbox].yellow-200.switch::after{background-color:#fff59d!important}.yellow-300,input[type=checkbox].yellow-300.switch::after{background-color:#fff176!important}.yellow-400{color:rgba(0,0,0,.8);background-color:#ffee58!important}.yellow-500,input[type=checkbox].yellow-500.switch::after{background-color:#ffeb3b!important}.yellow-600,input[type=checkbox].yellow-600.switch::after{background-color:#fdd835!important}.yellow-700,input[type=checkbox].yellow-700.switch::after{background-color:#fbc02d!important}.yellow-800,input[type=checkbox].yellow-800.switch::after{background-color:#f9a825!important}.yellow-900,input[type=checkbox].yellow-900.switch::after{background-color:#f57f17!important}.amber{color:rgba(255,255,255,.9);background-color:#ffc107!important}.amber-100,.amber-200,.amber-300,.amber-50,.amber-500,.amber-600,.amber-700,.amber-800,.amber-900{color:rgba(0,0,0,.8)}.amber-50,input[type=checkbox].amber-50.switch::after{background-color:#fff8e1!important}.amber-100,input[type=checkbox].amber-100.switch::after{background-color:#ffecb3!important}.amber-200,input[type=checkbox].amber-200.switch::after{background-color:#ffe082!important}.amber-300,input[type=checkbox].amber-300.switch::after{background-color:#ffd54f!important}.amber-400{color:rgba(0,0,0,.8);background-color:#ffca28!important}.amber-500,input[type=checkbox].amber-500.switch::after{background-color:#ffc107!important}.amber-600,input[type=checkbox].amber-600.switch::after{background-color:#ffb300!important}.amber-700,input[type=checkbox].amber-700.switch::after{background-color:#ffa000!important}.amber-800,input[type=checkbox].amber-800.switch::after{background-color:#ff8f00!important}.amber-900,input[type=checkbox].amber-900.switch::after{background-color:#ff6f00!important}.orange{color:rgba(255,255,255,.9);background-color:#ff9800!important}.orange-100,.orange-200,.orange-300,.orange-400,.orange-50,.orange-500,.orange-600,.orange-700{color:rgba(0,0,0,.8)}.orange-50,input[type=checkbox].orange-50.switch::after{background-color:#fff3e0!important}.orange-100,input[type=checkbox].orange-100.switch::after{background-color:#ffe0b2!important}.orange-200,input[type=checkbox].orange-200.switch::after{background-color:#ffcc80!important}.orange-300,input[type=checkbox].orange-300.switch::after{background-color:#ffb74d!important}.orange-400,input[type=checkbox].orange-400.switch::after{background-color:#ffa726!important}.orange-500,input[type=checkbox].orange-500.switch::after{background-color:#ff9800!important}.orange-600,input[type=checkbox].orange-600.switch::after{background-color:#fb8c00!important}.orange-700,input[type=checkbox].orange-700.switch::after{background-color:#f57c00!important}.deep-orange,.orange-800,.orange-900{color:rgba(255,255,255,.9)}.orange-800,input[type=checkbox].orange-800.switch::after{background-color:#ef6c00!important}.orange-900,input[type=checkbox].orange-900.switch::after{background-color:#e65100!important}.deep-orange,input[type=checkbox].deep-orange.switch::after{background-color:#ff5722!important}.deep-orange-100,.deep-orange-200,.deep-orange-300,.deep-orange-400,.deep-orange-50{color:rgba(0,0,0,.8)}.deep-orange-50,input[type=checkbox].deep-orange-50.switch::after{background-color:#fbe9e7!important}.deep-orange-100,input[type=checkbox].deep-orange-100.switch::after{background-color:#ffccbc!important}.deep-orange-200,input[type=checkbox].deep-orange-200.switch::after{background-color:#ffab91!important}.deep-orange-300,input[type=checkbox].deep-orange-300.switch::after{background-color:#ff8a65!important}.deep-orange-400,input[type=checkbox].deep-orange-400.switch::after{background-color:#ff7043!important}.brown,.deep-orange-500,.deep-orange-600,.deep-orange-700,.deep-orange-800,.deep-orange-900{color:rgba(255,255,255,.9)}.deep-orange-500,input[type=checkbox].deep-orange-500.switch::after{background-color:#ff5722!important}.deep-orange-600,input[type=checkbox].deep-orange-600.switch::after{background-color:#f4511e!important}.deep-orange-700,input[type=checkbox].deep-orange-700.switch::after{background-color:#e64a19!important}.deep-orange-800,input[type=checkbox].deep-orange-800.switch::after{background-color:#d84315!important}.deep-orange-900,input[type=checkbox].deep-orange-900.switch::after{background-color:#bf360c!important}.brown,input[type=checkbox].brown.switch::after{background-color:#795548!important}.brown-100,.brown-200,.brown-50{color:rgba(0,0,0,.8)}.brown-50,input[type=checkbox].brown-50.switch::after{background-color:#efebe9!important}.brown-100,input[type=checkbox].brown-100.switch::after{background-color:#d7ccc8!important}.brown-200,input[type=checkbox].brown-200.switch::after{background-color:#bcaaa4!important}.brown-300,.brown-400,.brown-500,.brown-600,.brown-700,.brown-800,.brown-900,.grey{color:rgba(255,255,255,.9)}.brown-300,input[type=checkbox].brown-300.switch::after{background-color:#a1887f!important}.brown-400,input[type=checkbox].brown-400.switch::after{background-color:#8d6e63!important}.brown-500,input[type=checkbox].brown-500.switch::after{background-color:#795548!important}.brown-600,input[type=checkbox].brown-600.switch::after{background-color:#6d4c41!important}.brown-700,input[type=checkbox].brown-700.switch::after{background-color:#5d4037!important}.brown-800,input[type=checkbox].brown-800.switch::after{background-color:#4e342e!important}.brown-900,input[type=checkbox].brown-900.switch::after{background-color:#3e2723!important}.grey,input[type=checkbox].grey.switch::after{background-color:#9e9e9e!important}.grey-100,.grey-200,.grey-300,.grey-400,.grey-50,.grey-500{color:rgba(0,0,0,.8)}.grey-50,input[type=checkbox].grey-50.switch::after{background-color:#fafafa!important}.grey-100,input[type=checkbox].grey-100.switch::after{background-color:#f5f5f5!important}.grey-200,input[type=checkbox].grey-200.switch::after{background-color:#eee!important}.grey-300,input[type=checkbox].grey-300.switch::after{background-color:#e0e0e0!important}.grey-400,input[type=checkbox].grey-400.switch::after{background-color:#bdbdbd!important}.grey-500,input[type=checkbox].grey-500.switch::after{background-color:#9e9e9e!important}.blue-grey,.grey-600,.grey-700,.grey-800,.grey-900{color:rgba(255,255,255,.9)}.grey-600,input[type=checkbox].grey-600.switch::after{background-color:#757575!important}.grey-700,input[type=checkbox].grey-700.switch::after{background-color:#616161!important}.grey-800,input[type=checkbox].grey-800.switch::after{background-color:#424242!important}.grey-900,input[type=checkbox].grey-900.switch::after{background-color:#212121!important}.blue-grey,input[type=checkbox].blue-grey.switch::after{background-color:#607d8b!important}.blue-grey-100,.blue-grey-200,.blue-grey-300,.blue-grey-50{color:rgba(0,0,0,.8)}.blue-grey-50,input[type=checkbox].blue-grey-50.switch::after{background-color:#eceff1!important}.blue-grey-100,input[type=checkbox].blue-grey-100.switch::after{background-color:#cfd8dc!important}.blue-grey-200,input[type=checkbox].blue-grey-200.switch::after{background-color:#b0bec5!important}.blue-grey-300,input[type=checkbox].blue-grey-300.switch::after{background-color:#90a4ae!important}.black,.blue-grey-400,.blue-grey-500,.blue-grey-600,.blue-grey-700,.blue-grey-800,.blue-grey-900{color:rgba(255,255,255,.9)}.blue-grey-400,input[type=checkbox].blue-grey-400.switch::after{background-color:#78909c!important}.transparent{background-color:rgba(0,0,0,0)!important}.blue-grey-500,input[type=checkbox].blue-grey-500.switch::after{background-color:#607d8b!important}.blue-grey-600,input[type=checkbox].blue-grey-600.switch::after{background-color:#546e7a!important}.blue-grey-700,input[type=checkbox].blue-grey-700.switch::after{background-color:#455a64!important}.blue-grey-800,input[type=checkbox].blue-grey-800.switch::after{background-color:#37474f!important}.blue-grey-900,input[type=checkbox].blue-grey-900.switch::after{background-color:#263238!important}.black,input[type=checkbox].black.switch::after{background-color:#000!important}.black-opacity-90{background-color:rgba(0,0,0,.9)}.black-opacity-70{background-color:rgba(0,0,0,.7)}.black-opacity-50{background-color:rgba(0,0,0,.5)}.black-opacity-30{background-color:rgba(0,0,0,.3)}.black-opacity-10{background-color:rgba(0,0,0,.1)}.white{color:rgba(0,0,0,.8);background-color:#fff!important}.white-opacity-90{background-color:rgba(255,255,255,.9)}.white-opacity-70{background-color:rgba(255,255,255,.7)}.white-opacity-50{background-color:rgba(255,255,255,.5)}.white-opacity-30{background-color:rgba(255,255,255,.3)}.white-opacity-10{background-color:rgba(255,255,255,.1)}.text-red,i.red{color:#f44336}.text-red-50,i.red-50{color:#ffebee}.text-red-100,i.red-100{color:#ffcdd2}.text-red-200,i.red-200{color:#ef9a9a}.text-red-300,i.red-300{color:#e57373}.text-red-400,i.red-400{color:#ef5350}.text-red-500,i.red-500{color:#f44336}.text-red-600,i.red-600{color:#e53935}.text-red-700,i.red-700{color:#d32f2f}.text-red-800,i.red-800{color:#c62828}.text-red-900,i.red-900{color:#b71c1c}.text-pink,i.pink{color:#e91e63}.text-pink-50,i.pink-50{color:#fce4ec}.text-pink-100,i.pink-100{color:#f8bbd0}.text-pink-200,i.pink-200{color:#f48fb1}.text-Pink-300,i.Pink-300{color:#f06292}.text-pink-400,i.pink-400{color:#ec407a}.text-pink-500,i.pink-500{color:#e91e63}.text-pink-600,i.pink-600{color:#d81b60}.text-pink-700,i.pink-700{color:#c2185b}.text-pink-800,i.pink-800{color:#ad1457}.text-pink-900,i.pink-900{color:#880e4f}.text-purple,i.purple{color:#9c27b0}.text-purple-50,i.purple-50{color:#f3e5f5}.text-purple-100,i.purple-100{color:#e1bee7}.text-purple-200,i.purple-200{color:#ce93d8}.text-purple-300,i.purple-300{color:#ba68c8}.text-purple-400,i.purple-400{color:#ab47bc}.text-purple-500,i.purple-500{color:#9c27b0}.text-purple-600,i.purple-600{color:#8e24aa}.text-purple-700,i.purple-700{color:#7b1fa2}.text-purple-800,i.purple-800{color:#6a1b9a}.text-purple-900,i.purple-900{color:#4a148c}.text-deep-purple,i.deep-purple{color:#673ab7}.text-deep-purple-50,i.deep-purple-50{color:#ede7f6}.text-deep-purple-100,i.deep-purple-100{color:#d1c4e9}.text-deep-purple-200,i.deep-purple-200{color:#b39ddb}.text-deep-purple-300,i.deep-purple-300{color:#9575cd}.text-deep-purple-400,i.deep-purple-400{color:#7e57c2}.text-deep-purple-500,i.deep-purple-500{color:#673ab7}.text-deep-purple-600,i.deep-purple-600{color:#5e35b1}.text-deep-purple-700,i.deep-purple-700{color:#512da8}.text-deep-purple-800,i.deep-purple-800{color:#4527a0}.text-deep-purple-900,i.deep-purple-900{color:#311b92}.text-indigo,i.indigo{color:#3f51b5}.text-indigo-50,i.indigo-50{color:#e8eaf6}.text-indigo-100,i.indigo-100{color:#c5cae9}.text-indigo-200,i.indigo-200{color:#9fa8da}.text-indigo-300,i.indigo-300{color:#7986cb}.text-indigo-400,i.indigo-400{color:#5c6bc0}.text-indigo-500,i.indigo-500{color:#3f51b5}.text-indigo-600,i.indigo-600{color:#3949ab}.text-indigo-700,i.indigo-700{color:#303f9f}.text-indigo-800,i.indigo-800{color:#283593}.text-indigo-900,i.indigo-900{color:#1a237e}.text-blue,i.blue{color:#2196f3}.text-blue-50,i.blue-50{color:#e3f2fd}.text-blue-100,i.blue-100{color:#bbdefb}.text-blue-200,i.blue-200{color:#90caf9}.text-blue-300,i.blue-300{color:#64b5f6}.text-blue-400,i.blue-400{color:#42a5f5}.text-blue-500,i.blue-500{color:#2196f3}.text-blue-600,i.blue-600{color:#1e88e5}.text-blue-700,i.blue-700{color:#1976d2}.text-blue-800,i.blue-800{color:#1565c0}.text-blue-900,i.blue-900{color:#0d47a1}.text-light-blue,i.light-blue{color:#03a9f4}.text-light-blue-50,i.light-blue-50{color:#e1f5fe}.text-light-blue-100,i.light-blue-100{color:#b3e5fc}.text-light-blue-200,i.light-blue-200{color:#81d4fa}.text-light-blue-300,i.light-blue-300{color:#4fc3f7}.text-light-blue-400,i.light-blue-400{color:#29b6f6}.text-light-blue-500,i.light-blue-500{color:#03a9f4}.text-light-blue-600,i.light-blue-600{color:#039be5}.text-light-blue-700,i.light-blue-700{color:#0288d1}.text-light-blue-800,i.light-blue-800{color:#0277bd}.text-light-blue-900,i.light-blue-900{color:#01579b}.text-cyan,i.cyan{color:#00bcd4}.text-cyan-50,i.cyan-50{color:#e0f7fa}.text-cyan-100,i.cyan-100{color:#b2ebf2}.text-cyan-200,i.cyan-200{color:#80deea}.text-cyan-300,i.cyan-300{color:#4dd0e1}.text-cyan-400,i.cyan-400{color:#26c6da}.text-cyan-500,i.cyan-500{color:#00bcd4}.text-cyan-600,i.cyan-600{color:#00acc1}.text-cyan-700,i.cyan-700{color:#0097a7}.text-cyan-800,i.cyan-800{color:#00838f}.text-cyan-900,i.cyan-900{color:#006064}.text-teal,i.teal{color:#009688}.text-teal-50,i.teal-50{color:#e0f2f1}.text-teal-100,i.teal-100{color:#b2dfdb}.text-teal-200,i.teal-200{color:#80cbc4}.text-teal-300,i.teal-300{color:#4db6ac}.text-teal-400,i.teal-400{color:#26a69a}.text-teal-500,i.teal-500{color:#009688}.text-teal-600,i.teal-600{color:#00897b}.text-teal-700,i.teal-700{color:#00796b}.text-teal-800,i.teal-800{color:#00695c}.text-teal-900,i.teal-900{color:#004d40}.text-green,i.green{color:#4caf50}.text-green-50,i.green-50{color:#e8f5e9}.text-green-100,i.green-100{color:#c8e6c9}.text-green-200,i.green-200{color:#a5d6a7}.text-green-300,i.green-300{color:#81c784}.text-green-400,i.green-400{color:#66bb6a}.text-green-500,i.green-500{color:#4caf50}.text-green-600,i.green-600{color:#43a047}.text-green-700,i.green-700{color:#388e3c}.text-green-800,i.green-800{color:#2e7d32}.text-green-900,i.green-900{color:#1b5e20}.text-light-green,i.light-green{color:#8bc34a}.text-light-green-50,i.light-green-50{color:#f1f8e9}.text-light-green-100,i.light-green-100{color:#dcedc8}.text-light-green-200,i.light-green-200{color:#c5e1a5}.text-light-green-300,i.light-green-300{color:#aed581}.text-light-green-400,i.light-green-400{color:#9ccc65}.text-light-green-500,i.light-green-500{color:#8bc34a}.text-light-green-600,i.light-green-600{color:#7cb342}.text-light-green-700,i.light-green-700{color:#689f38}.text-light-green-800,i.light-green-800{color:#558b2f}.text-light-green-900,i.light-green-900{color:#33691e}.text-lime,i.lime{color:#cddc39}.text-lime-50,i.lime-50{color:#f9fbe7}.text-lime-100,i.lime-100{color:#f0f4c3}.text-lime-200,i.lime-200{color:#e6ee9c}.text-lime-300,i.lime-300{color:#dce775}.text-lime-400,i.lime-400{color:#d4e157}.text-lime-500,i.lime-500{color:#cddc39}.text-lime-600,i.lime-600{color:#c0ca33}.text-lime-700,i.lime-700{color:#afb42b}.text-lime-800,i.lime-800{color:#9e9d24}.text-lime-900,i.lime-900{color:#827717}.text-yellow,i.yellow{color:#ffeb3b}.text-yellow-50,i.yellow-50{color:#fffde7}.text-yellow-100,i.yellow-100{color:#fff9c4}.text-yellow-200,i.yellow-200{color:#fff59d}.text-yellow-300,i.yellow-300{color:#fff176}.text-yellow-400,i.yellow-400{color:#ffee58}.text-yellow-500,i.yellow-500{color:#ffeb3b}.text-yellow-600,i.yellow-600{color:#fdd835}.text-yellow-700,i.yellow-700{color:#fbc02d}.text-yellow-800,i.yellow-800{color:#f9a825}.text-yellow-900,i.yellow-900{color:#f57f17}.text-amber,i.amber{color:#ffc107}.text-amber-50,i.amber-50{color:#fff8e1}.text-amber-100,i.amber-100{color:#ffecb3}.text-amber-200,i.amber-200{color:#ffe082}.text-amber-300,i.amber-300{color:#ffd54f}.text-amber-400,i.amber-400{color:#ffca28}.text-amber-500,i.amber-500{color:#ffc107}.text-amber-600,i.amber-600{color:#ffb300}.text-amber-700,i.amber-700{color:#ffa000}.text-amber-800,i.amber-800{color:#ff8f00}.text-amber-900,i.amber-900{color:#ff6f00}.text-orange,i.orange{color:#ff9800}.text-orange-50,i.orange-50{color:#fff3e0}.text-orange-100,i.orange-100{color:#ffe0b2}.text-orange-200,i.orange-200{color:#ffcc80}.text-orange-300,i.orange-300{color:#ffb74d}.text-orange-400,i.orange-400{color:#ffa726}.text-orange-500,i.orange-500{color:#ff9800}.text-orange-600,i.orange-600{color:#fb8c00}.text-orange-700,i.orange-700{color:#f57c00}.text-orange-800,i.orange-800{color:#ef6c00}.text-orange-900,i.orange-900{color:#e65100}.text-deep-orange,i.deep-orange{color:#ff5722}.text-deep-orange-50,i.deep-orange-50{color:#fbe9e7}.text-deep-orange-100,i.deep-orange-100{color:#ffccbc}.text-deep-orange-200,i.deep-orange-200{color:#ffab91}.text-deep-orange-300,i.deep-orange-300{color:#ff8a65}.text-deep-orange-400,i.deep-orange-400{color:#ff7043}.text-deep-orange-500,i.deep-orange-500{color:#ff5722}.text-deep-orange-600,i.deep-orange-600{color:#f4511e}.text-deep-orange-700,i.deep-orange-700{color:#e64a19}.text-deep-orange-800,i.deep-orange-800{color:#d84315}.text-deep-orange-900,i.deep-orange-900{color:#bf360c}.text-brown,i.brown{color:#795548}.text-brown-50,i.brown-50{color:#efebe9}.text-brown-100,i.brown-100{color:#d7ccc8}.text-brown-200,i.brown-200{color:#bcaaa4}.text-brown-300,i.brown-300{color:#a1887f}.text-brown-400,i.brown-400{color:#8d6e63}.text-brown-500,i.brown-500{color:#795548}.text-brown-600,i.brown-600{color:#6d4c41}.text-brown-700,i.brown-700{color:#5d4037}.text-brown-800,i.brown-800{color:#4e342e}.text-brown-900,i.brown-900{color:#3e2723}.text-grey,i.grey{color:#9e9e9e}.text-grey-50,i.grey-50{color:#fafafa}.text-grey-100,i.grey-100{color:#f5f5f5}.text-grey-200,i.grey-200{color:#eee}.text-grey-300,i.grey-300{color:#e0e0e0}.text-grey-400,i.grey-400{color:#bdbdbd}.text-grey-500,i.grey-500{color:#9e9e9e}.text-grey-600,i.grey-600{color:#757575}.text-grey-700,i.grey-700{color:#616161}.text-grey-800,i.grey-800{color:#424242}.text-grey-900,i.grey-900{color:#212121}.text-blue-grey,i.blue-grey{color:#607d8b}.text-blue-grey-50,i.blue-grey-50{color:#eceff1}.text-blue-grey-100,i.blue-grey-100{color:#cfd8dc}.text-blue-grey-200,i.blue-grey-200{color:#b0bec5}.text-blue-grey-300,i.blue-grey-300{color:#90a4ae}.text-blue-grey-400,i.blue-grey-400{color:#78909c}.text-blue-grey-500,i.blue-grey-500{color:#607d8b}.text-blue-grey-600,i.blue-grey-600{color:#546e7a}.text-blue-grey-700,i.blue-grey-700{color:#455a64}.text-blue-grey-800,i.blue-grey-800{color:#37474f}.text-blue-grey-900,i.blue-grey-900{color:#263238}.text-black,i.black{color:#000}.text-white,i.white{color:#fff}.border-red{border:1px solid #f44336}.border-red-50{border:1px solid #ffebee}.border-red-100{border:1px solid #ffcdd2}.border-red-200{border:1px solid #ef9a9a}.border-red-300{border:1px solid #e57373}.border-red-400{border:1px solid #ef5350}.border-red-500{border:1px solid #f44336}.border-red-600{border:1px solid #e53935}.border-red-700{border:1px solid #d32f2f}.border-red-800{border:1px solid #c62828}.border-red-900{border:1px solid #b71c1c}.border-pink{border:1px solid #e91e63}.border-pink-50{border:1px solid #fce4ec}.border-pink-100{border:1px solid #f8bbd0}.border-pink-200{border:1px solid #f48fb1}.border-pink-300{border:1px solid #f06292}.border-pink-400{border:1px solid #ec407a}.border-pink-500{border:1px solid #e91e63}.border-pink-600{border:1px solid #d81b60}.border-pink-700{border:1px solid #c2185b}.border-pink-800{border:1px solid #ad1457}.border-pink-900{border:1px solid #880e4f}.border-purple{border:1px solid #9c27b0}.border-purple-50{border:1px solid #f3e5f5}.border-purple-100{border:1px solid #e1bee7}.border-purple-200{border:1px solid #ce93d8}.border-purple-300{border:1px solid #ba68c8}.border-purple-400{border:1px solid #ab47bc}.border-purple-500{border:1px solid #9c27b0}.border-purple-600{border:1px solid #8e24aa}.border-purple-700{border:1px solid #7b1fa2}.border-purple-800{border:1px solid #6a1b9a}.border-purple-900{border:1px solid #4a148c}.border-deep-purple{border:1px solid #673ab7}.border-deep-purple-50{border:1px solid #ede7f6}.border-deep-purple-100{border:1px solid #d1c4e9}.border-deep-purple-200{border:1px solid #b39ddb}.border-deep-purple-300{border:1px solid #9575cd}.border-deep-purple-400{border:1px solid #7e57c2}.border-deep-purple-500{border:1px solid #673ab7}.border-deep-purple-600{border:1px solid #5e35b1}.border-deep-purple-700{border:1px solid #512da8}.border-deep-purple-800{border:1px solid #4527a0}.border-deep-purple-900{border:1px solid #311b92}.border-indigo{border:1px solid #3f51b5}.border-indigo-50{border:1px solid #e8eaf6}.border-indigo-100{border:1px solid #c5cae9}.border-indigo-200{border:1px solid #9fa8da}.border-indigo-300{border:1px solid #7986cb}.border-indigo-400{border:1px solid #5c6bc0}.border-indigo-500{border:1px solid #3f51b5}.border-indigo-600{border:1px solid #3949ab}.border-indigo-700{border:1px solid #303f9f}.border-indigo-800{border:1px solid #283593}.border-indigo-900{border:1px solid #1a237e}.border-blue{border:1px solid #2196f3}.border-blue-50{border:1px solid #e3f2fd}.border-blue-100{border:1px solid #bbdefb}.border-blue-200{border:1px solid #90caf9}.border-blue-300{border:1px solid #64b5f6}.border-blue-400{border:1px solid #42a5f5}.border-blue-500{border:1px solid #2196f3}.border-blue-600{border:1px solid #1e88e5}.border-blue-700{border:1px solid #1976d2}.border-blue-800{border:1px solid #1565c0}.border-blue-900{border:1px solid #0d47a1}.border-light-blue{border:1px solid #03a9f4}.border-light-blue-50{border:1px solid #e1f5fe}.border-light-blue-100{border:1px solid #b3e5fc}.border-light-blue-200{border:1px solid #81d4fa}.border-light-blue-300{border:1px solid #4fc3f7}.border-light-blue-400{border:1px solid #29b6f6}.border-light-blue-500{border:1px solid #03a9f4}.border-light-blue-600{border:1px solid #039be5}.border-light-blue-700{border:1px solid #0288d1}.border-light-blue-800{border:1px solid #0277bd}.border-light-blue-900{border:1px solid #01579b}.border-cyan{border:1px solid #00bcd4}.border-cyan-50{border:1px solid #e0f7fa}.border-cyan-100{border:1px solid #b2ebf2}.border-cyan-200{border:1px solid #80deea}.border-cyan-300{border:1px solid #4dd0e1}.border-cyan-400{border:1px solid #26c6da}.border-cyan-500{border:1px solid #00bcd4}.border-cyan-600{border:1px solid #00acc1}.border-cyan-700{border:1px solid #0097a7}.border-cyan-800{border:1px solid #00838f}.border-cyan-900{border:1px solid #006064}.border-teal{border:1px solid #009688}.border-teal-50{border:1px solid #e0f2f1}.border-teal-100{border:1px solid #b2dfdb}.border-teal-200{border:1px solid #80cbc4}.border-teal-300{border:1px solid #4db6ac}.border-teal-400{border:1px solid #26a69a}.border-teal-500{border:1px solid #009688}.border-teal-600{border:1px solid #00897b}.border-teal-700{border:1px solid #00796b}.border-teal-800{border:1px solid #00695c}.border-teal-900{border:1px solid #004d40}.border-green{border:1px solid #4caf50}.border-green-50{border:1px solid #e8f5e9}.border-green-100{border:1px solid #c8e6c9}.border-green-200{border:1px solid #a5d6a7}.border-green-300{border:1px solid #81c784}.border-green-400{border:1px solid #66bb6a}.border-green-500{border:1px solid #4caf50}.border-green-600{border:1px solid #43a047}.border-green-700{border:1px solid #388e3c}.border-green-800{border:1px solid #2e7d32}.border-green-900{border:1px solid #1b5e20}.border-light-green{border:1px solid #8bc34a}.border-light-green-50{border:1px solid #f1f8e9}.border-light-green-100{border:1px solid #dcedc8}.border-light-green-200{border:1px solid #c5e1a5}.border-light-green-300{border:1px solid #aed581}.border-light-green-400{border:1px solid #9ccc65}.border-light-green-500{border:1px solid #8bc34a}.border-light-green-600{border:1px solid #7cb342}.border-light-green-700{border:1px solid #689f38}.border-light-green-800{border:1px solid #558b2f}.border-light-green-900{border:1px solid #33691e}.border-lime{border:1px solid #cddc39}.border-lime-50{border:1px solid #f9fbe7}.border-lime-100{border:1px solid #f0f4c3}.border-lime-200{border:1px solid #e6ee9c}.border-lime-300{border:1px solid #dce775}.border-lime-400{border:1px solid #d4e157}.border-lime-500{border:1px solid #cddc39}.border-lime-600{border:1px solid #c0ca33}.border-lime-700{border:1px solid #afb42b}.border-lime-800{border:1px solid #9e9d24}.border-lime-900{border:1px solid #827717}.border-yellow{border:1px solid #ffeb3b}.border-yellow-50{border:1px solid #fffde7}.border-yellow-100{border:1px solid #fff9c4}.border-yellow-200{border:1px solid #fff59d}.border-yellow-300{border:1px solid #fff176}.border-yellow-400{border:1px solid #ffee58}.border-yellow-500{border:1px solid #ffeb3b}.border-yellow-600{border:1px solid #fdd835}.border-yellow-700{border:1px solid #fbc02d}.border-yellow-800{border:1px solid #f9a825}.border-yellow-900{border:1px solid #f57f17}.border-amber{border:1px solid #ffc107}.border-amber-50{border:1px solid #fff8e1}.border-amber-100{border:1px solid #ffecb3}.border-amber-200{border:1px solid #ffe082}.border-amber-300{border:1px solid #ffd54f}.border-amber-400{border:1px solid #ffca28}.border-amber-500{border:1px solid #ffc107}.border-amber-600{border:1px solid #ffb300}.border-amber-700{border:1px solid #ffa000}.border-amber-800{border:1px solid #ff8f00}.border-amber-900{border:1px solid #ff6f00}.border-orange{border:1px solid #ff9800}.border-orange-50{border:1px solid #fff3e0}.border-orange-100{border:1px solid #ffe0b2}.border-orange-200{border:1px solid #ffcc80}.border-orange-300{border:1px solid #ffb74d}.border-orange-400{border:1px solid #ffa726}.border-orange-500{border:1px solid #ff9800}.border-orange-600{border:1px solid #fb8c00}.border-orange-700{border:1px solid #f57c00}.border-orange-800{border:1px solid #ef6c00}.border-orange-900{border:1px solid #e65100}.border-deep-orange{border:1px solid #ff5722}.border-deep-orange-50{border:1px solid #fbe9e7}.border-deep-orange-100{border:1px solid #ffccbc}.border-deep-orange-200{border:1px solid #ffab91}.border-deep-orange-300{border:1px solid #ff8a65}.border-deep-orange-400{border:1px solid #ff7043}.border-deep-orange-500{border:1px solid #ff5722}.border-deep-orange-600{border:1px solid #f4511e}.border-deep-orange-700{border:1px solid #e64a19}.border-deep-orange-800{border:1px solid #d84315}.border-deep-orange-900{border:1px solid #bf360c}.border-brown{border:1px solid #795548}.border-brown-50{border:1px solid #efebe9}.border-brown-100{border:1px solid #d7ccc8}.border-brown-200{border:1px solid #bcaaa4}.border-brown-300{border:1px solid #a1887f}.border-brown-400{border:1px solid #8d6e63}.border-brown-500{border:1px solid #795548}.border-brown-600{border:1px solid #6d4c41}.border-brown-700{border:1px solid #5d4037}.border-brown-800{border:1px solid #4e342e}.border-brown-900{border:1px solid #3e2723}.border-grey{border:1px solid #9e9e9e}.border-grey-50{border:1px solid #fafafa}.border-grey-100{border:1px solid #f5f5f5}.border-grey-200{border:1px solid #eee}.border-grey-300{border:1px solid #e0e0e0}.border-grey-400{border:1px solid #bdbdbd}.border-grey-500{border:1px solid #9e9e9e}.border-grey-600{border:1px solid #757575}.border-grey-700{border:1px solid #616161}.border-grey-800{border:1px solid #424242}.border-grey-900{border:1px solid #212121}.border-blue-grey{border:1px solid #607d8b}.border-blue-grey-50{border:1px solid #eceff1}.border-blue-grey-100{border:1px solid #cfd8dc}.border-blue-grey-200{border:1px solid #b0bec5}.border-blue-grey-300{border:1px solid #90a4ae}.border-blue-grey-400{border:1px solid #78909c}.border-blue-grey-500{border:1px solid #607d8b}.border-blue-grey-600{border:1px solid #546e7a}.border-blue-grey-700{border:1px solid #455a64}.border-blue-grey-800{border:1px solid #37474f}.border-blue-grey-900{border:1px solid #263238}.border-black{border:1px solid #000}.border-white{border:1px solid #fff}@font-face{font-family:Roboto;font-style:normal;font-weight:300;src:local('Roboto Light'),local('Roboto-Light'),url(fonts/robotolight.woff2) format('woff2');unicode-range:U+0460-052F,U+20B4,U+2DE0-2DFF,U+A640-A69F}@font-face{font-family:Roboto;font-style:normal;font-weight:400;src:local('Roboto'),local('Roboto-Regular'),url(fonts/sTdaA6j0Psb920Vjv-mrzH-_kf6ByYO6CLYdB4HQE-Y.woff2) format('woff2');unicode-range:U+0460-052F,U+20B4,U+2DE0-2DFF,U+A640-A69F}@font-face{font-family:Roboto;font-style:normal;font-weight:900;src:local('Roboto Black'),local('Roboto-Black'),url(fonts/robotoblack.woff2) format('woff2');unicode-range:U+0460-052F,U+20B4,U+2DE0-2DFF,U+A640-A69F}@font-face{font-family:Ionicons;src:url(fonts/ionicons.woff?v=2.0.0) format("woff");font-weight:400;font-style:normal}i.icon{background:0 0!important}.ion,.ion-alert-circled:before,.ion-alert:before,.ion-android-add-circle:before,.ion-android-add:before,.ion-android-alarm-clock:before,.ion-android-alert:before,.ion-android-apps:before,.ion-android-archive:before,.ion-android-arrow-back:before,.ion-android-arrow-down:before,.ion-android-arrow-dropdown-circle:before,.ion-android-arrow-dropdown:before,.ion-android-arrow-dropleft-circle:before,.ion-android-arrow-dropleft:before,.ion-android-arrow-dropright-circle:before,.ion-android-arrow-dropright:before,.ion-android-arrow-dropup-circle:before,.ion-android-arrow-dropup:before,.ion-android-arrow-forward:before,.ion-android-arrow-up:before,.ion-android-attach:before,.ion-android-bar:before,.ion-android-bicycle:before,.ion-android-boat:before,.ion-android-bookmark:before,.ion-android-bulb:before,.ion-android-bus:before,.ion-android-calendar:before,.ion-android-call:before,.ion-android-camera:before,.ion-android-cancel:before,.ion-android-car:before,.ion-android-cart:before,.ion-android-chat:before,.ion-android-checkbox-blank:before,.ion-android-checkbox-outline-blank:before,.ion-android-checkbox-outline:before,.ion-android-checkbox:before,.ion-android-checkmark-circle:before,.ion-android-clipboard:before,.ion-android-close:before,.ion-android-cloud-circle:before,.ion-android-cloud-done:before,.ion-android-cloud-outline:before,.ion-android-cloud:before,.ion-android-color-palette:before,.ion-android-compass:before,.ion-android-contact:before,.ion-android-contacts:before,.ion-android-contract:before,.ion-android-create:before,.ion-android-delete:before,.ion-android-desktop:before,.ion-android-document:before,.ion-android-done-all:before,.ion-android-done:before,.ion-android-download:before,.ion-android-drafts:before,.ion-android-exit:before,.ion-android-expand:before,.ion-android-favorite-outline:before,.ion-android-favorite:before,.ion-android-film:before,.ion-android-folder-open:before,.ion-android-folder:before,.ion-android-funnel:before,.ion-android-globe:before,.ion-android-hand:before,.ion-android-hangout:before,.ion-android-happy:before,.ion-android-home:before,.ion-android-image:before,.ion-android-laptop:before,.ion-android-list:before,.ion-android-locate:before,.ion-android-lock:before,.ion-android-mail:before,.ion-android-map:before,.ion-android-menu:before,.ion-android-microphone-off:before,.ion-android-microphone:before,.ion-android-more-horizontal:before,.ion-android-more-vertical:before,.ion-android-navigate:before,.ion-android-notifications-none:before,.ion-android-notifications-off:before,.ion-android-notifications:before,.ion-android-open:before,.ion-android-options:before,.ion-android-people:before,.ion-android-person-add:before,.ion-android-person:before,.ion-android-phone-landscape:before,.ion-android-phone-portrait:before,.ion-android-pin:before,.ion-android-plane:before,.ion-android-playstore:before,.ion-android-print:before,.ion-android-radio-button-off:before,.ion-android-radio-button-on:before,.ion-android-refresh:before,.ion-android-remove-circle:before,.ion-android-remove:before,.ion-android-restaurant:before,.ion-android-sad:before,.ion-android-search:before,.ion-android-send:before,.ion-android-settings:before,.ion-android-share-alt:before,.ion-android-share:before,.ion-android-star-half:before,.ion-android-star-outline:before,.ion-android-star:before,.ion-android-stopwatch:before,.ion-android-subway:before,.ion-android-sunny:before,.ion-android-sync:before,.ion-android-textsms:before,.ion-android-time:before,.ion-android-train:before,.ion-android-unlock:before,.ion-android-upload:before,.ion-android-volume-down:before,.ion-android-volume-mute:before,.ion-android-volume-off:before,.ion-android-volume-up:before,.ion-android-walk:before,.ion-android-warning:before,.ion-android-watch:before,.ion-android-wifi:before,.ion-aperture:before,.ion-archive:before,.ion-arrow-down-a:before,.ion-arrow-down-b:before,.ion-arrow-down-c:before,.ion-arrow-expand:before,.ion-arrow-graph-down-left:before,.ion-arrow-graph-down-right:before,.ion-arrow-graph-up-left:before,.ion-arrow-graph-up-right:before,.ion-arrow-left-a:before,.ion-arrow-left-b:before,.ion-arrow-left-c:before,.ion-arrow-move:before,.ion-arrow-resize:before,.ion-arrow-return-left:before,.ion-arrow-return-right:before,.ion-arrow-right-a:before,.ion-arrow-right-b:before,.ion-arrow-right-c:before,.ion-arrow-shrink:before,.ion-arrow-swap:before,.ion-arrow-up-a:before,.ion-arrow-up-b:before,.ion-arrow-up-c:before,.ion-asterisk:before,.ion-at:before,.ion-backspace-outline:before,.ion-backspace:before,.ion-bag:before,.ion-battery-charging:before,.ion-battery-empty:before,.ion-battery-full:before,.ion-battery-half:before,.ion-battery-low:before,.ion-beaker:before,.ion-beer:before,.ion-bluetooth:before,.ion-bonfire:before,.ion-bookmark:before,.ion-bowtie:before,.ion-briefcase:before,.ion-bug:before,.ion-calculator:before,.ion-calendar:before,.ion-camera:before,.ion-card:before,.ion-cash:before,.ion-chatbox-working:before,.ion-chatbox:before,.ion-chatboxes:before,.ion-chatbubble-working:before,.ion-chatbubble:before,.ion-chatbubbles:before,.ion-checkmark-circled:before,.ion-checkmark-round:before,.ion-checkmark:before,.ion-chevron-down:before,.ion-chevron-left:before,.ion-chevron-right:before,.ion-chevron-up:before,.ion-clipboard:before,.ion-clock:before,.ion-close-circled:before,.ion-close-round:before,.ion-close:before,.ion-closed-captioning:before,.ion-cloud:before,.ion-code-download:before,.ion-code-working:before,.ion-code:before,.ion-coffee:before,.ion-compass:before,.ion-compose:before,.ion-connection-bars:before,.ion-contrast:before,.ion-crop:before,.ion-cube:before,.ion-disc:before,.ion-document-text:before,.ion-document:before,.ion-drag:before,.ion-earth:before,.ion-easel:before,.ion-edit:before,.ion-egg:before,.ion-eject:before,.ion-email-unread:before,.ion-email:before,.ion-erlenmeyer-flask-bubbles:before,.ion-erlenmeyer-flask:before,.ion-eye-disabled:before,.ion-eye:before,.ion-female:before,.ion-filing:before,.ion-film-marker:before,.ion-fireball:before,.ion-flag:before,.ion-flame:before,.ion-flash-off:before,.ion-flash:before,.ion-folder:before,.ion-fork-repo:before,.ion-fork:before,.ion-forward:before,.ion-funnel:before,.ion-gear-a:before,.ion-gear-b:before,.ion-grid:before,.ion-hammer:before,.ion-happy-outline:before,.ion-happy:before,.ion-headphone:before,.ion-heart-broken:before,.ion-heart:before,.ion-help-buoy:before,.ion-help-circled:before,.ion-help:before,.ion-home:before,.ion-icecream:before,.ion-image:before,.ion-images:before,.ion-information-circled:before,.ion-information:before,.ion-ionic:before,.ion-ios-alarm-outline:before,.ion-ios-alarm:before,.ion-ios-albums-outline:before,.ion-ios-albums:before,.ion-ios-americanfootball-outline:before,.ion-ios-americanfootball:before,.ion-ios-analytics-outline:before,.ion-ios-analytics:before,.ion-ios-arrow-back:before,.ion-ios-arrow-down:before,.ion-ios-arrow-forward:before,.ion-ios-arrow-left:before,.ion-ios-arrow-right:before,.ion-ios-arrow-thin-down:before,.ion-ios-arrow-thin-left:before,.ion-ios-arrow-thin-right:before,.ion-ios-arrow-thin-up:before,.ion-ios-arrow-up:before,.ion-ios-at-outline:before,.ion-ios-at:before,.ion-ios-barcode-outline:before,.ion-ios-barcode:before,.ion-ios-baseball-outline:before,.ion-ios-baseball:before,.ion-ios-basketball-outline:before,.ion-ios-basketball:before,.ion-ios-bell-outline:before,.ion-ios-bell:before,.ion-ios-body-outline:before,.ion-ios-body:before,.ion-ios-bolt-outline:before,.ion-ios-bolt:before,.ion-ios-book-outline:before,.ion-ios-book:before,.ion-ios-bookmarks-outline:before,.ion-ios-bookmarks:before,.ion-ios-box-outline:before,.ion-ios-box:before,.ion-ios-briefcase-outline:before,.ion-ios-briefcase:before,.ion-ios-browsers-outline:before,.ion-ios-browsers:before,.ion-ios-calculator-outline:before,.ion-ios-calculator:before,.ion-ios-calendar-outline:before,.ion-ios-calendar:before,.ion-ios-camera-outline:before,.ion-ios-camera:before,.ion-ios-cart-outline:before,.ion-ios-cart:before,.ion-ios-chatboxes-outline:before,.ion-ios-chatboxes:before,.ion-ios-chatbubble-outline:before,.ion-ios-chatbubble:before,.ion-ios-checkmark-empty:before,.ion-ios-checkmark-outline:before,.ion-ios-checkmark:before,.ion-ios-circle-filled:before,.ion-ios-circle-outline:before,.ion-ios-clock-outline:before,.ion-ios-clock:before,.ion-ios-close-empty:before,.ion-ios-close-outline:before,.ion-ios-close:before,.ion-ios-cloud-download-outline:before,.ion-ios-cloud-download:before,.ion-ios-cloud-outline:before,.ion-ios-cloud-upload-outline:before,.ion-ios-cloud-upload:before,.ion-ios-cloud:before,.ion-ios-cloudy-night-outline:before,.ion-ios-cloudy-night:before,.ion-ios-cloudy-outline:before,.ion-ios-cloudy:before,.ion-ios-cog-outline:before,.ion-ios-cog:before,.ion-ios-color-filter-outline:before,.ion-ios-color-filter:before,.ion-ios-color-wand-outline:before,.ion-ios-color-wand:before,.ion-ios-compose-outline:before,.ion-ios-compose:before,.ion-ios-contact-outline:before,.ion-ios-contact:before,.ion-ios-copy-outline:before,.ion-ios-copy:before,.ion-ios-crop-strong:before,.ion-ios-crop:before,.ion-ios-download-outline:before,.ion-ios-download:before,.ion-ios-drag:before,.ion-ios-email-outline:before,.ion-ios-email:before,.ion-ios-eye-outline:before,.ion-ios-eye:before,.ion-ios-fastforward-outline:before,.ion-ios-fastforward:before,.ion-ios-filing-outline:before,.ion-ios-filing:before,.ion-ios-film-outline:before,.ion-ios-film:before,.ion-ios-flag-outline:before,.ion-ios-flag:before,.ion-ios-flame-outline:before,.ion-ios-flame:before,.ion-ios-flask-outline:before,.ion-ios-flask:before,.ion-ios-flower-outline:before,.ion-ios-flower:before,.ion-ios-folder-outline:before,.ion-ios-folder:before,.ion-ios-football-outline:before,.ion-ios-football:before,.ion-ios-game-controller-a-outline:before,.ion-ios-game-controller-a:before,.ion-ios-game-controller-b-outline:before,.ion-ios-game-controller-b:before,.ion-ios-gear-outline:before,.ion-ios-gear:before,.ion-ios-glasses-outline:before,.ion-ios-glasses:before,.ion-ios-grid-view-outline:before,.ion-ios-grid-view:before,.ion-ios-heart-outline:before,.ion-ios-heart:before,.ion-ios-help-empty:before,.ion-ios-help-outline:before,.ion-ios-help:before,.ion-ios-home-outline:before,.ion-ios-home:before,.ion-ios-infinite-outline:before,.ion-ios-infinite:before,.ion-ios-information-empty:before,.ion-ios-information-outline:before,.ion-ios-information:before,.ion-ios-ionic-outline:before,.ion-ios-keypad-outline:before,.ion-ios-keypad:before,.ion-ios-lightbulb-outline:before,.ion-ios-lightbulb:before,.ion-ios-list-outline:before,.ion-ios-list:before,.ion-ios-location-outline:before,.ion-ios-location:before,.ion-ios-locked-outline:before,.ion-ios-locked:before,.ion-ios-loop-strong:before,.ion-ios-loop:before,.ion-ios-medical-outline:before,.ion-ios-medical:before,.ion-ios-medkit-outline:before,.ion-ios-medkit:before,.ion-ios-mic-off:before,.ion-ios-mic-outline:before,.ion-ios-mic:before,.ion-ios-minus-empty:before,.ion-ios-minus-outline:before,.ion-ios-minus:before,.ion-ios-monitor-outline:before,.ion-ios-monitor:before,.ion-ios-moon-outline:before,.ion-ios-moon:before,.ion-ios-more-outline:before,.ion-ios-more:before,.ion-ios-musical-note:before,.ion-ios-musical-notes:before,.ion-ios-navigate-outline:before,.ion-ios-navigate:before,.ion-ios-nutrition-outline:before,.ion-ios-nutrition:before,.ion-ios-paper-outline:before,.ion-ios-paper:before,.ion-ios-paperplane-outline:before,.ion-ios-paperplane:before,.ion-ios-partlysunny-outline:before,.ion-ios-partlysunny:before,.ion-ios-pause-outline:before,.ion-ios-pause:before,.ion-ios-paw-outline:before,.ion-ios-paw:before,.ion-ios-people-outline:before,.ion-ios-people:before,.ion-ios-person-outline:before,.ion-ios-person:before,.ion-ios-personadd-outline:before,.ion-ios-personadd:before,.ion-ios-photos-outline:before,.ion-ios-photos:before,.ion-ios-pie-outline:before,.ion-ios-pie:before,.ion-ios-pint-outline:before,.ion-ios-pint:before,.ion-ios-play-outline:before,.ion-ios-play:before,.ion-ios-plus-empty:before,.ion-ios-plus-outline:before,.ion-ios-plus:before,.ion-ios-pricetag-outline:before,.ion-ios-pricetag:before,.ion-ios-pricetags-outline:before,.ion-ios-pricetags:before,.ion-ios-printer-outline:before,.ion-ios-printer:before,.ion-ios-pulse-strong:before,.ion-ios-pulse:before,.ion-ios-rainy-outline:before,.ion-ios-rainy:before,.ion-ios-recording-outline:before,.ion-ios-recording:before,.ion-ios-redo-outline:before,.ion-ios-redo:before,.ion-ios-refresh-empty:before,.ion-ios-refresh-outline:before,.ion-ios-refresh:before,.ion-ios-reload:before,.ion-ios-reverse-camera-outline:before,.ion-ios-reverse-camera:before,.ion-ios-rewind-outline:before,.ion-ios-rewind:before,.ion-ios-rose-outline:before,.ion-ios-rose:before,.ion-ios-search-strong:before,.ion-ios-search:before,.ion-ios-settings-strong:before,.ion-ios-settings:before,.ion-ios-shuffle-strong:before,.ion-ios-shuffle:before,.ion-ios-skipbackward-outline:before,.ion-ios-skipbackward:before,.ion-ios-skipforward-outline:before,.ion-ios-skipforward:before,.ion-ios-snowy:before,.ion-ios-speedometer-outline:before,.ion-ios-speedometer:before,.ion-ios-star-half:before,.ion-ios-star-outline:before,.ion-ios-star:before,.ion-ios-stopwatch-outline:before,.ion-ios-stopwatch:before,.ion-ios-sunny-outline:before,.ion-ios-sunny:before,.ion-ios-telephone-outline:before,.ion-ios-telephone:before,.ion-ios-tennisball-outline:before,.ion-ios-tennisball:before,.ion-ios-thunderstorm-outline:before,.ion-ios-thunderstorm:before,.ion-ios-time-outline:before,.ion-ios-time:before,.ion-ios-timer-outline:before,.ion-ios-timer:before,.ion-ios-toggle-outline:before,.ion-ios-toggle:before,.ion-ios-trash-outline:before,.ion-ios-trash:before,.ion-ios-undo-outline:before,.ion-ios-undo:before,.ion-ios-unlocked-outline:before,.ion-ios-unlocked:before,.ion-ios-upload-outline:before,.ion-ios-upload:before,.ion-ios-videocam-outline:before,.ion-ios-videocam:before,.ion-ios-volume-high:before,.ion-ios-volume-low:before,.ion-ios-wineglass-outline:before,.ion-ios-wineglass:before,.ion-ios-world-outline:before,.ion-ios-world:before,.ion-ipad:before,.ion-iphone:before,.ion-ipod:before,.ion-jet:before,.ion-key:before,.ion-knife:before,.ion-laptop:before,.ion-leaf:before,.ion-levels:before,.ion-lightbulb:before,.ion-link:before,.ion-load-a:before,.ion-load-b:before,.ion-load-c:before,.ion-load-d:before,.ion-location:before,.ion-lock-combination:before,.ion-locked:before,.ion-log-in:before,.ion-log-out:before,.ion-loop:before,.ion-magnet:before,.ion-male:before,.ion-man:before,.ion-map:before,.ion-medkit:before,.ion-merge:before,.ion-mic-a:before,.ion-mic-b:before,.ion-mic-c:before,.ion-minus-circled:before,.ion-minus-round:before,.ion-minus:before,.ion-model-s:before,.ion-monitor:before,.ion-more:before,.ion-mouse:before,.ion-music-note:before,.ion-navicon-round:before,.ion-navicon:before,.ion-navigate:before,.ion-network:before,.ion-no-smoking:before,.ion-nuclear:before,.ion-outlet:before,.ion-paintbrush:before,.ion-paintbucket:before,.ion-paper-airplane:before,.ion-paperclip:before,.ion-pause:before,.ion-person-add:before,.ion-person-stalker:before,.ion-person:before,.ion-pie-graph:before,.ion-pin:before,.ion-pinpoint:before,.ion-pizza:before,.ion-plane:before,.ion-planet:before,.ion-play:before,.ion-playstation:before,.ion-plus-circled:before,.ion-plus-round:before,.ion-plus:before,.ion-podium:before,.ion-pound:before,.ion-power:before,.ion-pricetag:before,.ion-pricetags:before,.ion-printer:before,.ion-pull-request:before,.ion-qr-scanner:before,.ion-quote:before,.ion-radio-waves:before,.ion-record:before,.ion-refresh:before,.ion-reply-all:before,.ion-reply:before,.ion-ribbon-a:before,.ion-ribbon-b:before,.ion-sad-outline:before,.ion-sad:before,.ion-scissors:before,.ion-search:before,.ion-settings:before,.ion-share:before,.ion-shuffle:before,.ion-skip-backward:before,.ion-skip-forward:before,.ion-social-android-outline:before,.ion-social-android:before,.ion-social-angular-outline:before,.ion-social-angular:before,.ion-social-apple-outline:before,.ion-social-apple:before,.ion-social-bitcoin-outline:before,.ion-social-bitcoin:before,.ion-social-buffer-outline:before,.ion-social-buffer:before,.ion-social-chrome-outline:before,.ion-social-chrome:before,.ion-social-codepen-outline:before,.ion-social-codepen:before,.ion-social-css3-outline:before,.ion-social-css3:before,.ion-social-designernews-outline:before,.ion-social-designernews:before,.ion-social-dribbble-outline:before,.ion-social-dribbble:before,.ion-social-dropbox-outline:before,.ion-social-dropbox:before,.ion-social-euro-outline:before,.ion-social-euro:before,.ion-social-facebook-outline:before,.ion-social-facebook:before,.ion-social-foursquare-outline:before,.ion-social-foursquare:before,.ion-social-freebsd-devil:before,.ion-social-github-outline:before,.ion-social-github:before,.ion-social-google-outline:before,.ion-social-google:before,.ion-social-googleplus-outline:before,.ion-social-googleplus:before,.ion-social-hackernews-outline:before,.ion-social-hackernews:before,.ion-social-html5-outline:before,.ion-social-html5:before,.ion-social-instagram-outline:before,.ion-social-instagram:before,.ion-social-javascript-outline:before,.ion-social-javascript:before,.ion-social-linkedin-outline:before,.ion-social-linkedin:before,.ion-social-markdown:before,.ion-social-nodejs:before,.ion-social-octocat:before,.ion-social-pinterest-outline:before,.ion-social-pinterest:before,.ion-social-python:before,.ion-social-reddit-outline:before,.ion-social-reddit:before,.ion-social-rss-outline:before,.ion-social-rss:before,.ion-social-sass:before,.ion-social-skype-outline:before,.ion-social-skype:before,.ion-social-snapchat-outline:before,.ion-social-snapchat:before,.ion-social-tumblr-outline:before,.ion-social-tumblr:before,.ion-social-tux:before,.ion-social-twitch-outline:before,.ion-social-twitch:before,.ion-social-twitter-outline:before,.ion-social-twitter:before,.ion-social-usd-outline:before,.ion-social-usd:before,.ion-social-vimeo-outline:before,.ion-social-vimeo:before,.ion-social-whatsapp-outline:before,.ion-social-whatsapp:before,.ion-social-windows-outline:before,.ion-social-windows:before,.ion-social-wordpress-outline:before,.ion-social-wordpress:before,.ion-social-yahoo-outline:before,.ion-social-yahoo:before,.ion-social-yen-outline:before,.ion-social-yen:before,.ion-social-youtube-outline:before,.ion-social-youtube:before,.ion-soup-can-outline:before,.ion-soup-can:before,.ion-speakerphone:before,.ion-speedometer:before,.ion-spoon:before,.ion-star:before,.ion-stats-bars:before,.ion-steam:before,.ion-stop:before,.ion-thermometer:before,.ion-thumbsdown:before,.ion-thumbsup:before,.ion-toggle-filled:before,.ion-toggle:before,.ion-transgender:before,.ion-trash-a:before,.ion-trash-b:before,.ion-trophy:before,.ion-tshirt-outline:before,.ion-tshirt:before,.ion-umbrella:before,.ion-university:before,.ion-unlocked:before,.ion-upload:before,.ion-usb:before,.ion-videocamera:before,.ion-volume-high:before,.ion-volume-low:before,.ion-volume-medium:before,.ion-volume-mute:before,.ion-wand:before,.ion-waterdrop:before,.ion-wifi:before,.ion-wineglass:before,.ion-woman:before,.ion-wrench:before,.ion-xbox:before,.ionicons{display:inline-block;font-family:Ionicons;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;text-rendering:auto;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;min-width:22px;text-align:center}.ion-alert:before{content:"\f101"}.ion-alert-circled:before{content:"\f100"}.ion-android-add:before{content:"\f2c7"}.ion-android-add-circle:before{content:"\f359"}.ion-android-alarm-clock:before{content:"\f35a"}.ion-android-alert:before{content:"\f35b"}.ion-android-apps:before{content:"\f35c"}.ion-android-archive:before{content:"\f2c9"}.ion-android-arrow-back:before{content:"\f2ca"}.ion-android-arrow-down:before{content:"\f35d"}.ion-android-arrow-dropdown:before{content:"\f35f"}.ion-android-arrow-dropdown-circle:before{content:"\f35e"}.ion-android-arrow-dropleft:before{content:"\f361"}.ion-android-arrow-dropleft-circle:before{content:"\f360"}.ion-android-arrow-dropright:before{content:"\f363"}.ion-android-arrow-dropright-circle:before{content:"\f362"}.ion-android-arrow-dropup:before{content:"\f365"}.ion-android-arrow-dropup-circle:before{content:"\f364"}.ion-android-arrow-forward:before{content:"\f30f"}.ion-android-arrow-up:before{content:"\f366"}.ion-android-attach:before{content:"\f367"}.ion-android-bar:before{content:"\f368"}.ion-android-bicycle:before{content:"\f369"}.ion-android-boat:before{content:"\f36a"}.ion-android-bookmark:before{content:"\f36b"}.ion-android-bulb:before{content:"\f36c"}.ion-android-bus:before{content:"\f36d"}.ion-android-calendar:before{content:"\f2d1"}.ion-android-call:before{content:"\f2d2"}.ion-android-camera:before{content:"\f2d3"}.ion-android-cancel:before{content:"\f36e"}.ion-android-car:before{content:"\f36f"}.ion-android-cart:before{content:"\f370"}.ion-android-chat:before{content:"\f2d4"}.ion-android-checkbox:before{content:"\f374"}.ion-android-checkbox-blank:before{content:"\f371"}.ion-android-checkbox-outline:before{content:"\f373"}.ion-android-checkbox-outline-blank:before{content:"\f372"}.ion-android-checkmark-circle:before{content:"\f375"}.ion-android-clipboard:before{content:"\f376"}.ion-android-close:before{content:"\f2d7"}.ion-android-cloud:before{content:"\f37a"}.ion-android-cloud-circle:before{content:"\f377"}.ion-android-cloud-done:before{content:"\f378"}.ion-android-cloud-outline:before{content:"\f379"}.ion-android-color-palette:before{content:"\f37b"}.ion-android-compass:before{content:"\f37c"}.ion-android-contact:before{content:"\f2d8"}.ion-android-contacts:before{content:"\f2d9"}.ion-android-contract:before{content:"\f37d"}.ion-android-create:before{content:"\f37e"}.ion-android-delete:before{content:"\f37f"}.ion-android-desktop:before{content:"\f380"}.ion-android-document:before{content:"\f381"}.ion-android-done:before{content:"\f383"}.ion-android-done-all:before{content:"\f382"}.ion-android-download:before{content:"\f2dd"}.ion-android-drafts:before{content:"\f384"}.ion-android-exit:before{content:"\f385"}.ion-android-expand:before{content:"\f386"}.ion-android-favorite:before{content:"\f388"}.ion-android-favorite-outline:before{content:"\f387"}.ion-android-film:before{content:"\f389"}.ion-android-folder:before{content:"\f2e0"}.ion-android-folder-open:before{content:"\f38a"}.ion-android-funnel:before{content:"\f38b"}.ion-android-globe:before{content:"\f38c"}.ion-android-hand:before{content:"\f2e3"}.ion-android-hangout:before{content:"\f38d"}.ion-android-happy:before{content:"\f38e"}.ion-android-home:before{content:"\f38f"}.ion-android-image:before{content:"\f2e4"}.ion-android-laptop:before{content:"\f390"}.ion-android-list:before{content:"\f391"}.ion-android-locate:before{content:"\f2e9"}.ion-android-lock:before{content:"\f392"}.ion-android-mail:before{content:"\f2eb"}.ion-android-map:before{content:"\f393"}.ion-android-menu:before{content:"\f394"}.ion-android-microphone:before{content:"\f2ec"}.ion-android-microphone-off:before{content:"\f395"}.ion-android-more-horizontal:before{content:"\f396"}.ion-android-more-vertical:before{content:"\f397"}.ion-android-navigate:before{content:"\f398"}.ion-android-notifications:before{content:"\f39b"}.ion-android-notifications-none:before{content:"\f399"}.ion-android-notifications-off:before{content:"\f39a"}.ion-android-open:before{content:"\f39c"}.ion-android-options:before{content:"\f39d"}.ion-android-people:before{content:"\f39e"}.ion-android-person:before{content:"\f3a0"}.ion-android-person-add:before{content:"\f39f"}.ion-android-phone-landscape:before{content:"\f3a1"}.ion-android-phone-portrait:before{content:"\f3a2"}.ion-android-pin:before{content:"\f3a3"}.ion-android-plane:before{content:"\f3a4"}.ion-android-playstore:before{content:"\f2f0"}.ion-android-print:before{content:"\f3a5"}.ion-android-radio-button-off:before{content:"\f3a6"}.ion-android-radio-button-on:before{content:"\f3a7"}.ion-android-refresh:before{content:"\f3a8"}.ion-android-remove:before{content:"\f2f4"}.ion-android-remove-circle:before{content:"\f3a9"}.ion-android-restaurant:before{content:"\f3aa"}.ion-android-sad:before{content:"\f3ab"}.ion-android-search:before{content:"\f2f5"}.ion-android-send:before{content:"\f2f6"}.ion-android-settings:before{content:"\f2f7"}.ion-android-share:before{content:"\f2f8"}.ion-android-share-alt:before{content:"\f3ac"}.ion-android-star:before{content:"\f2fc"}.ion-android-star-half:before{content:"\f3ad"}.ion-android-star-outline:before{content:"\f3ae"}.ion-android-stopwatch:before{content:"\f2fd"}.ion-android-subway:before{content:"\f3af"}.ion-android-sunny:before{content:"\f3b0"}.ion-android-sync:before{content:"\f3b1"}.ion-android-textsms:before{content:"\f3b2"}.ion-android-time:before{content:"\f3b3"}.ion-android-train:before{content:"\f3b4"}.ion-android-unlock:before{content:"\f3b5"}.ion-android-upload:before{content:"\f3b6"}.ion-android-volume-down:before{content:"\f3b7"}.ion-android-volume-mute:before{content:"\f3b8"}.ion-android-volume-off:before{content:"\f3b9"}.ion-android-volume-up:before{content:"\f3ba"}.ion-android-walk:before{content:"\f3bb"}.ion-android-warning:before{content:"\f3bc"}.ion-android-watch:before{content:"\f3bd"}.ion-android-wifi:before{content:"\f305"}.ion-aperture:before{content:"\f313"}.ion-archive:before{content:"\f102"}.ion-arrow-down-a:before{content:"\f103"}.ion-arrow-down-b:before{content:"\f104"}.ion-arrow-down-c:before{content:"\f105"}.ion-arrow-expand:before{content:"\f25e"}.ion-arrow-graph-down-left:before{content:"\f25f"}.ion-arrow-graph-down-right:before{content:"\f260"}.ion-arrow-graph-up-left:before{content:"\f261"}.ion-arrow-graph-up-right:before{content:"\f262"}.ion-arrow-left-a:before{content:"\f106"}.ion-arrow-left-b:before{content:"\f107"}.ion-arrow-left-c:before{content:"\f108"}.ion-arrow-move:before{content:"\f263"}.ion-arrow-resize:before{content:"\f264"}.ion-arrow-return-left:before{content:"\f265"}.ion-arrow-return-right:before{content:"\f266"}.ion-arrow-right-a:before{content:"\f109"}.ion-arrow-right-b:before{content:"\f10a"}.ion-arrow-right-c:before{content:"\f10b"}.ion-arrow-shrink:before{content:"\f267"}.ion-arrow-swap:before{content:"\f268"}.ion-arrow-up-a:before{content:"\f10c"}.ion-arrow-up-b:before{content:"\f10d"}.ion-arrow-up-c:before{content:"\f10e"}.ion-asterisk:before{content:"\f314"}.ion-at:before{content:"\f10f"}.ion-backspace:before{content:"\f3bf"}.ion-backspace-outline:before{content:"\f3be"}.ion-bag:before{content:"\f110"}.ion-battery-charging:before{content:"\f111"}.ion-battery-empty:before{content:"\f112"}.ion-battery-full:before{content:"\f113"}.ion-battery-half:before{content:"\f114"}.ion-battery-low:before{content:"\f115"}.ion-beaker:before{content:"\f269"}.ion-beer:before{content:"\f26a"}.ion-bluetooth:before{content:"\f116"}.ion-bonfire:before{content:"\f315"}.ion-bookmark:before{content:"\f26b"}.ion-bowtie:before{content:"\f3c0"}.ion-briefcase:before{content:"\f26c"}.ion-bug:before{content:"\f2be"}.ion-calculator:before{content:"\f26d"}.ion-calendar:before{content:"\f117"}.ion-camera:before{content:"\f118"}.ion-card:before{content:"\f119"}.ion-cash:before{content:"\f316"}.ion-chatbox:before{content:"\f11b"}.ion-chatbox-working:before{content:"\f11a"}.ion-chatboxes:before{content:"\f11c"}.ion-chatbubble:before{content:"\f11e"}.ion-chatbubble-working:before{content:"\f11d"}.ion-chatbubbles:before{content:"\f11f"}.ion-checkmark:before{content:"\f122"}.ion-checkmark-circled:before{content:"\f120"}.ion-checkmark-round:before{content:"\f121"}.ion-chevron-down:before{content:"\f123"}.ion-chevron-left:before{content:"\f124"}.ion-chevron-right:before{content:"\f125"}.ion-chevron-up:before{content:"\f126"}.ion-clipboard:before{content:"\f127"}.ion-clock:before{content:"\f26e"}.ion-close:before{content:"\f12a"}.ion-close-circled:before{content:"\f128"}.ion-close-round:before{content:"\f129"}.ion-closed-captioning:before{content:"\f317"}.ion-cloud:before{content:"\f12b"}.ion-code:before{content:"\f271"}.ion-code-download:before{content:"\f26f"}.ion-code-working:before{content:"\f270"}.ion-coffee:before{content:"\f272"}.ion-compass:before{content:"\f273"}.ion-compose:before{content:"\f12c"}.ion-connection-bars:before{content:"\f274"}.ion-contrast:before{content:"\f275"}.ion-crop:before{content:"\f3c1"}.ion-cube:before{content:"\f318"}.ion-disc:before{content:"\f12d"}.ion-document:before{content:"\f12f"}.ion-document-text:before{content:"\f12e"}.ion-drag:before{content:"\f130"}.ion-earth:before{content:"\f276"}.ion-easel:before{content:"\f3c2"}.ion-edit:before{content:"\f2bf"}.ion-egg:before{content:"\f277"}.ion-eject:before{content:"\f131"}.ion-email:before{content:"\f132"}.ion-email-unread:before{content:"\f3c3"}.ion-erlenmeyer-flask:before{content:"\f3c5"}.ion-erlenmeyer-flask-bubbles:before{content:"\f3c4"}.ion-eye:before{content:"\f133"}.ion-eye-disabled:before{content:"\f306"}.ion-female:before{content:"\f278"}.ion-filing:before{content:"\f134"}.ion-film-marker:before{content:"\f135"}.ion-fireball:before{content:"\f319"}.ion-flag:before{content:"\f279"}.ion-flame:before{content:"\f31a"}.ion-flash:before{content:"\f137"}.ion-flash-off:before{content:"\f136"}.ion-folder:before{content:"\f139"}.ion-fork:before{content:"\f27a"}.ion-fork-repo:before{content:"\f2c0"}.ion-forward:before{content:"\f13a"}.ion-funnel:before{content:"\f31b"}.ion-gear-a:before{content:"\f13d"}.ion-gear-b:before{content:"\f13e"}.ion-grid:before{content:"\f13f"}.ion-hammer:before{content:"\f27b"}.ion-happy:before{content:"\f31c"}.ion-happy-outline:before{content:"\f3c6"}.ion-headphone:before{content:"\f140"}.ion-heart:before{content:"\f141"}.ion-heart-broken:before{content:"\f31d"}.ion-help:before{content:"\f143"}.ion-help-buoy:before{content:"\f27c"}.ion-help-circled:before{content:"\f142"}.ion-home:before{content:"\f144"}.ion-icecream:before{content:"\f27d"}.ion-image:before{content:"\f147"}.ion-images:before{content:"\f148"}.ion-information:before{content:"\f14a"}.ion-information-circled:before{content:"\f149"}.ion-ionic:before{content:"\f14b"}.ion-ios-alarm:before{content:"\f3c8"}.ion-ios-alarm-outline:before{content:"\f3c7"}.ion-ios-albums:before{content:"\f3ca"}.ion-ios-albums-outline:before{content:"\f3c9"}.ion-ios-americanfootball:before{content:"\f3cc"}.ion-ios-americanfootball-outline:before{content:"\f3cb"}.ion-ios-analytics:before{content:"\f3ce"}.ion-ios-analytics-outline:before{content:"\f3cd"}.ion-ios-arrow-back:before{content:"\f3cf"}.ion-ios-arrow-down:before{content:"\f3d0"}.ion-ios-arrow-forward:before{content:"\f3d1"}.ion-ios-arrow-left:before{content:"\f3d2"}.ion-ios-arrow-right:before{content:"\f3d3"}.ion-ios-arrow-thin-down:before{content:"\f3d4"}.ion-ios-arrow-thin-left:before{content:"\f3d5"}.ion-ios-arrow-thin-right:before{content:"\f3d6"}.ion-ios-arrow-thin-up:before{content:"\f3d7"}.ion-ios-arrow-up:before{content:"\f3d8"}.ion-ios-at:before{content:"\f3da"}.ion-ios-at-outline:before{content:"\f3d9"}.ion-ios-barcode:before{content:"\f3dc"}.ion-ios-barcode-outline:before{content:"\f3db"}.ion-ios-baseball:before{content:"\f3de"}.ion-ios-baseball-outline:before{content:"\f3dd"}.ion-ios-basketball:before{content:"\f3e0"}.ion-ios-basketball-outline:before{content:"\f3df"}.ion-ios-bell:before{content:"\f3e2"}.ion-ios-bell-outline:before{content:"\f3e1"}.ion-ios-body:before{content:"\f3e4"}.ion-ios-body-outline:before{content:"\f3e3"}.ion-ios-bolt:before{content:"\f3e6"}.ion-ios-bolt-outline:before{content:"\f3e5"}.ion-ios-book:before{content:"\f3e8"}.ion-ios-book-outline:before{content:"\f3e7"}.ion-ios-bookmarks:before{content:"\f3ea"}.ion-ios-bookmarks-outline:before{content:"\f3e9"}.ion-ios-box:before{content:"\f3ec"}.ion-ios-box-outline:before{content:"\f3eb"}.ion-ios-briefcase:before{content:"\f3ee"}.ion-ios-briefcase-outline:before{content:"\f3ed"}.ion-ios-browsers:before{content:"\f3f0"}.ion-ios-browsers-outline:before{content:"\f3ef"}.ion-ios-calculator:before{content:"\f3f2"}.ion-ios-calculator-outline:before{content:"\f3f1"}.ion-ios-calendar:before{content:"\f3f4"}.ion-ios-calendar-outline:before{content:"\f3f3"}.ion-ios-camera:before{content:"\f3f6"}.ion-ios-camera-outline:before{content:"\f3f5"}.ion-ios-cart:before{content:"\f3f8"}.ion-ios-cart-outline:before{content:"\f3f7"}.ion-ios-chatboxes:before{content:"\f3fa"}.ion-ios-chatboxes-outline:before{content:"\f3f9"}.ion-ios-chatbubble:before{content:"\f3fc"}.ion-ios-chatbubble-outline:before{content:"\f3fb"}.ion-ios-checkmark:before{content:"\f3ff"}.ion-ios-checkmark-empty:before{content:"\f3fd"}.ion-ios-checkmark-outline:before{content:"\f3fe"}.ion-ios-circle-filled:before{content:"\f400"}.ion-ios-circle-outline:before{content:"\f401"}.ion-ios-clock:before{content:"\f403"}.ion-ios-clock-outline:before{content:"\f402"}.ion-ios-close:before{content:"\f406"}.ion-ios-close-empty:before{content:"\f404"}.ion-ios-close-outline:before{content:"\f405"}.ion-ios-cloud:before{content:"\f40c"}.ion-ios-cloud-download:before{content:"\f408"}.ion-ios-cloud-download-outline:before{content:"\f407"}.ion-ios-cloud-outline:before{content:"\f409"}.ion-ios-cloud-upload:before{content:"\f40b"}.ion-ios-cloud-upload-outline:before{content:"\f40a"}.ion-ios-cloudy:before{content:"\f410"}.ion-ios-cloudy-night:before{content:"\f40e"}.ion-ios-cloudy-night-outline:before{content:"\f40d"}.ion-ios-cloudy-outline:before{content:"\f40f"}.ion-ios-cog:before{content:"\f412"}.ion-ios-cog-outline:before{content:"\f411"}.ion-ios-color-filter:before{content:"\f414"}.ion-ios-color-filter-outline:before{content:"\f413"}.ion-ios-color-wand:before{content:"\f416"}.ion-ios-color-wand-outline:before{content:"\f415"}.ion-ios-compose:before{content:"\f418"}.ion-ios-compose-outline:before{content:"\f417"}.ion-ios-contact:before{content:"\f41a"}.ion-ios-contact-outline:before{content:"\f419"}.ion-ios-copy:before{content:"\f41c"}.ion-ios-copy-outline:before{content:"\f41b"}.ion-ios-crop:before{content:"\f41e"}.ion-ios-crop-strong:before{content:"\f41d"}.ion-ios-download:before{content:"\f420"}.ion-ios-download-outline:before{content:"\f41f"}.ion-ios-drag:before{content:"\f421"}.ion-ios-email:before{content:"\f423"}.ion-ios-email-outline:before{content:"\f422"}.ion-ios-eye:before{content:"\f425"}.ion-ios-eye-outline:before{content:"\f424"}.ion-ios-fastforward:before{content:"\f427"}.ion-ios-fastforward-outline:before{content:"\f426"}.ion-ios-filing:before{content:"\f429"}.ion-ios-filing-outline:before{content:"\f428"}.ion-ios-film:before{content:"\f42b"}.ion-ios-film-outline:before{content:"\f42a"}.ion-ios-flag:before{content:"\f42d"}.ion-ios-flag-outline:before{content:"\f42c"}.ion-ios-flame:before{content:"\f42f"}.ion-ios-flame-outline:before{content:"\f42e"}.ion-ios-flask:before{content:"\f431"}.ion-ios-flask-outline:before{content:"\f430"}.ion-ios-flower:before{content:"\f433"}.ion-ios-flower-outline:before{content:"\f432"}.ion-ios-folder:before{content:"\f435"}.ion-ios-folder-outline:before{content:"\f434"}.ion-ios-football:before{content:"\f437"}.ion-ios-football-outline:before{content:"\f436"}.ion-ios-game-controller-a:before{content:"\f439"}.ion-ios-game-controller-a-outline:before{content:"\f438"}.ion-ios-game-controller-b:before{content:"\f43b"}.ion-ios-game-controller-b-outline:before{content:"\f43a"}.ion-ios-gear:before{content:"\f43d"}.ion-ios-gear-outline:before{content:"\f43c"}.ion-ios-glasses:before{content:"\f43f"}.ion-ios-glasses-outline:before{content:"\f43e"}.ion-ios-grid-view:before{content:"\f441"}.ion-ios-grid-view-outline:before{content:"\f440"}.ion-ios-heart:before{content:"\f443"}.ion-ios-heart-outline:before{content:"\f442"}.ion-ios-help:before{content:"\f446"}.ion-ios-help-empty:before{content:"\f444"}.ion-ios-help-outline:before{content:"\f445"}.ion-ios-home:before{content:"\f448"}.ion-ios-home-outline:before{content:"\f447"}.ion-ios-infinite:before{content:"\f44a"}.ion-ios-infinite-outline:before{content:"\f449"}.ion-ios-information:before{content:"\f44d"}.ion-ios-information-empty:before{content:"\f44b"}.ion-ios-information-outline:before{content:"\f44c"}.ion-ios-ionic-outline:before{content:"\f44e"}.ion-ios-keypad:before{content:"\f450"}.ion-ios-keypad-outline:before{content:"\f44f"}.ion-ios-lightbulb:before{content:"\f452"}.ion-ios-lightbulb-outline:before{content:"\f451"}.ion-ios-list:before{content:"\f454"}.ion-ios-list-outline:before{content:"\f453"}.ion-ios-location:before{content:"\f456"}.ion-ios-location-outline:before{content:"\f455"}.ion-ios-locked:before{content:"\f458"}.ion-ios-locked-outline:before{content:"\f457"}.ion-ios-loop:before{content:"\f45a"}.ion-ios-loop-strong:before{content:"\f459"}.ion-ios-medical:before{content:"\f45c"}.ion-ios-medical-outline:before{content:"\f45b"}.ion-ios-medkit:before{content:"\f45e"}.ion-ios-medkit-outline:before{content:"\f45d"}.ion-ios-mic:before{content:"\f461"}.ion-ios-mic-off:before{content:"\f45f"}.ion-ios-mic-outline:before{content:"\f460"}.ion-ios-minus:before{content:"\f464"}.ion-ios-minus-empty:before{content:"\f462"}.ion-ios-minus-outline:before{content:"\f463"}.ion-ios-monitor:before{content:"\f466"}.ion-ios-monitor-outline:before{content:"\f465"}.ion-ios-moon:before{content:"\f468"}.ion-ios-moon-outline:before{content:"\f467"}.ion-ios-more:before{content:"\f46a"}.ion-ios-more-outline:before{content:"\f469"}.ion-ios-musical-note:before{content:"\f46b"}.ion-ios-musical-notes:before{content:"\f46c"}.ion-ios-navigate:before{content:"\f46e"}.ion-ios-navigate-outline:before{content:"\f46d"}.ion-ios-nutrition:before{content:"\f470"}.ion-ios-nutrition-outline:before{content:"\f46f"}.ion-ios-paper:before{content:"\f472"}.ion-ios-paper-outline:before{content:"\f471"}.ion-ios-paperplane:before{content:"\f474"}.ion-ios-paperplane-outline:before{content:"\f473"}.ion-ios-partlysunny:before{content:"\f476"}.ion-ios-partlysunny-outline:before{content:"\f475"}.ion-ios-pause:before{content:"\f478"}.ion-ios-pause-outline:before{content:"\f477"}.ion-ios-paw:before{content:"\f47a"}.ion-ios-paw-outline:before{content:"\f479"}.ion-ios-people:before{content:"\f47c"}.ion-ios-people-outline:before{content:"\f47b"}.ion-ios-person:before{content:"\f47e"}.ion-ios-person-outline:before{content:"\f47d"}.ion-ios-personadd:before{content:"\f480"}.ion-ios-personadd-outline:before{content:"\f47f"}.ion-ios-photos:before{content:"\f482"}.ion-ios-photos-outline:before{content:"\f481"}.ion-ios-pie:before{content:"\f484"}.ion-ios-pie-outline:before{content:"\f483"}.ion-ios-pint:before{content:"\f486"}.ion-ios-pint-outline:before{content:"\f485"}.ion-ios-play:before{content:"\f488"}.ion-ios-play-outline:before{content:"\f487"}.ion-ios-plus:before{content:"\f48b"}.ion-ios-plus-empty:before{content:"\f489"}.ion-ios-plus-outline:before{content:"\f48a"}.ion-ios-pricetag:before{content:"\f48d"}.ion-ios-pricetag-outline:before{content:"\f48c"}.ion-ios-pricetags:before{content:"\f48f"}.ion-ios-pricetags-outline:before{content:"\f48e"}.ion-ios-printer:before{content:"\f491"}.ion-ios-printer-outline:before{content:"\f490"}.ion-ios-pulse:before{content:"\f493"}.ion-ios-pulse-strong:before{content:"\f492"}.ion-ios-rainy:before{content:"\f495"}.ion-ios-rainy-outline:before{content:"\f494"}.ion-ios-recording:before{content:"\f497"}.ion-ios-recording-outline:before{content:"\f496"}.ion-ios-redo:before{content:"\f499"}.ion-ios-redo-outline:before{content:"\f498"}.ion-ios-refresh:before{content:"\f49c"}.ion-ios-refresh-empty:before{content:"\f49a"}.ion-ios-refresh-outline:before{content:"\f49b"}.ion-ios-reload:before{content:"\f49d"}.ion-ios-reverse-camera:before{content:"\f49f"}.ion-ios-reverse-camera-outline:before{content:"\f49e"}.ion-ios-rewind:before{content:"\f4a1"}.ion-ios-rewind-outline:before{content:"\f4a0"}.ion-ios-rose:before{content:"\f4a3"}.ion-ios-rose-outline:before{content:"\f4a2"}.ion-ios-search:before{content:"\f4a5"}.ion-ios-search-strong:before{content:"\f4a4"}.ion-ios-settings:before{content:"\f4a7"}.ion-ios-settings-strong:before{content:"\f4a6"}.ion-ios-shuffle:before{content:"\f4a9"}.ion-ios-shuffle-strong:before{content:"\f4a8"}.ion-ios-skipbackward:before{content:"\f4ab"}.ion-ios-skipbackward-outline:before{content:"\f4aa"}.ion-ios-skipforward:before{content:"\f4ad"}.ion-ios-skipforward-outline:before{content:"\f4ac"}.ion-ios-snowy:before{content:"\f4ae"}.ion-ios-speedometer:before{content:"\f4b0"}.ion-ios-speedometer-outline:before{content:"\f4af"}.ion-ios-star:before{content:"\f4b3"}.ion-ios-star-half:before{content:"\f4b1"}.ion-ios-star-outline:before{content:"\f4b2"}.ion-ios-stopwatch:before{content:"\f4b5"}.ion-ios-stopwatch-outline:before{content:"\f4b4"}.ion-ios-sunny:before{content:"\f4b7"}.ion-ios-sunny-outline:before{content:"\f4b6"}.ion-ios-telephone:before{content:"\f4b9"}.ion-ios-telephone-outline:before{content:"\f4b8"}.ion-ios-tennisball:before{content:"\f4bb"}.ion-ios-tennisball-outline:before{content:"\f4ba"}.ion-ios-thunderstorm:before{content:"\f4bd"}.ion-ios-thunderstorm-outline:before{content:"\f4bc"}.ion-ios-time:before{content:"\f4bf"}.ion-ios-time-outline:before{content:"\f4be"}.ion-ios-timer:before{content:"\f4c1"}.ion-ios-timer-outline:before{content:"\f4c0"}.ion-ios-toggle:before{content:"\f4c3"}.ion-ios-toggle-outline:before{content:"\f4c2"}.ion-ios-trash:before{content:"\f4c5"}.ion-ios-trash-outline:before{content:"\f4c4"}.ion-ios-undo:before{content:"\f4c7"}.ion-ios-undo-outline:before{content:"\f4c6"}.ion-ios-unlocked:before{content:"\f4c9"}.ion-ios-unlocked-outline:before{content:"\f4c8"}.ion-ios-upload:before{content:"\f4cb"}.ion-ios-upload-outline:before{content:"\f4ca"}.ion-ios-videocam:before{content:"\f4cd"}.ion-ios-videocam-outline:before{content:"\f4cc"}.ion-ios-volume-high:before{content:"\f4ce"}.ion-ios-volume-low:before{content:"\f4cf"}.ion-ios-wineglass:before{content:"\f4d1"}.ion-ios-wineglass-outline:before{content:"\f4d0"}.ion-ios-world:before{content:"\f4d3"}.ion-ios-world-outline:before{content:"\f4d2"}.ion-ipad:before{content:"\f1f9"}.ion-iphone:before{content:"\f1fa"}.ion-ipod:before{content:"\f1fb"}.ion-jet:before{content:"\f295"}.ion-key:before{content:"\f296"}.ion-knife:before{content:"\f297"}.ion-laptop:before{content:"\f1fc"}.ion-leaf:before{content:"\f1fd"}.ion-levels:before{content:"\f298"}.ion-lightbulb:before{content:"\f299"}.ion-link:before{content:"\f1fe"}.ion-load-a:before{content:"\f29a"}.ion-load-b:before{content:"\f29b"}.ion-load-c:before{content:"\f29c"}.ion-load-d:before{content:"\f29d"}.ion-location:before{content:"\f1ff"}.ion-lock-combination:before{content:"\f4d4"}.ion-locked:before{content:"\f200"}.ion-log-in:before{content:"\f29e"}.ion-log-out:before{content:"\f29f"}.ion-loop:before{content:"\f201"}.ion-magnet:before{content:"\f2a0"}.ion-male:before{content:"\f2a1"}.ion-man:before{content:"\f202"}.ion-map:before{content:"\f203"}.ion-medkit:before{content:"\f2a2"}.ion-merge:before{content:"\f33f"}.ion-mic-a:before{content:"\f204"}.ion-mic-b:before{content:"\f205"}.ion-mic-c:before{content:"\f206"}.ion-minus:before{content:"\f209"}.ion-minus-circled:before{content:"\f207"}.ion-minus-round:before{content:"\f208"}.ion-model-s:before{content:"\f2c1"}.ion-monitor:before{content:"\f20a"}.ion-more:before{content:"\f20b"}.ion-mouse:before{content:"\f340"}.ion-music-note:before{content:"\f20c"}.ion-navicon:before{content:"\f20e"}.ion-navicon-round:before{content:"\f20d"}.ion-navigate:before{content:"\f2a3"}.ion-network:before{content:"\f341"}.ion-no-smoking:before{content:"\f2c2"}.ion-nuclear:before{content:"\f2a4"}.ion-outlet:before{content:"\f342"}.ion-paintbrush:before{content:"\f4d5"}.ion-paintbucket:before{content:"\f4d6"}.ion-paper-airplane:before{content:"\f2c3"}.ion-paperclip:before{content:"\f20f"}.ion-pause:before{content:"\f210"}.ion-person:before{content:"\f213"}.ion-person-add:before{content:"\f211"}.ion-person-stalker:before{content:"\f212"}.ion-pie-graph:before{content:"\f2a5"}.ion-pin:before{content:"\f2a6"}.ion-pinpoint:before{content:"\f2a7"}.ion-pizza:before{content:"\f2a8"}.ion-plane:before{content:"\f214"}.ion-planet:before{content:"\f343"}.ion-play:before{content:"\f215"}.ion-playstation:before{content:"\f30a"}.ion-plus:before{content:"\f218"}.ion-plus-circled:before{content:"\f216"}.ion-plus-round:before{content:"\f217"}.ion-podium:before{content:"\f344"}.ion-pound:before{content:"\f219"}.ion-power:before{content:"\f2a9"}.ion-pricetag:before{content:"\f2aa"}.ion-pricetags:before{content:"\f2ab"}.ion-printer:before{content:"\f21a"}.ion-pull-request:before{content:"\f345"}.ion-qr-scanner:before{content:"\f346"}.ion-quote:before{content:"\f347"}.ion-radio-waves:before{content:"\f2ac"}.ion-record:before{content:"\f21b"}.ion-refresh:before{content:"\f21c"}.ion-reply:before{content:"\f21e"}.ion-reply-all:before{content:"\f21d"}.ion-ribbon-a:before{content:"\f348"}.ion-ribbon-b:before{content:"\f349"}.ion-sad:before{content:"\f34a"}.ion-sad-outline:before{content:"\f4d7"}.ion-scissors:before{content:"\f34b"}.ion-search:before{content:"\f21f"}.ion-settings:before{content:"\f2ad"}.ion-share:before{content:"\f220"}.ion-shuffle:before{content:"\f221"}.ion-skip-backward:before{content:"\f222"}.ion-skip-forward:before{content:"\f223"}.ion-social-android:before{content:"\f225"}.ion-social-android-outline:before{content:"\f224"}.ion-social-angular:before{content:"\f4d9"}.ion-social-angular-outline:before{content:"\f4d8"}.ion-social-apple:before{content:"\f227"}.ion-social-apple-outline:before{content:"\f226"}.ion-social-bitcoin:before{content:"\f2af"}.ion-social-bitcoin-outline:before{content:"\f2ae"}.ion-social-buffer:before{content:"\f229"}.ion-social-buffer-outline:before{content:"\f228"}.ion-social-chrome:before{content:"\f4db"}.ion-social-chrome-outline:before{content:"\f4da"}.ion-social-codepen:before{content:"\f4dd"}.ion-social-codepen-outline:before{content:"\f4dc"}.ion-social-css3:before{content:"\f4df"}.ion-social-css3-outline:before{content:"\f4de"}.ion-social-designernews:before{content:"\f22b"}.ion-social-designernews-outline:before{content:"\f22a"}.ion-social-dribbble:before{content:"\f22d"}.ion-social-dribbble-outline:before{content:"\f22c"}.ion-social-dropbox:before{content:"\f22f"}.ion-social-dropbox-outline:before{content:"\f22e"}.ion-social-euro:before{content:"\f4e1"}.ion-social-euro-outline:before{content:"\f4e0"}.ion-social-facebook:before{content:"\f231"}.ion-social-facebook-outline:before{content:"\f230"}.ion-social-foursquare:before{content:"\f34d"}.ion-social-foursquare-outline:before{content:"\f34c"}.ion-social-freebsd-devil:before{content:"\f2c4"}.ion-social-github:before{content:"\f233"}.ion-social-github-outline:before{content:"\f232"}.ion-social-google:before{content:"\f34f"}.ion-social-google-outline:before{content:"\f34e"}.ion-social-googleplus:before{content:"\f235"}.ion-social-googleplus-outline:before{content:"\f234"}.ion-social-hackernews:before{content:"\f237"}.ion-social-hackernews-outline:before{content:"\f236"}.ion-social-html5:before{content:"\f4e3"}.ion-social-html5-outline:before{content:"\f4e2"}.ion-social-instagram:before{content:"\f351"}.ion-social-instagram-outline:before{content:"\f350"}.ion-social-javascript:before{content:"\f4e5"}.ion-social-javascript-outline:before{content:"\f4e4"}.ion-social-linkedin:before{content:"\f239"}.ion-social-linkedin-outline:before{content:"\f238"}.ion-social-markdown:before{content:"\f4e6"}.ion-social-nodejs:before{content:"\f4e7"}.ion-social-octocat:before{content:"\f4e8"}.ion-social-pinterest:before{content:"\f2b1"}.ion-social-pinterest-outline:before{content:"\f2b0"}.ion-social-python:before{content:"\f4e9"}.ion-social-reddit:before{content:"\f23b"}.ion-social-reddit-outline:before{content:"\f23a"}.ion-social-rss:before{content:"\f23d"}.ion-social-rss-outline:before{content:"\f23c"}.ion-social-sass:before{content:"\f4ea"}.ion-social-skype:before{content:"\f23f"}.ion-social-skype-outline:before{content:"\f23e"}.ion-social-snapchat:before{content:"\f4ec"}.ion-social-snapchat-outline:before{content:"\f4eb"}.ion-social-tumblr:before{content:"\f241"}.ion-social-tumblr-outline:before{content:"\f240"}.ion-social-tux:before{content:"\f2c5"}.ion-social-twitch:before{content:"\f4ee"}.ion-social-twitch-outline:before{content:"\f4ed"}.ion-social-twitter:before{content:"\f243"}.ion-social-twitter-outline:before{content:"\f242"}.ion-social-usd:before{content:"\f353"}.ion-social-usd-outline:before{content:"\f352"}.ion-social-vimeo:before{content:"\f245"}.ion-social-vimeo-outline:before{content:"\f244"}.ion-social-whatsapp:before{content:"\f4f0"}.ion-social-whatsapp-outline:before{content:"\f4ef"}.ion-social-windows:before{content:"\f247"}.ion-social-windows-outline:before{content:"\f246"}.ion-social-wordpress:before{content:"\f249"}.ion-social-wordpress-outline:before{content:"\f248"}.ion-social-yahoo:before{content:"\f24b"}.ion-social-yahoo-outline:before{content:"\f24a"}.ion-social-yen:before{content:"\f4f2"}.ion-social-yen-outline:before{content:"\f4f1"}.ion-social-youtube:before{content:"\f24d"}.ion-social-youtube-outline:before{content:"\f24c"}.ion-soup-can:before{content:"\f4f4"}.ion-soup-can-outline:before{content:"\f4f3"}.ion-speakerphone:before{content:"\f2b2"}.ion-speedometer:before{content:"\f2b3"}.ion-spoon:before{content:"\f2b4"}.ion-star:before{content:"\f24e"}.ion-stats-bars:before{content:"\f2b5"}.ion-steam:before{content:"\f30b"}.ion-stop:before{content:"\f24f"}.ion-thermometer:before{content:"\f2b6"}.ion-thumbsdown:before{content:"\f250"}.ion-thumbsup:before{content:"\f251"}.ion-toggle:before{content:"\f355"}.ion-toggle-filled:before{content:"\f354"}.ion-transgender:before{content:"\f4f5"}.ion-trash-a:before{content:"\f252"}.ion-trash-b:before{content:"\f253"}.ion-trophy:before{content:"\f356"}.ion-tshirt:before{content:"\f4f7"}.ion-tshirt-outline:before{content:"\f4f6"}.ion-umbrella:before{content:"\f2b7"}.ion-university:before{content:"\f357"}.ion-unlocked:before{content:"\f254"}.ion-upload:before{content:"\f255"}.ion-usb:before{content:"\f2b8"}.ion-videocamera:before{content:"\f256"}.ion-volume-high:before{content:"\f257"}.ion-volume-low:before{content:"\f258"}.ion-volume-medium:before{content:"\f259"}.ion-volume-mute:before{content:"\f25a"}.ion-wand:before{content:"\f358"}.ion-waterdrop:before{content:"\f25b"}.ion-wifi:before{content:"\f25c"}.ion-wineglass:before{content:"\f2b9"}.ion-woman:before{content:"\f25d"}.ion-wrench:before{content:"\f2ba"}.ion-xbox:before{content:"\f30c"}
+
+.component-header{display:block}.footer,.header{font-size:18px;display:inline-block;width:100%;position:fixed;top:0;left:0;height:52px;z-index:9}.footer{top:initial;bottom:0}.header.sub{top:52px}.footer.sub{top:initial;bottom:52px}.has-header{padding-top:52px!important}.has-header.has-sub-header{padding-top:104px!important}.has-footer{padding-bottom:52px!important}.has-footer.has-sub-footer{padding-bottom:104px!important}.footer .left,.footer .right,.footer .title,.footer h1,.header .left,.header .right,.header .title,.header h1{margin-top:15px;margin-bottom:5px}.header .avatar{height:40px;margin-top:-8px;margin-left:4px}.header .border-big{border-width:2px;border-style:solid}.footer h2,.header h2{padding-top:8px;padding-left:10px}.footer p,.header p{padding-left:10px;margin:0;margin-top:-4px}.footer .left,.header .left{padding-left:5px}.footer .right,.header .right{padding-right:5px}.footer .title,.footer h1,.header .title,.header h1{margin-bottom:15px;padding-left:10px;padding-right:15px;display:inline-block}.footer button,.header button{margin-top:-10px}.footer button.icon,.header button.icon{font-size:30px;margin-top:-10px;z-index:99;background:0 0;border:none;padding:0 6px}.footer button.icon:not([class*=red]):not([class*=pink]):not([class*=white]):not([class*=purple]):not([class*=indigo]):not([class*=blue]):not([class*=cyan]):not([class*=teal]):not([class*=green]):not([class*=lime]):not([class*=yellow]):not([class*=amber]):not([class*=orange]):not([class*=brown]):not([class*=grey]):not([class*=black]):not([class*=white]),.header button.icon:not([class*=red]):not([class*=pink]):not([class*=white]):not([class*=purple]):not([class*=indigo]):not([class*=blue]):not([class*=cyan]):not([class*=teal]):not([class*=green]):not([class*=lime]):not([class*=yellow]):not([class*=amber]):not([class*=orange]):not([class*=brown]):not([class*=grey]):not([class*=black]):not([class*=white]){color:#fff}.footer button.icon.left,.footer button.icon.right,.header button.icon.left,.header button.icon.right{margin-top:5px;margin-bottom:5px}.footer button.icon.left,.header button.icon.left{margin-left:5px}.footer button.icon.right,.header button.icon.right{margin-right:5px}.footer .title.align-center,.footer h1.align-center,.footer p.align-center,.header .title.align-center,.header h1.align-center,.header p.align-center{width:100%;position:inherit;padding-right:15px;left:0;z-index:9}.footer .icon-badge,.header .icon-badge{position:absolute;margin-left:-6px;margin-top:-8px;border-radius:8px;z-index:999}.footer .buttons-group,.header .buttons-group{margin-top:15px;margin-left:5px;margin-right:5px}.footer .buttons-group.small,.header .buttons-group.small{margin-top:20px;margin-left:10px;margin-right:10px}.header input::-webkit-input-placeholder{color:rgba(0,0,0,.8)}.header input.placeholder-white::-webkit-input-placeholder{color:rgba(255,255,255,.8)}.header input{padding:15px;position:absolute}.header .left+input{padding-right:50px}
+.component-button{display:block}button{-webkit-transition:color .2s ease;-moz-transition:color .2s ease;-ms-transition:color .2s ease;-o-transition:color .2s ease;transition:color .2s ease;font-size:14px;border:none;background-color:rgba(0,0,0,0);color:#444;position:relative;display:inline-block;margin:0;padding:0 12px;min-height:42px;vertical-align:top;text-align:center;text-overflow:ellipsis;font-size:16px;line-height:42px;cursor:pointer;overflow:hidden}button[disabled]{opacity:.8}button .icon{position:absolute;left:10px}button.circle{width:42px;height:42px;text-align:center;padding:0;line-height:0;font-size:22px;z-index:10}button.icon-text{padding-left:40px}button.icon-text i{font-size:22px}button.icon-text.icon-right{padding-left:12px;padding-right:40px;position:relative}button.icon-right i{position:absolute;right:12px;text-align:right;margin-top:2px}button[class*=border-]{min-height:40px;line-height:40px}button.full{width:100%}.buttons-group.big button,button.big{font-size:22px;min-height:50px;line-height:50px}button.circle.big{width:50px;height:50px;font-size:28px}button.big.icon-text{padding-left:40px}button.big.icon-text.icon-right{padding-left:12px;padding-right:40px}button.big.icon-text i{font-size:26px}.buttons-group.small button,button.small{font-size:12px;min-height:30px;line-height:30px}button.circle.small{width:30px;height:30px;font-size:18px}button.small.icon-text{padding-left:30px}button.small.icon-text.icon-right{padding-left:12px;padding-right:35px}button.small.icon-text i{font-size:18px}.buttons-group.huge button,button.huge{font-size:32px;min-height:70px;line-height:70px}button.circle.huge{width:70px;height:70px;font-size:32px}button.huge.icon-text{padding-left:40px}button.huge.icon-text.icon-right{padding-left:12px;padding-right:40px}button.huge.icon-text i{font-size:32px}.buttons-group{display:inline-block}.buttons-group button{float:left;margin-left:-1px}.buttons-group button:first-child{margin-left:0}.buttons-group.full{display:flex}.buttons-group.full button{flex:1}.ripple{position:absolute;background:rgba(255,255,255,.25);border-radius:100%;-webkit-transform:scale(0);-moz-transform:scale(0);-ms-transform:scale(0);-o-transform:scale(0);transform:scale(0);pointer-events:none}.ripple.show{-webkit-animation:ripple .5s ease-out;-moz-animation:ripple .5s ease-out;-o-animation:ripple .5s ease-out;animation:ripple .5s ease-out}@-webkit-keyframes ripple{to{-webkit-transform:scale(1.5);opacity:0}}@-moz-keyframes ripple{to{-moz-transform:scale(1.5);opacity:0}}@-o-keyframes ripple{to{-o-transform:scale(1.5);opacity:0}}@keyframes ripple{to{transform:scale(1.5);opacity:0}}
+.alert-mobileui .alert {
+    font-family: Roboto,Noto,sans-serif;
+    position: relative;
+    border-radius: 4px;
+    box-shadow: 0 16px 24px 2px rgba(0,0,0,.14), 0 6px 30px 5px rgba(0,0,0,.12), 0 8px 10px -5px rgba(0,0,0,.4);
+    max-width: 270px;
+    word-break: break-all;
+}
+.alert-mobileui {
+    display: -webkit-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-pack: center;
+    -ms-flex-pack: center;
+    justify-content: center;
+    -webkit-box-align: center;
+    -ms-flex-align: center;
+    align-items: center;
+    position: absolute;
+    top:40%;
+    left: 0;
+    right: 0;
+}
+.backdrop {
+    height: 100%;
+    background-color: #000;
+    opacity: .01;
+    z-index: 9999;
+    transition-duration: 280ms;
+}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/paypwdset.html b/platforms/android/app/src/main/assets/www/paypwdset.html
new file mode 100644
index 0000000..1714ab1
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/paypwdset.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <link rel="stylesheet" type="text/css" href="mobileui/style.css">
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="viewport-fit=cover, initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <link rel="stylesheet" type="text/css" href="css/aui.css">
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <title>设置支付密码</title>
+</head>
+<body>
+    <header class="aui-bar aui-bar-nav" style="padding-top:25px;">
+        <a class="aui-pull-left" href="javascript:window.history.back()">
+            <span class="aui-iconfont aui-icon-left"></span>
+        </a>
+        <div class="aui-title">设置支付密码</div>
+    </header>
+    <div>
+        <div class="weui-cells weui-cells_form">
+            <div class="weui-cell">
+                <div class="weui-cell__hd"><label class="weui-label">支付密码</label></div>
+                <div class="weui-cell__bd">
+                    <input class="weui-input" type="password" id="pwd"  pattern="[0-9]*" placeholder="6位数字" maxlength="6">
+                </div>
+            </div>
+            <div class="weui-cell">
+                <div class="weui-cell__hd"><label class="weui-label">确认密码</label></div>
+                <div class="weui-cell__bd">
+                    <input class="weui-input" type="password" id="repwd"  pattern="[0-9]*" placeholder="6位数字" maxlength="6">
+                </div>
+            </div>
+        </div>
+        <div style="padding: 20px;">
+            <a href="javascript:app.doNext();" class="weui-btn weui-btn_primary">保存</a>
+        </div>
+    </div>
+</body>
+</html>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/lib/jquery-weui.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
+<script type="text/javascript" src="js/paypwdset.js"></script>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/advanced-http.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/advanced-http.js
new file mode 100644
index 0000000..5faece0
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/advanced-http.js
@@ -0,0 +1,23 @@
+cordova.define("cordova-plugin-advanced-http.http", function(require, exports, module) {
+/*
+ * A native HTTP Plugin for Cordova / PhoneGap.
+ */
+
+var pluginId = module.id.slice(0, module.id.lastIndexOf('.'));
+
+var exec = require('cordova/exec');
+var base64 = require('cordova/base64');
+var messages = require(pluginId + '.messages');
+var globalConfigs = require(pluginId + '.global-configs');
+var jsUtil = require(pluginId + '.js-util');
+var ToughCookie = require(pluginId + '.tough-cookie');
+var lodash = require(pluginId + '.lodash');
+var WebStorageCookieStore = require(pluginId + '.local-storage-store')(ToughCookie, lodash);
+var cookieHandler = require(pluginId + '.cookie-handler')(window.localStorage, ToughCookie, WebStorageCookieStore);
+var helpers = require(pluginId + '.helpers')(jsUtil, cookieHandler, messages, base64);
+var urlUtil = require(pluginId + '.url-util')(jsUtil);
+var publicInterface = require(pluginId + '.public-interface')(exec, cookieHandler, urlUtil, helpers, globalConfigs);
+
+module.exports = publicInterface;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/cookie-handler.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/cookie-handler.js
new file mode 100644
index 0000000..e7cdb39
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/cookie-handler.js
@@ -0,0 +1,73 @@
+cordova.define("cordova-plugin-advanced-http.cookie-handler", function(require, exports, module) {
+module.exports = function init(storage, ToughCookie, WebStorageCookieStore) {
+  var storeKey = '__advancedHttpCookieStore__';
+
+  var store = new WebStorageCookieStore(storage, storeKey);
+  var cookieJar = new ToughCookie.CookieJar(store);
+
+  return {
+    setCookieFromString: setCookieFromString,
+    setCookie: setCookie,
+    getCookieString: getCookieString,
+    clearCookies: clearCookies,
+    removeCookies: removeCookies
+  };
+
+  function splitCookieString(cookieStr) {
+    var cookieParts = cookieStr.split(',');
+    var splitCookies = [];
+    var processedCookie = null;
+
+    for (var i = 0; i < cookieParts.length; ++i) {
+      if (cookieParts[i].substr(-11, 8).toLowerCase() === 'expires=') {
+        processedCookie = cookieParts[i] + ',' + cookieParts[i + 1];
+        i++;
+      } else {
+        processedCookie = cookieParts[i];
+      }
+
+      processedCookie = processedCookie.trim();
+      splitCookies.push(processedCookie);
+    }
+
+    return splitCookies;
+  }
+
+  function setCookieFromString(url, cookieStr) {
+    if (!cookieStr) return;
+
+    var cookies = splitCookieString(cookieStr);
+
+    for (var i = 0; i < cookies.length; ++i) {
+      cookieJar.setCookieSync(cookies[i], url, { ignoreError: true });
+    }
+  }
+
+  function setCookie(url, cookie, options) {
+    options = options || {};
+    options.ignoreError = false;
+    cookieJar.setCookieSync(cookie, url, options);
+  }
+
+  function getCookieString(url) {
+    return cookieJar.getCookieStringSync(url);
+  }
+
+  function clearCookies() {
+    window.localStorage.removeItem(storeKey);
+  }
+
+  function removeCookies(url, cb) {
+    cookieJar.getCookies(url, function (error, cookies) {
+      if (!cookies || cookies.length === 0) {
+        return cb(null, []);
+      }
+
+      var domain = cookies[0].domain;
+
+      cookieJar.store.removeCookies(domain, null, cb);
+    });
+  }
+};
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/global-configs.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/global-configs.js
new file mode 100644
index 0000000..5e85416
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/global-configs.js
@@ -0,0 +1,11 @@
+cordova.define("cordova-plugin-advanced-http.global-configs", function(require, exports, module) {
+var globalConfigs = {
+  headers: {},
+  serializer: 'urlencoded',
+  followRedirect: true,
+  timeout: 60.0,
+};
+
+module.exports = globalConfigs;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/helpers.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/helpers.js
new file mode 100644
index 0000000..855e84c
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/helpers.js
@@ -0,0 +1,353 @@
+cordova.define("cordova-plugin-advanced-http.helpers", function(require, exports, module) {
+module.exports = function init(jsUtil, cookieHandler, messages, base64) {
+  var validSerializers = ['urlencoded', 'json', 'utf8'];
+  var validCertModes = ['default', 'nocheck', 'pinned', 'legacy'];
+  var validClientAuthModes = ['none', 'systemstore', 'buffer'];
+  var validHttpMethods = ['get', 'put', 'post', 'patch', 'head', 'delete', 'upload', 'download'];
+  var validResponseTypes = ['text','arraybuffer', 'blob'];
+
+  var interface = {
+    b64EncodeUnicode: b64EncodeUnicode,
+    checkSerializer: checkSerializer,
+    checkSSLCertMode: checkSSLCertMode,
+    checkClientAuthMode: checkClientAuthMode,
+    checkClientAuthOptions: checkClientAuthOptions,
+    checkForBlacklistedHeaderKey: checkForBlacklistedHeaderKey,
+    checkForInvalidHeaderValue: checkForInvalidHeaderValue,
+    checkTimeoutValue: checkTimeoutValue,
+    checkFollowRedirectValue: checkFollowRedirectValue,
+    injectCookieHandler: injectCookieHandler,
+    injectRawResponseHandler: injectRawResponseHandler,
+    injectFileEntryHandler: injectFileEntryHandler,
+    getMergedHeaders: getMergedHeaders,
+    getProcessedData: getProcessedData,
+    handleMissingCallbacks: handleMissingCallbacks,
+    handleMissingOptions: handleMissingOptions
+  };
+
+  // expose all functions for testing purposes
+  if (init.debug) {
+    interface.mergeHeaders = mergeHeaders;
+    interface.checkForValidStringValue = checkForValidStringValue;
+    interface.checkKeyValuePairObject = checkKeyValuePairObject;
+    interface.checkHttpMethod = checkHttpMethod;
+    interface.checkResponseType = checkResponseType;
+    interface.checkHeadersObject = checkHeadersObject;
+    interface.checkParamsObject = checkParamsObject;
+    interface.resolveCookieString = resolveCookieString;
+    interface.createFileEntry = createFileEntry;
+    interface.getCookieHeader = getCookieHeader;
+    interface.getMatchingHostHeaders = getMatchingHostHeaders;
+    interface.getAllowedDataTypes = getAllowedDataTypes;
+  }
+
+  return interface;
+
+  // Thanks Mozilla: https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_.22Unicode_Problem.22
+  function b64EncodeUnicode(str) {
+    return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
+      return String.fromCharCode('0x' + p1);
+    }));
+  }
+
+  function mergeHeaders(globalHeaders, localHeaders) {
+    var globalKeys = Object.keys(globalHeaders);
+    var key;
+
+    for (var i = 0; i < globalKeys.length; i++) {
+      key = globalKeys[i];
+
+      if (!localHeaders.hasOwnProperty(key)) {
+        localHeaders[key] = globalHeaders[key];
+      }
+    }
+
+    return localHeaders;
+  }
+
+  function checkForValidStringValue(list, value, onInvalidValueMessage) {
+    if (jsUtil.getTypeOf(value) !== 'String') {
+      throw new Error(onInvalidValueMessage + ' ' + list.join(', '));
+    }
+
+    value = value.trim().toLowerCase();
+
+    if (list.indexOf(value) === -1) {
+      throw new Error(onInvalidValueMessage + ' ' + list.join(', '));
+    }
+
+    return value;
+  }
+
+  function checkKeyValuePairObject(obj, allowedChildren, onInvalidValueMessage) {
+    if (jsUtil.getTypeOf(obj) !== 'Object') {
+      throw new Error(onInvalidValueMessage);
+    }
+
+    var keys = Object.keys(obj);
+
+    for (var i = 0; i < keys.length; i++) {
+      if (allowedChildren.indexOf(jsUtil.getTypeOf(obj[keys[i]])) === -1) {
+        throw new Error(onInvalidValueMessage);
+      }
+    }
+
+    return obj;
+  }
+
+  function checkHttpMethod(method) {
+    return checkForValidStringValue(validHttpMethods, method, messages.INVALID_HTTP_METHOD);
+  }
+
+  function checkResponseType(type) {
+    return checkForValidStringValue(validResponseTypes, type, messages.INVALID_RESPONSE_TYPE);
+  }
+
+  function checkSerializer(serializer) {
+    return checkForValidStringValue(validSerializers, serializer, messages.INVALID_DATA_SERIALIZER);
+  }
+
+  function checkSSLCertMode(mode) {
+    return checkForValidStringValue(validCertModes, mode, messages.INVALID_SSL_CERT_MODE);
+  }
+
+  function checkClientAuthMode(mode) {
+    return checkForValidStringValue(validClientAuthModes, mode, messages.INVALID_CLIENT_AUTH_MODE);
+  }
+
+  function checkClientAuthOptions(mode, options) {
+    options = options || {};
+
+    // none
+    if (mode === validClientAuthModes[0]) {
+      return {
+        alias: null,
+        rawPkcs: null,
+        pkcsPassword: ''
+      };
+    }
+
+    if (jsUtil.getTypeOf(options) !== 'Object') {
+      throw new Error(messages.INVALID_CLIENT_AUTH_OPTIONS);
+    }
+
+    // systemstore
+    if (mode === validClientAuthModes[1]) {
+      if (jsUtil.getTypeOf(options.alias) !== 'String'
+        && jsUtil.getTypeOf(options.alias) !== 'Undefined') {
+        throw new Error(messages.INVALID_CLIENT_AUTH_ALIAS);
+      }
+
+      return {
+        alias: jsUtil.getTypeOf(options.alias) === 'Undefined' ? null : options.alias,
+        rawPkcs: null,
+        pkcsPassword: ''
+      };
+    }
+
+    // buffer
+    if (mode === validClientAuthModes[2]) {
+      if (jsUtil.getTypeOf(options.rawPkcs) !== 'ArrayBuffer') {
+        throw new Error(messages.INVALID_CLIENT_AUTH_RAW_PKCS);
+      }
+
+      if (jsUtil.getTypeOf(options.pkcsPassword) !== 'String') {
+        throw new Error(messages.INVALID_CLIENT_AUTH_PKCS_PASSWORD);
+      }
+
+      return {
+        alias: null,
+        rawPkcs: options.rawPkcs,
+        pkcsPassword: options.pkcsPassword
+      }
+    }
+  }
+
+  function checkForBlacklistedHeaderKey(key) {
+    if (key.toLowerCase() === 'cookie') {
+      throw new Error(messages.ADDING_COOKIES_NOT_SUPPORTED);
+    }
+
+    return key;
+  }
+
+  function checkForInvalidHeaderValue(value) {
+    if (jsUtil.getTypeOf(value) !== 'String') {
+      throw new Error(messages.INVALID_HEADERS_VALUE);
+    }
+
+    return value;
+  }
+
+  function checkTimeoutValue(timeout) {
+    if (jsUtil.getTypeOf(timeout) !== 'Number' || timeout < 0) {
+      throw new Error(messages.INVALID_TIMEOUT_VALUE);
+    }
+
+    return timeout;
+  }
+
+  function checkFollowRedirectValue(follow) {
+    if (jsUtil.getTypeOf(follow) !== 'Boolean') {
+      throw new Error(messages.INVALID_FOLLOW_REDIRECT_VALUE);
+    }
+
+    return follow;
+  }
+
+  function checkHeadersObject(headers) {
+    return checkKeyValuePairObject(headers, ['String'], messages.INVALID_HEADERS_VALUE);
+  }
+
+  function checkParamsObject(params) {
+    return checkKeyValuePairObject(params, ['String', 'Array'], messages.INVALID_PARAMS_VALUE);
+  }
+
+  function resolveCookieString(headers) {
+    var keys = Object.keys(headers || {});
+
+    for (var i = 0; i < keys.length; ++i) {
+      if (keys[i].match(/^set-cookie$/i)) {
+        return headers[keys[i]];
+      }
+    }
+
+    return null;
+  }
+
+  function createFileEntry(rawEntry) {
+    var entry = new (require('cordova-plugin-file.FileEntry'))();
+
+    entry.isDirectory = rawEntry.isDirectory;
+    entry.isFile = rawEntry.isFile;
+    entry.name = rawEntry.name;
+    entry.fullPath = rawEntry.fullPath;
+    entry.filesystem = new FileSystem(rawEntry.filesystemName || (rawEntry.filesystem == window.PERSISTENT ? 'persistent' : 'temporary'));
+    entry.nativeURL = rawEntry.nativeURL;
+
+    return entry;
+  }
+
+  function injectCookieHandler(url, cb) {
+    return function (response) {
+      cookieHandler.setCookieFromString(url, resolveCookieString(response.headers));
+      cb(response);
+    }
+  }
+
+  function injectRawResponseHandler(responseType, cb) {
+    return function (response) {
+      var dataType = jsUtil.getTypeOf(response.data);
+
+      // don't need post-processing if it's already binary type (on browser platform)
+      if (dataType === 'ArrayBuffer' || dataType === 'Blob') {
+        return cb(response);
+      }
+
+      // arraybuffer
+      if (responseType === validResponseTypes[1]) {
+        var buffer = base64.toArrayBuffer(response.data);
+        response.data = buffer;
+      }
+
+      // blob
+      if (responseType === validResponseTypes[2]) {
+        var buffer = base64.toArrayBuffer(response.data);
+        var type = response.headers['content-type'] || '';
+        var blob = new Blob([ buffer ], { type: type });
+        response.data = blob;
+      }
+
+      cb(response);
+    }
+  }
+
+  function injectFileEntryHandler(cb) {
+    return function (response) {
+      cb(createFileEntry(response.file));
+    }
+  }
+
+  function getCookieHeader(url) {
+    var cookieString = cookieHandler.getCookieString(url);
+
+    if (cookieString.length) {
+      return { Cookie: cookieHandler.getCookieString(url) };
+    }
+
+    return {};
+  }
+
+  function getMatchingHostHeaders(url, headersList) {
+    var matches = url.match(/^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i);
+    var domain = matches && matches[1];
+
+    return headersList[domain] || null;
+  }
+
+  function getMergedHeaders(url, requestHeaders, predefinedHeaders) {
+    var globalHeaders = predefinedHeaders['*'] || {};
+    var hostHeaders = getMatchingHostHeaders(url, predefinedHeaders) || {};
+    var mergedHeaders = mergeHeaders(globalHeaders, hostHeaders);
+
+    mergedHeaders = mergeHeaders(mergedHeaders, requestHeaders);
+    mergedHeaders = mergeHeaders(mergedHeaders, getCookieHeader(url));
+
+    return mergedHeaders;
+  }
+
+  function getAllowedDataTypes(dataSerializer) {
+    switch (dataSerializer) {
+      case 'utf8':
+        return ['String'];
+      case 'urlencoded':
+        return ['Object'];
+      default:
+        return ['Array', 'Object'];
+    }
+  }
+
+  function getProcessedData(data, dataSerializer) {
+    var currentDataType = jsUtil.getTypeOf(data);
+    var allowedDataTypes = getAllowedDataTypes(dataSerializer);
+
+    if (allowedDataTypes.indexOf(currentDataType) === -1) {
+      throw new Error(messages.DATA_TYPE_MISMATCH + ' ' + allowedDataTypes.join(', '));
+    }
+
+    if (dataSerializer === 'utf8') {
+      data = { text: data };
+    }
+
+    return data;
+  }
+
+  function handleMissingCallbacks(successFn, failFn) {
+    if (jsUtil.getTypeOf(successFn) !== 'Function') {
+      throw new Error(messages.MANDATORY_SUCCESS);
+    }
+
+    if (jsUtil.getTypeOf(failFn) !== 'Function') {
+      throw new Error(messages.MANDATORY_FAIL);
+    }
+  }
+
+  function handleMissingOptions(options, globals) {
+    options = options || {};
+
+    return {
+      method: checkHttpMethod(options.method || validHttpMethods[0]),
+      responseType: checkResponseType(options.responseType || validResponseTypes[0]),
+      serializer: checkSerializer(options.serializer || globals.serializer),
+      timeout: checkTimeoutValue(options.timeout || globals.timeout),
+      followRedirect: checkFollowRedirectValue(options.followRedirect || globals.followRedirect),
+      headers: checkHeadersObject(options.headers || {}),
+      params: checkParamsObject(options.params || {}),
+      data: jsUtil.getTypeOf(options.data) === 'Undefined' ? null : options.data,
+      filePath: options.filePath || '',
+      name: options.name || ''
+    };
+  }
+};
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/js-util.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/js-util.js
new file mode 100644
index 0000000..cbe1c51
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/js-util.js
@@ -0,0 +1,33 @@
+cordova.define("cordova-plugin-advanced-http.js-util", function(require, exports, module) {
+module.exports = {
+  // typeof is not working reliably in JS
+  getTypeOf: function (object) {
+    switch (Object.prototype.toString.call(object)) {
+      case '[object Array]':
+        return 'Array';
+      case '[object Blob]':
+        return 'Blob';
+      case '[object ArrayBuffer]':
+        return 'ArrayBuffer';
+      case '[object Boolean]':
+        return 'Boolean';
+      case '[object Function]':
+        return 'Function';
+      case '[object Null]':
+        return 'Null';
+      case '[object Number]':
+        return 'Number';
+      case '[object Object]':
+        return 'Object';
+      case '[object String]':
+        return 'String';
+      case '[object Undefined]':
+        return 'Undefined';
+      default:
+        return 'Unknown';
+    }
+  }
+}
+
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/local-storage-store.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/local-storage-store.js
new file mode 100644
index 0000000..800c6b7
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/local-storage-store.js
@@ -0,0 +1,184 @@
+cordova.define("cordova-plugin-advanced-http.local-storage-store", function(require, exports, module) {
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Exponent
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Based on "tough-cookie-web-storage-store" v1.0.0
+ * Thanks James Ide: https://github.com/exponentjs/tough-cookie-web-storage-store
+ *
+ * Modified by Sefa Ilkimen for cordova plugin integration
+ *
+ */
+
+'use strict';
+
+module.exports = function init(ToughCookie, _) {
+  function WebStorageCookieStore(storage, storeKey) {
+    ToughCookie.Store.call(this);
+    this._storage = storage;
+    this._storeKey = storeKey || '__cookieStore__';
+    this.synchronous = true;
+  }
+
+  WebStorageCookieStore.prototype = Object.create(ToughCookie.Store);
+
+  WebStorageCookieStore.prototype.findCookie = function (domain, path, key, callback) {
+    var store = this._readStore();
+    var cookie = _.get(store, [domain, path, key], null);
+
+    callback(null, ToughCookie.Cookie.fromJSON(cookie));
+  };
+
+  WebStorageCookieStore.prototype.findCookies = function (domain, path, callback) {
+    if (!domain) {
+      callback(null, []);
+      return;
+    }
+
+    var that = this;
+    var cookies = [];
+    var store = this._readStore();
+    var domains = ToughCookie.permuteDomain(domain) || [domain];
+
+    domains.forEach(function (domain) {
+      if (!store[domain]) {
+        return;
+      }
+
+      var matchingPaths = Object.keys(store[domain]);
+
+      if (path != null) {
+        matchingPaths = matchingPaths.filter(function (cookiePath) {
+          return that._isOnPath(cookiePath, path);
+        });
+      }
+
+      matchingPaths.forEach(function (path) {
+        Array.prototype.push.apply(cookies, _.values(store[domain][path]));
+      });
+    });
+
+    cookies = cookies.map(function (cookie) {
+      return ToughCookie.Cookie.fromJSON(cookie);
+    });
+
+    callback(null, cookies);
+  };
+
+  /**
+   * Returns whether `cookiePath` is on the given `urlPath`
+   */
+  WebStorageCookieStore.prototype._isOnPath = function (cookiePath, urlPath) {
+    if (!cookiePath) {
+      return false;
+    }
+
+    if (cookiePath === urlPath) {
+      return true;
+    }
+
+    if (urlPath.indexOf(cookiePath) !== 0) {
+      return false;
+    }
+
+    if (cookiePath[cookiePath.length - 1] !== '/' && urlPath[cookiePath.length] !== '/') {
+      return false;
+    }
+
+    return true;
+  };
+
+  WebStorageCookieStore.prototype.putCookie = function (cookie, callback) {
+    var store = this._readStore();
+
+    _.set(store, [cookie.domain, cookie.path, cookie.key], cookie);
+    this._writeStore(store);
+    callback(null);
+  };
+
+  WebStorageCookieStore.prototype.updateCookie = function (oldCookie, newCookie, callback) {
+    this.putCookie(newCookie, callback);
+  };
+
+
+  WebStorageCookieStore.prototype.removeCookie = function (domain, path, key, callback) {
+    var store = this._readStore();
+
+    _.unset(store, [domain, path, key]);
+    this._writeStore(store);
+    callback(null);
+  };
+
+  WebStorageCookieStore.prototype.removeCookies = function (domain, path, callback) {
+    var store = this._readStore();
+
+    if (path == null) {
+      _.unset(store, [domain]);
+    } else {
+      _.unset(store, [domain, path]);
+    }
+
+    this._writeStore(store);
+    callback(null);
+  };
+
+  WebStorageCookieStore.prototype.getAllCookies = function (callback) {
+    var cookies = [];
+    var store = this._readStore();
+
+    Object.keys(store).forEach(function (domain) {
+      Object.keys(store[domain]).forEach(function (path) {
+        Array.protype.push.apply(cookies, _.values(store[domain][path]));
+      });
+    });
+
+    cookies = cookies.map(function (cookie) {
+      return ToughCookie.Cookie.fromJSON(cookie);
+    });
+
+    cookies.sort(function (c1, c2) {
+      return (c1.creationIndex || 0) - (c2.creationIndex || 0);
+    });
+
+    callback(null, cookies);
+  };
+
+  WebStorageCookieStore.prototype._readStore = function () {
+    var json = this._storage.getItem(this._storeKey);
+
+    if (json !== null) {
+      try {
+        return JSON.parse(json);
+      } catch (e) { }
+    }
+
+    return {};
+  };
+
+  WebStorageCookieStore.prototype._writeStore = function (store) {
+    this._storage.setItem(this._storeKey, JSON.stringify(store));
+  };
+
+  return WebStorageCookieStore;
+};
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/lodash.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/lodash.js
new file mode 100644
index 0000000..f35be77
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/lodash.js
@@ -0,0 +1,22 @@
+cordova.define("cordova-plugin-advanced-http.lodash", function(require, exports, module) {
+/**
+ * @license
+ * Lodash (Custom Build) lodash.com/license | Underscore.js 1.8.3 underscorejs.org/LICENSE
+ * Build: `lodash include="get,set,unset,values" exports="node"`
+ */
+;(function(){function t(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r<n;)o[r]=e(t[r],r,t);return o}function e(t){return function(e){return t(e)}}function r(e,r){return t(r,function(t){return e[t]})}function n(){}function o(t){var e=-1,r=null==t?0:t.length;for(this.clear();++e<r;){var n=t[e];this.set(n[0],n[1])}}function u(t){var e=-1,r=null==t?0:t.length;for(this.clear();++e<r;){var n=t[e];this.set(n[0],n[1])}}function i(t){var e=-1,r=null==t?0:t.length;for(this.clear();++e<r;){var n=t[e];this.set(n[0],n[1]);
+}}function c(t,e){for(var r=t.length;r--;)if(m(t[r][0],e))return r;return-1}function a(t,e){e=h(e,t);for(var r=0,n=e.length;null!=t&&r<n;)t=t[j(e[r++])];return r&&r==n?t:E}function l(t){if(null==t)return t===E?"[object Undefined]":"[object Null]";t=Object(t);var e;if(nt&&nt in t){var r=Q.call(t,nt),n=t[nt];try{t[nt]=E,e=true}catch(t){}var o=Y.call(t);e&&(r?t[nt]=n:delete t[nt]),e=o}else e=Y.call(t);return e}function s(t){return w(t)&&"[object Arguments]"==l(t)}function f(t){return w(t)&&z(t.length)&&!!M[l(t)];
+}function p(e){if(typeof e=="string")return e;if(ft(e))return t(e,p)+"";if(x(e))return at?at.call(e):"";var r=e+"";return"0"==r&&1/e==-T?"-0":r}function h(t,e){var r;return ft(t)?r=t:(ft(t)?r=false:(r=typeof t,r=!("number"!=r&&"symbol"!=r&&"boolean"!=r&&null!=t&&!x(t))||(B.test(t)||!I.test(t)||null!=e&&t in Object(e))),r=r?[t]:lt(F(t))),r}function y(t,e){var r=t.__data__,n=typeof e;return("string"==n||"number"==n||"symbol"==n||"boolean"==n?"__proto__"!==e:null===e)?r[typeof e=="string"?"string":"hash"]:r.map;
+}function b(t,e){var r=null==t?E:t[e];return(!S(r)||X&&X in r?0:(O(r)?Z:L).test(g(r)))?r:E}function _(t,e){return e=null==e?9007199254740991:e,!!e&&(typeof t=="number"||R.test(t))&&-1<t&&0==t%1&&t<e}function j(t){if(typeof t=="string"||x(t))return t;var e=t+"";return"0"==e&&1/t==-T?"-0":e}function g(t){if(null!=t){try{return K.call(t)}catch(t){}return t+""}return""}function v(t){var e=null==t?0:t.length;return e?t[e-1]:E}function d(t,e){function r(){var n=arguments,o=e?e.apply(this,n):n[0],u=r.cache;
+return u.has(o)?u.get(o):(n=t.apply(this,n),r.cache=u.set(o,n)||u,n)}if(typeof t!="function"||null!=e&&typeof e!="function")throw new TypeError("Expected a function");return r.cache=new(d.Cache||i),r}function m(t,e){return t===e||t!==t&&e!==e}function A(t){return null!=t&&z(t.length)&&!O(t)}function O(t){return!!S(t)&&(t=l(t),"[object Function]"==t||"[object GeneratorFunction]"==t||"[object AsyncFunction]"==t||"[object Proxy]"==t)}function z(t){return typeof t=="number"&&-1<t&&0==t%1&&9007199254740991>=t;
+}function S(t){var e=typeof t;return null!=t&&("object"==e||"function"==e)}function w(t){return null!=t&&typeof t=="object"}function x(t){return typeof t=="symbol"||w(t)&&"[object Symbol]"==l(t)}function F(t){return null==t?"":p(t)}function $(t){if(A(t)){var e=ft(t),r=!e&&st(t),n=!e&&!r&&pt(t),o=!e&&!r&&!n&&ht(t);if(e=e||r||n||o){for(var r=t.length,u=String,i=-1,c=Array(r);++i<r;)c[i]=u(i);r=c}else r=[];var a,u=r.length;for(a in t)!Q.call(t,a)||e&&("length"==a||n&&("offset"==a||"parent"==a)||o&&("buffer"==a||"byteLength"==a||"byteOffset"==a)||_(a,u))||r.push(a);
+t=r}else if(a=t&&t.constructor,t===(typeof a=="function"&&a.prototype||H)){a=[];for(n in Object(t))Q.call(t,n)&&"constructor"!=n&&a.push(n);t=a}else t=ut(t);return t}function k(){return false}var E,T=1/0,I=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,B=/^\w*$/,P=/^\./,U=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,C=/\\(\\)?/g,L=/^\[object .+?Constructor\]$/,R=/^(?:0|[1-9]\d*)$/,M={};M["[object Float32Array]"]=M["[object Float64Array]"]=M["[object Int8Array]"]=M["[object Int16Array]"]=M["[object Int32Array]"]=M["[object Uint8Array]"]=M["[object Uint8ClampedArray]"]=M["[object Uint16Array]"]=M["[object Uint32Array]"]=true,
+M["[object Arguments]"]=M["[object Array]"]=M["[object ArrayBuffer]"]=M["[object Boolean]"]=M["[object DataView]"]=M["[object Date]"]=M["[object Error]"]=M["[object Function]"]=M["[object Map]"]=M["[object Number]"]=M["[object Object]"]=M["[object RegExp]"]=M["[object Set]"]=M["[object String]"]=M["[object WeakMap]"]=false;var N,D=typeof global=="object"&&global&&global.Object===Object&&global,V=typeof self=="object"&&self&&self.Object===Object&&self,q=D||V||Function("return this")(),G=(V=typeof exports=="object"&&exports&&!exports.nodeType&&exports)&&typeof module=="object"&&module&&!module.nodeType&&module,W=G&&G.exports===V,D=W&&D.process;
+t:{try{N=D&&D.binding&&D.binding("util");break t}catch(t){}N=void 0}N=N&&N.isTypedArray;var D=Array.prototype,H=Object.prototype,J=q["__core-js_shared__"],K=Function.prototype.toString,Q=H.hasOwnProperty,X=function(){var t=/[^.]+$/.exec(J&&J.keys&&J.keys.IE_PROTO||"");return t?"Symbol(src)_1."+t:""}(),Y=H.toString,Z=RegExp("^"+K.call(Q).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),tt=W?q.Buffer:E,W=q.Symbol,et=H.propertyIsEnumerable,rt=D.splice,nt=W?W.toStringTag:E,ot=function(){
+try{var t=b(Object,"defineProperty");return t({},"",{}),t}catch(t){}}(),D=tt?tt.isBuffer:E,ut=function(t,e){return function(r){return t(e(r))}}(Object.keys,Object),it=b(q,"Map"),ct=b(Object,"create"),at=(q=W?W.prototype:E)?q.toString:E;o.prototype.clear=function(){this.__data__=ct?ct(null):{},this.size=0},o.prototype.delete=function(t){return t=this.has(t)&&delete this.__data__[t],this.size-=t?1:0,t},o.prototype.get=function(t){var e=this.__data__;return ct?(t=e[t],"__lodash_hash_undefined__"===t?E:t):Q.call(e,t)?e[t]:E;
+},o.prototype.has=function(t){var e=this.__data__;return ct?e[t]!==E:Q.call(e,t)},o.prototype.set=function(t,e){var r=this.__data__;return this.size+=this.has(t)?0:1,r[t]=ct&&e===E?"__lodash_hash_undefined__":e,this},u.prototype.clear=function(){this.__data__=[],this.size=0},u.prototype.delete=function(t){var e=this.__data__;return t=c(e,t),!(0>t)&&(t==e.length-1?e.pop():rt.call(e,t,1),--this.size,true)},u.prototype.get=function(t){var e=this.__data__;return t=c(e,t),0>t?E:e[t][1]},u.prototype.has=function(t){
+return-1<c(this.__data__,t)},u.prototype.set=function(t,e){var r=this.__data__,n=c(r,t);return 0>n?(++this.size,r.push([t,e])):r[n][1]=e,this},i.prototype.clear=function(){this.size=0,this.__data__={hash:new o,map:new(it||u),string:new o}},i.prototype.delete=function(t){return t=y(this,t).delete(t),this.size-=t?1:0,t},i.prototype.get=function(t){return y(this,t).get(t)},i.prototype.has=function(t){return y(this,t).has(t)},i.prototype.set=function(t,e){var r=y(this,t),n=r.size;return r.set(t,e),this.size+=r.size==n?0:1,
+this};var lt=function(t){t=d(t,function(t){return 500===e.size&&e.clear(),t});var e=t.cache;return t}(function(t){var e=[];return P.test(t)&&e.push(""),t.replace(U,function(t,r,n,o){e.push(n?o.replace(C,"$1"):r||t)}),e});d.Cache=i;var st=s(function(){return arguments}())?s:function(t){return w(t)&&Q.call(t,"callee")&&!et.call(t,"callee")},ft=Array.isArray,pt=D||k,ht=N?e(N):f;n.keys=$,n.memoize=d,n.set=function(t,e,r){if(null!=t&&S(t)){e=h(e,t);for(var n=-1,o=e.length,u=o-1,i=t;null!=i&&++n<o;){var c=j(e[n]),a=r;
+if(n!=u){var l=i[c],a=E;a===E&&(a=S(l)?l:_(e[n+1])?[]:{})}var s=i,l=c,f=s[l];Q.call(s,l)&&m(f,a)&&(a!==E||l in s)||("__proto__"==l&&ot?ot(s,l,{configurable:true,enumerable:true,value:a,writable:true}):s[l]=a),i=i[c]}}return t},n.unset=function(t,e){var r;if(null==t)r=true;else{var n=t,o=r=h(e,n);if(!(2>o.length)){var u=0,i=-1,c=-1,l=o.length;for(0>u&&(u=-u>l?0:l+u),i=i>l?l:i,0>i&&(i+=l),l=u>i?0:i-u>>>0,u>>>=0,i=Array(l);++c<l;)i[c]=o[c+u];n=a(n,i)}r=j(v(r)),r=!(null!=n&&Q.call(n,r))||delete n[r]}return r;
+},n.values=function(t){return null==t?[]:r(t,$(t))},n.eq=m,n.get=function(t,e,r){return t=null==t?E:a(t,e),t===E?r:t},n.isArguments=st,n.isArray=ft,n.isArrayLike=A,n.isBuffer=pt,n.isFunction=O,n.isLength=z,n.isObject=S,n.isObjectLike=w,n.isSymbol=x,n.isTypedArray=ht,n.last=v,n.stubFalse=k,n.toString=F,n.VERSION="4.17.1",G&&((G.exports=n)._=n,V._=n)}).call(this);
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/messages.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/messages.js
new file mode 100644
index 0000000..13efb2b
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/messages.js
@@ -0,0 +1,22 @@
+cordova.define("cordova-plugin-advanced-http.messages", function(require, exports, module) {
+module.exports = {
+  ADDING_COOKIES_NOT_SUPPORTED: 'advanced-http: "setHeader" does not support adding cookies, please use "setCookie" function instead',
+  DATA_TYPE_MISMATCH: 'advanced-http: "data" argument supports only following data types:',
+  INVALID_CLIENT_AUTH_ALIAS: 'advanced-http: invalid client certificate alias, needs to be a string or undefined',
+  INVALID_CLIENT_AUTH_MODE: 'advanced-http: invalid client certificate authentication mode, supported modes are:',
+  INVALID_CLIENT_AUTH_OPTIONS: 'advanced-http: invalid client certificate authentication options, needs to be an object',
+  INVALID_CLIENT_AUTH_PKCS_PASSWORD: 'advanced-http: invalid PKCS12 container password, needs to be a string',
+  INVALID_CLIENT_AUTH_RAW_PKCS: 'advanced-http: invalid PKCS12 container, needs to be an array buffer',
+  INVALID_DATA_SERIALIZER: 'advanced-http: invalid serializer, supported serializers are:',
+  INVALID_FOLLOW_REDIRECT_VALUE: 'advanced-http: invalid follow redirect value, needs to be a boolean value',
+  INVALID_HEADERS_VALUE: 'advanced-http: header values must be strings',
+  INVALID_HTTP_METHOD: 'advanced-http: invalid HTTP method, supported methods are:',
+  INVALID_PARAMS_VALUE: 'advanced-http: invalid params object, needs to be an object with strings',
+  INVALID_RESPONSE_TYPE: 'advanced-http: invalid response type, supported types are:',
+  INVALID_SSL_CERT_MODE: 'advanced-http: invalid SSL cert mode, supported modes are:',
+  INVALID_TIMEOUT_VALUE: 'advanced-http: invalid timeout value, needs to be a positive numeric value',
+  MANDATORY_FAIL: 'advanced-http: missing mandatory "onFail" callback function',
+  MANDATORY_SUCCESS: 'advanced-http: missing mandatory "onSuccess" callback function',
+};
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/public-interface.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/public-interface.js
new file mode 100644
index 0000000..a77c8e0
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/public-interface.js
@@ -0,0 +1,202 @@
+cordova.define("cordova-plugin-advanced-http.public-interface", function(require, exports, module) {
+module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConfigs) {
+  const publicInterface = {
+    getBasicAuthHeader: getBasicAuthHeader,
+    useBasicAuth: useBasicAuth,
+    getHeaders: getHeaders,
+    setHeader: setHeader,
+    getDataSerializer: getDataSerializer,
+    setDataSerializer: setDataSerializer,
+    setCookie: setCookie,
+    clearCookies: clearCookies,
+    removeCookies: removeCookies,
+    getCookieString: getCookieString,
+    getRequestTimeout: getRequestTimeout,
+    setRequestTimeout: setRequestTimeout,
+    getFollowRedirect: getFollowRedirect,
+    setFollowRedirect: setFollowRedirect,
+    // @DEPRECATED
+    disableRedirect: disableRedirect,
+    // @DEPRECATED
+    setSSLCertMode: setServerTrustMode,
+    setServerTrustMode: setServerTrustMode,
+    setClientAuthMode: setClientAuthMode,
+    sendRequest: sendRequest,
+    post: post,
+    get: get,
+    put: put,
+    patch: patch,
+    delete: del,
+    head: head,
+    uploadFile: uploadFile,
+    downloadFile: downloadFile
+  };
+
+  function getBasicAuthHeader(username, password) {
+    return { 'Authorization': 'Basic ' + helpers.b64EncodeUnicode(username + ':' + password) };
+  }
+
+  function useBasicAuth(username, password) {
+    this.setHeader('*', 'Authorization', 'Basic ' + helpers.b64EncodeUnicode(username + ':' + password));
+  }
+
+  function getHeaders(host) {
+    return globalConfigs.headers[host || '*'] || null;
+  }
+
+  function setHeader() {
+    // this one is for being backward compatible
+    var host = '*';
+    var header = arguments[0];
+    var value = arguments[1];
+
+    if (arguments.length === 3) {
+      host = arguments[0];
+      header = arguments[1];
+      value = arguments[2];
+    }
+
+    helpers.checkForBlacklistedHeaderKey(header);
+    helpers.checkForInvalidHeaderValue(value);
+
+    globalConfigs.headers[host] = globalConfigs.headers[host] || {};
+    globalConfigs.headers[host][header] = value;
+  }
+
+  function getDataSerializer() {
+    return globalConfigs.serializer;
+  }
+
+  function setDataSerializer(serializer) {
+    globalConfigs.serializer = helpers.checkSerializer(serializer);
+  }
+
+  function setCookie(url, cookie, options) {
+    cookieHandler.setCookie(url, cookie, options);
+  }
+
+  function clearCookies() {
+    cookieHandler.clearCookies();
+  }
+
+  function removeCookies(url, callback) {
+    cookieHandler.removeCookies(url, callback);
+  }
+
+  function getCookieString(url) {
+    return cookieHandler.getCookieString(url);
+  }
+
+  function getRequestTimeout() {
+    return globalConfigs.timeout;
+  }
+
+  function setRequestTimeout(timeout) {
+    globalConfigs.timeout = helpers.checkTimeoutValue(timeout);
+  }
+
+  function getFollowRedirect() {
+    return globalConfigs.followRedirect;
+  }
+
+  function setFollowRedirect(follow) {
+    globalConfigs.followRedirect = helpers.checkFollowRedirectValue(follow);
+  }
+
+  // @DEPRECATED
+  function disableRedirect(disable, success, failure) {
+    helpers.handleMissingCallbacks(success, failure);
+
+    setFollowRedirect(!disable);
+    success();
+  }
+
+  function setServerTrustMode(mode, success, failure) {
+    helpers.handleMissingCallbacks(success, failure);
+
+    return exec(success, failure, 'CordovaHttpPlugin', 'setServerTrustMode', [helpers.checkSSLCertMode(mode)]);
+  }
+
+  function setClientAuthMode() {
+    var mode = arguments[0];
+    var options = null;
+    var success = arguments[1];
+    var failure = arguments[2];
+
+    if (arguments.length === 4) {
+      options = arguments[1];
+      success = arguments[2];
+      failure = arguments[3];
+    }
+
+    mode = helpers.checkClientAuthMode(mode);
+    options = helpers.checkClientAuthOptions(mode, options);
+
+    helpers.handleMissingCallbacks(success, failure);
+
+    return exec(success, failure, 'CordovaHttpPlugin', 'setClientAuthMode', [mode, options.alias, options.rawPkcs, options.pkcsPassword]);
+  }
+
+  function sendRequest(url, options, success, failure) {
+    helpers.handleMissingCallbacks(success, failure);
+
+    options = helpers.handleMissingOptions(options, globalConfigs);
+    url = urlUtil.appendQueryParamsString(url, urlUtil.serializeQueryParams(options.params, true));
+
+    var headers = helpers.getMergedHeaders(url, options.headers, globalConfigs.headers);
+
+    var onFail = helpers.injectCookieHandler(url, failure);
+    var onSuccess = helpers.injectCookieHandler(url, helpers.injectRawResponseHandler(options.responseType, success));
+
+    switch (options.method) {
+      case 'post':
+      case 'put':
+      case 'patch':
+        var data = helpers.getProcessedData(options.data, options.serializer);
+        return exec(onSuccess, onFail, 'CordovaHttpPlugin', options.method, [url, data, options.serializer, headers, options.timeout, options.followRedirect, options.responseType]);
+      case 'upload':
+        return exec(onSuccess, onFail, 'CordovaHttpPlugin', 'uploadFile', [url, headers, options.filePath, options.name, options.timeout, options.followRedirect, options.responseType]);
+      case 'download':
+        var onDownloadSuccess = helpers.injectCookieHandler(url, helpers.injectFileEntryHandler(success));
+        return exec(onDownloadSuccess, onFail, 'CordovaHttpPlugin', 'downloadFile', [url, headers, options.filePath, options.timeout, options.followRedirect]);
+      default:
+        return exec(onSuccess, onFail, 'CordovaHttpPlugin', options.method, [url, headers, options.timeout, options.followRedirect, options.responseType]);
+    }
+  }
+
+  function post(url, data, headers, success, failure) {
+    return publicInterface.sendRequest(url, { method: 'post', data: data, headers: headers }, success, failure);
+  };
+
+  function get(url, params, headers, success, failure) {
+    return publicInterface.sendRequest(url, { method: 'get', params: params, headers: headers }, success, failure);
+  };
+
+  function put(url, data, headers, success, failure) {
+    return publicInterface.sendRequest(url, { method: 'put', data: data, headers: headers }, success, failure);
+  }
+
+  function patch(url, data, headers, success, failure) {
+    return publicInterface.sendRequest(url, { method: 'patch', data: data, headers: headers }, success, failure);
+  }
+
+  function del(url, params, headers, success, failure) {
+    return publicInterface.sendRequest(url, { method: 'delete', params: params, headers: headers }, success, failure);
+  }
+
+  function head(url, params, headers, success, failure) {
+    return publicInterface.sendRequest(url, { method: 'head', params: params, headers: headers }, success, failure);
+  }
+
+  function uploadFile(url, params, headers, filePath, name, success, failure) {
+    return publicInterface.sendRequest(url, { method: 'upload', params: params, headers: headers, filePath: filePath, name: name }, success, failure);
+  }
+
+  function downloadFile(url, params, headers, filePath, success, failure) {
+    return publicInterface.sendRequest(url, { method: 'download', params: params, headers: headers, filePath: filePath }, success, failure);
+  }
+
+  return publicInterface;
+}
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/umd-tough-cookie.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/umd-tough-cookie.js
new file mode 100644
index 0000000..bd8ab68
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/umd-tough-cookie.js
@@ -0,0 +1,5091 @@
+cordova.define("cordova-plugin-advanced-http.tough-cookie", function(require, exports, module) {
+(function webpackUniversalModuleDefinition(root, factory) {
+	if(typeof exports === 'object' && typeof module === 'object')
+		module.exports = factory();
+	else if(typeof define === 'function' && define.amd)
+		define([], factory);
+	else if(typeof exports === 'object')
+		exports["ToughCookie"] = factory();
+	else
+		root["ToughCookie"] = factory();
+})(this, function() {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ 	// The module cache
+/******/ 	var installedModules = {};
+
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+
+/******/ 		// Check if module is in cache
+/******/ 		if(installedModules[moduleId])
+/******/ 			return installedModules[moduleId].exports;
+
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = installedModules[moduleId] = {
+/******/ 			exports: {},
+/******/ 			id: moduleId,
+/******/ 			loaded: false
+/******/ 		};
+
+/******/ 		// Execute the module function
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ 		// Flag the module as loaded
+/******/ 		module.loaded = true;
+
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+
+
+/******/ 	// expose the modules object (__webpack_modules__)
+/******/ 	__webpack_require__.m = modules;
+
+/******/ 	// expose the module cache
+/******/ 	__webpack_require__.c = installedModules;
+
+/******/ 	// __webpack_public_path__
+/******/ 	__webpack_require__.p = "";
+
+/******/ 	// Load entry module and return exports
+/******/ 	return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/*!
+	 * Copyright (c) 2015, Salesforce.com, Inc.
+	 * All rights reserved.
+	 *
+	 * Redistribution and use in source and binary forms, with or without
+	 * modification, are permitted provided that the following conditions are met:
+	 *
+	 * 1. Redistributions of source code must retain the above copyright notice,
+	 * this list of conditions and the following disclaimer.
+	 *
+	 * 2. Redistributions in binary form must reproduce the above copyright notice,
+	 * this list of conditions and the following disclaimer in the documentation
+	 * and/or other materials provided with the distribution.
+	 *
+	 * 3. Neither the name of Salesforce.com nor the names of its contributors may
+	 * be used to endorse or promote products derived from this software without
+	 * specific prior written permission.
+	 *
+	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+	 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+	 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+	 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+	 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+	 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	 * POSSIBILITY OF SUCH DAMAGE.
+	 */
+	'use strict';
+	var net = __webpack_require__(1);
+	var urlParse = __webpack_require__(2).parse;
+	var util = __webpack_require__(9);
+	var pubsuffix = __webpack_require__(13);
+	var Store = __webpack_require__(17).Store;
+	var MemoryCookieStore = __webpack_require__(18).MemoryCookieStore;
+	var pathMatch = __webpack_require__(20).pathMatch;
+	var VERSION = __webpack_require__(21).version;
+
+	var punycode;
+	try {
+	  punycode = __webpack_require__(15);
+	} catch(e) {
+	  console.warn("tough-cookie: can't load punycode; won't use punycode for domain normalization");
+	}
+
+	// From RFC6265 S4.1.1
+	// note that it excludes \x3B ";"
+	var COOKIE_OCTETS = /^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]+$/;
+
+	var CONTROL_CHARS = /[\x00-\x1F]/;
+
+	// From Chromium // '\r', '\n' and '\0' should be treated as a terminator in
+	// the "relaxed" mode, see:
+	// https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/parsed_cookie.cc#L60
+	var TERMINATORS = ['\n', '\r', '\0'];
+
+	// RFC6265 S4.1.1 defines path value as 'any CHAR except CTLs or ";"'
+	// Note ';' is \x3B
+	var PATH_VALUE = /[\x20-\x3A\x3C-\x7E]+/;
+
+	// date-time parsing constants (RFC6265 S5.1.1)
+
+	var DATE_DELIM = /[\x09\x20-\x2F\x3B-\x40\x5B-\x60\x7B-\x7E]/;
+
+	var MONTH_TO_NUM = {
+	  jan:0, feb:1, mar:2, apr:3, may:4, jun:5,
+	  jul:6, aug:7, sep:8, oct:9, nov:10, dec:11
+	};
+	var NUM_TO_MONTH = [
+	  'Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'
+	];
+	var NUM_TO_DAY = [
+	  'Sun','Mon','Tue','Wed','Thu','Fri','Sat'
+	];
+
+	var MAX_TIME = 2147483647000; // 31-bit max
+	var MIN_TIME = 0; // 31-bit min
+
+	/*
+	 * Parses a Natural number (i.e., non-negative integer) with either the
+	 *    <min>*<max>DIGIT ( non-digit *OCTET )
+	 * or
+	 *    <min>*<max>DIGIT
+	 * grammar (RFC6265 S5.1.1).
+	 *
+	 * The "trailingOK" boolean controls if the grammar accepts a
+	 * "( non-digit *OCTET )" trailer.
+	 */
+	function parseDigits(token, minDigits, maxDigits, trailingOK) {
+	  var count = 0;
+	  while (count < token.length) {
+	    var c = token.charCodeAt(count);
+	    // "non-digit = %x00-2F / %x3A-FF"
+	    if (c <= 0x2F || c >= 0x3A) {
+	      break;
+	    }
+	    count++;
+	  }
+
+	  // constrain to a minimum and maximum number of digits.
+	  if (count < minDigits || count > maxDigits) {
+	    return null;
+	  }
+
+	  if (!trailingOK && count != token.length) {
+	    return null;
+	  }
+
+	  return parseInt(token.substr(0,count), 10);
+	}
+
+	function parseTime(token) {
+	  var parts = token.split(':');
+	  var result = [0,0,0];
+
+	  /* RF6256 S5.1.1:
+	   *      time            = hms-time ( non-digit *OCTET )
+	   *      hms-time        = time-field ":" time-field ":" time-field
+	   *      time-field      = 1*2DIGIT
+	   */
+
+	  if (parts.length !== 3) {
+	    return null;
+	  }
+
+	  for (var i = 0; i < 3; i++) {
+	    // "time-field" must be strictly "1*2DIGIT", HOWEVER, "hms-time" can be
+	    // followed by "( non-digit *OCTET )" so therefore the last time-field can
+	    // have a trailer
+	    var trailingOK = (i == 2);
+	    var num = parseDigits(parts[i], 1, 2, trailingOK);
+	    if (num === null) {
+	      return null;
+	    }
+	    result[i] = num;
+	  }
+
+	  return result;
+	}
+
+	function parseMonth(token) {
+	  token = String(token).substr(0,3).toLowerCase();
+	  var num = MONTH_TO_NUM[token];
+	  return num >= 0 ? num : null;
+	}
+
+	/*
+	 * RFC6265 S5.1.1 date parser (see RFC for full grammar)
+	 */
+	function parseDate(str) {
+	  if (!str) {
+	    return;
+	  }
+
+	  /* RFC6265 S5.1.1:
+	   * 2. Process each date-token sequentially in the order the date-tokens
+	   * appear in the cookie-date
+	   */
+	  var tokens = str.split(DATE_DELIM);
+	  if (!tokens) {
+	    return;
+	  }
+
+	  var hour = null;
+	  var minute = null;
+	  var second = null;
+	  var dayOfMonth = null;
+	  var month = null;
+	  var year = null;
+
+	  for (var i=0; i<tokens.length; i++) {
+	    var token = tokens[i].trim();
+	    if (!token.length) {
+	      continue;
+	    }
+
+	    var result;
+
+	    /* 2.1. If the found-time flag is not set and the token matches the time
+	     * production, set the found-time flag and set the hour- value,
+	     * minute-value, and second-value to the numbers denoted by the digits in
+	     * the date-token, respectively.  Skip the remaining sub-steps and continue
+	     * to the next date-token.
+	     */
+	    if (second === null) {
+	      result = parseTime(token);
+	      if (result) {
+	        hour = result[0];
+	        minute = result[1];
+	        second = result[2];
+	        continue;
+	      }
+	    }
+
+	    /* 2.2. If the found-day-of-month flag is not set and the date-token matches
+	     * the day-of-month production, set the found-day-of- month flag and set
+	     * the day-of-month-value to the number denoted by the date-token.  Skip
+	     * the remaining sub-steps and continue to the next date-token.
+	     */
+	    if (dayOfMonth === null) {
+	      // "day-of-month = 1*2DIGIT ( non-digit *OCTET )"
+	      result = parseDigits(token, 1, 2, true);
+	      if (result !== null) {
+	        dayOfMonth = result;
+	        continue;
+	      }
+	    }
+
+	    /* 2.3. If the found-month flag is not set and the date-token matches the
+	     * month production, set the found-month flag and set the month-value to
+	     * the month denoted by the date-token.  Skip the remaining sub-steps and
+	     * continue to the next date-token.
+	     */
+	    if (month === null) {
+	      result = parseMonth(token);
+	      if (result !== null) {
+	        month = result;
+	        continue;
+	      }
+	    }
+
+	    /* 2.4. If the found-year flag is not set and the date-token matches the
+	     * year production, set the found-year flag and set the year-value to the
+	     * number denoted by the date-token.  Skip the remaining sub-steps and
+	     * continue to the next date-token.
+	     */
+	    if (year === null) {
+	      // "year = 2*4DIGIT ( non-digit *OCTET )"
+	      result = parseDigits(token, 2, 4, true);
+	      if (result !== null) {
+	        year = result;
+	        /* From S5.1.1:
+	         * 3.  If the year-value is greater than or equal to 70 and less
+	         * than or equal to 99, increment the year-value by 1900.
+	         * 4.  If the year-value is greater than or equal to 0 and less
+	         * than or equal to 69, increment the year-value by 2000.
+	         */
+	        if (year >= 70 && year <= 99) {
+	          year += 1900;
+	        } else if (year >= 0 && year <= 69) {
+	          year += 2000;
+	        }
+	      }
+	    }
+	  }
+
+	  /* RFC 6265 S5.1.1
+	   * "5. Abort these steps and fail to parse the cookie-date if:
+	   *     *  at least one of the found-day-of-month, found-month, found-
+	   *        year, or found-time flags is not set,
+	   *     *  the day-of-month-value is less than 1 or greater than 31,
+	   *     *  the year-value is less than 1601,
+	   *     *  the hour-value is greater than 23,
+	   *     *  the minute-value is greater than 59, or
+	   *     *  the second-value is greater than 59.
+	   *     (Note that leap seconds cannot be represented in this syntax.)"
+	   *
+	   * So, in order as above:
+	   */
+	  if (
+	    dayOfMonth === null || month === null || year === null || second === null ||
+	    dayOfMonth < 1 || dayOfMonth > 31 ||
+	    year < 1601 ||
+	    hour > 23 ||
+	    minute > 59 ||
+	    second > 59
+	  ) {
+	    return;
+	  }
+
+	  return new Date(Date.UTC(year, month, dayOfMonth, hour, minute, second));
+	}
+
+	function formatDate(date) {
+	  var d = date.getUTCDate(); d = d >= 10 ? d : '0'+d;
+	  var h = date.getUTCHours(); h = h >= 10 ? h : '0'+h;
+	  var m = date.getUTCMinutes(); m = m >= 10 ? m : '0'+m;
+	  var s = date.getUTCSeconds(); s = s >= 10 ? s : '0'+s;
+	  return NUM_TO_DAY[date.getUTCDay()] + ', ' +
+	    d+' '+ NUM_TO_MONTH[date.getUTCMonth()] +' '+ date.getUTCFullYear() +' '+
+	    h+':'+m+':'+s+' GMT';
+	}
+
+	// S5.1.2 Canonicalized Host Names
+	function canonicalDomain(str) {
+	  if (str == null) {
+	    return null;
+	  }
+	  str = str.trim().replace(/^\./,''); // S4.1.2.3 & S5.2.3: ignore leading .
+
+	  // convert to IDN if any non-ASCII characters
+	  if (punycode && /[^\u0001-\u007f]/.test(str)) {
+	    str = punycode.toASCII(str);
+	  }
+
+	  return str.toLowerCase();
+	}
+
+	// S5.1.3 Domain Matching
+	function domainMatch(str, domStr, canonicalize) {
+	  if (str == null || domStr == null) {
+	    return null;
+	  }
+	  if (canonicalize !== false) {
+	    str = canonicalDomain(str);
+	    domStr = canonicalDomain(domStr);
+	  }
+
+	  /*
+	   * "The domain string and the string are identical. (Note that both the
+	   * domain string and the string will have been canonicalized to lower case at
+	   * this point)"
+	   */
+	  if (str == domStr) {
+	    return true;
+	  }
+
+	  /* "All of the following [three] conditions hold:" (order adjusted from the RFC) */
+
+	  /* "* The string is a host name (i.e., not an IP address)." */
+	  if (net.isIP(str)) {
+	    return false;
+	  }
+
+	  /* "* The domain string is a suffix of the string" */
+	  var idx = str.indexOf(domStr);
+	  if (idx <= 0) {
+	    return false; // it's a non-match (-1) or prefix (0)
+	  }
+
+	  // e.g "a.b.c".indexOf("b.c") === 2
+	  // 5 === 3+2
+	  if (str.length !== domStr.length + idx) { // it's not a suffix
+	    return false;
+	  }
+
+	  /* "* The last character of the string that is not included in the domain
+	  * string is a %x2E (".") character." */
+	  if (str.substr(idx-1,1) !== '.') {
+	    return false;
+	  }
+
+	  return true;
+	}
+
+
+	// RFC6265 S5.1.4 Paths and Path-Match
+
+	/*
+	 * "The user agent MUST use an algorithm equivalent to the following algorithm
+	 * to compute the default-path of a cookie:"
+	 *
+	 * Assumption: the path (and not query part or absolute uri) is passed in.
+	 */
+	function defaultPath(path) {
+	  // "2. If the uri-path is empty or if the first character of the uri-path is not
+	  // a %x2F ("/") character, output %x2F ("/") and skip the remaining steps.
+	  if (!path || path.substr(0,1) !== "/") {
+	    return "/";
+	  }
+
+	  // "3. If the uri-path contains no more than one %x2F ("/") character, output
+	  // %x2F ("/") and skip the remaining step."
+	  if (path === "/") {
+	    return path;
+	  }
+
+	  var rightSlash = path.lastIndexOf("/");
+	  if (rightSlash === 0) {
+	    return "/";
+	  }
+
+	  // "4. Output the characters of the uri-path from the first character up to,
+	  // but not including, the right-most %x2F ("/")."
+	  return path.slice(0, rightSlash);
+	}
+
+	function trimTerminator(str) {
+	  for (var t = 0; t < TERMINATORS.length; t++) {
+	    var terminatorIdx = str.indexOf(TERMINATORS[t]);
+	    if (terminatorIdx !== -1) {
+	      str = str.substr(0,terminatorIdx);
+	    }
+	  }
+
+	  return str;
+	}
+
+	function parseCookiePair(cookiePair, looseMode) {
+	  cookiePair = trimTerminator(cookiePair);
+
+	  var firstEq = cookiePair.indexOf('=');
+	  if (looseMode) {
+	    if (firstEq === 0) { // '=' is immediately at start
+	      cookiePair = cookiePair.substr(1);
+	      firstEq = cookiePair.indexOf('='); // might still need to split on '='
+	    }
+	  } else { // non-loose mode
+	    if (firstEq <= 0) { // no '=' or is at start
+	      return; // needs to have non-empty "cookie-name"
+	    }
+	  }
+
+	  var cookieName, cookieValue;
+	  if (firstEq <= 0) {
+	    cookieName = "";
+	    cookieValue = cookiePair.trim();
+	  } else {
+	    cookieName = cookiePair.substr(0, firstEq).trim();
+	    cookieValue = cookiePair.substr(firstEq+1).trim();
+	  }
+
+	  if (CONTROL_CHARS.test(cookieName) || CONTROL_CHARS.test(cookieValue)) {
+	    return;
+	  }
+
+	  var c = new Cookie();
+	  c.key = cookieName;
+	  c.value = cookieValue;
+	  return c;
+	}
+
+	function parse(str, options) {
+	  if (!options || typeof options !== 'object') {
+	    options = {};
+	  }
+	  str = str.trim();
+
+	  // We use a regex to parse the "name-value-pair" part of S5.2
+	  var firstSemi = str.indexOf(';'); // S5.2 step 1
+	  var cookiePair = (firstSemi === -1) ? str : str.substr(0, firstSemi);
+	  var c = parseCookiePair(cookiePair, !!options.loose);
+	  if (!c) {
+	    return;
+	  }
+
+	  if (firstSemi === -1) {
+	    return c;
+	  }
+
+	  // S5.2.3 "unparsed-attributes consist of the remainder of the set-cookie-string
+	  // (including the %x3B (";") in question)." plus later on in the same section
+	  // "discard the first ";" and trim".
+	  var unparsed = str.slice(firstSemi + 1).trim();
+
+	  // "If the unparsed-attributes string is empty, skip the rest of these
+	  // steps."
+	  if (unparsed.length === 0) {
+	    return c;
+	  }
+
+	  /*
+	   * S5.2 says that when looping over the items "[p]rocess the attribute-name
+	   * and attribute-value according to the requirements in the following
+	   * subsections" for every item.  Plus, for many of the individual attributes
+	   * in S5.3 it says to use the "attribute-value of the last attribute in the
+	   * cookie-attribute-list".  Therefore, in this implementation, we overwrite
+	   * the previous value.
+	   */
+	  var cookie_avs = unparsed.split(';');
+	  while (cookie_avs.length) {
+	    var av = cookie_avs.shift().trim();
+	    if (av.length === 0) { // happens if ";;" appears
+	      continue;
+	    }
+	    var av_sep = av.indexOf('=');
+	    var av_key, av_value;
+
+	    if (av_sep === -1) {
+	      av_key = av;
+	      av_value = null;
+	    } else {
+	      av_key = av.substr(0,av_sep);
+	      av_value = av.substr(av_sep+1);
+	    }
+
+	    av_key = av_key.trim().toLowerCase();
+
+	    if (av_value) {
+	      av_value = av_value.trim();
+	    }
+
+	    switch(av_key) {
+	    case 'expires': // S5.2.1
+	      if (av_value) {
+	        var exp = parseDate(av_value);
+	        // "If the attribute-value failed to parse as a cookie date, ignore the
+	        // cookie-av."
+	        if (exp) {
+	          // over and underflow not realistically a concern: V8's getTime() seems to
+	          // store something larger than a 32-bit time_t (even with 32-bit node)
+	          c.expires = exp;
+	        }
+	      }
+	      break;
+
+	    case 'max-age': // S5.2.2
+	      if (av_value) {
+	        // "If the first character of the attribute-value is not a DIGIT or a "-"
+	        // character ...[or]... If the remainder of attribute-value contains a
+	        // non-DIGIT character, ignore the cookie-av."
+	        if (/^-?[0-9]+$/.test(av_value)) {
+	          var delta = parseInt(av_value, 10);
+	          // "If delta-seconds is less than or equal to zero (0), let expiry-time
+	          // be the earliest representable date and time."
+	          c.setMaxAge(delta);
+	        }
+	      }
+	      break;
+
+	    case 'domain': // S5.2.3
+	      // "If the attribute-value is empty, the behavior is undefined.  However,
+	      // the user agent SHOULD ignore the cookie-av entirely."
+	      if (av_value) {
+	        // S5.2.3 "Let cookie-domain be the attribute-value without the leading %x2E
+	        // (".") character."
+	        var domain = av_value.trim().replace(/^\./, '');
+	        if (domain) {
+	          // "Convert the cookie-domain to lower case."
+	          c.domain = domain.toLowerCase();
+	        }
+	      }
+	      break;
+
+	    case 'path': // S5.2.4
+	      /*
+	       * "If the attribute-value is empty or if the first character of the
+	       * attribute-value is not %x2F ("/"):
+	       *   Let cookie-path be the default-path.
+	       * Otherwise:
+	       *   Let cookie-path be the attribute-value."
+	       *
+	       * We'll represent the default-path as null since it depends on the
+	       * context of the parsing.
+	       */
+	      c.path = av_value && av_value[0] === "/" ? av_value : null;
+	      break;
+
+	    case 'secure': // S5.2.5
+	      /*
+	       * "If the attribute-name case-insensitively matches the string "Secure",
+	       * the user agent MUST append an attribute to the cookie-attribute-list
+	       * with an attribute-name of Secure and an empty attribute-value."
+	       */
+	      c.secure = true;
+	      break;
+
+	    case 'httponly': // S5.2.6 -- effectively the same as 'secure'
+	      c.httpOnly = true;
+	      break;
+
+	    default:
+	      c.extensions = c.extensions || [];
+	      c.extensions.push(av);
+	      break;
+	    }
+	  }
+
+	  return c;
+	}
+
+	// avoid the V8 deoptimization monster!
+	function jsonParse(str) {
+	  var obj;
+	  try {
+	    obj = JSON.parse(str);
+	  } catch (e) {
+	    return e;
+	  }
+	  return obj;
+	}
+
+	function fromJSON(str) {
+	  if (!str) {
+	    return null;
+	  }
+
+	  var obj;
+	  if (typeof str === 'string') {
+	    obj = jsonParse(str);
+	    if (obj instanceof Error) {
+	      return null;
+	    }
+	  } else {
+	    // assume it's an Object
+	    obj = str;
+	  }
+
+	  var c = new Cookie();
+	  for (var i=0; i<Cookie.serializableProperties.length; i++) {
+	    var prop = Cookie.serializableProperties[i];
+	    if (obj[prop] === undefined ||
+	        obj[prop] === Cookie.prototype[prop])
+	    {
+	      continue; // leave as prototype default
+	    }
+
+	    if (prop === 'expires' ||
+	        prop === 'creation' ||
+	        prop === 'lastAccessed')
+	    {
+	      if (obj[prop] === null) {
+	        c[prop] = null;
+	      } else {
+	        c[prop] = obj[prop] == "Infinity" ?
+	          "Infinity" : new Date(obj[prop]);
+	      }
+	    } else {
+	      c[prop] = obj[prop];
+	    }
+	  }
+
+	  return c;
+	}
+
+	/* Section 5.4 part 2:
+	 * "*  Cookies with longer paths are listed before cookies with
+	 *     shorter paths.
+	 *
+	 *  *  Among cookies that have equal-length path fields, cookies with
+	 *     earlier creation-times are listed before cookies with later
+	 *     creation-times."
+	 */
+
+	function cookieCompare(a,b) {
+	  var cmp = 0;
+
+	  // descending for length: b CMP a
+	  var aPathLen = a.path ? a.path.length : 0;
+	  var bPathLen = b.path ? b.path.length : 0;
+	  cmp = bPathLen - aPathLen;
+	  if (cmp !== 0) {
+	    return cmp;
+	  }
+
+	  // ascending for time: a CMP b
+	  var aTime = a.creation ? a.creation.getTime() : MAX_TIME;
+	  var bTime = b.creation ? b.creation.getTime() : MAX_TIME;
+	  cmp = aTime - bTime;
+	  if (cmp !== 0) {
+	    return cmp;
+	  }
+
+	  // break ties for the same millisecond (precision of JavaScript's clock)
+	  cmp = a.creationIndex - b.creationIndex;
+
+	  return cmp;
+	}
+
+	// Gives the permutation of all possible pathMatch()es of a given path. The
+	// array is in longest-to-shortest order.  Handy for indexing.
+	function permutePath(path) {
+	  if (path === '/') {
+	    return ['/'];
+	  }
+	  if (path.lastIndexOf('/') === path.length-1) {
+	    path = path.substr(0,path.length-1);
+	  }
+	  var permutations = [path];
+	  while (path.length > 1) {
+	    var lindex = path.lastIndexOf('/');
+	    if (lindex === 0) {
+	      break;
+	    }
+	    path = path.substr(0,lindex);
+	    permutations.push(path);
+	  }
+	  permutations.push('/');
+	  return permutations;
+	}
+
+	function getCookieContext(url) {
+	  if (url instanceof Object) {
+	    return url;
+	  }
+	  // NOTE: decodeURI will throw on malformed URIs (see GH-32).
+	  // Therefore, we will just skip decoding for such URIs.
+	  try {
+	    url = decodeURI(url);
+	  }
+	  catch(err) {
+	    // Silently swallow error
+	  }
+
+	  return urlParse(url);
+	}
+
+	function Cookie(options) {
+	  options = options || {};
+
+	  Object.keys(options).forEach(function(prop) {
+	    if (Cookie.prototype.hasOwnProperty(prop) &&
+	        Cookie.prototype[prop] !== options[prop] &&
+	        prop.substr(0,1) !== '_')
+	    {
+	      this[prop] = options[prop];
+	    }
+	  }, this);
+
+	  this.creation = this.creation || new Date();
+
+	  // used to break creation ties in cookieCompare():
+	  Object.defineProperty(this, 'creationIndex', {
+	    configurable: false,
+	    enumerable: false, // important for assert.deepEqual checks
+	    writable: true,
+	    value: ++Cookie.cookiesCreated
+	  });
+	}
+
+	Cookie.cookiesCreated = 0; // incremented each time a cookie is created
+
+	Cookie.parse = parse;
+	Cookie.fromJSON = fromJSON;
+
+	Cookie.prototype.key = "";
+	Cookie.prototype.value = "";
+
+	// the order in which the RFC has them:
+	Cookie.prototype.expires = "Infinity"; // coerces to literal Infinity
+	Cookie.prototype.maxAge = null; // takes precedence over expires for TTL
+	Cookie.prototype.domain = null;
+	Cookie.prototype.path = null;
+	Cookie.prototype.secure = false;
+	Cookie.prototype.httpOnly = false;
+	Cookie.prototype.extensions = null;
+
+	// set by the CookieJar:
+	Cookie.prototype.hostOnly = null; // boolean when set
+	Cookie.prototype.pathIsDefault = null; // boolean when set
+	Cookie.prototype.creation = null; // Date when set; defaulted by Cookie.parse
+	Cookie.prototype.lastAccessed = null; // Date when set
+	Object.defineProperty(Cookie.prototype, 'creationIndex', {
+	  configurable: true,
+	  enumerable: false,
+	  writable: true,
+	  value: 0
+	});
+
+	Cookie.serializableProperties = Object.keys(Cookie.prototype)
+	  .filter(function(prop) {
+	    return !(
+	      Cookie.prototype[prop] instanceof Function ||
+	      prop === 'creationIndex' ||
+	      prop.substr(0,1) === '_'
+	    );
+	  });
+
+	Cookie.prototype.inspect = function inspect() {
+	  var now = Date.now();
+	  return 'Cookie="'+this.toString() +
+	    '; hostOnly='+(this.hostOnly != null ? this.hostOnly : '?') +
+	    '; aAge='+(this.lastAccessed ? (now-this.lastAccessed.getTime())+'ms' : '?') +
+	    '; cAge='+(this.creation ? (now-this.creation.getTime())+'ms' : '?') +
+	    '"';
+	};
+
+	// Use the new custom inspection symbol to add the custom inspect function if
+	// available.
+	if (util.inspect.custom) {
+	  Cookie.prototype[util.inspect.custom] = Cookie.prototype.inspect;
+	}
+
+	Cookie.prototype.toJSON = function() {
+	  var obj = {};
+
+	  var props = Cookie.serializableProperties;
+	  for (var i=0; i<props.length; i++) {
+	    var prop = props[i];
+	    if (this[prop] === Cookie.prototype[prop]) {
+	      continue; // leave as prototype default
+	    }
+
+	    if (prop === 'expires' ||
+	        prop === 'creation' ||
+	        prop === 'lastAccessed')
+	    {
+	      if (this[prop] === null) {
+	        obj[prop] = null;
+	      } else {
+	        obj[prop] = this[prop] == "Infinity" ? // intentionally not ===
+	          "Infinity" : this[prop].toISOString();
+	      }
+	    } else if (prop === 'maxAge') {
+	      if (this[prop] !== null) {
+	        // again, intentionally not ===
+	        obj[prop] = (this[prop] == Infinity || this[prop] == -Infinity) ?
+	          this[prop].toString() : this[prop];
+	      }
+	    } else {
+	      if (this[prop] !== Cookie.prototype[prop]) {
+	        obj[prop] = this[prop];
+	      }
+	    }
+	  }
+
+	  return obj;
+	};
+
+	Cookie.prototype.clone = function() {
+	  return fromJSON(this.toJSON());
+	};
+
+	Cookie.prototype.validate = function validate() {
+	  if (!COOKIE_OCTETS.test(this.value)) {
+	    return false;
+	  }
+	  if (this.expires != Infinity && !(this.expires instanceof Date) && !parseDate(this.expires)) {
+	    return false;
+	  }
+	  if (this.maxAge != null && this.maxAge <= 0) {
+	    return false; // "Max-Age=" non-zero-digit *DIGIT
+	  }
+	  if (this.path != null && !PATH_VALUE.test(this.path)) {
+	    return false;
+	  }
+
+	  var cdomain = this.cdomain();
+	  if (cdomain) {
+	    if (cdomain.match(/\.$/)) {
+	      return false; // S4.1.2.3 suggests that this is bad. domainMatch() tests confirm this
+	    }
+	    var suffix = pubsuffix.getPublicSuffix(cdomain);
+	    if (suffix == null) { // it's a public suffix
+	      return false;
+	    }
+	  }
+	  return true;
+	};
+
+	Cookie.prototype.setExpires = function setExpires(exp) {
+	  if (exp instanceof Date) {
+	    this.expires = exp;
+	  } else {
+	    this.expires = parseDate(exp) || "Infinity";
+	  }
+	};
+
+	Cookie.prototype.setMaxAge = function setMaxAge(age) {
+	  if (age === Infinity || age === -Infinity) {
+	    this.maxAge = age.toString(); // so JSON.stringify() works
+	  } else {
+	    this.maxAge = age;
+	  }
+	};
+
+	// gives Cookie header format
+	Cookie.prototype.cookieString = function cookieString() {
+	  var val = this.value;
+	  if (val == null) {
+	    val = '';
+	  }
+	  if (this.key === '') {
+	    return val;
+	  }
+	  return this.key+'='+val;
+	};
+
+	// gives Set-Cookie header format
+	Cookie.prototype.toString = function toString() {
+	  var str = this.cookieString();
+
+	  if (this.expires != Infinity) {
+	    if (this.expires instanceof Date) {
+	      str += '; Expires='+formatDate(this.expires);
+	    } else {
+	      str += '; Expires='+this.expires;
+	    }
+	  }
+
+	  if (this.maxAge != null && this.maxAge != Infinity) {
+	    str += '; Max-Age='+this.maxAge;
+	  }
+
+	  if (this.domain && !this.hostOnly) {
+	    str += '; Domain='+this.domain;
+	  }
+	  if (this.path) {
+	    str += '; Path='+this.path;
+	  }
+
+	  if (this.secure) {
+	    str += '; Secure';
+	  }
+	  if (this.httpOnly) {
+	    str += '; HttpOnly';
+	  }
+	  if (this.extensions) {
+	    this.extensions.forEach(function(ext) {
+	      str += '; '+ext;
+	    });
+	  }
+
+	  return str;
+	};
+
+	// TTL() partially replaces the "expiry-time" parts of S5.3 step 3 (setCookie()
+	// elsewhere)
+	// S5.3 says to give the "latest representable date" for which we use Infinity
+	// For "expired" we use 0
+	Cookie.prototype.TTL = function TTL(now) {
+	  /* RFC6265 S4.1.2.2 If a cookie has both the Max-Age and the Expires
+	   * attribute, the Max-Age attribute has precedence and controls the
+	   * expiration date of the cookie.
+	   * (Concurs with S5.3 step 3)
+	   */
+	  if (this.maxAge != null) {
+	    return this.maxAge<=0 ? 0 : this.maxAge*1000;
+	  }
+
+	  var expires = this.expires;
+	  if (expires != Infinity) {
+	    if (!(expires instanceof Date)) {
+	      expires = parseDate(expires) || Infinity;
+	    }
+
+	    if (expires == Infinity) {
+	      return Infinity;
+	    }
+
+	    return expires.getTime() - (now || Date.now());
+	  }
+
+	  return Infinity;
+	};
+
+	// expiryTime() replaces the "expiry-time" parts of S5.3 step 3 (setCookie()
+	// elsewhere)
+	Cookie.prototype.expiryTime = function expiryTime(now) {
+	  if (this.maxAge != null) {
+	    var relativeTo = now || this.creation || new Date();
+	    var age = (this.maxAge <= 0) ? -Infinity : this.maxAge*1000;
+	    return relativeTo.getTime() + age;
+	  }
+
+	  if (this.expires == Infinity) {
+	    return Infinity;
+	  }
+	  return this.expires.getTime();
+	};
+
+	// expiryDate() replaces the "expiry-time" parts of S5.3 step 3 (setCookie()
+	// elsewhere), except it returns a Date
+	Cookie.prototype.expiryDate = function expiryDate(now) {
+	  var millisec = this.expiryTime(now);
+	  if (millisec == Infinity) {
+	    return new Date(MAX_TIME);
+	  } else if (millisec == -Infinity) {
+	    return new Date(MIN_TIME);
+	  } else {
+	    return new Date(millisec);
+	  }
+	};
+
+	// This replaces the "persistent-flag" parts of S5.3 step 3
+	Cookie.prototype.isPersistent = function isPersistent() {
+	  return (this.maxAge != null || this.expires != Infinity);
+	};
+
+	// Mostly S5.1.2 and S5.2.3:
+	Cookie.prototype.cdomain =
+	Cookie.prototype.canonicalizedDomain = function canonicalizedDomain() {
+	  if (this.domain == null) {
+	    return null;
+	  }
+	  return canonicalDomain(this.domain);
+	};
+
+	function CookieJar(store, options) {
+	  if (typeof options === "boolean") {
+	    options = {rejectPublicSuffixes: options};
+	  } else if (options == null) {
+	    options = {};
+	  }
+	  if (options.rejectPublicSuffixes != null) {
+	    this.rejectPublicSuffixes = options.rejectPublicSuffixes;
+	  }
+	  if (options.looseMode != null) {
+	    this.enableLooseMode = options.looseMode;
+	  }
+
+	  if (!store) {
+	    store = new MemoryCookieStore();
+	  }
+	  this.store = store;
+	}
+	CookieJar.prototype.store = null;
+	CookieJar.prototype.rejectPublicSuffixes = true;
+	CookieJar.prototype.enableLooseMode = false;
+	var CAN_BE_SYNC = [];
+
+	CAN_BE_SYNC.push('setCookie');
+	CookieJar.prototype.setCookie = function(cookie, url, options, cb) {
+	  var err;
+	  var context = getCookieContext(url);
+	  if (options instanceof Function) {
+	    cb = options;
+	    options = {};
+	  }
+
+	  var host = canonicalDomain(context.hostname);
+	  var loose = this.enableLooseMode;
+	  if (options.loose != null) {
+	    loose = options.loose;
+	  }
+
+	  // S5.3 step 1
+	  if (!(cookie instanceof Cookie)) {
+	    cookie = Cookie.parse(cookie, { loose: loose });
+	  }
+	  if (!cookie) {
+	    err = new Error("Cookie failed to parse");
+	    return cb(options.ignoreError ? null : err);
+	  }
+
+	  // S5.3 step 2
+	  var now = options.now || new Date(); // will assign later to save effort in the face of errors
+
+	  // S5.3 step 3: NOOP; persistent-flag and expiry-time is handled by getCookie()
+
+	  // S5.3 step 4: NOOP; domain is null by default
+
+	  // S5.3 step 5: public suffixes
+	  if (this.rejectPublicSuffixes && cookie.domain) {
+	    var suffix = pubsuffix.getPublicSuffix(cookie.cdomain());
+	    if (suffix == null) { // e.g. "com"
+	      err = new Error("Cookie has domain set to a public suffix");
+	      return cb(options.ignoreError ? null : err);
+	    }
+	  }
+
+	  // S5.3 step 6:
+	  if (cookie.domain) {
+	    if (!domainMatch(host, cookie.cdomain(), false)) {
+	      err = new Error("Cookie not in this host's domain. Cookie:"+cookie.cdomain()+" Request:"+host);
+	      return cb(options.ignoreError ? null : err);
+	    }
+
+	    if (cookie.hostOnly == null) { // don't reset if already set
+	      cookie.hostOnly = false;
+	    }
+
+	  } else {
+	    cookie.hostOnly = true;
+	    cookie.domain = host;
+	  }
+
+	  //S5.2.4 If the attribute-value is empty or if the first character of the
+	  //attribute-value is not %x2F ("/"):
+	  //Let cookie-path be the default-path.
+	  if (!cookie.path || cookie.path[0] !== '/') {
+	    cookie.path = defaultPath(context.pathname);
+	    cookie.pathIsDefault = true;
+	  }
+
+	  // S5.3 step 8: NOOP; secure attribute
+	  // S5.3 step 9: NOOP; httpOnly attribute
+
+	  // S5.3 step 10
+	  if (options.http === false && cookie.httpOnly) {
+	    err = new Error("Cookie is HttpOnly and this isn't an HTTP API");
+	    return cb(options.ignoreError ? null : err);
+	  }
+
+	  var store = this.store;
+
+	  if (!store.updateCookie) {
+	    store.updateCookie = function(oldCookie, newCookie, cb) {
+	      this.putCookie(newCookie, cb);
+	    };
+	  }
+
+	  function withCookie(err, oldCookie) {
+	    if (err) {
+	      return cb(err);
+	    }
+
+	    var next = function(err) {
+	      if (err) {
+	        return cb(err);
+	      } else {
+	        cb(null, cookie);
+	      }
+	    };
+
+	    if (oldCookie) {
+	      // S5.3 step 11 - "If the cookie store contains a cookie with the same name,
+	      // domain, and path as the newly created cookie:"
+	      if (options.http === false && oldCookie.httpOnly) { // step 11.2
+	        err = new Error("old Cookie is HttpOnly and this isn't an HTTP API");
+	        return cb(options.ignoreError ? null : err);
+	      }
+	      cookie.creation = oldCookie.creation; // step 11.3
+	      cookie.creationIndex = oldCookie.creationIndex; // preserve tie-breaker
+	      cookie.lastAccessed = now;
+	      // Step 11.4 (delete cookie) is implied by just setting the new one:
+	      store.updateCookie(oldCookie, cookie, next); // step 12
+
+	    } else {
+	      cookie.creation = cookie.lastAccessed = now;
+	      store.putCookie(cookie, next); // step 12
+	    }
+	  }
+
+	  store.findCookie(cookie.domain, cookie.path, cookie.key, withCookie);
+	};
+
+	// RFC6365 S5.4
+	CAN_BE_SYNC.push('getCookies');
+	CookieJar.prototype.getCookies = function(url, options, cb) {
+	  var context = getCookieContext(url);
+	  if (options instanceof Function) {
+	    cb = options;
+	    options = {};
+	  }
+
+	  var host = canonicalDomain(context.hostname);
+	  var path = context.pathname || '/';
+
+	  var secure = options.secure;
+	  if (secure == null && context.protocol &&
+	      (context.protocol == 'https:' || context.protocol == 'wss:'))
+	  {
+	    secure = true;
+	  }
+
+	  var http = options.http;
+	  if (http == null) {
+	    http = true;
+	  }
+
+	  var now = options.now || Date.now();
+	  var expireCheck = options.expire !== false;
+	  var allPaths = !!options.allPaths;
+	  var store = this.store;
+
+	  function matchingCookie(c) {
+	    // "Either:
+	    //   The cookie's host-only-flag is true and the canonicalized
+	    //   request-host is identical to the cookie's domain.
+	    // Or:
+	    //   The cookie's host-only-flag is false and the canonicalized
+	    //   request-host domain-matches the cookie's domain."
+	    if (c.hostOnly) {
+	      if (c.domain != host) {
+	        return false;
+	      }
+	    } else {
+	      if (!domainMatch(host, c.domain, false)) {
+	        return false;
+	      }
+	    }
+
+	    // "The request-uri's path path-matches the cookie's path."
+	    if (!allPaths && !pathMatch(path, c.path)) {
+	      return false;
+	    }
+
+	    // "If the cookie's secure-only-flag is true, then the request-uri's
+	    // scheme must denote a "secure" protocol"
+	    if (c.secure && !secure) {
+	      return false;
+	    }
+
+	    // "If the cookie's http-only-flag is true, then exclude the cookie if the
+	    // cookie-string is being generated for a "non-HTTP" API"
+	    if (c.httpOnly && !http) {
+	      return false;
+	    }
+
+	    // deferred from S5.3
+	    // non-RFC: allow retention of expired cookies by choice
+	    if (expireCheck && c.expiryTime() <= now) {
+	      store.removeCookie(c.domain, c.path, c.key, function(){}); // result ignored
+	      return false;
+	    }
+
+	    return true;
+	  }
+
+	  store.findCookies(host, allPaths ? null : path, function(err,cookies) {
+	    if (err) {
+	      return cb(err);
+	    }
+
+	    cookies = cookies.filter(matchingCookie);
+
+	    // sorting of S5.4 part 2
+	    if (options.sort !== false) {
+	      cookies = cookies.sort(cookieCompare);
+	    }
+
+	    // S5.4 part 3
+	    var now = new Date();
+	    cookies.forEach(function(c) {
+	      c.lastAccessed = now;
+	    });
+	    // TODO persist lastAccessed
+
+	    cb(null,cookies);
+	  });
+	};
+
+	CAN_BE_SYNC.push('getCookieString');
+	CookieJar.prototype.getCookieString = function(/*..., cb*/) {
+	  var args = Array.prototype.slice.call(arguments,0);
+	  var cb = args.pop();
+	  var next = function(err,cookies) {
+	    if (err) {
+	      cb(err);
+	    } else {
+	      cb(null, cookies
+	        .sort(cookieCompare)
+	        .map(function(c){
+	          return c.cookieString();
+	        })
+	        .join('; '));
+	    }
+	  };
+	  args.push(next);
+	  this.getCookies.apply(this,args);
+	};
+
+	CAN_BE_SYNC.push('getSetCookieStrings');
+	CookieJar.prototype.getSetCookieStrings = function(/*..., cb*/) {
+	  var args = Array.prototype.slice.call(arguments,0);
+	  var cb = args.pop();
+	  var next = function(err,cookies) {
+	    if (err) {
+	      cb(err);
+	    } else {
+	      cb(null, cookies.map(function(c){
+	        return c.toString();
+	      }));
+	    }
+	  };
+	  args.push(next);
+	  this.getCookies.apply(this,args);
+	};
+
+	CAN_BE_SYNC.push('serialize');
+	CookieJar.prototype.serialize = function(cb) {
+	  var type = this.store.constructor.name;
+	  if (type === 'Object') {
+	    type = null;
+	  }
+
+	  // update README.md "Serialization Format" if you change this, please!
+	  var serialized = {
+	    // The version of tough-cookie that serialized this jar. Generally a good
+	    // practice since future versions can make data import decisions based on
+	    // known past behavior. When/if this matters, use `semver`.
+	    version: 'tough-cookie@'+VERSION,
+
+	    // add the store type, to make humans happy:
+	    storeType: type,
+
+	    // CookieJar configuration:
+	    rejectPublicSuffixes: !!this.rejectPublicSuffixes,
+
+	    // this gets filled from getAllCookies:
+	    cookies: []
+	  };
+
+	  if (!(this.store.getAllCookies &&
+	        typeof this.store.getAllCookies === 'function'))
+	  {
+	    return cb(new Error('store does not support getAllCookies and cannot be serialized'));
+	  }
+
+	  this.store.getAllCookies(function(err,cookies) {
+	    if (err) {
+	      return cb(err);
+	    }
+
+	    serialized.cookies = cookies.map(function(cookie) {
+	      // convert to serialized 'raw' cookies
+	      cookie = (cookie instanceof Cookie) ? cookie.toJSON() : cookie;
+
+	      // Remove the index so new ones get assigned during deserialization
+	      delete cookie.creationIndex;
+
+	      return cookie;
+	    });
+
+	    return cb(null, serialized);
+	  });
+	};
+
+	// well-known name that JSON.stringify calls
+	CookieJar.prototype.toJSON = function() {
+	  return this.serializeSync();
+	};
+
+	// use the class method CookieJar.deserialize instead of calling this directly
+	CAN_BE_SYNC.push('_importCookies');
+	CookieJar.prototype._importCookies = function(serialized, cb) {
+	  var jar = this;
+	  var cookies = serialized.cookies;
+	  if (!cookies || !Array.isArray(cookies)) {
+	    return cb(new Error('serialized jar has no cookies array'));
+	  }
+	  cookies = cookies.slice(); // do not modify the original
+
+	  function putNext(err) {
+	    if (err) {
+	      return cb(err);
+	    }
+
+	    if (!cookies.length) {
+	      return cb(err, jar);
+	    }
+
+	    var cookie;
+	    try {
+	      cookie = fromJSON(cookies.shift());
+	    } catch (e) {
+	      return cb(e);
+	    }
+
+	    if (cookie === null) {
+	      return putNext(null); // skip this cookie
+	    }
+
+	    jar.store.putCookie(cookie, putNext);
+	  }
+
+	  putNext();
+	};
+
+	CookieJar.deserialize = function(strOrObj, store, cb) {
+	  if (arguments.length !== 3) {
+	    // store is optional
+	    cb = store;
+	    store = null;
+	  }
+
+	  var serialized;
+	  if (typeof strOrObj === 'string') {
+	    serialized = jsonParse(strOrObj);
+	    if (serialized instanceof Error) {
+	      return cb(serialized);
+	    }
+	  } else {
+	    serialized = strOrObj;
+	  }
+
+	  var jar = new CookieJar(store, serialized.rejectPublicSuffixes);
+	  jar._importCookies(serialized, function(err) {
+	    if (err) {
+	      return cb(err);
+	    }
+	    cb(null, jar);
+	  });
+	};
+
+	CookieJar.deserializeSync = function(strOrObj, store) {
+	  var serialized = typeof strOrObj === 'string' ?
+	    JSON.parse(strOrObj) : strOrObj;
+	  var jar = new CookieJar(store, serialized.rejectPublicSuffixes);
+
+	  // catch this mistake early:
+	  if (!jar.store.synchronous) {
+	    throw new Error('CookieJar store is not synchronous; use async API instead.');
+	  }
+
+	  jar._importCookiesSync(serialized);
+	  return jar;
+	};
+	CookieJar.fromJSON = CookieJar.deserializeSync;
+
+	CAN_BE_SYNC.push('clone');
+	CookieJar.prototype.clone = function(newStore, cb) {
+	  if (arguments.length === 1) {
+	    cb = newStore;
+	    newStore = null;
+	  }
+
+	  this.serialize(function(err,serialized) {
+	    if (err) {
+	      return cb(err);
+	    }
+	    CookieJar.deserialize(newStore, serialized, cb);
+	  });
+	};
+
+	// Use a closure to provide a true imperative API for synchronous stores.
+	function syncWrap(method) {
+	  return function() {
+	    if (!this.store.synchronous) {
+	      throw new Error('CookieJar store is not synchronous; use async API instead.');
+	    }
+
+	    var args = Array.prototype.slice.call(arguments);
+	    var syncErr, syncResult;
+	    args.push(function syncCb(err, result) {
+	      syncErr = err;
+	      syncResult = result;
+	    });
+	    this[method].apply(this, args);
+
+	    if (syncErr) {
+	      throw syncErr;
+	    }
+	    return syncResult;
+	  };
+	}
+
+	// wrap all declared CAN_BE_SYNC methods in the sync wrapper
+	CAN_BE_SYNC.forEach(function(method) {
+	  CookieJar.prototype[method+'Sync'] = syncWrap(method);
+	});
+
+	exports.CookieJar = CookieJar;
+	exports.Cookie = Cookie;
+	exports.Store = Store;
+	exports.MemoryCookieStore = MemoryCookieStore;
+	exports.parseDate = parseDate;
+	exports.formatDate = formatDate;
+	exports.parse = parse;
+	exports.fromJSON = fromJSON;
+	exports.domainMatch = domainMatch;
+	exports.defaultPath = defaultPath;
+	exports.pathMatch = pathMatch;
+	exports.getPublicSuffix = pubsuffix.getPublicSuffix;
+	exports.cookieCompare = cookieCompare;
+	exports.permuteDomain = __webpack_require__(19).permuteDomain;
+	exports.permutePath = permutePath;
+	exports.canonicalDomain = canonicalDomain;
+
+
+/***/ }),
+/* 1 */
+/***/ (function(module, exports) {
+
+	/*
+	* Tests if a given ip or host string is a valid IPv4 or IPv6 address.
+	* Regex found at: https://stackoverflow.com/questions/9208814/validate-ipv4-ipv6-and-hostname
+	*/
+
+	var patternIPv4 = /^\s*((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\s*$/g;
+	var patternIPv6 = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/g;
+
+	function isIPv4(hostOrIp) {
+	  return hostOrIp.match(patternIPv4) ? true : false;
+	}
+
+	function isIPv6(hostOrIp) {
+	  return hostOrIp.match(patternIPv6) ? true : false;
+	}
+
+	function isIP(hostOrIp) {
+	  if (isIPv4(hostOrIp)) {
+	    return 4;
+	  }
+
+	  if (isIPv6(hostOrIp)) {
+	    return 6;
+	  }
+
+	  return 0;
+	}
+
+	module.exports = {
+	  isIPv4: isIPv4,
+	  isIPv6: isIPv6,
+	  isIP: isIP
+	};
+
+
+/***/ }),
+/* 2 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	// Copyright Joyent, Inc. and other Node contributors.
+	//
+	// Permission is hereby granted, free of charge, to any person obtaining a
+	// copy of this software and associated documentation files (the
+	// "Software"), to deal in the Software without restriction, including
+	// without limitation the rights to use, copy, modify, merge, publish,
+	// distribute, sublicense, and/or sell copies of the Software, and to permit
+	// persons to whom the Software is furnished to do so, subject to the
+	// following conditions:
+	//
+	// The above copyright notice and this permission notice shall be included
+	// in all copies or substantial portions of the Software.
+	//
+	// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+	// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+	// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+	// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+	// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+	// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+	// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+	'use strict';
+
+	var punycode = __webpack_require__(3);
+	var util = __webpack_require__(5);
+
+	exports.parse = urlParse;
+	exports.resolve = urlResolve;
+	exports.resolveObject = urlResolveObject;
+	exports.format = urlFormat;
+
+	exports.Url = Url;
+
+	function Url() {
+	  this.protocol = null;
+	  this.slashes = null;
+	  this.auth = null;
+	  this.host = null;
+	  this.port = null;
+	  this.hostname = null;
+	  this.hash = null;
+	  this.search = null;
+	  this.query = null;
+	  this.pathname = null;
+	  this.path = null;
+	  this.href = null;
+	}
+
+	// Reference: RFC 3986, RFC 1808, RFC 2396
+
+	// define these here so at least they only have to be
+	// compiled once on the first module load.
+	var protocolPattern = /^([a-z0-9.+-]+:)/i,
+	    portPattern = /:[0-9]*$/,
+
+	    // Special case for a simple path URL
+	    simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,
+
+	    // RFC 2396: characters reserved for delimiting URLs.
+	    // We actually just auto-escape these.
+	    delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'],
+
+	    // RFC 2396: characters not allowed for various reasons.
+	    unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims),
+
+	    // Allowed by RFCs, but cause of XSS attacks.  Always escape these.
+	    autoEscape = ['\''].concat(unwise),
+	    // Characters that are never ever allowed in a hostname.
+	    // Note that any invalid chars are also handled, but these
+	    // are the ones that are *expected* to be seen, so we fast-path
+	    // them.
+	    nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape),
+	    hostEndingChars = ['/', '?', '#'],
+	    hostnameMaxLen = 255,
+	    hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/,
+	    hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/,
+	    // protocols that can allow "unsafe" and "unwise" chars.
+	    unsafeProtocol = {
+	      'javascript': true,
+	      'javascript:': true
+	    },
+	    // protocols that never have a hostname.
+	    hostlessProtocol = {
+	      'javascript': true,
+	      'javascript:': true
+	    },
+	    // protocols that always contain a // bit.
+	    slashedProtocol = {
+	      'http': true,
+	      'https': true,
+	      'ftp': true,
+	      'gopher': true,
+	      'file': true,
+	      'http:': true,
+	      'https:': true,
+	      'ftp:': true,
+	      'gopher:': true,
+	      'file:': true
+	    },
+	    querystring = __webpack_require__(6);
+
+	function urlParse(url, parseQueryString, slashesDenoteHost) {
+	  if (url && util.isObject(url) && url instanceof Url) return url;
+
+	  var u = new Url;
+	  u.parse(url, parseQueryString, slashesDenoteHost);
+	  return u;
+	}
+
+	Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
+	  if (!util.isString(url)) {
+	    throw new TypeError("Parameter 'url' must be a string, not " + typeof url);
+	  }
+
+	  // Copy chrome, IE, opera backslash-handling behavior.
+	  // Back slashes before the query string get converted to forward slashes
+	  // See: https://code.google.com/p/chromium/issues/detail?id=25916
+	  var queryIndex = url.indexOf('?'),
+	      splitter =
+	          (queryIndex !== -1 && queryIndex < url.indexOf('#')) ? '?' : '#',
+	      uSplit = url.split(splitter),
+	      slashRegex = /\\/g;
+	  uSplit[0] = uSplit[0].replace(slashRegex, '/');
+	  url = uSplit.join(splitter);
+
+	  var rest = url;
+
+	  // trim before proceeding.
+	  // This is to support parse stuff like "  http://foo.com  \n"
+	  rest = rest.trim();
+
+	  if (!slashesDenoteHost && url.split('#').length === 1) {
+	    // Try fast path regexp
+	    var simplePath = simplePathPattern.exec(rest);
+	    if (simplePath) {
+	      this.path = rest;
+	      this.href = rest;
+	      this.pathname = simplePath[1];
+	      if (simplePath[2]) {
+	        this.search = simplePath[2];
+	        if (parseQueryString) {
+	          this.query = querystring.parse(this.search.substr(1));
+	        } else {
+	          this.query = this.search.substr(1);
+	        }
+	      } else if (parseQueryString) {
+	        this.search = '';
+	        this.query = {};
+	      }
+	      return this;
+	    }
+	  }
+
+	  var proto = protocolPattern.exec(rest);
+	  if (proto) {
+	    proto = proto[0];
+	    var lowerProto = proto.toLowerCase();
+	    this.protocol = lowerProto;
+	    rest = rest.substr(proto.length);
+	  }
+
+	  // figure out if it's got a host
+	  // user@server is *always* interpreted as a hostname, and url
+	  // resolution will treat //foo/bar as host=foo,path=bar because that's
+	  // how the browser resolves relative URLs.
+	  if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) {
+	    var slashes = rest.substr(0, 2) === '//';
+	    if (slashes && !(proto && hostlessProtocol[proto])) {
+	      rest = rest.substr(2);
+	      this.slashes = true;
+	    }
+	  }
+
+	  if (!hostlessProtocol[proto] &&
+	      (slashes || (proto && !slashedProtocol[proto]))) {
+
+	    // there's a hostname.
+	    // the first instance of /, ?, ;, or # ends the host.
+	    //
+	    // If there is an @ in the hostname, then non-host chars *are* allowed
+	    // to the left of the last @ sign, unless some host-ending character
+	    // comes *before* the @-sign.
+	    // URLs are obnoxious.
+	    //
+	    // ex:
+	    // http://a@b@c/ => user:a@b host:c
+	    // http://a@b?@c => user:a host:c path:/?@c
+
+	    // v0.12 TODO(isaacs): This is not quite how Chrome does things.
+	    // Review our test case against browsers more comprehensively.
+
+	    // find the first instance of any hostEndingChars
+	    var hostEnd = -1;
+	    for (var i = 0; i < hostEndingChars.length; i++) {
+	      var hec = rest.indexOf(hostEndingChars[i]);
+	      if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))
+	        hostEnd = hec;
+	    }
+
+	    // at this point, either we have an explicit point where the
+	    // auth portion cannot go past, or the last @ char is the decider.
+	    var auth, atSign;
+	    if (hostEnd === -1) {
+	      // atSign can be anywhere.
+	      atSign = rest.lastIndexOf('@');
+	    } else {
+	      // atSign must be in auth portion.
+	      // http://a@b/c@d => host:b auth:a path:/c@d
+	      atSign = rest.lastIndexOf('@', hostEnd);
+	    }
+
+	    // Now we have a portion which is definitely the auth.
+	    // Pull that off.
+	    if (atSign !== -1) {
+	      auth = rest.slice(0, atSign);
+	      rest = rest.slice(atSign + 1);
+	      this.auth = decodeURIComponent(auth);
+	    }
+
+	    // the host is the remaining to the left of the first non-host char
+	    hostEnd = -1;
+	    for (var i = 0; i < nonHostChars.length; i++) {
+	      var hec = rest.indexOf(nonHostChars[i]);
+	      if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))
+	        hostEnd = hec;
+	    }
+	    // if we still have not hit it, then the entire thing is a host.
+	    if (hostEnd === -1)
+	      hostEnd = rest.length;
+
+	    this.host = rest.slice(0, hostEnd);
+	    rest = rest.slice(hostEnd);
+
+	    // pull out port.
+	    this.parseHost();
+
+	    // we've indicated that there is a hostname,
+	    // so even if it's empty, it has to be present.
+	    this.hostname = this.hostname || '';
+
+	    // if hostname begins with [ and ends with ]
+	    // assume that it's an IPv6 address.
+	    var ipv6Hostname = this.hostname[0] === '[' &&
+	        this.hostname[this.hostname.length - 1] === ']';
+
+	    // validate a little.
+	    if (!ipv6Hostname) {
+	      var hostparts = this.hostname.split(/\./);
+	      for (var i = 0, l = hostparts.length; i < l; i++) {
+	        var part = hostparts[i];
+	        if (!part) continue;
+	        if (!part.match(hostnamePartPattern)) {
+	          var newpart = '';
+	          for (var j = 0, k = part.length; j < k; j++) {
+	            if (part.charCodeAt(j) > 127) {
+	              // we replace non-ASCII char with a temporary placeholder
+	              // we need this to make sure size of hostname is not
+	              // broken by replacing non-ASCII by nothing
+	              newpart += 'x';
+	            } else {
+	              newpart += part[j];
+	            }
+	          }
+	          // we test again with ASCII char only
+	          if (!newpart.match(hostnamePartPattern)) {
+	            var validParts = hostparts.slice(0, i);
+	            var notHost = hostparts.slice(i + 1);
+	            var bit = part.match(hostnamePartStart);
+	            if (bit) {
+	              validParts.push(bit[1]);
+	              notHost.unshift(bit[2]);
+	            }
+	            if (notHost.length) {
+	              rest = '/' + notHost.join('.') + rest;
+	            }
+	            this.hostname = validParts.join('.');
+	            break;
+	          }
+	        }
+	      }
+	    }
+
+	    if (this.hostname.length > hostnameMaxLen) {
+	      this.hostname = '';
+	    } else {
+	      // hostnames are always lower case.
+	      this.hostname = this.hostname.toLowerCase();
+	    }
+
+	    if (!ipv6Hostname) {
+	      // IDNA Support: Returns a punycoded representation of "domain".
+	      // It only converts parts of the domain name that
+	      // have non-ASCII characters, i.e. it doesn't matter if
+	      // you call it with a domain that already is ASCII-only.
+	      this.hostname = punycode.toASCII(this.hostname);
+	    }
+
+	    var p = this.port ? ':' + this.port : '';
+	    var h = this.hostname || '';
+	    this.host = h + p;
+	    this.href += this.host;
+
+	    // strip [ and ] from the hostname
+	    // the host field still retains them, though
+	    if (ipv6Hostname) {
+	      this.hostname = this.hostname.substr(1, this.hostname.length - 2);
+	      if (rest[0] !== '/') {
+	        rest = '/' + rest;
+	      }
+	    }
+	  }
+
+	  // now rest is set to the post-host stuff.
+	  // chop off any delim chars.
+	  if (!unsafeProtocol[lowerProto]) {
+
+	    // First, make 100% sure that any "autoEscape" chars get
+	    // escaped, even if encodeURIComponent doesn't think they
+	    // need to be.
+	    for (var i = 0, l = autoEscape.length; i < l; i++) {
+	      var ae = autoEscape[i];
+	      if (rest.indexOf(ae) === -1)
+	        continue;
+	      var esc = encodeURIComponent(ae);
+	      if (esc === ae) {
+	        esc = escape(ae);
+	      }
+	      rest = rest.split(ae).join(esc);
+	    }
+	  }
+
+
+	  // chop off from the tail first.
+	  var hash = rest.indexOf('#');
+	  if (hash !== -1) {
+	    // got a fragment string.
+	    this.hash = rest.substr(hash);
+	    rest = rest.slice(0, hash);
+	  }
+	  var qm = rest.indexOf('?');
+	  if (qm !== -1) {
+	    this.search = rest.substr(qm);
+	    this.query = rest.substr(qm + 1);
+	    if (parseQueryString) {
+	      this.query = querystring.parse(this.query);
+	    }
+	    rest = rest.slice(0, qm);
+	  } else if (parseQueryString) {
+	    // no query string, but parseQueryString still requested
+	    this.search = '';
+	    this.query = {};
+	  }
+	  if (rest) this.pathname = rest;
+	  if (slashedProtocol[lowerProto] &&
+	      this.hostname && !this.pathname) {
+	    this.pathname = '/';
+	  }
+
+	  //to support http.request
+	  if (this.pathname || this.search) {
+	    var p = this.pathname || '';
+	    var s = this.search || '';
+	    this.path = p + s;
+	  }
+
+	  // finally, reconstruct the href based on what has been validated.
+	  this.href = this.format();
+	  return this;
+	};
+
+	// format a parsed object into a url string
+	function urlFormat(obj) {
+	  // ensure it's an object, and not a string url.
+	  // If it's an obj, this is a no-op.
+	  // this way, you can call url_format() on strings
+	  // to clean up potentially wonky urls.
+	  if (util.isString(obj)) obj = urlParse(obj);
+	  if (!(obj instanceof Url)) return Url.prototype.format.call(obj);
+	  return obj.format();
+	}
+
+	Url.prototype.format = function() {
+	  var auth = this.auth || '';
+	  if (auth) {
+	    auth = encodeURIComponent(auth);
+	    auth = auth.replace(/%3A/i, ':');
+	    auth += '@';
+	  }
+
+	  var protocol = this.protocol || '',
+	      pathname = this.pathname || '',
+	      hash = this.hash || '',
+	      host = false,
+	      query = '';
+
+	  if (this.host) {
+	    host = auth + this.host;
+	  } else if (this.hostname) {
+	    host = auth + (this.hostname.indexOf(':') === -1 ?
+	        this.hostname :
+	        '[' + this.hostname + ']');
+	    if (this.port) {
+	      host += ':' + this.port;
+	    }
+	  }
+
+	  if (this.query &&
+	      util.isObject(this.query) &&
+	      Object.keys(this.query).length) {
+	    query = querystring.stringify(this.query);
+	  }
+
+	  var search = this.search || (query && ('?' + query)) || '';
+
+	  if (protocol && protocol.substr(-1) !== ':') protocol += ':';
+
+	  // only the slashedProtocols get the //.  Not mailto:, xmpp:, etc.
+	  // unless they had them to begin with.
+	  if (this.slashes ||
+	      (!protocol || slashedProtocol[protocol]) && host !== false) {
+	    host = '//' + (host || '');
+	    if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname;
+	  } else if (!host) {
+	    host = '';
+	  }
+
+	  if (hash && hash.charAt(0) !== '#') hash = '#' + hash;
+	  if (search && search.charAt(0) !== '?') search = '?' + search;
+
+	  pathname = pathname.replace(/[?#]/g, function(match) {
+	    return encodeURIComponent(match);
+	  });
+	  search = search.replace('#', '%23');
+
+	  return protocol + host + pathname + search + hash;
+	};
+
+	function urlResolve(source, relative) {
+	  return urlParse(source, false, true).resolve(relative);
+	}
+
+	Url.prototype.resolve = function(relative) {
+	  return this.resolveObject(urlParse(relative, false, true)).format();
+	};
+
+	function urlResolveObject(source, relative) {
+	  if (!source) return relative;
+	  return urlParse(source, false, true).resolveObject(relative);
+	}
+
+	Url.prototype.resolveObject = function(relative) {
+	  if (util.isString(relative)) {
+	    var rel = new Url();
+	    rel.parse(relative, false, true);
+	    relative = rel;
+	  }
+
+	  var result = new Url();
+	  var tkeys = Object.keys(this);
+	  for (var tk = 0; tk < tkeys.length; tk++) {
+	    var tkey = tkeys[tk];
+	    result[tkey] = this[tkey];
+	  }
+
+	  // hash is always overridden, no matter what.
+	  // even href="" will remove it.
+	  result.hash = relative.hash;
+
+	  // if the relative url is empty, then there's nothing left to do here.
+	  if (relative.href === '') {
+	    result.href = result.format();
+	    return result;
+	  }
+
+	  // hrefs like //foo/bar always cut to the protocol.
+	  if (relative.slashes && !relative.protocol) {
+	    // take everything except the protocol from relative
+	    var rkeys = Object.keys(relative);
+	    for (var rk = 0; rk < rkeys.length; rk++) {
+	      var rkey = rkeys[rk];
+	      if (rkey !== 'protocol')
+	        result[rkey] = relative[rkey];
+	    }
+
+	    //urlParse appends trailing / to urls like http://www.example.com
+	    if (slashedProtocol[result.protocol] &&
+	        result.hostname && !result.pathname) {
+	      result.path = result.pathname = '/';
+	    }
+
+	    result.href = result.format();
+	    return result;
+	  }
+
+	  if (relative.protocol && relative.protocol !== result.protocol) {
+	    // if it's a known url protocol, then changing
+	    // the protocol does weird things
+	    // first, if it's not file:, then we MUST have a host,
+	    // and if there was a path
+	    // to begin with, then we MUST have a path.
+	    // if it is file:, then the host is dropped,
+	    // because that's known to be hostless.
+	    // anything else is assumed to be absolute.
+	    if (!slashedProtocol[relative.protocol]) {
+	      var keys = Object.keys(relative);
+	      for (var v = 0; v < keys.length; v++) {
+	        var k = keys[v];
+	        result[k] = relative[k];
+	      }
+	      result.href = result.format();
+	      return result;
+	    }
+
+	    result.protocol = relative.protocol;
+	    if (!relative.host && !hostlessProtocol[relative.protocol]) {
+	      var relPath = (relative.pathname || '').split('/');
+	      while (relPath.length && !(relative.host = relPath.shift()));
+	      if (!relative.host) relative.host = '';
+	      if (!relative.hostname) relative.hostname = '';
+	      if (relPath[0] !== '') relPath.unshift('');
+	      if (relPath.length < 2) relPath.unshift('');
+	      result.pathname = relPath.join('/');
+	    } else {
+	      result.pathname = relative.pathname;
+	    }
+	    result.search = relative.search;
+	    result.query = relative.query;
+	    result.host = relative.host || '';
+	    result.auth = relative.auth;
+	    result.hostname = relative.hostname || relative.host;
+	    result.port = relative.port;
+	    // to support http.request
+	    if (result.pathname || result.search) {
+	      var p = result.pathname || '';
+	      var s = result.search || '';
+	      result.path = p + s;
+	    }
+	    result.slashes = result.slashes || relative.slashes;
+	    result.href = result.format();
+	    return result;
+	  }
+
+	  var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'),
+	      isRelAbs = (
+	          relative.host ||
+	          relative.pathname && relative.pathname.charAt(0) === '/'
+	      ),
+	      mustEndAbs = (isRelAbs || isSourceAbs ||
+	                    (result.host && relative.pathname)),
+	      removeAllDots = mustEndAbs,
+	      srcPath = result.pathname && result.pathname.split('/') || [],
+	      relPath = relative.pathname && relative.pathname.split('/') || [],
+	      psychotic = result.protocol && !slashedProtocol[result.protocol];
+
+	  // if the url is a non-slashed url, then relative
+	  // links like ../.. should be able
+	  // to crawl up to the hostname, as well.  This is strange.
+	  // result.protocol has already been set by now.
+	  // Later on, put the first path part into the host field.
+	  if (psychotic) {
+	    result.hostname = '';
+	    result.port = null;
+	    if (result.host) {
+	      if (srcPath[0] === '') srcPath[0] = result.host;
+	      else srcPath.unshift(result.host);
+	    }
+	    result.host = '';
+	    if (relative.protocol) {
+	      relative.hostname = null;
+	      relative.port = null;
+	      if (relative.host) {
+	        if (relPath[0] === '') relPath[0] = relative.host;
+	        else relPath.unshift(relative.host);
+	      }
+	      relative.host = null;
+	    }
+	    mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === '');
+	  }
+
+	  if (isRelAbs) {
+	    // it's absolute.
+	    result.host = (relative.host || relative.host === '') ?
+	                  relative.host : result.host;
+	    result.hostname = (relative.hostname || relative.hostname === '') ?
+	                      relative.hostname : result.hostname;
+	    result.search = relative.search;
+	    result.query = relative.query;
+	    srcPath = relPath;
+	    // fall through to the dot-handling below.
+	  } else if (relPath.length) {
+	    // it's relative
+	    // throw away the existing file, and take the new path instead.
+	    if (!srcPath) srcPath = [];
+	    srcPath.pop();
+	    srcPath = srcPath.concat(relPath);
+	    result.search = relative.search;
+	    result.query = relative.query;
+	  } else if (!util.isNullOrUndefined(relative.search)) {
+	    // just pull out the search.
+	    // like href='?foo'.
+	    // Put this after the other two cases because it simplifies the booleans
+	    if (psychotic) {
+	      result.hostname = result.host = srcPath.shift();
+	      //occationaly the auth can get stuck only in host
+	      //this especially happens in cases like
+	      //url.resolveObject('mailto:local1@domain1', 'local2@domain2')
+	      var authInHost = result.host && result.host.indexOf('@') > 0 ?
+	                       result.host.split('@') : false;
+	      if (authInHost) {
+	        result.auth = authInHost.shift();
+	        result.host = result.hostname = authInHost.shift();
+	      }
+	    }
+	    result.search = relative.search;
+	    result.query = relative.query;
+	    //to support http.request
+	    if (!util.isNull(result.pathname) || !util.isNull(result.search)) {
+	      result.path = (result.pathname ? result.pathname : '') +
+	                    (result.search ? result.search : '');
+	    }
+	    result.href = result.format();
+	    return result;
+	  }
+
+	  if (!srcPath.length) {
+	    // no path at all.  easy.
+	    // we've already handled the other stuff above.
+	    result.pathname = null;
+	    //to support http.request
+	    if (result.search) {
+	      result.path = '/' + result.search;
+	    } else {
+	      result.path = null;
+	    }
+	    result.href = result.format();
+	    return result;
+	  }
+
+	  // if a url ENDs in . or .., then it must get a trailing slash.
+	  // however, if it ends in anything else non-slashy,
+	  // then it must NOT get a trailing slash.
+	  var last = srcPath.slice(-1)[0];
+	  var hasTrailingSlash = (
+	      (result.host || relative.host || srcPath.length > 1) &&
+	      (last === '.' || last === '..') || last === '');
+
+	  // strip single dots, resolve double dots to parent dir
+	  // if the path tries to go above the root, `up` ends up > 0
+	  var up = 0;
+	  for (var i = srcPath.length; i >= 0; i--) {
+	    last = srcPath[i];
+	    if (last === '.') {
+	      srcPath.splice(i, 1);
+	    } else if (last === '..') {
+	      srcPath.splice(i, 1);
+	      up++;
+	    } else if (up) {
+	      srcPath.splice(i, 1);
+	      up--;
+	    }
+	  }
+
+	  // if the path is allowed to go above the root, restore leading ..s
+	  if (!mustEndAbs && !removeAllDots) {
+	    for (; up--; up) {
+	      srcPath.unshift('..');
+	    }
+	  }
+
+	  if (mustEndAbs && srcPath[0] !== '' &&
+	      (!srcPath[0] || srcPath[0].charAt(0) !== '/')) {
+	    srcPath.unshift('');
+	  }
+
+	  if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) {
+	    srcPath.push('');
+	  }
+
+	  var isAbsolute = srcPath[0] === '' ||
+	      (srcPath[0] && srcPath[0].charAt(0) === '/');
+
+	  // put the host back
+	  if (psychotic) {
+	    result.hostname = result.host = isAbsolute ? '' :
+	                                    srcPath.length ? srcPath.shift() : '';
+	    //occationaly the auth can get stuck only in host
+	    //this especially happens in cases like
+	    //url.resolveObject('mailto:local1@domain1', 'local2@domain2')
+	    var authInHost = result.host && result.host.indexOf('@') > 0 ?
+	                     result.host.split('@') : false;
+	    if (authInHost) {
+	      result.auth = authInHost.shift();
+	      result.host = result.hostname = authInHost.shift();
+	    }
+	  }
+
+	  mustEndAbs = mustEndAbs || (result.host && srcPath.length);
+
+	  if (mustEndAbs && !isAbsolute) {
+	    srcPath.unshift('');
+	  }
+
+	  if (!srcPath.length) {
+	    result.pathname = null;
+	    result.path = null;
+	  } else {
+	    result.pathname = srcPath.join('/');
+	  }
+
+	  //to support request.http
+	  if (!util.isNull(result.pathname) || !util.isNull(result.search)) {
+	    result.path = (result.pathname ? result.pathname : '') +
+	                  (result.search ? result.search : '');
+	  }
+	  result.auth = relative.auth || result.auth;
+	  result.slashes = result.slashes || relative.slashes;
+	  result.href = result.format();
+	  return result;
+	};
+
+	Url.prototype.parseHost = function() {
+	  var host = this.host;
+	  var port = portPattern.exec(host);
+	  if (port) {
+	    port = port[0];
+	    if (port !== ':') {
+	      this.port = port.substr(1);
+	    }
+	    host = host.substr(0, host.length - port.length);
+	  }
+	  if (host) this.hostname = host;
+	};
+
+
+/***/ }),
+/* 3 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(module, global) {/*! https://mths.be/punycode v1.3.2 by @mathias */
+	;(function(root) {
+
+		/** Detect free variables */
+		var freeExports = typeof exports == 'object' && exports &&
+			!exports.nodeType && exports;
+		var freeModule = typeof module == 'object' && module &&
+			!module.nodeType && module;
+		var freeGlobal = typeof global == 'object' && global;
+		if (
+			freeGlobal.global === freeGlobal ||
+			freeGlobal.window === freeGlobal ||
+			freeGlobal.self === freeGlobal
+		) {
+			root = freeGlobal;
+		}
+
+		/**
+		 * The `punycode` object.
+		 * @name punycode
+		 * @type Object
+		 */
+		var punycode,
+
+		/** Highest positive signed 32-bit float value */
+		maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
+
+		/** Bootstring parameters */
+		base = 36,
+		tMin = 1,
+		tMax = 26,
+		skew = 38,
+		damp = 700,
+		initialBias = 72,
+		initialN = 128, // 0x80
+		delimiter = '-', // '\x2D'
+
+		/** Regular expressions */
+		regexPunycode = /^xn--/,
+		regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
+		regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators
+
+		/** Error messages */
+		errors = {
+			'overflow': 'Overflow: input needs wider integers to process',
+			'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
+			'invalid-input': 'Invalid input'
+		},
+
+		/** Convenience shortcuts */
+		baseMinusTMin = base - tMin,
+		floor = Math.floor,
+		stringFromCharCode = String.fromCharCode,
+
+		/** Temporary variable */
+		key;
+
+		/*--------------------------------------------------------------------------*/
+
+		/**
+		 * A generic error utility function.
+		 * @private
+		 * @param {String} type The error type.
+		 * @returns {Error} Throws a `RangeError` with the applicable error message.
+		 */
+		function error(type) {
+			throw RangeError(errors[type]);
+		}
+
+		/**
+		 * A generic `Array#map` utility function.
+		 * @private
+		 * @param {Array} array The array to iterate over.
+		 * @param {Function} callback The function that gets called for every array
+		 * item.
+		 * @returns {Array} A new array of values returned by the callback function.
+		 */
+		function map(array, fn) {
+			var length = array.length;
+			var result = [];
+			while (length--) {
+				result[length] = fn(array[length]);
+			}
+			return result;
+		}
+
+		/**
+		 * A simple `Array#map`-like wrapper to work with domain name strings or email
+		 * addresses.
+		 * @private
+		 * @param {String} domain The domain name or email address.
+		 * @param {Function} callback The function that gets called for every
+		 * character.
+		 * @returns {Array} A new string of characters returned by the callback
+		 * function.
+		 */
+		function mapDomain(string, fn) {
+			var parts = string.split('@');
+			var result = '';
+			if (parts.length > 1) {
+				// In email addresses, only the domain name should be punycoded. Leave
+				// the local part (i.e. everything up to `@`) intact.
+				result = parts[0] + '@';
+				string = parts[1];
+			}
+			// Avoid `split(regex)` for IE8 compatibility. See #17.
+			string = string.replace(regexSeparators, '\x2E');
+			var labels = string.split('.');
+			var encoded = map(labels, fn).join('.');
+			return result + encoded;
+		}
+
+		/**
+		 * Creates an array containing the numeric code points of each Unicode
+		 * character in the string. While JavaScript uses UCS-2 internally,
+		 * this function will convert a pair of surrogate halves (each of which
+		 * UCS-2 exposes as separate characters) into a single code point,
+		 * matching UTF-16.
+		 * @see `punycode.ucs2.encode`
+		 * @see <https://mathiasbynens.be/notes/javascript-encoding>
+		 * @memberOf punycode.ucs2
+		 * @name decode
+		 * @param {String} string The Unicode input string (UCS-2).
+		 * @returns {Array} The new array of code points.
+		 */
+		function ucs2decode(string) {
+			var output = [],
+			    counter = 0,
+			    length = string.length,
+			    value,
+			    extra;
+			while (counter < length) {
+				value = string.charCodeAt(counter++);
+				if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
+					// high surrogate, and there is a next character
+					extra = string.charCodeAt(counter++);
+					if ((extra & 0xFC00) == 0xDC00) { // low surrogate
+						output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+					} else {
+						// unmatched surrogate; only append this code unit, in case the next
+						// code unit is the high surrogate of a surrogate pair
+						output.push(value);
+						counter--;
+					}
+				} else {
+					output.push(value);
+				}
+			}
+			return output;
+		}
+
+		/**
+		 * Creates a string based on an array of numeric code points.
+		 * @see `punycode.ucs2.decode`
+		 * @memberOf punycode.ucs2
+		 * @name encode
+		 * @param {Array} codePoints The array of numeric code points.
+		 * @returns {String} The new Unicode string (UCS-2).
+		 */
+		function ucs2encode(array) {
+			return map(array, function(value) {
+				var output = '';
+				if (value > 0xFFFF) {
+					value -= 0x10000;
+					output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
+					value = 0xDC00 | value & 0x3FF;
+				}
+				output += stringFromCharCode(value);
+				return output;
+			}).join('');
+		}
+
+		/**
+		 * Converts a basic code point into a digit/integer.
+		 * @see `digitToBasic()`
+		 * @private
+		 * @param {Number} codePoint The basic numeric code point value.
+		 * @returns {Number} The numeric value of a basic code point (for use in
+		 * representing integers) in the range `0` to `base - 1`, or `base` if
+		 * the code point does not represent a value.
+		 */
+		function basicToDigit(codePoint) {
+			if (codePoint - 48 < 10) {
+				return codePoint - 22;
+			}
+			if (codePoint - 65 < 26) {
+				return codePoint - 65;
+			}
+			if (codePoint - 97 < 26) {
+				return codePoint - 97;
+			}
+			return base;
+		}
+
+		/**
+		 * Converts a digit/integer into a basic code point.
+		 * @see `basicToDigit()`
+		 * @private
+		 * @param {Number} digit The numeric value of a basic code point.
+		 * @returns {Number} The basic code point whose value (when used for
+		 * representing integers) is `digit`, which needs to be in the range
+		 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
+		 * used; else, the lowercase form is used. The behavior is undefined
+		 * if `flag` is non-zero and `digit` has no uppercase form.
+		 */
+		function digitToBasic(digit, flag) {
+			//  0..25 map to ASCII a..z or A..Z
+			// 26..35 map to ASCII 0..9
+			return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
+		}
+
+		/**
+		 * Bias adaptation function as per section 3.4 of RFC 3492.
+		 * http://tools.ietf.org/html/rfc3492#section-3.4
+		 * @private
+		 */
+		function adapt(delta, numPoints, firstTime) {
+			var k = 0;
+			delta = firstTime ? floor(delta / damp) : delta >> 1;
+			delta += floor(delta / numPoints);
+			for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
+				delta = floor(delta / baseMinusTMin);
+			}
+			return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
+		}
+
+		/**
+		 * Converts a Punycode string of ASCII-only symbols to a string of Unicode
+		 * symbols.
+		 * @memberOf punycode
+		 * @param {String} input The Punycode string of ASCII-only symbols.
+		 * @returns {String} The resulting string of Unicode symbols.
+		 */
+		function decode(input) {
+			// Don't use UCS-2
+			var output = [],
+			    inputLength = input.length,
+			    out,
+			    i = 0,
+			    n = initialN,
+			    bias = initialBias,
+			    basic,
+			    j,
+			    index,
+			    oldi,
+			    w,
+			    k,
+			    digit,
+			    t,
+			    /** Cached calculation results */
+			    baseMinusT;
+
+			// Handle the basic code points: let `basic` be the number of input code
+			// points before the last delimiter, or `0` if there is none, then copy
+			// the first basic code points to the output.
+
+			basic = input.lastIndexOf(delimiter);
+			if (basic < 0) {
+				basic = 0;
+			}
+
+			for (j = 0; j < basic; ++j) {
+				// if it's not a basic code point
+				if (input.charCodeAt(j) >= 0x80) {
+					error('not-basic');
+				}
+				output.push(input.charCodeAt(j));
+			}
+
+			// Main decoding loop: start just after the last delimiter if any basic code
+			// points were copied; start at the beginning otherwise.
+
+			for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
+
+				// `index` is the index of the next character to be consumed.
+				// Decode a generalized variable-length integer into `delta`,
+				// which gets added to `i`. The overflow checking is easier
+				// if we increase `i` as we go, then subtract off its starting
+				// value at the end to obtain `delta`.
+				for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
+
+					if (index >= inputLength) {
+						error('invalid-input');
+					}
+
+					digit = basicToDigit(input.charCodeAt(index++));
+
+					if (digit >= base || digit > floor((maxInt - i) / w)) {
+						error('overflow');
+					}
+
+					i += digit * w;
+					t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+
+					if (digit < t) {
+						break;
+					}
+
+					baseMinusT = base - t;
+					if (w > floor(maxInt / baseMinusT)) {
+						error('overflow');
+					}
+
+					w *= baseMinusT;
+
+				}
+
+				out = output.length + 1;
+				bias = adapt(i - oldi, out, oldi == 0);
+
+				// `i` was supposed to wrap around from `out` to `0`,
+				// incrementing `n` each time, so we'll fix that now:
+				if (floor(i / out) > maxInt - n) {
+					error('overflow');
+				}
+
+				n += floor(i / out);
+				i %= out;
+
+				// Insert `n` at position `i` of the output
+				output.splice(i++, 0, n);
+
+			}
+
+			return ucs2encode(output);
+		}
+
+		/**
+		 * Converts a string of Unicode symbols (e.g. a domain name label) to a
+		 * Punycode string of ASCII-only symbols.
+		 * @memberOf punycode
+		 * @param {String} input The string of Unicode symbols.
+		 * @returns {String} The resulting Punycode string of ASCII-only symbols.
+		 */
+		function encode(input) {
+			var n,
+			    delta,
+			    handledCPCount,
+			    basicLength,
+			    bias,
+			    j,
+			    m,
+			    q,
+			    k,
+			    t,
+			    currentValue,
+			    output = [],
+			    /** `inputLength` will hold the number of code points in `input`. */
+			    inputLength,
+			    /** Cached calculation results */
+			    handledCPCountPlusOne,
+			    baseMinusT,
+			    qMinusT;
+
+			// Convert the input in UCS-2 to Unicode
+			input = ucs2decode(input);
+
+			// Cache the length
+			inputLength = input.length;
+
+			// Initialize the state
+			n = initialN;
+			delta = 0;
+			bias = initialBias;
+
+			// Handle the basic code points
+			for (j = 0; j < inputLength; ++j) {
+				currentValue = input[j];
+				if (currentValue < 0x80) {
+					output.push(stringFromCharCode(currentValue));
+				}
+			}
+
+			handledCPCount = basicLength = output.length;
+
+			// `handledCPCount` is the number of code points that have been handled;
+			// `basicLength` is the number of basic code points.
+
+			// Finish the basic string - if it is not empty - with a delimiter
+			if (basicLength) {
+				output.push(delimiter);
+			}
+
+			// Main encoding loop:
+			while (handledCPCount < inputLength) {
+
+				// All non-basic code points < n have been handled already. Find the next
+				// larger one:
+				for (m = maxInt, j = 0; j < inputLength; ++j) {
+					currentValue = input[j];
+					if (currentValue >= n && currentValue < m) {
+						m = currentValue;
+					}
+				}
+
+				// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
+				// but guard against overflow
+				handledCPCountPlusOne = handledCPCount + 1;
+				if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
+					error('overflow');
+				}
+
+				delta += (m - n) * handledCPCountPlusOne;
+				n = m;
+
+				for (j = 0; j < inputLength; ++j) {
+					currentValue = input[j];
+
+					if (currentValue < n && ++delta > maxInt) {
+						error('overflow');
+					}
+
+					if (currentValue == n) {
+						// Represent delta as a generalized variable-length integer
+						for (q = delta, k = base; /* no condition */; k += base) {
+							t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+							if (q < t) {
+								break;
+							}
+							qMinusT = q - t;
+							baseMinusT = base - t;
+							output.push(
+								stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
+							);
+							q = floor(qMinusT / baseMinusT);
+						}
+
+						output.push(stringFromCharCode(digitToBasic(q, 0)));
+						bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
+						delta = 0;
+						++handledCPCount;
+					}
+				}
+
+				++delta;
+				++n;
+
+			}
+			return output.join('');
+		}
+
+		/**
+		 * Converts a Punycode string representing a domain name or an email address
+		 * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
+		 * it doesn't matter if you call it on a string that has already been
+		 * converted to Unicode.
+		 * @memberOf punycode
+		 * @param {String} input The Punycoded domain name or email address to
+		 * convert to Unicode.
+		 * @returns {String} The Unicode representation of the given Punycode
+		 * string.
+		 */
+		function toUnicode(input) {
+			return mapDomain(input, function(string) {
+				return regexPunycode.test(string)
+					? decode(string.slice(4).toLowerCase())
+					: string;
+			});
+		}
+
+		/**
+		 * Converts a Unicode string representing a domain name or an email address to
+		 * Punycode. Only the non-ASCII parts of the domain name will be converted,
+		 * i.e. it doesn't matter if you call it with a domain that's already in
+		 * ASCII.
+		 * @memberOf punycode
+		 * @param {String} input The domain name or email address to convert, as a
+		 * Unicode string.
+		 * @returns {String} The Punycode representation of the given domain name or
+		 * email address.
+		 */
+		function toASCII(input) {
+			return mapDomain(input, function(string) {
+				return regexNonASCII.test(string)
+					? 'xn--' + encode(string)
+					: string;
+			});
+		}
+
+		/*--------------------------------------------------------------------------*/
+
+		/** Define the public API */
+		punycode = {
+			/**
+			 * A string representing the current Punycode.js version number.
+			 * @memberOf punycode
+			 * @type String
+			 */
+			'version': '1.3.2',
+			/**
+			 * An object of methods to convert from JavaScript's internal character
+			 * representation (UCS-2) to Unicode code points, and back.
+			 * @see <https://mathiasbynens.be/notes/javascript-encoding>
+			 * @memberOf punycode
+			 * @type Object
+			 */
+			'ucs2': {
+				'decode': ucs2decode,
+				'encode': ucs2encode
+			},
+			'decode': decode,
+			'encode': encode,
+			'toASCII': toASCII,
+			'toUnicode': toUnicode
+		};
+
+		/** Expose `punycode` */
+		// Some AMD build optimizers, like r.js, check for specific condition patterns
+		// like the following:
+		if (
+			true
+		) {
+			!(__WEBPACK_AMD_DEFINE_RESULT__ = function() {
+				return punycode;
+			}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+		} else if (freeExports && freeModule) {
+			if (module.exports == freeExports) { // in Node.js or RingoJS v0.8.0+
+				freeModule.exports = punycode;
+			} else { // in Narwhal or RingoJS v0.7.0-
+				for (key in punycode) {
+					punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
+				}
+			}
+		} else { // in Rhino or a web browser
+			root.punycode = punycode;
+		}
+
+	}(this));
+
+	/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)(module), (function() { return this; }())))
+
+/***/ }),
+/* 4 */
+/***/ (function(module, exports) {
+
+	module.exports = function(module) {

+		if(!module.webpackPolyfill) {

+			module.deprecate = function() {};

+			module.paths = [];

+			// module.parent = undefined by default

+			module.children = [];

+			module.webpackPolyfill = 1;

+		}

+		return module;

+	}

+
+
+/***/ }),
+/* 5 */
+/***/ (function(module, exports) {
+
+	'use strict';
+
+	module.exports = {
+	  isString: function(arg) {
+	    return typeof(arg) === 'string';
+	  },
+	  isObject: function(arg) {
+	    return typeof(arg) === 'object' && arg !== null;
+	  },
+	  isNull: function(arg) {
+	    return arg === null;
+	  },
+	  isNullOrUndefined: function(arg) {
+	    return arg == null;
+	  }
+	};
+
+
+/***/ }),
+/* 6 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	exports.decode = exports.parse = __webpack_require__(7);
+	exports.encode = exports.stringify = __webpack_require__(8);
+
+
+/***/ }),
+/* 7 */
+/***/ (function(module, exports) {
+
+	// Copyright Joyent, Inc. and other Node contributors.
+	//
+	// Permission is hereby granted, free of charge, to any person obtaining a
+	// copy of this software and associated documentation files (the
+	// "Software"), to deal in the Software without restriction, including
+	// without limitation the rights to use, copy, modify, merge, publish,
+	// distribute, sublicense, and/or sell copies of the Software, and to permit
+	// persons to whom the Software is furnished to do so, subject to the
+	// following conditions:
+	//
+	// The above copyright notice and this permission notice shall be included
+	// in all copies or substantial portions of the Software.
+	//
+	// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+	// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+	// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+	// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+	// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+	// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+	// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+	'use strict';
+
+	// If obj.hasOwnProperty has been overridden, then calling
+	// obj.hasOwnProperty(prop) will break.
+	// See: https://github.com/joyent/node/issues/1707
+	function hasOwnProperty(obj, prop) {
+	  return Object.prototype.hasOwnProperty.call(obj, prop);
+	}
+
+	module.exports = function(qs, sep, eq, options) {
+	  sep = sep || '&';
+	  eq = eq || '=';
+	  var obj = {};
+
+	  if (typeof qs !== 'string' || qs.length === 0) {
+	    return obj;
+	  }
+
+	  var regexp = /\+/g;
+	  qs = qs.split(sep);
+
+	  var maxKeys = 1000;
+	  if (options && typeof options.maxKeys === 'number') {
+	    maxKeys = options.maxKeys;
+	  }
+
+	  var len = qs.length;
+	  // maxKeys <= 0 means that we should not limit keys count
+	  if (maxKeys > 0 && len > maxKeys) {
+	    len = maxKeys;
+	  }
+
+	  for (var i = 0; i < len; ++i) {
+	    var x = qs[i].replace(regexp, '%20'),
+	        idx = x.indexOf(eq),
+	        kstr, vstr, k, v;
+
+	    if (idx >= 0) {
+	      kstr = x.substr(0, idx);
+	      vstr = x.substr(idx + 1);
+	    } else {
+	      kstr = x;
+	      vstr = '';
+	    }
+
+	    k = decodeURIComponent(kstr);
+	    v = decodeURIComponent(vstr);
+
+	    if (!hasOwnProperty(obj, k)) {
+	      obj[k] = v;
+	    } else if (Array.isArray(obj[k])) {
+	      obj[k].push(v);
+	    } else {
+	      obj[k] = [obj[k], v];
+	    }
+	  }
+
+	  return obj;
+	};
+
+
+/***/ }),
+/* 8 */
+/***/ (function(module, exports) {
+
+	// Copyright Joyent, Inc. and other Node contributors.
+	//
+	// Permission is hereby granted, free of charge, to any person obtaining a
+	// copy of this software and associated documentation files (the
+	// "Software"), to deal in the Software without restriction, including
+	// without limitation the rights to use, copy, modify, merge, publish,
+	// distribute, sublicense, and/or sell copies of the Software, and to permit
+	// persons to whom the Software is furnished to do so, subject to the
+	// following conditions:
+	//
+	// The above copyright notice and this permission notice shall be included
+	// in all copies or substantial portions of the Software.
+	//
+	// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+	// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+	// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+	// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+	// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+	// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+	// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+	'use strict';
+
+	var stringifyPrimitive = function(v) {
+	  switch (typeof v) {
+	    case 'string':
+	      return v;
+
+	    case 'boolean':
+	      return v ? 'true' : 'false';
+
+	    case 'number':
+	      return isFinite(v) ? v : '';
+
+	    default:
+	      return '';
+	  }
+	};
+
+	module.exports = function(obj, sep, eq, name) {
+	  sep = sep || '&';
+	  eq = eq || '=';
+	  if (obj === null) {
+	    obj = undefined;
+	  }
+
+	  if (typeof obj === 'object') {
+	    return Object.keys(obj).map(function(k) {
+	      var ks = encodeURIComponent(stringifyPrimitive(k)) + eq;
+	      if (Array.isArray(obj[k])) {
+	        return obj[k].map(function(v) {
+	          return ks + encodeURIComponent(stringifyPrimitive(v));
+	        }).join(sep);
+	      } else {
+	        return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
+	      }
+	    }).join(sep);
+
+	  }
+
+	  if (!name) return '';
+	  return encodeURIComponent(stringifyPrimitive(name)) + eq +
+	         encodeURIComponent(stringifyPrimitive(obj));
+	};
+
+
+/***/ }),
+/* 9 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/* WEBPACK VAR INJECTION */(function(global, process) {// Copyright Joyent, Inc. and other Node contributors.
+	//
+	// Permission is hereby granted, free of charge, to any person obtaining a
+	// copy of this software and associated documentation files (the
+	// "Software"), to deal in the Software without restriction, including
+	// without limitation the rights to use, copy, modify, merge, publish,
+	// distribute, sublicense, and/or sell copies of the Software, and to permit
+	// persons to whom the Software is furnished to do so, subject to the
+	// following conditions:
+	//
+	// The above copyright notice and this permission notice shall be included
+	// in all copies or substantial portions of the Software.
+	//
+	// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+	// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+	// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+	// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+	// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+	// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+	// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+	var formatRegExp = /%[sdj%]/g;
+	exports.format = function(f) {
+	  if (!isString(f)) {
+	    var objects = [];
+	    for (var i = 0; i < arguments.length; i++) {
+	      objects.push(inspect(arguments[i]));
+	    }
+	    return objects.join(' ');
+	  }
+
+	  var i = 1;
+	  var args = arguments;
+	  var len = args.length;
+	  var str = String(f).replace(formatRegExp, function(x) {
+	    if (x === '%%') return '%';
+	    if (i >= len) return x;
+	    switch (x) {
+	      case '%s': return String(args[i++]);
+	      case '%d': return Number(args[i++]);
+	      case '%j':
+	        try {
+	          return JSON.stringify(args[i++]);
+	        } catch (_) {
+	          return '[Circular]';
+	        }
+	      default:
+	        return x;
+	    }
+	  });
+	  for (var x = args[i]; i < len; x = args[++i]) {
+	    if (isNull(x) || !isObject(x)) {
+	      str += ' ' + x;
+	    } else {
+	      str += ' ' + inspect(x);
+	    }
+	  }
+	  return str;
+	};
+
+
+	// Mark that a method should not be used.
+	// Returns a modified function which warns once by default.
+	// If --no-deprecation is set, then it is a no-op.
+	exports.deprecate = function(fn, msg) {
+	  // Allow for deprecating things in the process of starting up.
+	  if (isUndefined(global.process)) {
+	    return function() {
+	      return exports.deprecate(fn, msg).apply(this, arguments);
+	    };
+	  }
+
+	  if (process.noDeprecation === true) {
+	    return fn;
+	  }
+
+	  var warned = false;
+	  function deprecated() {
+	    if (!warned) {
+	      if (process.throwDeprecation) {
+	        throw new Error(msg);
+	      } else if (process.traceDeprecation) {
+	        console.trace(msg);
+	      } else {
+	        console.error(msg);
+	      }
+	      warned = true;
+	    }
+	    return fn.apply(this, arguments);
+	  }
+
+	  return deprecated;
+	};
+
+
+	var debugs = {};
+	var debugEnviron;
+	exports.debuglog = function(set) {
+	  if (isUndefined(debugEnviron))
+	    debugEnviron = process.env.NODE_DEBUG || '';
+	  set = set.toUpperCase();
+	  if (!debugs[set]) {
+	    if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
+	      var pid = process.pid;
+	      debugs[set] = function() {
+	        var msg = exports.format.apply(exports, arguments);
+	        console.error('%s %d: %s', set, pid, msg);
+	      };
+	    } else {
+	      debugs[set] = function() {};
+	    }
+	  }
+	  return debugs[set];
+	};
+
+
+	/**
+	 * Echos the value of a value. Trys to print the value out
+	 * in the best way possible given the different types.
+	 *
+	 * @param {Object} obj The object to print out.
+	 * @param {Object} opts Optional options object that alters the output.
+	 */
+	/* legacy: obj, showHidden, depth, colors*/
+	function inspect(obj, opts) {
+	  // default options
+	  var ctx = {
+	    seen: [],
+	    stylize: stylizeNoColor
+	  };
+	  // legacy...
+	  if (arguments.length >= 3) ctx.depth = arguments[2];
+	  if (arguments.length >= 4) ctx.colors = arguments[3];
+	  if (isBoolean(opts)) {
+	    // legacy...
+	    ctx.showHidden = opts;
+	  } else if (opts) {
+	    // got an "options" object
+	    exports._extend(ctx, opts);
+	  }
+	  // set default options
+	  if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
+	  if (isUndefined(ctx.depth)) ctx.depth = 2;
+	  if (isUndefined(ctx.colors)) ctx.colors = false;
+	  if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
+	  if (ctx.colors) ctx.stylize = stylizeWithColor;
+	  return formatValue(ctx, obj, ctx.depth);
+	}
+	exports.inspect = inspect;
+
+
+	// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
+	inspect.colors = {
+	  'bold' : [1, 22],
+	  'italic' : [3, 23],
+	  'underline' : [4, 24],
+	  'inverse' : [7, 27],
+	  'white' : [37, 39],
+	  'grey' : [90, 39],
+	  'black' : [30, 39],
+	  'blue' : [34, 39],
+	  'cyan' : [36, 39],
+	  'green' : [32, 39],
+	  'magenta' : [35, 39],
+	  'red' : [31, 39],
+	  'yellow' : [33, 39]
+	};
+
+	// Don't use 'blue' not visible on cmd.exe
+	inspect.styles = {
+	  'special': 'cyan',
+	  'number': 'yellow',
+	  'boolean': 'yellow',
+	  'undefined': 'grey',
+	  'null': 'bold',
+	  'string': 'green',
+	  'date': 'magenta',
+	  // "name": intentionally not styling
+	  'regexp': 'red'
+	};
+
+
+	function stylizeWithColor(str, styleType) {
+	  var style = inspect.styles[styleType];
+
+	  if (style) {
+	    return '\u001b[' + inspect.colors[style][0] + 'm' + str +
+	           '\u001b[' + inspect.colors[style][1] + 'm';
+	  } else {
+	    return str;
+	  }
+	}
+
+
+	function stylizeNoColor(str, styleType) {
+	  return str;
+	}
+
+
+	function arrayToHash(array) {
+	  var hash = {};
+
+	  array.forEach(function(val, idx) {
+	    hash[val] = true;
+	  });
+
+	  return hash;
+	}
+
+
+	function formatValue(ctx, value, recurseTimes) {
+	  // Provide a hook for user-specified inspect functions.
+	  // Check that value is an object with an inspect function on it
+	  if (ctx.customInspect &&
+	      value &&
+	      isFunction(value.inspect) &&
+	      // Filter out the util module, it's inspect function is special
+	      value.inspect !== exports.inspect &&
+	      // Also filter out any prototype objects using the circular check.
+	      !(value.constructor && value.constructor.prototype === value)) {
+	    var ret = value.inspect(recurseTimes, ctx);
+	    if (!isString(ret)) {
+	      ret = formatValue(ctx, ret, recurseTimes);
+	    }
+	    return ret;
+	  }
+
+	  // Primitive types cannot have properties
+	  var primitive = formatPrimitive(ctx, value);
+	  if (primitive) {
+	    return primitive;
+	  }
+
+	  // Look up the keys of the object.
+	  var keys = Object.keys(value);
+	  var visibleKeys = arrayToHash(keys);
+
+	  if (ctx.showHidden) {
+	    keys = Object.getOwnPropertyNames(value);
+	  }
+
+	  // IE doesn't make error fields non-enumerable
+	  // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
+	  if (isError(value)
+	      && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
+	    return formatError(value);
+	  }
+
+	  // Some type of object without properties can be shortcutted.
+	  if (keys.length === 0) {
+	    if (isFunction(value)) {
+	      var name = value.name ? ': ' + value.name : '';
+	      return ctx.stylize('[Function' + name + ']', 'special');
+	    }
+	    if (isRegExp(value)) {
+	      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
+	    }
+	    if (isDate(value)) {
+	      return ctx.stylize(Date.prototype.toString.call(value), 'date');
+	    }
+	    if (isError(value)) {
+	      return formatError(value);
+	    }
+	  }
+
+	  var base = '', array = false, braces = ['{', '}'];
+
+	  // Make Array say that they are Array
+	  if (isArray(value)) {
+	    array = true;
+	    braces = ['[', ']'];
+	  }
+
+	  // Make functions say that they are functions
+	  if (isFunction(value)) {
+	    var n = value.name ? ': ' + value.name : '';
+	    base = ' [Function' + n + ']';
+	  }
+
+	  // Make RegExps say that they are RegExps
+	  if (isRegExp(value)) {
+	    base = ' ' + RegExp.prototype.toString.call(value);
+	  }
+
+	  // Make dates with properties first say the date
+	  if (isDate(value)) {
+	    base = ' ' + Date.prototype.toUTCString.call(value);
+	  }
+
+	  // Make error with message first say the error
+	  if (isError(value)) {
+	    base = ' ' + formatError(value);
+	  }
+
+	  if (keys.length === 0 && (!array || value.length == 0)) {
+	    return braces[0] + base + braces[1];
+	  }
+
+	  if (recurseTimes < 0) {
+	    if (isRegExp(value)) {
+	      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
+	    } else {
+	      return ctx.stylize('[Object]', 'special');
+	    }
+	  }
+
+	  ctx.seen.push(value);
+
+	  var output;
+	  if (array) {
+	    output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
+	  } else {
+	    output = keys.map(function(key) {
+	      return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
+	    });
+	  }
+
+	  ctx.seen.pop();
+
+	  return reduceToSingleString(output, base, braces);
+	}
+
+
+	function formatPrimitive(ctx, value) {
+	  if (isUndefined(value))
+	    return ctx.stylize('undefined', 'undefined');
+	  if (isString(value)) {
+	    var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
+	                                             .replace(/'/g, "\\'")
+	                                             .replace(/\\"/g, '"') + '\'';
+	    return ctx.stylize(simple, 'string');
+	  }
+	  if (isNumber(value))
+	    return ctx.stylize('' + value, 'number');
+	  if (isBoolean(value))
+	    return ctx.stylize('' + value, 'boolean');
+	  // For some reason typeof null is "object", so special case here.
+	  if (isNull(value))
+	    return ctx.stylize('null', 'null');
+	}
+
+
+	function formatError(value) {
+	  return '[' + Error.prototype.toString.call(value) + ']';
+	}
+
+
+	function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
+	  var output = [];
+	  for (var i = 0, l = value.length; i < l; ++i) {
+	    if (hasOwnProperty(value, String(i))) {
+	      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
+	          String(i), true));
+	    } else {
+	      output.push('');
+	    }
+	  }
+	  keys.forEach(function(key) {
+	    if (!key.match(/^\d+$/)) {
+	      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
+	          key, true));
+	    }
+	  });
+	  return output;
+	}
+
+
+	function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
+	  var name, str, desc;
+	  desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
+	  if (desc.get) {
+	    if (desc.set) {
+	      str = ctx.stylize('[Getter/Setter]', 'special');
+	    } else {
+	      str = ctx.stylize('[Getter]', 'special');
+	    }
+	  } else {
+	    if (desc.set) {
+	      str = ctx.stylize('[Setter]', 'special');
+	    }
+	  }
+	  if (!hasOwnProperty(visibleKeys, key)) {
+	    name = '[' + key + ']';
+	  }
+	  if (!str) {
+	    if (ctx.seen.indexOf(desc.value) < 0) {
+	      if (isNull(recurseTimes)) {
+	        str = formatValue(ctx, desc.value, null);
+	      } else {
+	        str = formatValue(ctx, desc.value, recurseTimes - 1);
+	      }
+	      if (str.indexOf('\n') > -1) {
+	        if (array) {
+	          str = str.split('\n').map(function(line) {
+	            return '  ' + line;
+	          }).join('\n').substr(2);
+	        } else {
+	          str = '\n' + str.split('\n').map(function(line) {
+	            return '   ' + line;
+	          }).join('\n');
+	        }
+	      }
+	    } else {
+	      str = ctx.stylize('[Circular]', 'special');
+	    }
+	  }
+	  if (isUndefined(name)) {
+	    if (array && key.match(/^\d+$/)) {
+	      return str;
+	    }
+	    name = JSON.stringify('' + key);
+	    if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
+	      name = name.substr(1, name.length - 2);
+	      name = ctx.stylize(name, 'name');
+	    } else {
+	      name = name.replace(/'/g, "\\'")
+	                 .replace(/\\"/g, '"')
+	                 .replace(/(^"|"$)/g, "'");
+	      name = ctx.stylize(name, 'string');
+	    }
+	  }
+
+	  return name + ': ' + str;
+	}
+
+
+	function reduceToSingleString(output, base, braces) {
+	  var numLinesEst = 0;
+	  var length = output.reduce(function(prev, cur) {
+	    numLinesEst++;
+	    if (cur.indexOf('\n') >= 0) numLinesEst++;
+	    return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
+	  }, 0);
+
+	  if (length > 60) {
+	    return braces[0] +
+	           (base === '' ? '' : base + '\n ') +
+	           ' ' +
+	           output.join(',\n  ') +
+	           ' ' +
+	           braces[1];
+	  }
+
+	  return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
+	}
+
+
+	// NOTE: These type checking functions intentionally don't use `instanceof`
+	// because it is fragile and can be easily faked with `Object.create()`.
+	function isArray(ar) {
+	  return Array.isArray(ar);
+	}
+	exports.isArray = isArray;
+
+	function isBoolean(arg) {
+	  return typeof arg === 'boolean';
+	}
+	exports.isBoolean = isBoolean;
+
+	function isNull(arg) {
+	  return arg === null;
+	}
+	exports.isNull = isNull;
+
+	function isNullOrUndefined(arg) {
+	  return arg == null;
+	}
+	exports.isNullOrUndefined = isNullOrUndefined;
+
+	function isNumber(arg) {
+	  return typeof arg === 'number';
+	}
+	exports.isNumber = isNumber;
+
+	function isString(arg) {
+	  return typeof arg === 'string';
+	}
+	exports.isString = isString;
+
+	function isSymbol(arg) {
+	  return typeof arg === 'symbol';
+	}
+	exports.isSymbol = isSymbol;
+
+	function isUndefined(arg) {
+	  return arg === void 0;
+	}
+	exports.isUndefined = isUndefined;
+
+	function isRegExp(re) {
+	  return isObject(re) && objectToString(re) === '[object RegExp]';
+	}
+	exports.isRegExp = isRegExp;
+
+	function isObject(arg) {
+	  return typeof arg === 'object' && arg !== null;
+	}
+	exports.isObject = isObject;
+
+	function isDate(d) {
+	  return isObject(d) && objectToString(d) === '[object Date]';
+	}
+	exports.isDate = isDate;
+
+	function isError(e) {
+	  return isObject(e) &&
+	      (objectToString(e) === '[object Error]' || e instanceof Error);
+	}
+	exports.isError = isError;
+
+	function isFunction(arg) {
+	  return typeof arg === 'function';
+	}
+	exports.isFunction = isFunction;
+
+	function isPrimitive(arg) {
+	  return arg === null ||
+	         typeof arg === 'boolean' ||
+	         typeof arg === 'number' ||
+	         typeof arg === 'string' ||
+	         typeof arg === 'symbol' ||  // ES6 symbol
+	         typeof arg === 'undefined';
+	}
+	exports.isPrimitive = isPrimitive;
+
+	exports.isBuffer = __webpack_require__(11);
+
+	function objectToString(o) {
+	  return Object.prototype.toString.call(o);
+	}
+
+
+	function pad(n) {
+	  return n < 10 ? '0' + n.toString(10) : n.toString(10);
+	}
+
+
+	var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
+	              'Oct', 'Nov', 'Dec'];
+
+	// 26 Feb 16:19:34
+	function timestamp() {
+	  var d = new Date();
+	  var time = [pad(d.getHours()),
+	              pad(d.getMinutes()),
+	              pad(d.getSeconds())].join(':');
+	  return [d.getDate(), months[d.getMonth()], time].join(' ');
+	}
+
+
+	// log is just a thin wrapper to console.log that prepends a timestamp
+	exports.log = function() {
+	  console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
+	};
+
+
+	/**
+	 * Inherit the prototype methods from one constructor into another.
+	 *
+	 * The Function.prototype.inherits from lang.js rewritten as a standalone
+	 * function (not on Function.prototype). NOTE: If this file is to be loaded
+	 * during bootstrapping this function needs to be rewritten using some native
+	 * functions as prototype setup using normal JavaScript does not work as
+	 * expected during bootstrapping (see mirror.js in r114903).
+	 *
+	 * @param {function} ctor Constructor function which needs to inherit the
+	 *     prototype.
+	 * @param {function} superCtor Constructor function to inherit prototype from.
+	 */
+	exports.inherits = __webpack_require__(12);
+
+	exports._extend = function(origin, add) {
+	  // Don't do anything if add isn't an object
+	  if (!add || !isObject(add)) return origin;
+
+	  var keys = Object.keys(add);
+	  var i = keys.length;
+	  while (i--) {
+	    origin[keys[i]] = add[keys[i]];
+	  }
+	  return origin;
+	};
+
+	function hasOwnProperty(obj, prop) {
+	  return Object.prototype.hasOwnProperty.call(obj, prop);
+	}
+
+	/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(10)))
+
+/***/ }),
+/* 10 */
+/***/ (function(module, exports) {
+
+	// shim for using process in browser
+	var process = module.exports = {};
+
+	// cached from whatever global is present so that test runners that stub it
+	// don't break things.  But we need to wrap it in a try catch in case it is
+	// wrapped in strict mode code which doesn't define any globals.  It's inside a
+	// function because try/catches deoptimize in certain engines.
+
+	var cachedSetTimeout;
+	var cachedClearTimeout;
+
+	function defaultSetTimout() {
+	    throw new Error('setTimeout has not been defined');
+	}
+	function defaultClearTimeout () {
+	    throw new Error('clearTimeout has not been defined');
+	}
+	(function () {
+	    try {
+	        if (typeof setTimeout === 'function') {
+	            cachedSetTimeout = setTimeout;
+	        } else {
+	            cachedSetTimeout = defaultSetTimout;
+	        }
+	    } catch (e) {
+	        cachedSetTimeout = defaultSetTimout;
+	    }
+	    try {
+	        if (typeof clearTimeout === 'function') {
+	            cachedClearTimeout = clearTimeout;
+	        } else {
+	            cachedClearTimeout = defaultClearTimeout;
+	        }
+	    } catch (e) {
+	        cachedClearTimeout = defaultClearTimeout;
+	    }
+	} ())
+	function runTimeout(fun) {
+	    if (cachedSetTimeout === setTimeout) {
+	        //normal enviroments in sane situations
+	        return setTimeout(fun, 0);
+	    }
+	    // if setTimeout wasn't available but was latter defined
+	    if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
+	        cachedSetTimeout = setTimeout;
+	        return setTimeout(fun, 0);
+	    }
+	    try {
+	        // when when somebody has screwed with setTimeout but no I.E. maddness
+	        return cachedSetTimeout(fun, 0);
+	    } catch(e){
+	        try {
+	            // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
+	            return cachedSetTimeout.call(null, fun, 0);
+	        } catch(e){
+	            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
+	            return cachedSetTimeout.call(this, fun, 0);
+	        }
+	    }
+
+
+	}
+	function runClearTimeout(marker) {
+	    if (cachedClearTimeout === clearTimeout) {
+	        //normal enviroments in sane situations
+	        return clearTimeout(marker);
+	    }
+	    // if clearTimeout wasn't available but was latter defined
+	    if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
+	        cachedClearTimeout = clearTimeout;
+	        return clearTimeout(marker);
+	    }
+	    try {
+	        // when when somebody has screwed with setTimeout but no I.E. maddness
+	        return cachedClearTimeout(marker);
+	    } catch (e){
+	        try {
+	            // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
+	            return cachedClearTimeout.call(null, marker);
+	        } catch (e){
+	            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
+	            // Some versions of I.E. have different rules for clearTimeout vs setTimeout
+	            return cachedClearTimeout.call(this, marker);
+	        }
+	    }
+
+
+
+	}
+	var queue = [];
+	var draining = false;
+	var currentQueue;
+	var queueIndex = -1;
+
+	function cleanUpNextTick() {
+	    if (!draining || !currentQueue) {
+	        return;
+	    }
+	    draining = false;
+	    if (currentQueue.length) {
+	        queue = currentQueue.concat(queue);
+	    } else {
+	        queueIndex = -1;
+	    }
+	    if (queue.length) {
+	        drainQueue();
+	    }
+	}
+
+	function drainQueue() {
+	    if (draining) {
+	        return;
+	    }
+	    var timeout = runTimeout(cleanUpNextTick);
+	    draining = true;
+
+	    var len = queue.length;
+	    while(len) {
+	        currentQueue = queue;
+	        queue = [];
+	        while (++queueIndex < len) {
+	            if (currentQueue) {
+	                currentQueue[queueIndex].run();
+	            }
+	        }
+	        queueIndex = -1;
+	        len = queue.length;
+	    }
+	    currentQueue = null;
+	    draining = false;
+	    runClearTimeout(timeout);
+	}
+
+	process.nextTick = function (fun) {
+	    var args = new Array(arguments.length - 1);
+	    if (arguments.length > 1) {
+	        for (var i = 1; i < arguments.length; i++) {
+	            args[i - 1] = arguments[i];
+	        }
+	    }
+	    queue.push(new Item(fun, args));
+	    if (queue.length === 1 && !draining) {
+	        runTimeout(drainQueue);
+	    }
+	};
+
+	// v8 likes predictible objects
+	function Item(fun, array) {
+	    this.fun = fun;
+	    this.array = array;
+	}
+	Item.prototype.run = function () {
+	    this.fun.apply(null, this.array);
+	};
+	process.title = 'browser';
+	process.browser = true;
+	process.env = {};
+	process.argv = [];
+	process.version = ''; // empty string to avoid regexp issues
+	process.versions = {};
+
+	function noop() {}
+
+	process.on = noop;
+	process.addListener = noop;
+	process.once = noop;
+	process.off = noop;
+	process.removeListener = noop;
+	process.removeAllListeners = noop;
+	process.emit = noop;
+	process.prependListener = noop;
+	process.prependOnceListener = noop;
+
+	process.listeners = function (name) { return [] }
+
+	process.binding = function (name) {
+	    throw new Error('process.binding is not supported');
+	};
+
+	process.cwd = function () { return '/' };
+	process.chdir = function (dir) {
+	    throw new Error('process.chdir is not supported');
+	};
+	process.umask = function() { return 0; };
+
+
+/***/ }),
+/* 11 */
+/***/ (function(module, exports) {
+
+	module.exports = function isBuffer(arg) {
+	  return arg && typeof arg === 'object'
+	    && typeof arg.copy === 'function'
+	    && typeof arg.fill === 'function'
+	    && typeof arg.readUInt8 === 'function';
+	}
+
+/***/ }),
+/* 12 */
+/***/ (function(module, exports) {
+
+	if (typeof Object.create === 'function') {
+	  // implementation from standard node.js 'util' module
+	  module.exports = function inherits(ctor, superCtor) {
+	    ctor.super_ = superCtor
+	    ctor.prototype = Object.create(superCtor.prototype, {
+	      constructor: {
+	        value: ctor,
+	        enumerable: false,
+	        writable: true,
+	        configurable: true
+	      }
+	    });
+	  };
+	} else {
+	  // old school shim for old browsers
+	  module.exports = function inherits(ctor, superCtor) {
+	    ctor.super_ = superCtor
+	    var TempCtor = function () {}
+	    TempCtor.prototype = superCtor.prototype
+	    ctor.prototype = new TempCtor()
+	    ctor.prototype.constructor = ctor
+	  }
+	}
+
+
+/***/ }),
+/* 13 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/*!
+	 * Copyright (c) 2018, Salesforce.com, Inc.
+	 * All rights reserved.
+	 *
+	 * Redistribution and use in source and binary forms, with or without
+	 * modification, are permitted provided that the following conditions are met:
+	 *
+	 * 1. Redistributions of source code must retain the above copyright notice,
+	 * this list of conditions and the following disclaimer.
+	 *
+	 * 2. Redistributions in binary form must reproduce the above copyright notice,
+	 * this list of conditions and the following disclaimer in the documentation
+	 * and/or other materials provided with the distribution.
+	 *
+	 * 3. Neither the name of Salesforce.com nor the names of its contributors may
+	 * be used to endorse or promote products derived from this software without
+	 * specific prior written permission.
+	 *
+	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+	 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+	 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+	 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+	 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+	 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	 * POSSIBILITY OF SUCH DAMAGE.
+	 */
+	'use strict';
+	var psl = __webpack_require__(14);
+
+	function getPublicSuffix(domain) {
+	  return psl.get(domain);
+	}
+
+	exports.getPublicSuffix = getPublicSuffix;
+
+
+/***/ }),
+/* 14 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/*eslint no-var:0, prefer-arrow-callback: 0, object-shorthand: 0 */
+	'use strict';
+
+
+	var Punycode = __webpack_require__(15);
+
+
+	var internals = {};
+
+
+	//
+	// Read rules from file.
+	//
+	internals.rules = __webpack_require__(16).map(function (rule) {
+
+	  return {
+	    rule: rule,
+	    suffix: rule.replace(/^(\*\.|\!)/, ''),
+	    punySuffix: -1,
+	    wildcard: rule.charAt(0) === '*',
+	    exception: rule.charAt(0) === '!'
+	  };
+	});
+
+
+	//
+	// Check is given string ends with `suffix`.
+	//
+	internals.endsWith = function (str, suffix) {
+
+	  return str.indexOf(suffix, str.length - suffix.length) !== -1;
+	};
+
+
+	//
+	// Find rule for a given domain.
+	//
+	internals.findRule = function (domain) {
+
+	  var punyDomain = Punycode.toASCII(domain);
+	  return internals.rules.reduce(function (memo, rule) {
+
+	    if (rule.punySuffix === -1){
+	      rule.punySuffix = Punycode.toASCII(rule.suffix);
+	    }
+	    if (!internals.endsWith(punyDomain, '.' + rule.punySuffix) && punyDomain !== rule.punySuffix) {
+	      return memo;
+	    }
+	    // This has been commented out as it never seems to run. This is because
+	    // sub tlds always appear after their parents and we never find a shorter
+	    // match.
+	    //if (memo) {
+	    //  var memoSuffix = Punycode.toASCII(memo.suffix);
+	    //  if (memoSuffix.length >= punySuffix.length) {
+	    //    return memo;
+	    //  }
+	    //}
+	    return rule;
+	  }, null);
+	};
+
+
+	//
+	// Error codes and messages.
+	//
+	exports.errorCodes = {
+	  DOMAIN_TOO_SHORT: 'Domain name too short.',
+	  DOMAIN_TOO_LONG: 'Domain name too long. It should be no more than 255 chars.',
+	  LABEL_STARTS_WITH_DASH: 'Domain name label can not start with a dash.',
+	  LABEL_ENDS_WITH_DASH: 'Domain name label can not end with a dash.',
+	  LABEL_TOO_LONG: 'Domain name label should be at most 63 chars long.',
+	  LABEL_TOO_SHORT: 'Domain name label should be at least 1 character long.',
+	  LABEL_INVALID_CHARS: 'Domain name label can only contain alphanumeric characters or dashes.'
+	};
+
+
+	//
+	// Validate domain name and throw if not valid.
+	//
+	// From wikipedia:
+	//
+	// Hostnames are composed of series of labels concatenated with dots, as are all
+	// domain names. Each label must be between 1 and 63 characters long, and the
+	// entire hostname (including the delimiting dots) has a maximum of 255 chars.
+	//
+	// Allowed chars:
+	//
+	// * `a-z`
+	// * `0-9`
+	// * `-` but not as a starting or ending character
+	// * `.` as a separator for the textual portions of a domain name
+	//
+	// * http://en.wikipedia.org/wiki/Domain_name
+	// * http://en.wikipedia.org/wiki/Hostname
+	//
+	internals.validate = function (input) {
+
+	  // Before we can validate we need to take care of IDNs with unicode chars.
+	  var ascii = Punycode.toASCII(input);
+
+	  if (ascii.length < 1) {
+	    return 'DOMAIN_TOO_SHORT';
+	  }
+	  if (ascii.length > 255) {
+	    return 'DOMAIN_TOO_LONG';
+	  }
+
+	  // Check each part's length and allowed chars.
+	  var labels = ascii.split('.');
+	  var label;
+
+	  for (var i = 0; i < labels.length; ++i) {
+	    label = labels[i];
+	    if (!label.length) {
+	      return 'LABEL_TOO_SHORT';
+	    }
+	    if (label.length > 63) {
+	      return 'LABEL_TOO_LONG';
+	    }
+	    if (label.charAt(0) === '-') {
+	      return 'LABEL_STARTS_WITH_DASH';
+	    }
+	    if (label.charAt(label.length - 1) === '-') {
+	      return 'LABEL_ENDS_WITH_DASH';
+	    }
+	    if (!/^[a-z0-9\-]+$/.test(label)) {
+	      return 'LABEL_INVALID_CHARS';
+	    }
+	  }
+	};
+
+
+	//
+	// Public API
+	//
+
+
+	//
+	// Parse domain.
+	//
+	exports.parse = function (input) {
+
+	  if (typeof input !== 'string') {
+	    throw new TypeError('Domain name must be a string.');
+	  }
+
+	  // Force domain to lowercase.
+	  var domain = input.slice(0).toLowerCase();
+
+	  // Handle FQDN.
+	  // TODO: Simply remove trailing dot?
+	  if (domain.charAt(domain.length - 1) === '.') {
+	    domain = domain.slice(0, domain.length - 1);
+	  }
+
+	  // Validate and sanitise input.
+	  var error = internals.validate(domain);
+	  if (error) {
+	    return {
+	      input: input,
+	      error: {
+	        message: exports.errorCodes[error],
+	        code: error
+	      }
+	    };
+	  }
+
+	  var parsed = {
+	    input: input,
+	    tld: null,
+	    sld: null,
+	    domain: null,
+	    subdomain: null,
+	    listed: false
+	  };
+
+	  var domainParts = domain.split('.');
+
+	  // Non-Internet TLD
+	  if (domainParts[domainParts.length - 1] === 'local') {
+	    return parsed;
+	  }
+
+	  var handlePunycode = function () {
+
+	    if (!/xn--/.test(domain)) {
+	      return parsed;
+	    }
+	    if (parsed.domain) {
+	      parsed.domain = Punycode.toASCII(parsed.domain);
+	    }
+	    if (parsed.subdomain) {
+	      parsed.subdomain = Punycode.toASCII(parsed.subdomain);
+	    }
+	    return parsed;
+	  };
+
+	  var rule = internals.findRule(domain);
+
+	  // Unlisted tld.
+	  if (!rule) {
+	    if (domainParts.length < 2) {
+	      return parsed;
+	    }
+	    parsed.tld = domainParts.pop();
+	    parsed.sld = domainParts.pop();
+	    parsed.domain = [parsed.sld, parsed.tld].join('.');
+	    if (domainParts.length) {
+	      parsed.subdomain = domainParts.pop();
+	    }
+	    return handlePunycode();
+	  }
+
+	  // At this point we know the public suffix is listed.
+	  parsed.listed = true;
+
+	  var tldParts = rule.suffix.split('.');
+	  var privateParts = domainParts.slice(0, domainParts.length - tldParts.length);
+
+	  if (rule.exception) {
+	    privateParts.push(tldParts.shift());
+	  }
+
+	  parsed.tld = tldParts.join('.');
+
+	  if (!privateParts.length) {
+	    return handlePunycode();
+	  }
+
+	  if (rule.wildcard) {
+	    tldParts.unshift(privateParts.pop());
+	    parsed.tld = tldParts.join('.');
+	  }
+
+	  if (!privateParts.length) {
+	    return handlePunycode();
+	  }
+
+	  parsed.sld = privateParts.pop();
+	  parsed.domain = [parsed.sld,  parsed.tld].join('.');
+
+	  if (privateParts.length) {
+	    parsed.subdomain = privateParts.join('.');
+	  }
+
+	  return handlePunycode();
+	};
+
+
+	//
+	// Get domain.
+	//
+	exports.get = function (domain) {
+
+	  if (!domain) {
+	    return null;
+	  }
+	  return exports.parse(domain).domain || null;
+	};
+
+
+	//
+	// Check whether domain belongs to a known public suffix.
+	//
+	exports.isValid = function (domain) {
+
+	  var parsed = exports.parse(domain);
+	  return Boolean(parsed.domain && parsed.listed);
+	};
+
+
+/***/ }),
+/* 15 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(module, global) {/*! https://mths.be/punycode v1.4.1 by @mathias */
+	;(function(root) {
+
+		/** Detect free variables */
+		var freeExports = typeof exports == 'object' && exports &&
+			!exports.nodeType && exports;
+		var freeModule = typeof module == 'object' && module &&
+			!module.nodeType && module;
+		var freeGlobal = typeof global == 'object' && global;
+		if (
+			freeGlobal.global === freeGlobal ||
+			freeGlobal.window === freeGlobal ||
+			freeGlobal.self === freeGlobal
+		) {
+			root = freeGlobal;
+		}
+
+		/**
+		 * The `punycode` object.
+		 * @name punycode
+		 * @type Object
+		 */
+		var punycode,
+
+		/** Highest positive signed 32-bit float value */
+		maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
+
+		/** Bootstring parameters */
+		base = 36,
+		tMin = 1,
+		tMax = 26,
+		skew = 38,
+		damp = 700,
+		initialBias = 72,
+		initialN = 128, // 0x80
+		delimiter = '-', // '\x2D'
+
+		/** Regular expressions */
+		regexPunycode = /^xn--/,
+		regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
+		regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators
+
+		/** Error messages */
+		errors = {
+			'overflow': 'Overflow: input needs wider integers to process',
+			'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
+			'invalid-input': 'Invalid input'
+		},
+
+		/** Convenience shortcuts */
+		baseMinusTMin = base - tMin,
+		floor = Math.floor,
+		stringFromCharCode = String.fromCharCode,
+
+		/** Temporary variable */
+		key;
+
+		/*--------------------------------------------------------------------------*/
+
+		/**
+		 * A generic error utility function.
+		 * @private
+		 * @param {String} type The error type.
+		 * @returns {Error} Throws a `RangeError` with the applicable error message.
+		 */
+		function error(type) {
+			throw new RangeError(errors[type]);
+		}
+
+		/**
+		 * A generic `Array#map` utility function.
+		 * @private
+		 * @param {Array} array The array to iterate over.
+		 * @param {Function} callback The function that gets called for every array
+		 * item.
+		 * @returns {Array} A new array of values returned by the callback function.
+		 */
+		function map(array, fn) {
+			var length = array.length;
+			var result = [];
+			while (length--) {
+				result[length] = fn(array[length]);
+			}
+			return result;
+		}
+
+		/**
+		 * A simple `Array#map`-like wrapper to work with domain name strings or email
+		 * addresses.
+		 * @private
+		 * @param {String} domain The domain name or email address.
+		 * @param {Function} callback The function that gets called for every
+		 * character.
+		 * @returns {Array} A new string of characters returned by the callback
+		 * function.
+		 */
+		function mapDomain(string, fn) {
+			var parts = string.split('@');
+			var result = '';
+			if (parts.length > 1) {
+				// In email addresses, only the domain name should be punycoded. Leave
+				// the local part (i.e. everything up to `@`) intact.
+				result = parts[0] + '@';
+				string = parts[1];
+			}
+			// Avoid `split(regex)` for IE8 compatibility. See #17.
+			string = string.replace(regexSeparators, '\x2E');
+			var labels = string.split('.');
+			var encoded = map(labels, fn).join('.');
+			return result + encoded;
+		}
+
+		/**
+		 * Creates an array containing the numeric code points of each Unicode
+		 * character in the string. While JavaScript uses UCS-2 internally,
+		 * this function will convert a pair of surrogate halves (each of which
+		 * UCS-2 exposes as separate characters) into a single code point,
+		 * matching UTF-16.
+		 * @see `punycode.ucs2.encode`
+		 * @see <https://mathiasbynens.be/notes/javascript-encoding>
+		 * @memberOf punycode.ucs2
+		 * @name decode
+		 * @param {String} string The Unicode input string (UCS-2).
+		 * @returns {Array} The new array of code points.
+		 */
+		function ucs2decode(string) {
+			var output = [],
+			    counter = 0,
+			    length = string.length,
+			    value,
+			    extra;
+			while (counter < length) {
+				value = string.charCodeAt(counter++);
+				if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
+					// high surrogate, and there is a next character
+					extra = string.charCodeAt(counter++);
+					if ((extra & 0xFC00) == 0xDC00) { // low surrogate
+						output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+					} else {
+						// unmatched surrogate; only append this code unit, in case the next
+						// code unit is the high surrogate of a surrogate pair
+						output.push(value);
+						counter--;
+					}
+				} else {
+					output.push(value);
+				}
+			}
+			return output;
+		}
+
+		/**
+		 * Creates a string based on an array of numeric code points.
+		 * @see `punycode.ucs2.decode`
+		 * @memberOf punycode.ucs2
+		 * @name encode
+		 * @param {Array} codePoints The array of numeric code points.
+		 * @returns {String} The new Unicode string (UCS-2).
+		 */
+		function ucs2encode(array) {
+			return map(array, function(value) {
+				var output = '';
+				if (value > 0xFFFF) {
+					value -= 0x10000;
+					output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
+					value = 0xDC00 | value & 0x3FF;
+				}
+				output += stringFromCharCode(value);
+				return output;
+			}).join('');
+		}
+
+		/**
+		 * Converts a basic code point into a digit/integer.
+		 * @see `digitToBasic()`
+		 * @private
+		 * @param {Number} codePoint The basic numeric code point value.
+		 * @returns {Number} The numeric value of a basic code point (for use in
+		 * representing integers) in the range `0` to `base - 1`, or `base` if
+		 * the code point does not represent a value.
+		 */
+		function basicToDigit(codePoint) {
+			if (codePoint - 48 < 10) {
+				return codePoint - 22;
+			}
+			if (codePoint - 65 < 26) {
+				return codePoint - 65;
+			}
+			if (codePoint - 97 < 26) {
+				return codePoint - 97;
+			}
+			return base;
+		}
+
+		/**
+		 * Converts a digit/integer into a basic code point.
+		 * @see `basicToDigit()`
+		 * @private
+		 * @param {Number} digit The numeric value of a basic code point.
+		 * @returns {Number} The basic code point whose value (when used for
+		 * representing integers) is `digit`, which needs to be in the range
+		 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
+		 * used; else, the lowercase form is used. The behavior is undefined
+		 * if `flag` is non-zero and `digit` has no uppercase form.
+		 */
+		function digitToBasic(digit, flag) {
+			//  0..25 map to ASCII a..z or A..Z
+			// 26..35 map to ASCII 0..9
+			return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
+		}
+
+		/**
+		 * Bias adaptation function as per section 3.4 of RFC 3492.
+		 * https://tools.ietf.org/html/rfc3492#section-3.4
+		 * @private
+		 */
+		function adapt(delta, numPoints, firstTime) {
+			var k = 0;
+			delta = firstTime ? floor(delta / damp) : delta >> 1;
+			delta += floor(delta / numPoints);
+			for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
+				delta = floor(delta / baseMinusTMin);
+			}
+			return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
+		}
+
+		/**
+		 * Converts a Punycode string of ASCII-only symbols to a string of Unicode
+		 * symbols.
+		 * @memberOf punycode
+		 * @param {String} input The Punycode string of ASCII-only symbols.
+		 * @returns {String} The resulting string of Unicode symbols.
+		 */
+		function decode(input) {
+			// Don't use UCS-2
+			var output = [],
+			    inputLength = input.length,
+			    out,
+			    i = 0,
+			    n = initialN,
+			    bias = initialBias,
+			    basic,
+			    j,
+			    index,
+			    oldi,
+			    w,
+			    k,
+			    digit,
+			    t,
+			    /** Cached calculation results */
+			    baseMinusT;
+
+			// Handle the basic code points: let `basic` be the number of input code
+			// points before the last delimiter, or `0` if there is none, then copy
+			// the first basic code points to the output.
+
+			basic = input.lastIndexOf(delimiter);
+			if (basic < 0) {
+				basic = 0;
+			}
+
+			for (j = 0; j < basic; ++j) {
+				// if it's not a basic code point
+				if (input.charCodeAt(j) >= 0x80) {
+					error('not-basic');
+				}
+				output.push(input.charCodeAt(j));
+			}
+
+			// Main decoding loop: start just after the last delimiter if any basic code
+			// points were copied; start at the beginning otherwise.
+
+			for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
+
+				// `index` is the index of the next character to be consumed.
+				// Decode a generalized variable-length integer into `delta`,
+				// which gets added to `i`. The overflow checking is easier
+				// if we increase `i` as we go, then subtract off its starting
+				// value at the end to obtain `delta`.
+				for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
+
+					if (index >= inputLength) {
+						error('invalid-input');
+					}
+
+					digit = basicToDigit(input.charCodeAt(index++));
+
+					if (digit >= base || digit > floor((maxInt - i) / w)) {
+						error('overflow');
+					}
+
+					i += digit * w;
+					t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+
+					if (digit < t) {
+						break;
+					}
+
+					baseMinusT = base - t;
+					if (w > floor(maxInt / baseMinusT)) {
+						error('overflow');
+					}
+
+					w *= baseMinusT;
+
+				}
+
+				out = output.length + 1;
+				bias = adapt(i - oldi, out, oldi == 0);
+
+				// `i` was supposed to wrap around from `out` to `0`,
+				// incrementing `n` each time, so we'll fix that now:
+				if (floor(i / out) > maxInt - n) {
+					error('overflow');
+				}
+
+				n += floor(i / out);
+				i %= out;
+
+				// Insert `n` at position `i` of the output
+				output.splice(i++, 0, n);
+
+			}
+
+			return ucs2encode(output);
+		}
+
+		/**
+		 * Converts a string of Unicode symbols (e.g. a domain name label) to a
+		 * Punycode string of ASCII-only symbols.
+		 * @memberOf punycode
+		 * @param {String} input The string of Unicode symbols.
+		 * @returns {String} The resulting Punycode string of ASCII-only symbols.
+		 */
+		function encode(input) {
+			var n,
+			    delta,
+			    handledCPCount,
+			    basicLength,
+			    bias,
+			    j,
+			    m,
+			    q,
+			    k,
+			    t,
+			    currentValue,
+			    output = [],
+			    /** `inputLength` will hold the number of code points in `input`. */
+			    inputLength,
+			    /** Cached calculation results */
+			    handledCPCountPlusOne,
+			    baseMinusT,
+			    qMinusT;
+
+			// Convert the input in UCS-2 to Unicode
+			input = ucs2decode(input);
+
+			// Cache the length
+			inputLength = input.length;
+
+			// Initialize the state
+			n = initialN;
+			delta = 0;
+			bias = initialBias;
+
+			// Handle the basic code points
+			for (j = 0; j < inputLength; ++j) {
+				currentValue = input[j];
+				if (currentValue < 0x80) {
+					output.push(stringFromCharCode(currentValue));
+				}
+			}
+
+			handledCPCount = basicLength = output.length;
+
+			// `handledCPCount` is the number of code points that have been handled;
+			// `basicLength` is the number of basic code points.
+
+			// Finish the basic string - if it is not empty - with a delimiter
+			if (basicLength) {
+				output.push(delimiter);
+			}
+
+			// Main encoding loop:
+			while (handledCPCount < inputLength) {
+
+				// All non-basic code points < n have been handled already. Find the next
+				// larger one:
+				for (m = maxInt, j = 0; j < inputLength; ++j) {
+					currentValue = input[j];
+					if (currentValue >= n && currentValue < m) {
+						m = currentValue;
+					}
+				}
+
+				// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
+				// but guard against overflow
+				handledCPCountPlusOne = handledCPCount + 1;
+				if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
+					error('overflow');
+				}
+
+				delta += (m - n) * handledCPCountPlusOne;
+				n = m;
+
+				for (j = 0; j < inputLength; ++j) {
+					currentValue = input[j];
+
+					if (currentValue < n && ++delta > maxInt) {
+						error('overflow');
+					}
+
+					if (currentValue == n) {
+						// Represent delta as a generalized variable-length integer
+						for (q = delta, k = base; /* no condition */; k += base) {
+							t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+							if (q < t) {
+								break;
+							}
+							qMinusT = q - t;
+							baseMinusT = base - t;
+							output.push(
+								stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
+							);
+							q = floor(qMinusT / baseMinusT);
+						}
+
+						output.push(stringFromCharCode(digitToBasic(q, 0)));
+						bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
+						delta = 0;
+						++handledCPCount;
+					}
+				}
+
+				++delta;
+				++n;
+
+			}
+			return output.join('');
+		}
+
+		/**
+		 * Converts a Punycode string representing a domain name or an email address
+		 * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
+		 * it doesn't matter if you call it on a string that has already been
+		 * converted to Unicode.
+		 * @memberOf punycode
+		 * @param {String} input The Punycoded domain name or email address to
+		 * convert to Unicode.
+		 * @returns {String} The Unicode representation of the given Punycode
+		 * string.
+		 */
+		function toUnicode(input) {
+			return mapDomain(input, function(string) {
+				return regexPunycode.test(string)
+					? decode(string.slice(4).toLowerCase())
+					: string;
+			});
+		}
+
+		/**
+		 * Converts a Unicode string representing a domain name or an email address to
+		 * Punycode. Only the non-ASCII parts of the domain name will be converted,
+		 * i.e. it doesn't matter if you call it with a domain that's already in
+		 * ASCII.
+		 * @memberOf punycode
+		 * @param {String} input The domain name or email address to convert, as a
+		 * Unicode string.
+		 * @returns {String} The Punycode representation of the given domain name or
+		 * email address.
+		 */
+		function toASCII(input) {
+			return mapDomain(input, function(string) {
+				return regexNonASCII.test(string)
+					? 'xn--' + encode(string)
+					: string;
+			});
+		}
+
+		/*--------------------------------------------------------------------------*/
+
+		/** Define the public API */
+		punycode = {
+			/**
+			 * A string representing the current Punycode.js version number.
+			 * @memberOf punycode
+			 * @type String
+			 */
+			'version': '1.4.1',
+			/**
+			 * An object of methods to convert from JavaScript's internal character
+			 * representation (UCS-2) to Unicode code points, and back.
+			 * @see <https://mathiasbynens.be/notes/javascript-encoding>
+			 * @memberOf punycode
+			 * @type Object
+			 */
+			'ucs2': {
+				'decode': ucs2decode,
+				'encode': ucs2encode
+			},
+			'decode': decode,
+			'encode': encode,
+			'toASCII': toASCII,
+			'toUnicode': toUnicode
+		};
+
+		/** Expose `punycode` */
+		// Some AMD build optimizers, like r.js, check for specific condition patterns
+		// like the following:
+		if (
+			true
+		) {
+			!(__WEBPACK_AMD_DEFINE_RESULT__ = function() {
+				return punycode;
+			}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+		} else if (freeExports && freeModule) {
+			if (module.exports == freeExports) {
+				// in Node.js, io.js, or RingoJS v0.8.0+
+				freeModule.exports = punycode;
+			} else {
+				// in Narwhal or RingoJS v0.7.0-
+				for (key in punycode) {
+					punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
+				}
+			}
+		} else {
+			// in Rhino or a web browser
+			root.punycode = punycode;
+		}
+
+	}(this));
+
+	/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)(module), (function() { return this; }())))
+
+/***/ }),
+/* 16 */
+/***/ (function(module, exports) {
+
+	module.exports = ["ac","com.ac","edu.ac","gov.ac","net.ac","mil.ac","org.ac","ad","nom.ad","ae","co.ae","net.ae","org.ae","sch.ae","ac.ae","gov.ae","mil.ae","aero","accident-investigation.aero","accident-prevention.aero","aerobatic.aero","aeroclub.aero","aerodrome.aero","agents.aero","aircraft.aero","airline.aero","airport.aero","air-surveillance.aero","airtraffic.aero","air-traffic-control.aero","ambulance.aero","amusement.aero","association.aero","author.aero","ballooning.aero","broker.aero","caa.aero","cargo.aero","catering.aero","certification.aero","championship.aero","charter.aero","civilaviation.aero","club.aero","conference.aero","consultant.aero","consulting.aero","control.aero","council.aero","crew.aero","design.aero","dgca.aero","educator.aero","emergency.aero","engine.aero","engineer.aero","entertainment.aero","equipment.aero","exchange.aero","express.aero","federation.aero","flight.aero","freight.aero","fuel.aero","gliding.aero","government.aero","groundhandling.aero","group.aero","hanggliding.aero","homebuilt.aero","insurance.aero","journal.aero","journalist.aero","leasing.aero","logistics.aero","magazine.aero","maintenance.aero","media.aero","microlight.aero","modelling.aero","navigation.aero","parachuting.aero","paragliding.aero","passenger-association.aero","pilot.aero","press.aero","production.aero","recreation.aero","repbody.aero","res.aero","research.aero","rotorcraft.aero","safety.aero","scientist.aero","services.aero","show.aero","skydiving.aero","software.aero","student.aero","trader.aero","trading.aero","trainer.aero","union.aero","workinggroup.aero","works.aero","af","gov.af","com.af","org.af","net.af","edu.af","ag","com.ag","org.ag","net.ag","co.ag","nom.ag","ai","off.ai","com.ai","net.ai","org.ai","al","com.al","edu.al","gov.al","mil.al","net.al","org.al","am","ao","ed.ao","gv.ao","og.ao","co.ao","pb.ao","it.ao","aq","ar","com.ar","edu.ar","gob.ar","gov.ar","int.ar","mil.ar","musica.ar","net.ar","org.ar","tur.ar","arpa","e164.arpa","in-addr.arpa","ip6.arpa","iris.arpa","uri.arpa","urn.arpa","as","gov.as","asia","at","ac.at","co.at","gv.at","or.at","au","com.au","net.au","org.au","edu.au","gov.au","asn.au","id.au","info.au","conf.au","oz.au","act.au","nsw.au","nt.au","qld.au","sa.au","tas.au","vic.au","wa.au","act.edu.au","nsw.edu.au","nt.edu.au","qld.edu.au","sa.edu.au","tas.edu.au","vic.edu.au","wa.edu.au","qld.gov.au","sa.gov.au","tas.gov.au","vic.gov.au","wa.gov.au","aw","com.aw","ax","az","com.az","net.az","int.az","gov.az","org.az","edu.az","info.az","pp.az","mil.az","name.az","pro.az","biz.az","ba","com.ba","edu.ba","gov.ba","mil.ba","net.ba","org.ba","bb","biz.bb","co.bb","com.bb","edu.bb","gov.bb","info.bb","net.bb","org.bb","store.bb","tv.bb","*.bd","be","ac.be","bf","gov.bf","bg","a.bg","b.bg","c.bg","d.bg","e.bg","f.bg","g.bg","h.bg","i.bg","j.bg","k.bg","l.bg","m.bg","n.bg","o.bg","p.bg","q.bg","r.bg","s.bg","t.bg","u.bg","v.bg","w.bg","x.bg","y.bg","z.bg","0.bg","1.bg","2.bg","3.bg","4.bg","5.bg","6.bg","7.bg","8.bg","9.bg","bh","com.bh","edu.bh","net.bh","org.bh","gov.bh","bi","co.bi","com.bi","edu.bi","or.bi","org.bi","biz","bj","asso.bj","barreau.bj","gouv.bj","bm","com.bm","edu.bm","gov.bm","net.bm","org.bm","*.bn","bo","com.bo","edu.bo","gob.bo","int.bo","org.bo","net.bo","mil.bo","tv.bo","web.bo","academia.bo","agro.bo","arte.bo","blog.bo","bolivia.bo","ciencia.bo","cooperativa.bo","democracia.bo","deporte.bo","ecologia.bo","economia.bo","empresa.bo","indigena.bo","industria.bo","info.bo","medicina.bo","movimiento.bo","musica.bo","natural.bo","nombre.bo","noticias.bo","patria.bo","politica.bo","profesional.bo","plurinacional.bo","pueblo.bo","revista.bo","salud.bo","tecnologia.bo","tksat.bo","transporte.bo","wiki.bo","br","9guacu.br","abc.br","adm.br","adv.br","agr.br","aju.br","am.br","anani.br","aparecida.br","arq.br","art.br","ato.br","b.br","barueri.br","belem.br","bhz.br","bio.br","blog.br","bmd.br","boavista.br","bsb.br","campinagrande.br","campinas.br","caxias.br","cim.br","cng.br","cnt.br","com.br","contagem.br","coop.br","cri.br","cuiaba.br","curitiba.br","def.br","ecn.br","eco.br","edu.br","emp.br","eng.br","esp.br","etc.br","eti.br","far.br","feira.br","flog.br","floripa.br","fm.br","fnd.br","fortal.br","fot.br","foz.br","fst.br","g12.br","ggf.br","goiania.br","gov.br","ac.gov.br","al.gov.br","am.gov.br","ap.gov.br","ba.gov.br","ce.gov.br","df.gov.br","es.gov.br","go.gov.br","ma.gov.br","mg.gov.br","ms.gov.br","mt.gov.br","pa.gov.br","pb.gov.br","pe.gov.br","pi.gov.br","pr.gov.br","rj.gov.br","rn.gov.br","ro.gov.br","rr.gov.br","rs.gov.br","sc.gov.br","se.gov.br","sp.gov.br","to.gov.br","gru.br","imb.br","ind.br","inf.br","jab.br","jampa.br","jdf.br","joinville.br","jor.br","jus.br","leg.br","lel.br","londrina.br","macapa.br","maceio.br","manaus.br","maringa.br","mat.br","med.br","mil.br","morena.br","mp.br","mus.br","natal.br","net.br","niteroi.br","*.nom.br","not.br","ntr.br","odo.br","org.br","osasco.br","palmas.br","poa.br","ppg.br","pro.br","psc.br","psi.br","pvh.br","qsl.br","radio.br","rec.br","recife.br","ribeirao.br","rio.br","riobranco.br","riopreto.br","salvador.br","sampa.br","santamaria.br","santoandre.br","saobernardo.br","saogonca.br","sjc.br","slg.br","slz.br","sorocaba.br","srv.br","taxi.br","teo.br","the.br","tmp.br","trd.br","tur.br","tv.br","udi.br","vet.br","vix.br","vlog.br","wiki.br","zlg.br","bs","com.bs","net.bs","org.bs","edu.bs","gov.bs","bt","com.bt","edu.bt","gov.bt","net.bt","org.bt","bv","bw","co.bw","org.bw","by","gov.by","mil.by","com.by","of.by","bz","com.bz","net.bz","org.bz","edu.bz","gov.bz","ca","ab.ca","bc.ca","mb.ca","nb.ca","nf.ca","nl.ca","ns.ca","nt.ca","nu.ca","on.ca","pe.ca","qc.ca","sk.ca","yk.ca","gc.ca","cat","cc","cd","gov.cd","cf","cg","ch","ci","org.ci","or.ci","com.ci","co.ci","edu.ci","ed.ci","ac.ci","net.ci","go.ci","asso.ci","aéroport.ci","int.ci","presse.ci","md.ci","gouv.ci","*.ck","!www.ck","cl","gov.cl","gob.cl","co.cl","mil.cl","cm","co.cm","com.cm","gov.cm","net.cm","cn","ac.cn","com.cn","edu.cn","gov.cn","net.cn","org.cn","mil.cn","公司.cn","网络.cn","網絡.cn","ah.cn","bj.cn","cq.cn","fj.cn","gd.cn","gs.cn","gz.cn","gx.cn","ha.cn","hb.cn","he.cn","hi.cn","hl.cn","hn.cn","jl.cn","js.cn","jx.cn","ln.cn","nm.cn","nx.cn","qh.cn","sc.cn","sd.cn","sh.cn","sn.cn","sx.cn","tj.cn","xj.cn","xz.cn","yn.cn","zj.cn","hk.cn","mo.cn","tw.cn","co","arts.co","com.co","edu.co","firm.co","gov.co","info.co","int.co","mil.co","net.co","nom.co","org.co","rec.co","web.co","com","coop","cr","ac.cr","co.cr","ed.cr","fi.cr","go.cr","or.cr","sa.cr","cu","com.cu","edu.cu","org.cu","net.cu","gov.cu","inf.cu","cv","cw","com.cw","edu.cw","net.cw","org.cw","cx","gov.cx","cy","ac.cy","biz.cy","com.cy","ekloges.cy","gov.cy","ltd.cy","name.cy","net.cy","org.cy","parliament.cy","press.cy","pro.cy","tm.cy","cz","de","dj","dk","dm","com.dm","net.dm","org.dm","edu.dm","gov.dm","do","art.do","com.do","edu.do","gob.do","gov.do","mil.do","net.do","org.do","sld.do","web.do","dz","com.dz","org.dz","net.dz","gov.dz","edu.dz","asso.dz","pol.dz","art.dz","ec","com.ec","info.ec","net.ec","fin.ec","k12.ec","med.ec","pro.ec","org.ec","edu.ec","gov.ec","gob.ec","mil.ec","edu","ee","edu.ee","gov.ee","riik.ee","lib.ee","med.ee","com.ee","pri.ee","aip.ee","org.ee","fie.ee","eg","com.eg","edu.eg","eun.eg","gov.eg","mil.eg","name.eg","net.eg","org.eg","sci.eg","*.er","es","com.es","nom.es","org.es","gob.es","edu.es","et","com.et","gov.et","org.et","edu.et","biz.et","name.et","info.et","net.et","eu","fi","aland.fi","*.fj","*.fk","fm","fo","fr","com.fr","asso.fr","nom.fr","prd.fr","presse.fr","tm.fr","aeroport.fr","assedic.fr","avocat.fr","avoues.fr","cci.fr","chambagri.fr","chirurgiens-dentistes.fr","experts-comptables.fr","geometre-expert.fr","gouv.fr","greta.fr","huissier-justice.fr","medecin.fr","notaires.fr","pharmacien.fr","port.fr","veterinaire.fr","ga","gb","gd","ge","com.ge","edu.ge","gov.ge","org.ge","mil.ge","net.ge","pvt.ge","gf","gg","co.gg","net.gg","org.gg","gh","com.gh","edu.gh","gov.gh","org.gh","mil.gh","gi","com.gi","ltd.gi","gov.gi","mod.gi","edu.gi","org.gi","gl","co.gl","com.gl","edu.gl","net.gl","org.gl","gm","gn","ac.gn","com.gn","edu.gn","gov.gn","org.gn","net.gn","gov","gp","com.gp","net.gp","mobi.gp","edu.gp","org.gp","asso.gp","gq","gr","com.gr","edu.gr","net.gr","org.gr","gov.gr","gs","gt","com.gt","edu.gt","gob.gt","ind.gt","mil.gt","net.gt","org.gt","gu","com.gu","edu.gu","gov.gu","guam.gu","info.gu","net.gu","org.gu","web.gu","gw","gy","co.gy","com.gy","edu.gy","gov.gy","net.gy","org.gy","hk","com.hk","edu.hk","gov.hk","idv.hk","net.hk","org.hk","公司.hk","教育.hk","敎育.hk","政府.hk","個人.hk","个人.hk","箇人.hk","網络.hk","网络.hk","组織.hk","網絡.hk","网絡.hk","组织.hk","組織.hk","組织.hk","hm","hn","com.hn","edu.hn","org.hn","net.hn","mil.hn","gob.hn","hr","iz.hr","from.hr","name.hr","com.hr","ht","com.ht","shop.ht","firm.ht","info.ht","adult.ht","net.ht","pro.ht","org.ht","med.ht","art.ht","coop.ht","pol.ht","asso.ht","edu.ht","rel.ht","gouv.ht","perso.ht","hu","co.hu","info.hu","org.hu","priv.hu","sport.hu","tm.hu","2000.hu","agrar.hu","bolt.hu","casino.hu","city.hu","erotica.hu","erotika.hu","film.hu","forum.hu","games.hu","hotel.hu","ingatlan.hu","jogasz.hu","konyvelo.hu","lakas.hu","media.hu","news.hu","reklam.hu","sex.hu","shop.hu","suli.hu","szex.hu","tozsde.hu","utazas.hu","video.hu","id","ac.id","biz.id","co.id","desa.id","go.id","mil.id","my.id","net.id","or.id","sch.id","web.id","ie","gov.ie","il","ac.il","co.il","gov.il","idf.il","k12.il","muni.il","net.il","org.il","im","ac.im","co.im","com.im","ltd.co.im","net.im","org.im","plc.co.im","tt.im","tv.im","in","co.in","firm.in","net.in","org.in","gen.in","ind.in","nic.in","ac.in","edu.in","res.in","gov.in","mil.in","info","int","eu.int","io","com.io","iq","gov.iq","edu.iq","mil.iq","com.iq","org.iq","net.iq","ir","ac.ir","co.ir","gov.ir","id.ir","net.ir","org.ir","sch.ir","ایران.ir","ايران.ir","is","net.is","com.is","edu.is","gov.is","org.is","int.is","it","gov.it","edu.it","abr.it","abruzzo.it","aosta-valley.it","aostavalley.it","bas.it","basilicata.it","cal.it","calabria.it","cam.it","campania.it","emilia-romagna.it","emiliaromagna.it","emr.it","friuli-v-giulia.it","friuli-ve-giulia.it","friuli-vegiulia.it","friuli-venezia-giulia.it","friuli-veneziagiulia.it","friuli-vgiulia.it","friuliv-giulia.it","friulive-giulia.it","friulivegiulia.it","friulivenezia-giulia.it","friuliveneziagiulia.it","friulivgiulia.it","fvg.it","laz.it","lazio.it","lig.it","liguria.it","lom.it","lombardia.it","lombardy.it","lucania.it","mar.it","marche.it","mol.it","molise.it","piedmont.it","piemonte.it","pmn.it","pug.it","puglia.it","sar.it","sardegna.it","sardinia.it","sic.it","sicilia.it","sicily.it","taa.it","tos.it","toscana.it","trentin-sud-tirol.it","trentin-süd-tirol.it","trentin-sudtirol.it","trentin-südtirol.it","trentin-sued-tirol.it","trentin-suedtirol.it","trentino-a-adige.it","trentino-aadige.it","trentino-alto-adige.it","trentino-altoadige.it","trentino-s-tirol.it","trentino-stirol.it","trentino-sud-tirol.it","trentino-süd-tirol.it","trentino-sudtirol.it","trentino-südtirol.it","trentino-sued-tirol.it","trentino-suedtirol.it","trentino.it","trentinoa-adige.it","trentinoaadige.it","trentinoalto-adige.it","trentinoaltoadige.it","trentinos-tirol.it","trentinostirol.it","trentinosud-tirol.it","trentinosüd-tirol.it","trentinosudtirol.it","trentinosüdtirol.it","trentinosued-tirol.it","trentinosuedtirol.it","trentinsud-tirol.it","trentinsüd-tirol.it","trentinsudtirol.it","trentinsüdtirol.it","trentinsued-tirol.it","trentinsuedtirol.it","tuscany.it","umb.it","umbria.it","val-d-aosta.it","val-daosta.it","vald-aosta.it","valdaosta.it","valle-aosta.it","valle-d-aosta.it","valle-daosta.it","valleaosta.it","valled-aosta.it","valledaosta.it","vallee-aoste.it","vallée-aoste.it","vallee-d-aoste.it","vallée-d-aoste.it","valleeaoste.it","valléeaoste.it","valleedaoste.it","valléedaoste.it","vao.it","vda.it","ven.it","veneto.it","ag.it","agrigento.it","al.it","alessandria.it","alto-adige.it","altoadige.it","an.it","ancona.it","andria-barletta-trani.it","andria-trani-barletta.it","andriabarlettatrani.it","andriatranibarletta.it","ao.it","aosta.it","aoste.it","ap.it","aq.it","aquila.it","ar.it","arezzo.it","ascoli-piceno.it","ascolipiceno.it","asti.it","at.it","av.it","avellino.it","ba.it","balsan-sudtirol.it","balsan-südtirol.it","balsan-suedtirol.it","balsan.it","bari.it","barletta-trani-andria.it","barlettatraniandria.it","belluno.it","benevento.it","bergamo.it","bg.it","bi.it","biella.it","bl.it","bn.it","bo.it","bologna.it","bolzano-altoadige.it","bolzano.it","bozen-sudtirol.it","bozen-südtirol.it","bozen-suedtirol.it","bozen.it","br.it","brescia.it","brindisi.it","bs.it","bt.it","bulsan-sudtirol.it","bulsan-südtirol.it","bulsan-suedtirol.it","bulsan.it","bz.it","ca.it","cagliari.it","caltanissetta.it","campidano-medio.it","campidanomedio.it","campobasso.it","carbonia-iglesias.it","carboniaiglesias.it","carrara-massa.it","carraramassa.it","caserta.it","catania.it","catanzaro.it","cb.it","ce.it","cesena-forli.it","cesena-forlì.it","cesenaforli.it","cesenaforlì.it","ch.it","chieti.it","ci.it","cl.it","cn.it","co.it","como.it","cosenza.it","cr.it","cremona.it","crotone.it","cs.it","ct.it","cuneo.it","cz.it","dell-ogliastra.it","dellogliastra.it","en.it","enna.it","fc.it","fe.it","fermo.it","ferrara.it","fg.it","fi.it","firenze.it","florence.it","fm.it","foggia.it","forli-cesena.it","forlì-cesena.it","forlicesena.it","forlìcesena.it","fr.it","frosinone.it","ge.it","genoa.it","genova.it","go.it","gorizia.it","gr.it","grosseto.it","iglesias-carbonia.it","iglesiascarbonia.it","im.it","imperia.it","is.it","isernia.it","kr.it","la-spezia.it","laquila.it","laspezia.it","latina.it","lc.it","le.it","lecce.it","lecco.it","li.it","livorno.it","lo.it","lodi.it","lt.it","lu.it","lucca.it","macerata.it","mantova.it","massa-carrara.it","massacarrara.it","matera.it","mb.it","mc.it","me.it","medio-campidano.it","mediocampidano.it","messina.it","mi.it","milan.it","milano.it","mn.it","mo.it","modena.it","monza-brianza.it","monza-e-della-brianza.it","monza.it","monzabrianza.it","monzaebrianza.it","monzaedellabrianza.it","ms.it","mt.it","na.it","naples.it","napoli.it","no.it","novara.it","nu.it","nuoro.it","og.it","ogliastra.it","olbia-tempio.it","olbiatempio.it","or.it","oristano.it","ot.it","pa.it","padova.it","padua.it","palermo.it","parma.it","pavia.it","pc.it","pd.it","pe.it","perugia.it","pesaro-urbino.it","pesarourbino.it","pescara.it","pg.it","pi.it","piacenza.it","pisa.it","pistoia.it","pn.it","po.it","pordenone.it","potenza.it","pr.it","prato.it","pt.it","pu.it","pv.it","pz.it","ra.it","ragusa.it","ravenna.it","rc.it","re.it","reggio-calabria.it","reggio-emilia.it","reggiocalabria.it","reggioemilia.it","rg.it","ri.it","rieti.it","rimini.it","rm.it","rn.it","ro.it","roma.it","rome.it","rovigo.it","sa.it","salerno.it","sassari.it","savona.it","si.it","siena.it","siracusa.it","so.it","sondrio.it","sp.it","sr.it","ss.it","suedtirol.it","südtirol.it","sv.it","ta.it","taranto.it","te.it","tempio-olbia.it","tempioolbia.it","teramo.it","terni.it","tn.it","to.it","torino.it","tp.it","tr.it","trani-andria-barletta.it","trani-barletta-andria.it","traniandriabarletta.it","tranibarlettaandria.it","trapani.it","trento.it","treviso.it","trieste.it","ts.it","turin.it","tv.it","ud.it","udine.it","urbino-pesaro.it","urbinopesaro.it","va.it","varese.it","vb.it","vc.it","ve.it","venezia.it","venice.it","verbania.it","vercelli.it","verona.it","vi.it","vibo-valentia.it","vibovalentia.it","vicenza.it","viterbo.it","vr.it","vs.it","vt.it","vv.it","je","co.je","net.je","org.je","*.jm","jo","com.jo","org.jo","net.jo","edu.jo","sch.jo","gov.jo","mil.jo","name.jo","jobs","jp","ac.jp","ad.jp","co.jp","ed.jp","go.jp","gr.jp","lg.jp","ne.jp","or.jp","aichi.jp","akita.jp","aomori.jp","chiba.jp","ehime.jp","fukui.jp","fukuoka.jp","fukushima.jp","gifu.jp","gunma.jp","hiroshima.jp","hokkaido.jp","hyogo.jp","ibaraki.jp","ishikawa.jp","iwate.jp","kagawa.jp","kagoshima.jp","kanagawa.jp","kochi.jp","kumamoto.jp","kyoto.jp","mie.jp","miyagi.jp","miyazaki.jp","nagano.jp","nagasaki.jp","nara.jp","niigata.jp","oita.jp","okayama.jp","okinawa.jp","osaka.jp","saga.jp","saitama.jp","shiga.jp","shimane.jp","shizuoka.jp","tochigi.jp","tokushima.jp","tokyo.jp","tottori.jp","toyama.jp","wakayama.jp","yamagata.jp","yamaguchi.jp","yamanashi.jp","栃木.jp","愛知.jp","愛媛.jp","兵庫.jp","熊本.jp","茨城.jp","北海道.jp","千葉.jp","和歌山.jp","長崎.jp","長野.jp","新潟.jp","青森.jp","静岡.jp","東京.jp","石川.jp","埼玉.jp","三重.jp","京都.jp","佐賀.jp","大分.jp","大阪.jp","奈良.jp","宮城.jp","宮崎.jp","富山.jp","山口.jp","山形.jp","山梨.jp","岩手.jp","岐阜.jp","岡山.jp","島根.jp","広島.jp","徳島.jp","沖縄.jp","滋賀.jp","神奈川.jp","福井.jp","福岡.jp","福島.jp","秋田.jp","群馬.jp","香川.jp","高知.jp","鳥取.jp","鹿児島.jp","*.kawasaki.jp","*.kitakyushu.jp","*.kobe.jp","*.nagoya.jp","*.sapporo.jp","*.sendai.jp","*.yokohama.jp","!city.kawasaki.jp","!city.kitakyushu.jp","!city.kobe.jp","!city.nagoya.jp","!city.sapporo.jp","!city.sendai.jp","!city.yokohama.jp","aisai.aichi.jp","ama.aichi.jp","anjo.aichi.jp","asuke.aichi.jp","chiryu.aichi.jp","chita.aichi.jp","fuso.aichi.jp","gamagori.aichi.jp","handa.aichi.jp","hazu.aichi.jp","hekinan.aichi.jp","higashiura.aichi.jp","ichinomiya.aichi.jp","inazawa.aichi.jp","inuyama.aichi.jp","isshiki.aichi.jp","iwakura.aichi.jp","kanie.aichi.jp","kariya.aichi.jp","kasugai.aichi.jp","kira.aichi.jp","kiyosu.aichi.jp","komaki.aichi.jp","konan.aichi.jp","kota.aichi.jp","mihama.aichi.jp","miyoshi.aichi.jp","nishio.aichi.jp","nisshin.aichi.jp","obu.aichi.jp","oguchi.aichi.jp","oharu.aichi.jp","okazaki.aichi.jp","owariasahi.aichi.jp","seto.aichi.jp","shikatsu.aichi.jp","shinshiro.aichi.jp","shitara.aichi.jp","tahara.aichi.jp","takahama.aichi.jp","tobishima.aichi.jp","toei.aichi.jp","togo.aichi.jp","tokai.aichi.jp","tokoname.aichi.jp","toyoake.aichi.jp","toyohashi.aichi.jp","toyokawa.aichi.jp","toyone.aichi.jp","toyota.aichi.jp","tsushima.aichi.jp","yatomi.aichi.jp","akita.akita.jp","daisen.akita.jp","fujisato.akita.jp","gojome.akita.jp","hachirogata.akita.jp","happou.akita.jp","higashinaruse.akita.jp","honjo.akita.jp","honjyo.akita.jp","ikawa.akita.jp","kamikoani.akita.jp","kamioka.akita.jp","katagami.akita.jp","kazuno.akita.jp","kitaakita.akita.jp","kosaka.akita.jp","kyowa.akita.jp","misato.akita.jp","mitane.akita.jp","moriyoshi.akita.jp","nikaho.akita.jp","noshiro.akita.jp","odate.akita.jp","oga.akita.jp","ogata.akita.jp","semboku.akita.jp","yokote.akita.jp","yurihonjo.akita.jp","aomori.aomori.jp","gonohe.aomori.jp","hachinohe.aomori.jp","hashikami.aomori.jp","hiranai.aomori.jp","hirosaki.aomori.jp","itayanagi.aomori.jp","kuroishi.aomori.jp","misawa.aomori.jp","mutsu.aomori.jp","nakadomari.aomori.jp","noheji.aomori.jp","oirase.aomori.jp","owani.aomori.jp","rokunohe.aomori.jp","sannohe.aomori.jp","shichinohe.aomori.jp","shingo.aomori.jp","takko.aomori.jp","towada.aomori.jp","tsugaru.aomori.jp","tsuruta.aomori.jp","abiko.chiba.jp","asahi.chiba.jp","chonan.chiba.jp","chosei.chiba.jp","choshi.chiba.jp","chuo.chiba.jp","funabashi.chiba.jp","futtsu.chiba.jp","hanamigawa.chiba.jp","ichihara.chiba.jp","ichikawa.chiba.jp","ichinomiya.chiba.jp","inzai.chiba.jp","isumi.chiba.jp","kamagaya.chiba.jp","kamogawa.chiba.jp","kashiwa.chiba.jp","katori.chiba.jp","katsuura.chiba.jp","kimitsu.chiba.jp","kisarazu.chiba.jp","kozaki.chiba.jp","kujukuri.chiba.jp","kyonan.chiba.jp","matsudo.chiba.jp","midori.chiba.jp","mihama.chiba.jp","minamiboso.chiba.jp","mobara.chiba.jp","mutsuzawa.chiba.jp","nagara.chiba.jp","nagareyama.chiba.jp","narashino.chiba.jp","narita.chiba.jp","noda.chiba.jp","oamishirasato.chiba.jp","omigawa.chiba.jp","onjuku.chiba.jp","otaki.chiba.jp","sakae.chiba.jp","sakura.chiba.jp","shimofusa.chiba.jp","shirako.chiba.jp","shiroi.chiba.jp","shisui.chiba.jp","sodegaura.chiba.jp","sosa.chiba.jp","tako.chiba.jp","tateyama.chiba.jp","togane.chiba.jp","tohnosho.chiba.jp","tomisato.chiba.jp","urayasu.chiba.jp","yachimata.chiba.jp","yachiyo.chiba.jp","yokaichiba.chiba.jp","yokoshibahikari.chiba.jp","yotsukaido.chiba.jp","ainan.ehime.jp","honai.ehime.jp","ikata.ehime.jp","imabari.ehime.jp","iyo.ehime.jp","kamijima.ehime.jp","kihoku.ehime.jp","kumakogen.ehime.jp","masaki.ehime.jp","matsuno.ehime.jp","matsuyama.ehime.jp","namikata.ehime.jp","niihama.ehime.jp","ozu.ehime.jp","saijo.ehime.jp","seiyo.ehime.jp","shikokuchuo.ehime.jp","tobe.ehime.jp","toon.ehime.jp","uchiko.ehime.jp","uwajima.ehime.jp","yawatahama.ehime.jp","echizen.fukui.jp","eiheiji.fukui.jp","fukui.fukui.jp","ikeda.fukui.jp","katsuyama.fukui.jp","mihama.fukui.jp","minamiechizen.fukui.jp","obama.fukui.jp","ohi.fukui.jp","ono.fukui.jp","sabae.fukui.jp","sakai.fukui.jp","takahama.fukui.jp","tsuruga.fukui.jp","wakasa.fukui.jp","ashiya.fukuoka.jp","buzen.fukuoka.jp","chikugo.fukuoka.jp","chikuho.fukuoka.jp","chikujo.fukuoka.jp","chikushino.fukuoka.jp","chikuzen.fukuoka.jp","chuo.fukuoka.jp","dazaifu.fukuoka.jp","fukuchi.fukuoka.jp","hakata.fukuoka.jp","higashi.fukuoka.jp","hirokawa.fukuoka.jp","hisayama.fukuoka.jp","iizuka.fukuoka.jp","inatsuki.fukuoka.jp","kaho.fukuoka.jp","kasuga.fukuoka.jp","kasuya.fukuoka.jp","kawara.fukuoka.jp","keisen.fukuoka.jp","koga.fukuoka.jp","kurate.fukuoka.jp","kurogi.fukuoka.jp","kurume.fukuoka.jp","minami.fukuoka.jp","miyako.fukuoka.jp","miyama.fukuoka.jp","miyawaka.fukuoka.jp","mizumaki.fukuoka.jp","munakata.fukuoka.jp","nakagawa.fukuoka.jp","nakama.fukuoka.jp","nishi.fukuoka.jp","nogata.fukuoka.jp","ogori.fukuoka.jp","okagaki.fukuoka.jp","okawa.fukuoka.jp","oki.fukuoka.jp","omuta.fukuoka.jp","onga.fukuoka.jp","onojo.fukuoka.jp","oto.fukuoka.jp","saigawa.fukuoka.jp","sasaguri.fukuoka.jp","shingu.fukuoka.jp","shinyoshitomi.fukuoka.jp","shonai.fukuoka.jp","soeda.fukuoka.jp","sue.fukuoka.jp","tachiarai.fukuoka.jp","tagawa.fukuoka.jp","takata.fukuoka.jp","toho.fukuoka.jp","toyotsu.fukuoka.jp","tsuiki.fukuoka.jp","ukiha.fukuoka.jp","umi.fukuoka.jp","usui.fukuoka.jp","yamada.fukuoka.jp","yame.fukuoka.jp","yanagawa.fukuoka.jp","yukuhashi.fukuoka.jp","aizubange.fukushima.jp","aizumisato.fukushima.jp","aizuwakamatsu.fukushima.jp","asakawa.fukushima.jp","bandai.fukushima.jp","date.fukushima.jp","fukushima.fukushima.jp","furudono.fukushima.jp","futaba.fukushima.jp","hanawa.fukushima.jp","higashi.fukushima.jp","hirata.fukushima.jp","hirono.fukushima.jp","iitate.fukushima.jp","inawashiro.fukushima.jp","ishikawa.fukushima.jp","iwaki.fukushima.jp","izumizaki.fukushima.jp","kagamiishi.fukushima.jp","kaneyama.fukushima.jp","kawamata.fukushima.jp","kitakata.fukushima.jp","kitashiobara.fukushima.jp","koori.fukushima.jp","koriyama.fukushima.jp","kunimi.fukushima.jp","miharu.fukushima.jp","mishima.fukushima.jp","namie.fukushima.jp","nango.fukushima.jp","nishiaizu.fukushima.jp","nishigo.fukushima.jp","okuma.fukushima.jp","omotego.fukushima.jp","ono.fukushima.jp","otama.fukushima.jp","samegawa.fukushima.jp","shimogo.fukushima.jp","shirakawa.fukushima.jp","showa.fukushima.jp","soma.fukushima.jp","sukagawa.fukushima.jp","taishin.fukushima.jp","tamakawa.fukushima.jp","tanagura.fukushima.jp","tenei.fukushima.jp","yabuki.fukushima.jp","yamato.fukushima.jp","yamatsuri.fukushima.jp","yanaizu.fukushima.jp","yugawa.fukushima.jp","anpachi.gifu.jp","ena.gifu.jp","gifu.gifu.jp","ginan.gifu.jp","godo.gifu.jp","gujo.gifu.jp","hashima.gifu.jp","hichiso.gifu.jp","hida.gifu.jp","higashishirakawa.gifu.jp","ibigawa.gifu.jp","ikeda.gifu.jp","kakamigahara.gifu.jp","kani.gifu.jp","kasahara.gifu.jp","kasamatsu.gifu.jp","kawaue.gifu.jp","kitagata.gifu.jp","mino.gifu.jp","minokamo.gifu.jp","mitake.gifu.jp","mizunami.gifu.jp","motosu.gifu.jp","nakatsugawa.gifu.jp","ogaki.gifu.jp","sakahogi.gifu.jp","seki.gifu.jp","sekigahara.gifu.jp","shirakawa.gifu.jp","tajimi.gifu.jp","takayama.gifu.jp","tarui.gifu.jp","toki.gifu.jp","tomika.gifu.jp","wanouchi.gifu.jp","yamagata.gifu.jp","yaotsu.gifu.jp","yoro.gifu.jp","annaka.gunma.jp","chiyoda.gunma.jp","fujioka.gunma.jp","higashiagatsuma.gunma.jp","isesaki.gunma.jp","itakura.gunma.jp","kanna.gunma.jp","kanra.gunma.jp","katashina.gunma.jp","kawaba.gunma.jp","kiryu.gunma.jp","kusatsu.gunma.jp","maebashi.gunma.jp","meiwa.gunma.jp","midori.gunma.jp","minakami.gunma.jp","naganohara.gunma.jp","nakanojo.gunma.jp","nanmoku.gunma.jp","numata.gunma.jp","oizumi.gunma.jp","ora.gunma.jp","ota.gunma.jp","shibukawa.gunma.jp","shimonita.gunma.jp","shinto.gunma.jp","showa.gunma.jp","takasaki.gunma.jp","takayama.gunma.jp","tamamura.gunma.jp","tatebayashi.gunma.jp","tomioka.gunma.jp","tsukiyono.gunma.jp","tsumagoi.gunma.jp","ueno.gunma.jp","yoshioka.gunma.jp","asaminami.hiroshima.jp","daiwa.hiroshima.jp","etajima.hiroshima.jp","fuchu.hiroshima.jp","fukuyama.hiroshima.jp","hatsukaichi.hiroshima.jp","higashihiroshima.hiroshima.jp","hongo.hiroshima.jp","jinsekikogen.hiroshima.jp","kaita.hiroshima.jp","kui.hiroshima.jp","kumano.hiroshima.jp","kure.hiroshima.jp","mihara.hiroshima.jp","miyoshi.hiroshima.jp","naka.hiroshima.jp","onomichi.hiroshima.jp","osakikamijima.hiroshima.jp","otake.hiroshima.jp","saka.hiroshima.jp","sera.hiroshima.jp","seranishi.hiroshima.jp","shinichi.hiroshima.jp","shobara.hiroshima.jp","takehara.hiroshima.jp","abashiri.hokkaido.jp","abira.hokkaido.jp","aibetsu.hokkaido.jp","akabira.hokkaido.jp","akkeshi.hokkaido.jp","asahikawa.hokkaido.jp","ashibetsu.hokkaido.jp","ashoro.hokkaido.jp","assabu.hokkaido.jp","atsuma.hokkaido.jp","bibai.hokkaido.jp","biei.hokkaido.jp","bifuka.hokkaido.jp","bihoro.hokkaido.jp","biratori.hokkaido.jp","chippubetsu.hokkaido.jp","chitose.hokkaido.jp","date.hokkaido.jp","ebetsu.hokkaido.jp","embetsu.hokkaido.jp","eniwa.hokkaido.jp","erimo.hokkaido.jp","esan.hokkaido.jp","esashi.hokkaido.jp","fukagawa.hokkaido.jp","fukushima.hokkaido.jp","furano.hokkaido.jp","furubira.hokkaido.jp","haboro.hokkaido.jp","hakodate.hokkaido.jp","hamatonbetsu.hokkaido.jp","hidaka.hokkaido.jp","higashikagura.hokkaido.jp","higashikawa.hokkaido.jp","hiroo.hokkaido.jp","hokuryu.hokkaido.jp","hokuto.hokkaido.jp","honbetsu.hokkaido.jp","horokanai.hokkaido.jp","horonobe.hokkaido.jp","ikeda.hokkaido.jp","imakane.hokkaido.jp","ishikari.hokkaido.jp","iwamizawa.hokkaido.jp","iwanai.hokkaido.jp","kamifurano.hokkaido.jp","kamikawa.hokkaido.jp","kamishihoro.hokkaido.jp","kamisunagawa.hokkaido.jp","kamoenai.hokkaido.jp","kayabe.hokkaido.jp","kembuchi.hokkaido.jp","kikonai.hokkaido.jp","kimobetsu.hokkaido.jp","kitahiroshima.hokkaido.jp","kitami.hokkaido.jp","kiyosato.hokkaido.jp","koshimizu.hokkaido.jp","kunneppu.hokkaido.jp","kuriyama.hokkaido.jp","kuromatsunai.hokkaido.jp","kushiro.hokkaido.jp","kutchan.hokkaido.jp","kyowa.hokkaido.jp","mashike.hokkaido.jp","matsumae.hokkaido.jp","mikasa.hokkaido.jp","minamifurano.hokkaido.jp","mombetsu.hokkaido.jp","moseushi.hokkaido.jp","mukawa.hokkaido.jp","muroran.hokkaido.jp","naie.hokkaido.jp","nakagawa.hokkaido.jp","nakasatsunai.hokkaido.jp","nakatombetsu.hokkaido.jp","nanae.hokkaido.jp","nanporo.hokkaido.jp","nayoro.hokkaido.jp","nemuro.hokkaido.jp","niikappu.hokkaido.jp","niki.hokkaido.jp","nishiokoppe.hokkaido.jp","noboribetsu.hokkaido.jp","numata.hokkaido.jp","obihiro.hokkaido.jp","obira.hokkaido.jp","oketo.hokkaido.jp","okoppe.hokkaido.jp","otaru.hokkaido.jp","otobe.hokkaido.jp","otofuke.hokkaido.jp","otoineppu.hokkaido.jp","oumu.hokkaido.jp","ozora.hokkaido.jp","pippu.hokkaido.jp","rankoshi.hokkaido.jp","rebun.hokkaido.jp","rikubetsu.hokkaido.jp","rishiri.hokkaido.jp","rishirifuji.hokkaido.jp","saroma.hokkaido.jp","sarufutsu.hokkaido.jp","shakotan.hokkaido.jp","shari.hokkaido.jp","shibecha.hokkaido.jp","shibetsu.hokkaido.jp","shikabe.hokkaido.jp","shikaoi.hokkaido.jp","shimamaki.hokkaido.jp","shimizu.hokkaido.jp","shimokawa.hokkaido.jp","shinshinotsu.hokkaido.jp","shintoku.hokkaido.jp","shiranuka.hokkaido.jp","shiraoi.hokkaido.jp","shiriuchi.hokkaido.jp","sobetsu.hokkaido.jp","sunagawa.hokkaido.jp","taiki.hokkaido.jp","takasu.hokkaido.jp","takikawa.hokkaido.jp","takinoue.hokkaido.jp","teshikaga.hokkaido.jp","tobetsu.hokkaido.jp","tohma.hokkaido.jp","tomakomai.hokkaido.jp","tomari.hokkaido.jp","toya.hokkaido.jp","toyako.hokkaido.jp","toyotomi.hokkaido.jp","toyoura.hokkaido.jp","tsubetsu.hokkaido.jp","tsukigata.hokkaido.jp","urakawa.hokkaido.jp","urausu.hokkaido.jp","uryu.hokkaido.jp","utashinai.hokkaido.jp","wakkanai.hokkaido.jp","wassamu.hokkaido.jp","yakumo.hokkaido.jp","yoichi.hokkaido.jp","aioi.hyogo.jp","akashi.hyogo.jp","ako.hyogo.jp","amagasaki.hyogo.jp","aogaki.hyogo.jp","asago.hyogo.jp","ashiya.hyogo.jp","awaji.hyogo.jp","fukusaki.hyogo.jp","goshiki.hyogo.jp","harima.hyogo.jp","himeji.hyogo.jp","ichikawa.hyogo.jp","inagawa.hyogo.jp","itami.hyogo.jp","kakogawa.hyogo.jp","kamigori.hyogo.jp","kamikawa.hyogo.jp","kasai.hyogo.jp","kasuga.hyogo.jp","kawanishi.hyogo.jp","miki.hyogo.jp","minamiawaji.hyogo.jp","nishinomiya.hyogo.jp","nishiwaki.hyogo.jp","ono.hyogo.jp","sanda.hyogo.jp","sannan.hyogo.jp","sasayama.hyogo.jp","sayo.hyogo.jp","shingu.hyogo.jp","shinonsen.hyogo.jp","shiso.hyogo.jp","sumoto.hyogo.jp","taishi.hyogo.jp","taka.hyogo.jp","takarazuka.hyogo.jp","takasago.hyogo.jp","takino.hyogo.jp","tamba.hyogo.jp","tatsuno.hyogo.jp","toyooka.hyogo.jp","yabu.hyogo.jp","yashiro.hyogo.jp","yoka.hyogo.jp","yokawa.hyogo.jp","ami.ibaraki.jp","asahi.ibaraki.jp","bando.ibaraki.jp","chikusei.ibaraki.jp","daigo.ibaraki.jp","fujishiro.ibaraki.jp","hitachi.ibaraki.jp","hitachinaka.ibaraki.jp","hitachiomiya.ibaraki.jp","hitachiota.ibaraki.jp","ibaraki.ibaraki.jp","ina.ibaraki.jp","inashiki.ibaraki.jp","itako.ibaraki.jp","iwama.ibaraki.jp","joso.ibaraki.jp","kamisu.ibaraki.jp","kasama.ibaraki.jp","kashima.ibaraki.jp","kasumigaura.ibaraki.jp","koga.ibaraki.jp","miho.ibaraki.jp","mito.ibaraki.jp","moriya.ibaraki.jp","naka.ibaraki.jp","namegata.ibaraki.jp","oarai.ibaraki.jp","ogawa.ibaraki.jp","omitama.ibaraki.jp","ryugasaki.ibaraki.jp","sakai.ibaraki.jp","sakuragawa.ibaraki.jp","shimodate.ibaraki.jp","shimotsuma.ibaraki.jp","shirosato.ibaraki.jp","sowa.ibaraki.jp","suifu.ibaraki.jp","takahagi.ibaraki.jp","tamatsukuri.ibaraki.jp","tokai.ibaraki.jp","tomobe.ibaraki.jp","tone.ibaraki.jp","toride.ibaraki.jp","tsuchiura.ibaraki.jp","tsukuba.ibaraki.jp","uchihara.ibaraki.jp","ushiku.ibaraki.jp","yachiyo.ibaraki.jp","yamagata.ibaraki.jp","yawara.ibaraki.jp","yuki.ibaraki.jp","anamizu.ishikawa.jp","hakui.ishikawa.jp","hakusan.ishikawa.jp","kaga.ishikawa.jp","kahoku.ishikawa.jp","kanazawa.ishikawa.jp","kawakita.ishikawa.jp","komatsu.ishikawa.jp","nakanoto.ishikawa.jp","nanao.ishikawa.jp","nomi.ishikawa.jp","nonoichi.ishikawa.jp","noto.ishikawa.jp","shika.ishikawa.jp","suzu.ishikawa.jp","tsubata.ishikawa.jp","tsurugi.ishikawa.jp","uchinada.ishikawa.jp","wajima.ishikawa.jp","fudai.iwate.jp","fujisawa.iwate.jp","hanamaki.iwate.jp","hiraizumi.iwate.jp","hirono.iwate.jp","ichinohe.iwate.jp","ichinoseki.iwate.jp","iwaizumi.iwate.jp","iwate.iwate.jp","joboji.iwate.jp","kamaishi.iwate.jp","kanegasaki.iwate.jp","karumai.iwate.jp","kawai.iwate.jp","kitakami.iwate.jp","kuji.iwate.jp","kunohe.iwate.jp","kuzumaki.iwate.jp","miyako.iwate.jp","mizusawa.iwate.jp","morioka.iwate.jp","ninohe.iwate.jp","noda.iwate.jp","ofunato.iwate.jp","oshu.iwate.jp","otsuchi.iwate.jp","rikuzentakata.iwate.jp","shiwa.iwate.jp","shizukuishi.iwate.jp","sumita.iwate.jp","tanohata.iwate.jp","tono.iwate.jp","yahaba.iwate.jp","yamada.iwate.jp","ayagawa.kagawa.jp","higashikagawa.kagawa.jp","kanonji.kagawa.jp","kotohira.kagawa.jp","manno.kagawa.jp","marugame.kagawa.jp","mitoyo.kagawa.jp","naoshima.kagawa.jp","sanuki.kagawa.jp","tadotsu.kagawa.jp","takamatsu.kagawa.jp","tonosho.kagawa.jp","uchinomi.kagawa.jp","utazu.kagawa.jp","zentsuji.kagawa.jp","akune.kagoshima.jp","amami.kagoshima.jp","hioki.kagoshima.jp","isa.kagoshima.jp","isen.kagoshima.jp","izumi.kagoshima.jp","kagoshima.kagoshima.jp","kanoya.kagoshima.jp","kawanabe.kagoshima.jp","kinko.kagoshima.jp","kouyama.kagoshima.jp","makurazaki.kagoshima.jp","matsumoto.kagoshima.jp","minamitane.kagoshima.jp","nakatane.kagoshima.jp","nishinoomote.kagoshima.jp","satsumasendai.kagoshima.jp","soo.kagoshima.jp","tarumizu.kagoshima.jp","yusui.kagoshima.jp","aikawa.kanagawa.jp","atsugi.kanagawa.jp","ayase.kanagawa.jp","chigasaki.kanagawa.jp","ebina.kanagawa.jp","fujisawa.kanagawa.jp","hadano.kanagawa.jp","hakone.kanagawa.jp","hiratsuka.kanagawa.jp","isehara.kanagawa.jp","kaisei.kanagawa.jp","kamakura.kanagawa.jp","kiyokawa.kanagawa.jp","matsuda.kanagawa.jp","minamiashigara.kanagawa.jp","miura.kanagawa.jp","nakai.kanagawa.jp","ninomiya.kanagawa.jp","odawara.kanagawa.jp","oi.kanagawa.jp","oiso.kanagawa.jp","sagamihara.kanagawa.jp","samukawa.kanagawa.jp","tsukui.kanagawa.jp","yamakita.kanagawa.jp","yamato.kanagawa.jp","yokosuka.kanagawa.jp","yugawara.kanagawa.jp","zama.kanagawa.jp","zushi.kanagawa.jp","aki.kochi.jp","geisei.kochi.jp","hidaka.kochi.jp","higashitsuno.kochi.jp","ino.kochi.jp","kagami.kochi.jp","kami.kochi.jp","kitagawa.kochi.jp","kochi.kochi.jp","mihara.kochi.jp","motoyama.kochi.jp","muroto.kochi.jp","nahari.kochi.jp","nakamura.kochi.jp","nankoku.kochi.jp","nishitosa.kochi.jp","niyodogawa.kochi.jp","ochi.kochi.jp","okawa.kochi.jp","otoyo.kochi.jp","otsuki.kochi.jp","sakawa.kochi.jp","sukumo.kochi.jp","susaki.kochi.jp","tosa.kochi.jp","tosashimizu.kochi.jp","toyo.kochi.jp","tsuno.kochi.jp","umaji.kochi.jp","yasuda.kochi.jp","yusuhara.kochi.jp","amakusa.kumamoto.jp","arao.kumamoto.jp","aso.kumamoto.jp","choyo.kumamoto.jp","gyokuto.kumamoto.jp","kamiamakusa.kumamoto.jp","kikuchi.kumamoto.jp","kumamoto.kumamoto.jp","mashiki.kumamoto.jp","mifune.kumamoto.jp","minamata.kumamoto.jp","minamioguni.kumamoto.jp","nagasu.kumamoto.jp","nishihara.kumamoto.jp","oguni.kumamoto.jp","ozu.kumamoto.jp","sumoto.kumamoto.jp","takamori.kumamoto.jp","uki.kumamoto.jp","uto.kumamoto.jp","yamaga.kumamoto.jp","yamato.kumamoto.jp","yatsushiro.kumamoto.jp","ayabe.kyoto.jp","fukuchiyama.kyoto.jp","higashiyama.kyoto.jp","ide.kyoto.jp","ine.kyoto.jp","joyo.kyoto.jp","kameoka.kyoto.jp","kamo.kyoto.jp","kita.kyoto.jp","kizu.kyoto.jp","kumiyama.kyoto.jp","kyotamba.kyoto.jp","kyotanabe.kyoto.jp","kyotango.kyoto.jp","maizuru.kyoto.jp","minami.kyoto.jp","minamiyamashiro.kyoto.jp","miyazu.kyoto.jp","muko.kyoto.jp","nagaokakyo.kyoto.jp","nakagyo.kyoto.jp","nantan.kyoto.jp","oyamazaki.kyoto.jp","sakyo.kyoto.jp","seika.kyoto.jp","tanabe.kyoto.jp","uji.kyoto.jp","ujitawara.kyoto.jp","wazuka.kyoto.jp","yamashina.kyoto.jp","yawata.kyoto.jp","asahi.mie.jp","inabe.mie.jp","ise.mie.jp","kameyama.mie.jp","kawagoe.mie.jp","kiho.mie.jp","kisosaki.mie.jp","kiwa.mie.jp","komono.mie.jp","kumano.mie.jp","kuwana.mie.jp","matsusaka.mie.jp","meiwa.mie.jp","mihama.mie.jp","minamiise.mie.jp","misugi.mie.jp","miyama.mie.jp","nabari.mie.jp","shima.mie.jp","suzuka.mie.jp","tado.mie.jp","taiki.mie.jp","taki.mie.jp","tamaki.mie.jp","toba.mie.jp","tsu.mie.jp","udono.mie.jp","ureshino.mie.jp","watarai.mie.jp","yokkaichi.mie.jp","furukawa.miyagi.jp","higashimatsushima.miyagi.jp","ishinomaki.miyagi.jp","iwanuma.miyagi.jp","kakuda.miyagi.jp","kami.miyagi.jp","kawasaki.miyagi.jp","marumori.miyagi.jp","matsushima.miyagi.jp","minamisanriku.miyagi.jp","misato.miyagi.jp","murata.miyagi.jp","natori.miyagi.jp","ogawara.miyagi.jp","ohira.miyagi.jp","onagawa.miyagi.jp","osaki.miyagi.jp","rifu.miyagi.jp","semine.miyagi.jp","shibata.miyagi.jp","shichikashuku.miyagi.jp","shikama.miyagi.jp","shiogama.miyagi.jp","shiroishi.miyagi.jp","tagajo.miyagi.jp","taiwa.miyagi.jp","tome.miyagi.jp","tomiya.miyagi.jp","wakuya.miyagi.jp","watari.miyagi.jp","yamamoto.miyagi.jp","zao.miyagi.jp","aya.miyazaki.jp","ebino.miyazaki.jp","gokase.miyazaki.jp","hyuga.miyazaki.jp","kadogawa.miyazaki.jp","kawaminami.miyazaki.jp","kijo.miyazaki.jp","kitagawa.miyazaki.jp","kitakata.miyazaki.jp","kitaura.miyazaki.jp","kobayashi.miyazaki.jp","kunitomi.miyazaki.jp","kushima.miyazaki.jp","mimata.miyazaki.jp","miyakonojo.miyazaki.jp","miyazaki.miyazaki.jp","morotsuka.miyazaki.jp","nichinan.miyazaki.jp","nishimera.miyazaki.jp","nobeoka.miyazaki.jp","saito.miyazaki.jp","shiiba.miyazaki.jp","shintomi.miyazaki.jp","takaharu.miyazaki.jp","takanabe.miyazaki.jp","takazaki.miyazaki.jp","tsuno.miyazaki.jp","achi.nagano.jp","agematsu.nagano.jp","anan.nagano.jp","aoki.nagano.jp","asahi.nagano.jp","azumino.nagano.jp","chikuhoku.nagano.jp","chikuma.nagano.jp","chino.nagano.jp","fujimi.nagano.jp","hakuba.nagano.jp","hara.nagano.jp","hiraya.nagano.jp","iida.nagano.jp","iijima.nagano.jp","iiyama.nagano.jp","iizuna.nagano.jp","ikeda.nagano.jp","ikusaka.nagano.jp","ina.nagano.jp","karuizawa.nagano.jp","kawakami.nagano.jp","kiso.nagano.jp","kisofukushima.nagano.jp","kitaaiki.nagano.jp","komagane.nagano.jp","komoro.nagano.jp","matsukawa.nagano.jp","matsumoto.nagano.jp","miasa.nagano.jp","minamiaiki.nagano.jp","minamimaki.nagano.jp","minamiminowa.nagano.jp","minowa.nagano.jp","miyada.nagano.jp","miyota.nagano.jp","mochizuki.nagano.jp","nagano.nagano.jp","nagawa.nagano.jp","nagiso.nagano.jp","nakagawa.nagano.jp","nakano.nagano.jp","nozawaonsen.nagano.jp","obuse.nagano.jp","ogawa.nagano.jp","okaya.nagano.jp","omachi.nagano.jp","omi.nagano.jp","ookuwa.nagano.jp","ooshika.nagano.jp","otaki.nagano.jp","otari.nagano.jp","sakae.nagano.jp","sakaki.nagano.jp","saku.nagano.jp","sakuho.nagano.jp","shimosuwa.nagano.jp","shinanomachi.nagano.jp","shiojiri.nagano.jp","suwa.nagano.jp","suzaka.nagano.jp","takagi.nagano.jp","takamori.nagano.jp","takayama.nagano.jp","tateshina.nagano.jp","tatsuno.nagano.jp","togakushi.nagano.jp","togura.nagano.jp","tomi.nagano.jp","ueda.nagano.jp","wada.nagano.jp","yamagata.nagano.jp","yamanouchi.nagano.jp","yasaka.nagano.jp","yasuoka.nagano.jp","chijiwa.nagasaki.jp","futsu.nagasaki.jp","goto.nagasaki.jp","hasami.nagasaki.jp","hirado.nagasaki.jp","iki.nagasaki.jp","isahaya.nagasaki.jp","kawatana.nagasaki.jp","kuchinotsu.nagasaki.jp","matsuura.nagasaki.jp","nagasaki.nagasaki.jp","obama.nagasaki.jp","omura.nagasaki.jp","oseto.nagasaki.jp","saikai.nagasaki.jp","sasebo.nagasaki.jp","seihi.nagasaki.jp","shimabara.nagasaki.jp","shinkamigoto.nagasaki.jp","togitsu.nagasaki.jp","tsushima.nagasaki.jp","unzen.nagasaki.jp","ando.nara.jp","gose.nara.jp","heguri.nara.jp","higashiyoshino.nara.jp","ikaruga.nara.jp","ikoma.nara.jp","kamikitayama.nara.jp","kanmaki.nara.jp","kashiba.nara.jp","kashihara.nara.jp","katsuragi.nara.jp","kawai.nara.jp","kawakami.nara.jp","kawanishi.nara.jp","koryo.nara.jp","kurotaki.nara.jp","mitsue.nara.jp","miyake.nara.jp","nara.nara.jp","nosegawa.nara.jp","oji.nara.jp","ouda.nara.jp","oyodo.nara.jp","sakurai.nara.jp","sango.nara.jp","shimoichi.nara.jp","shimokitayama.nara.jp","shinjo.nara.jp","soni.nara.jp","takatori.nara.jp","tawaramoto.nara.jp","tenkawa.nara.jp","tenri.nara.jp","uda.nara.jp","yamatokoriyama.nara.jp","yamatotakada.nara.jp","yamazoe.nara.jp","yoshino.nara.jp","aga.niigata.jp","agano.niigata.jp","gosen.niigata.jp","itoigawa.niigata.jp","izumozaki.niigata.jp","joetsu.niigata.jp","kamo.niigata.jp","kariwa.niigata.jp","kashiwazaki.niigata.jp","minamiuonuma.niigata.jp","mitsuke.niigata.jp","muika.niigata.jp","murakami.niigata.jp","myoko.niigata.jp","nagaoka.niigata.jp","niigata.niigata.jp","ojiya.niigata.jp","omi.niigata.jp","sado.niigata.jp","sanjo.niigata.jp","seiro.niigata.jp","seirou.niigata.jp","sekikawa.niigata.jp","shibata.niigata.jp","tagami.niigata.jp","tainai.niigata.jp","tochio.niigata.jp","tokamachi.niigata.jp","tsubame.niigata.jp","tsunan.niigata.jp","uonuma.niigata.jp","yahiko.niigata.jp","yoita.niigata.jp","yuzawa.niigata.jp","beppu.oita.jp","bungoono.oita.jp","bungotakada.oita.jp","hasama.oita.jp","hiji.oita.jp","himeshima.oita.jp","hita.oita.jp","kamitsue.oita.jp","kokonoe.oita.jp","kuju.oita.jp","kunisaki.oita.jp","kusu.oita.jp","oita.oita.jp","saiki.oita.jp","taketa.oita.jp","tsukumi.oita.jp","usa.oita.jp","usuki.oita.jp","yufu.oita.jp","akaiwa.okayama.jp","asakuchi.okayama.jp","bizen.okayama.jp","hayashima.okayama.jp","ibara.okayama.jp","kagamino.okayama.jp","kasaoka.okayama.jp","kibichuo.okayama.jp","kumenan.okayama.jp","kurashiki.okayama.jp","maniwa.okayama.jp","misaki.okayama.jp","nagi.okayama.jp","niimi.okayama.jp","nishiawakura.okayama.jp","okayama.okayama.jp","satosho.okayama.jp","setouchi.okayama.jp","shinjo.okayama.jp","shoo.okayama.jp","soja.okayama.jp","takahashi.okayama.jp","tamano.okayama.jp","tsuyama.okayama.jp","wake.okayama.jp","yakage.okayama.jp","aguni.okinawa.jp","ginowan.okinawa.jp","ginoza.okinawa.jp","gushikami.okinawa.jp","haebaru.okinawa.jp","higashi.okinawa.jp","hirara.okinawa.jp","iheya.okinawa.jp","ishigaki.okinawa.jp","ishikawa.okinawa.jp","itoman.okinawa.jp","izena.okinawa.jp","kadena.okinawa.jp","kin.okinawa.jp","kitadaito.okinawa.jp","kitanakagusuku.okinawa.jp","kumejima.okinawa.jp","kunigami.okinawa.jp","minamidaito.okinawa.jp","motobu.okinawa.jp","nago.okinawa.jp","naha.okinawa.jp","nakagusuku.okinawa.jp","nakijin.okinawa.jp","nanjo.okinawa.jp","nishihara.okinawa.jp","ogimi.okinawa.jp","okinawa.okinawa.jp","onna.okinawa.jp","shimoji.okinawa.jp","taketomi.okinawa.jp","tarama.okinawa.jp","tokashiki.okinawa.jp","tomigusuku.okinawa.jp","tonaki.okinawa.jp","urasoe.okinawa.jp","uruma.okinawa.jp","yaese.okinawa.jp","yomitan.okinawa.jp","yonabaru.okinawa.jp","yonaguni.okinawa.jp","zamami.okinawa.jp","abeno.osaka.jp","chihayaakasaka.osaka.jp","chuo.osaka.jp","daito.osaka.jp","fujiidera.osaka.jp","habikino.osaka.jp","hannan.osaka.jp","higashiosaka.osaka.jp","higashisumiyoshi.osaka.jp","higashiyodogawa.osaka.jp","hirakata.osaka.jp","ibaraki.osaka.jp","ikeda.osaka.jp","izumi.osaka.jp","izumiotsu.osaka.jp","izumisano.osaka.jp","kadoma.osaka.jp","kaizuka.osaka.jp","kanan.osaka.jp","kashiwara.osaka.jp","katano.osaka.jp","kawachinagano.osaka.jp","kishiwada.osaka.jp","kita.osaka.jp","kumatori.osaka.jp","matsubara.osaka.jp","minato.osaka.jp","minoh.osaka.jp","misaki.osaka.jp","moriguchi.osaka.jp","neyagawa.osaka.jp","nishi.osaka.jp","nose.osaka.jp","osakasayama.osaka.jp","sakai.osaka.jp","sayama.osaka.jp","sennan.osaka.jp","settsu.osaka.jp","shijonawate.osaka.jp","shimamoto.osaka.jp","suita.osaka.jp","tadaoka.osaka.jp","taishi.osaka.jp","tajiri.osaka.jp","takaishi.osaka.jp","takatsuki.osaka.jp","tondabayashi.osaka.jp","toyonaka.osaka.jp","toyono.osaka.jp","yao.osaka.jp","ariake.saga.jp","arita.saga.jp","fukudomi.saga.jp","genkai.saga.jp","hamatama.saga.jp","hizen.saga.jp","imari.saga.jp","kamimine.saga.jp","kanzaki.saga.jp","karatsu.saga.jp","kashima.saga.jp","kitagata.saga.jp","kitahata.saga.jp","kiyama.saga.jp","kouhoku.saga.jp","kyuragi.saga.jp","nishiarita.saga.jp","ogi.saga.jp","omachi.saga.jp","ouchi.saga.jp","saga.saga.jp","shiroishi.saga.jp","taku.saga.jp","tara.saga.jp","tosu.saga.jp","yoshinogari.saga.jp","arakawa.saitama.jp","asaka.saitama.jp","chichibu.saitama.jp","fujimi.saitama.jp","fujimino.saitama.jp","fukaya.saitama.jp","hanno.saitama.jp","hanyu.saitama.jp","hasuda.saitama.jp","hatogaya.saitama.jp","hatoyama.saitama.jp","hidaka.saitama.jp","higashichichibu.saitama.jp","higashimatsuyama.saitama.jp","honjo.saitama.jp","ina.saitama.jp","iruma.saitama.jp","iwatsuki.saitama.jp","kamiizumi.saitama.jp","kamikawa.saitama.jp","kamisato.saitama.jp","kasukabe.saitama.jp","kawagoe.saitama.jp","kawaguchi.saitama.jp","kawajima.saitama.jp","kazo.saitama.jp","kitamoto.saitama.jp","koshigaya.saitama.jp","kounosu.saitama.jp","kuki.saitama.jp","kumagaya.saitama.jp","matsubushi.saitama.jp","minano.saitama.jp","misato.saitama.jp","miyashiro.saitama.jp","miyoshi.saitama.jp","moroyama.saitama.jp","nagatoro.saitama.jp","namegawa.saitama.jp","niiza.saitama.jp","ogano.saitama.jp","ogawa.saitama.jp","ogose.saitama.jp","okegawa.saitama.jp","omiya.saitama.jp","otaki.saitama.jp","ranzan.saitama.jp","ryokami.saitama.jp","saitama.saitama.jp","sakado.saitama.jp","satte.saitama.jp","sayama.saitama.jp","shiki.saitama.jp","shiraoka.saitama.jp","soka.saitama.jp","sugito.saitama.jp","toda.saitama.jp","tokigawa.saitama.jp","tokorozawa.saitama.jp","tsurugashima.saitama.jp","urawa.saitama.jp","warabi.saitama.jp","yashio.saitama.jp","yokoze.saitama.jp","yono.saitama.jp","yorii.saitama.jp","yoshida.saitama.jp","yoshikawa.saitama.jp","yoshimi.saitama.jp","aisho.shiga.jp","gamo.shiga.jp","higashiomi.shiga.jp","hikone.shiga.jp","koka.shiga.jp","konan.shiga.jp","kosei.shiga.jp","koto.shiga.jp","kusatsu.shiga.jp","maibara.shiga.jp","moriyama.shiga.jp","nagahama.shiga.jp","nishiazai.shiga.jp","notogawa.shiga.jp","omihachiman.shiga.jp","otsu.shiga.jp","ritto.shiga.jp","ryuoh.shiga.jp","takashima.shiga.jp","takatsuki.shiga.jp","torahime.shiga.jp","toyosato.shiga.jp","yasu.shiga.jp","akagi.shimane.jp","ama.shimane.jp","gotsu.shimane.jp","hamada.shimane.jp","higashiizumo.shimane.jp","hikawa.shimane.jp","hikimi.shimane.jp","izumo.shimane.jp","kakinoki.shimane.jp","masuda.shimane.jp","matsue.shimane.jp","misato.shimane.jp","nishinoshima.shimane.jp","ohda.shimane.jp","okinoshima.shimane.jp","okuizumo.shimane.jp","shimane.shimane.jp","tamayu.shimane.jp","tsuwano.shimane.jp","unnan.shimane.jp","yakumo.shimane.jp","yasugi.shimane.jp","yatsuka.shimane.jp","arai.shizuoka.jp","atami.shizuoka.jp","fuji.shizuoka.jp","fujieda.shizuoka.jp","fujikawa.shizuoka.jp","fujinomiya.shizuoka.jp","fukuroi.shizuoka.jp","gotemba.shizuoka.jp","haibara.shizuoka.jp","hamamatsu.shizuoka.jp","higashiizu.shizuoka.jp","ito.shizuoka.jp","iwata.shizuoka.jp","izu.shizuoka.jp","izunokuni.shizuoka.jp","kakegawa.shizuoka.jp","kannami.shizuoka.jp","kawanehon.shizuoka.jp","kawazu.shizuoka.jp","kikugawa.shizuoka.jp","kosai.shizuoka.jp","makinohara.shizuoka.jp","matsuzaki.shizuoka.jp","minamiizu.shizuoka.jp","mishima.shizuoka.jp","morimachi.shizuoka.jp","nishiizu.shizuoka.jp","numazu.shizuoka.jp","omaezaki.shizuoka.jp","shimada.shizuoka.jp","shimizu.shizuoka.jp","shimoda.shizuoka.jp","shizuoka.shizuoka.jp","susono.shizuoka.jp","yaizu.shizuoka.jp","yoshida.shizuoka.jp","ashikaga.tochigi.jp","bato.tochigi.jp","haga.tochigi.jp","ichikai.tochigi.jp","iwafune.tochigi.jp","kaminokawa.tochigi.jp","kanuma.tochigi.jp","karasuyama.tochigi.jp","kuroiso.tochigi.jp","mashiko.tochigi.jp","mibu.tochigi.jp","moka.tochigi.jp","motegi.tochigi.jp","nasu.tochigi.jp","nasushiobara.tochigi.jp","nikko.tochigi.jp","nishikata.tochigi.jp","nogi.tochigi.jp","ohira.tochigi.jp","ohtawara.tochigi.jp","oyama.tochigi.jp","sakura.tochigi.jp","sano.tochigi.jp","shimotsuke.tochigi.jp","shioya.tochigi.jp","takanezawa.tochigi.jp","tochigi.tochigi.jp","tsuga.tochigi.jp","ujiie.tochigi.jp","utsunomiya.tochigi.jp","yaita.tochigi.jp","aizumi.tokushima.jp","anan.tokushima.jp","ichiba.tokushima.jp","itano.tokushima.jp","kainan.tokushima.jp","komatsushima.tokushima.jp","matsushige.tokushima.jp","mima.tokushima.jp","minami.tokushima.jp","miyoshi.tokushima.jp","mugi.tokushima.jp","nakagawa.tokushima.jp","naruto.tokushima.jp","sanagochi.tokushima.jp","shishikui.tokushima.jp","tokushima.tokushima.jp","wajiki.tokushima.jp","adachi.tokyo.jp","akiruno.tokyo.jp","akishima.tokyo.jp","aogashima.tokyo.jp","arakawa.tokyo.jp","bunkyo.tokyo.jp","chiyoda.tokyo.jp","chofu.tokyo.jp","chuo.tokyo.jp","edogawa.tokyo.jp","fuchu.tokyo.jp","fussa.tokyo.jp","hachijo.tokyo.jp","hachioji.tokyo.jp","hamura.tokyo.jp","higashikurume.tokyo.jp","higashimurayama.tokyo.jp","higashiyamato.tokyo.jp","hino.tokyo.jp","hinode.tokyo.jp","hinohara.tokyo.jp","inagi.tokyo.jp","itabashi.tokyo.jp","katsushika.tokyo.jp","kita.tokyo.jp","kiyose.tokyo.jp","kodaira.tokyo.jp","koganei.tokyo.jp","kokubunji.tokyo.jp","komae.tokyo.jp","koto.tokyo.jp","kouzushima.tokyo.jp","kunitachi.tokyo.jp","machida.tokyo.jp","meguro.tokyo.jp","minato.tokyo.jp","mitaka.tokyo.jp","mizuho.tokyo.jp","musashimurayama.tokyo.jp","musashino.tokyo.jp","nakano.tokyo.jp","nerima.tokyo.jp","ogasawara.tokyo.jp","okutama.tokyo.jp","ome.tokyo.jp","oshima.tokyo.jp","ota.tokyo.jp","setagaya.tokyo.jp","shibuya.tokyo.jp","shinagawa.tokyo.jp","shinjuku.tokyo.jp","suginami.tokyo.jp","sumida.tokyo.jp","tachikawa.tokyo.jp","taito.tokyo.jp","tama.tokyo.jp","toshima.tokyo.jp","chizu.tottori.jp","hino.tottori.jp","kawahara.tottori.jp","koge.tottori.jp","kotoura.tottori.jp","misasa.tottori.jp","nanbu.tottori.jp","nichinan.tottori.jp","sakaiminato.tottori.jp","tottori.tottori.jp","wakasa.tottori.jp","yazu.tottori.jp","yonago.tottori.jp","asahi.toyama.jp","fuchu.toyama.jp","fukumitsu.toyama.jp","funahashi.toyama.jp","himi.toyama.jp","imizu.toyama.jp","inami.toyama.jp","johana.toyama.jp","kamiichi.toyama.jp","kurobe.toyama.jp","nakaniikawa.toyama.jp","namerikawa.toyama.jp","nanto.toyama.jp","nyuzen.toyama.jp","oyabe.toyama.jp","taira.toyama.jp","takaoka.toyama.jp","tateyama.toyama.jp","toga.toyama.jp","tonami.toyama.jp","toyama.toyama.jp","unazuki.toyama.jp","uozu.toyama.jp","yamada.toyama.jp","arida.wakayama.jp","aridagawa.wakayama.jp","gobo.wakayama.jp","hashimoto.wakayama.jp","hidaka.wakayama.jp","hirogawa.wakayama.jp","inami.wakayama.jp","iwade.wakayama.jp","kainan.wakayama.jp","kamitonda.wakayama.jp","katsuragi.wakayama.jp","kimino.wakayama.jp","kinokawa.wakayama.jp","kitayama.wakayama.jp","koya.wakayama.jp","koza.wakayama.jp","kozagawa.wakayama.jp","kudoyama.wakayama.jp","kushimoto.wakayama.jp","mihama.wakayama.jp","misato.wakayama.jp","nachikatsuura.wakayama.jp","shingu.wakayama.jp","shirahama.wakayama.jp","taiji.wakayama.jp","tanabe.wakayama.jp","wakayama.wakayama.jp","yuasa.wakayama.jp","yura.wakayama.jp","asahi.yamagata.jp","funagata.yamagata.jp","higashine.yamagata.jp","iide.yamagata.jp","kahoku.yamagata.jp","kaminoyama.yamagata.jp","kaneyama.yamagata.jp","kawanishi.yamagata.jp","mamurogawa.yamagata.jp","mikawa.yamagata.jp","murayama.yamagata.jp","nagai.yamagata.jp","nakayama.yamagata.jp","nanyo.yamagata.jp","nishikawa.yamagata.jp","obanazawa.yamagata.jp","oe.yamagata.jp","oguni.yamagata.jp","ohkura.yamagata.jp","oishida.yamagata.jp","sagae.yamagata.jp","sakata.yamagata.jp","sakegawa.yamagata.jp","shinjo.yamagata.jp","shirataka.yamagata.jp","shonai.yamagata.jp","takahata.yamagata.jp","tendo.yamagata.jp","tozawa.yamagata.jp","tsuruoka.yamagata.jp","yamagata.yamagata.jp","yamanobe.yamagata.jp","yonezawa.yamagata.jp","yuza.yamagata.jp","abu.yamaguchi.jp","hagi.yamaguchi.jp","hikari.yamaguchi.jp","hofu.yamaguchi.jp","iwakuni.yamaguchi.jp","kudamatsu.yamaguchi.jp","mitou.yamaguchi.jp","nagato.yamaguchi.jp","oshima.yamaguchi.jp","shimonoseki.yamaguchi.jp","shunan.yamaguchi.jp","tabuse.yamaguchi.jp","tokuyama.yamaguchi.jp","toyota.yamaguchi.jp","ube.yamaguchi.jp","yuu.yamaguchi.jp","chuo.yamanashi.jp","doshi.yamanashi.jp","fuefuki.yamanashi.jp","fujikawa.yamanashi.jp","fujikawaguchiko.yamanashi.jp","fujiyoshida.yamanashi.jp","hayakawa.yamanashi.jp","hokuto.yamanashi.jp","ichikawamisato.yamanashi.jp","kai.yamanashi.jp","kofu.yamanashi.jp","koshu.yamanashi.jp","kosuge.yamanashi.jp","minami-alps.yamanashi.jp","minobu.yamanashi.jp","nakamichi.yamanashi.jp","nanbu.yamanashi.jp","narusawa.yamanashi.jp","nirasaki.yamanashi.jp","nishikatsura.yamanashi.jp","oshino.yamanashi.jp","otsuki.yamanashi.jp","showa.yamanashi.jp","tabayama.yamanashi.jp","tsuru.yamanashi.jp","uenohara.yamanashi.jp","yamanakako.yamanashi.jp","yamanashi.yamanashi.jp","ke","ac.ke","co.ke","go.ke","info.ke","me.ke","mobi.ke","ne.ke","or.ke","sc.ke","kg","org.kg","net.kg","com.kg","edu.kg","gov.kg","mil.kg","*.kh","ki","edu.ki","biz.ki","net.ki","org.ki","gov.ki","info.ki","com.ki","km","org.km","nom.km","gov.km","prd.km","tm.km","edu.km","mil.km","ass.km","com.km","coop.km","asso.km","presse.km","medecin.km","notaires.km","pharmaciens.km","veterinaire.km","gouv.km","kn","net.kn","org.kn","edu.kn","gov.kn","kp","com.kp","edu.kp","gov.kp","org.kp","rep.kp","tra.kp","kr","ac.kr","co.kr","es.kr","go.kr","hs.kr","kg.kr","mil.kr","ms.kr","ne.kr","or.kr","pe.kr","re.kr","sc.kr","busan.kr","chungbuk.kr","chungnam.kr","daegu.kr","daejeon.kr","gangwon.kr","gwangju.kr","gyeongbuk.kr","gyeonggi.kr","gyeongnam.kr","incheon.kr","jeju.kr","jeonbuk.kr","jeonnam.kr","seoul.kr","ulsan.kr","kw","com.kw","edu.kw","emb.kw","gov.kw","ind.kw","net.kw","org.kw","ky","edu.ky","gov.ky","com.ky","org.ky","net.ky","kz","org.kz","edu.kz","net.kz","gov.kz","mil.kz","com.kz","la","int.la","net.la","info.la","edu.la","gov.la","per.la","com.la","org.la","lb","com.lb","edu.lb","gov.lb","net.lb","org.lb","lc","com.lc","net.lc","co.lc","org.lc","edu.lc","gov.lc","li","lk","gov.lk","sch.lk","net.lk","int.lk","com.lk","org.lk","edu.lk","ngo.lk","soc.lk","web.lk","ltd.lk","assn.lk","grp.lk","hotel.lk","ac.lk","lr","com.lr","edu.lr","gov.lr","org.lr","net.lr","ls","co.ls","org.ls","lt","gov.lt","lu","lv","com.lv","edu.lv","gov.lv","org.lv","mil.lv","id.lv","net.lv","asn.lv","conf.lv","ly","com.ly","net.ly","gov.ly","plc.ly","edu.ly","sch.ly","med.ly","org.ly","id.ly","ma","co.ma","net.ma","gov.ma","org.ma","ac.ma","press.ma","mc","tm.mc","asso.mc","md","me","co.me","net.me","org.me","edu.me","ac.me","gov.me","its.me","priv.me","mg","org.mg","nom.mg","gov.mg","prd.mg","tm.mg","edu.mg","mil.mg","com.mg","co.mg","mh","mil","mk","com.mk","org.mk","net.mk","edu.mk","gov.mk","inf.mk","name.mk","ml","com.ml","edu.ml","gouv.ml","gov.ml","net.ml","org.ml","presse.ml","*.mm","mn","gov.mn","edu.mn","org.mn","mo","com.mo","net.mo","org.mo","edu.mo","gov.mo","mobi","mp","mq","mr","gov.mr","ms","com.ms","edu.ms","gov.ms","net.ms","org.ms","mt","com.mt","edu.mt","net.mt","org.mt","mu","com.mu","net.mu","org.mu","gov.mu","ac.mu","co.mu","or.mu","museum","academy.museum","agriculture.museum","air.museum","airguard.museum","alabama.museum","alaska.museum","amber.museum","ambulance.museum","american.museum","americana.museum","americanantiques.museum","americanart.museum","amsterdam.museum","and.museum","annefrank.museum","anthro.museum","anthropology.museum","antiques.museum","aquarium.museum","arboretum.museum","archaeological.museum","archaeology.museum","architecture.museum","art.museum","artanddesign.museum","artcenter.museum","artdeco.museum","arteducation.museum","artgallery.museum","arts.museum","artsandcrafts.museum","asmatart.museum","assassination.museum","assisi.museum","association.museum","astronomy.museum","atlanta.museum","austin.museum","australia.museum","automotive.museum","aviation.museum","axis.museum","badajoz.museum","baghdad.museum","bahn.museum","bale.museum","baltimore.museum","barcelona.museum","baseball.museum","basel.museum","baths.museum","bauern.museum","beauxarts.museum","beeldengeluid.museum","bellevue.museum","bergbau.museum","berkeley.museum","berlin.museum","bern.museum","bible.museum","bilbao.museum","bill.museum","birdart.museum","birthplace.museum","bonn.museum","boston.museum","botanical.museum","botanicalgarden.museum","botanicgarden.museum","botany.museum","brandywinevalley.museum","brasil.museum","bristol.museum","british.museum","britishcolumbia.museum","broadcast.museum","brunel.museum","brussel.museum","brussels.museum","bruxelles.museum","building.museum","burghof.museum","bus.museum","bushey.museum","cadaques.museum","california.museum","cambridge.museum","can.museum","canada.museum","capebreton.museum","carrier.museum","cartoonart.museum","casadelamoneda.museum","castle.museum","castres.museum","celtic.museum","center.museum","chattanooga.museum","cheltenham.museum","chesapeakebay.museum","chicago.museum","children.museum","childrens.museum","childrensgarden.museum","chiropractic.museum","chocolate.museum","christiansburg.museum","cincinnati.museum","cinema.museum","circus.museum","civilisation.museum","civilization.museum","civilwar.museum","clinton.museum","clock.museum","coal.museum","coastaldefence.museum","cody.museum","coldwar.museum","collection.museum","colonialwilliamsburg.museum","coloradoplateau.museum","columbia.museum","columbus.museum","communication.museum","communications.museum","community.museum","computer.museum","computerhistory.museum","comunicações.museum","contemporary.museum","contemporaryart.museum","convent.museum","copenhagen.museum","corporation.museum","correios-e-telecomunicações.museum","corvette.museum","costume.museum","countryestate.museum","county.museum","crafts.museum","cranbrook.museum","creation.museum","cultural.museum","culturalcenter.museum","culture.museum","cyber.museum","cymru.museum","dali.museum","dallas.museum","database.museum","ddr.museum","decorativearts.museum","delaware.museum","delmenhorst.museum","denmark.museum","depot.museum","design.museum","detroit.museum","dinosaur.museum","discovery.museum","dolls.museum","donostia.museum","durham.museum","eastafrica.museum","eastcoast.museum","education.museum","educational.museum","egyptian.museum","eisenbahn.museum","elburg.museum","elvendrell.museum","embroidery.museum","encyclopedic.museum","england.museum","entomology.museum","environment.museum","environmentalconservation.museum","epilepsy.museum","essex.museum","estate.museum","ethnology.museum","exeter.museum","exhibition.museum","family.museum","farm.museum","farmequipment.museum","farmers.museum","farmstead.museum","field.museum","figueres.museum","filatelia.museum","film.museum","fineart.museum","finearts.museum","finland.museum","flanders.museum","florida.museum","force.museum","fortmissoula.museum","fortworth.museum","foundation.museum","francaise.museum","frankfurt.museum","franziskaner.museum","freemasonry.museum","freiburg.museum","fribourg.museum","frog.museum","fundacio.museum","furniture.museum","gallery.museum","garden.museum","gateway.museum","geelvinck.museum","gemological.museum","geology.museum","georgia.museum","giessen.museum","glas.museum","glass.museum","gorge.museum","grandrapids.museum","graz.museum","guernsey.museum","halloffame.museum","hamburg.museum","handson.museum","harvestcelebration.museum","hawaii.museum","health.museum","heimatunduhren.museum","hellas.museum","helsinki.museum","hembygdsforbund.museum","heritage.museum","histoire.museum","historical.museum","historicalsociety.museum","historichouses.museum","historisch.museum","historisches.museum","history.museum","historyofscience.museum","horology.museum","house.museum","humanities.museum","illustration.museum","imageandsound.museum","indian.museum","indiana.museum","indianapolis.museum","indianmarket.museum","intelligence.museum","interactive.museum","iraq.museum","iron.museum","isleofman.museum","jamison.museum","jefferson.museum","jerusalem.museum","jewelry.museum","jewish.museum","jewishart.museum","jfk.museum","journalism.museum","judaica.museum","judygarland.museum","juedisches.museum","juif.museum","karate.museum","karikatur.museum","kids.museum","koebenhavn.museum","koeln.museum","kunst.museum","kunstsammlung.museum","kunstunddesign.museum","labor.museum","labour.museum","lajolla.museum","lancashire.museum","landes.museum","lans.museum","läns.museum","larsson.museum","lewismiller.museum","lincoln.museum","linz.museum","living.museum","livinghistory.museum","localhistory.museum","london.museum","losangeles.museum","louvre.museum","loyalist.museum","lucerne.museum","luxembourg.museum","luzern.museum","mad.museum","madrid.museum","mallorca.museum","manchester.museum","mansion.museum","mansions.museum","manx.museum","marburg.museum","maritime.museum","maritimo.museum","maryland.museum","marylhurst.museum","media.museum","medical.museum","medizinhistorisches.museum","meeres.museum","memorial.museum","mesaverde.museum","michigan.museum","midatlantic.museum","military.museum","mill.museum","miners.museum","mining.museum","minnesota.museum","missile.museum","missoula.museum","modern.museum","moma.museum","money.museum","monmouth.museum","monticello.museum","montreal.museum","moscow.museum","motorcycle.museum","muenchen.museum","muenster.museum","mulhouse.museum","muncie.museum","museet.museum","museumcenter.museum","museumvereniging.museum","music.museum","national.museum","nationalfirearms.museum","nationalheritage.museum","nativeamerican.museum","naturalhistory.museum","naturalhistorymuseum.museum","naturalsciences.museum","nature.museum","naturhistorisches.museum","natuurwetenschappen.museum","naumburg.museum","naval.museum","nebraska.museum","neues.museum","newhampshire.museum","newjersey.museum","newmexico.museum","newport.museum","newspaper.museum","newyork.museum","niepce.museum","norfolk.museum","north.museum","nrw.museum","nuernberg.museum","nuremberg.museum","nyc.museum","nyny.museum","oceanographic.museum","oceanographique.museum","omaha.museum","online.museum","ontario.museum","openair.museum","oregon.museum","oregontrail.museum","otago.museum","oxford.museum","pacific.museum","paderborn.museum","palace.museum","paleo.museum","palmsprings.museum","panama.museum","paris.museum","pasadena.museum","pharmacy.museum","philadelphia.museum","philadelphiaarea.museum","philately.museum","phoenix.museum","photography.museum","pilots.museum","pittsburgh.museum","planetarium.museum","plantation.museum","plants.museum","plaza.museum","portal.museum","portland.museum","portlligat.museum","posts-and-telecommunications.museum","preservation.museum","presidio.museum","press.museum","project.museum","public.museum","pubol.museum","quebec.museum","railroad.museum","railway.museum","research.museum","resistance.museum","riodejaneiro.museum","rochester.museum","rockart.museum","roma.museum","russia.museum","saintlouis.museum","salem.museum","salvadordali.museum","salzburg.museum","sandiego.museum","sanfrancisco.museum","santabarbara.museum","santacruz.museum","santafe.museum","saskatchewan.museum","satx.museum","savannahga.museum","schlesisches.museum","schoenbrunn.museum","schokoladen.museum","school.museum","schweiz.museum","science.museum","scienceandhistory.museum","scienceandindustry.museum","sciencecenter.museum","sciencecenters.museum","science-fiction.museum","sciencehistory.museum","sciences.museum","sciencesnaturelles.museum","scotland.museum","seaport.museum","settlement.museum","settlers.museum","shell.museum","sherbrooke.museum","sibenik.museum","silk.museum","ski.museum","skole.museum","society.museum","sologne.museum","soundandvision.museum","southcarolina.museum","southwest.museum","space.museum","spy.museum","square.museum","stadt.museum","stalbans.museum","starnberg.museum","state.museum","stateofdelaware.museum","station.museum","steam.museum","steiermark.museum","stjohn.museum","stockholm.museum","stpetersburg.museum","stuttgart.museum","suisse.museum","surgeonshall.museum","surrey.museum","svizzera.museum","sweden.museum","sydney.museum","tank.museum","tcm.museum","technology.museum","telekommunikation.museum","television.museum","texas.museum","textile.museum","theater.museum","time.museum","timekeeping.museum","topology.museum","torino.museum","touch.museum","town.museum","transport.museum","tree.museum","trolley.museum","trust.museum","trustee.museum","uhren.museum","ulm.museum","undersea.museum","university.museum","usa.museum","usantiques.museum","usarts.museum","uscountryestate.museum","usculture.museum","usdecorativearts.museum","usgarden.museum","ushistory.museum","ushuaia.museum","uslivinghistory.museum","utah.museum","uvic.museum","valley.museum","vantaa.museum","versailles.museum","viking.museum","village.museum","virginia.museum","virtual.museum","virtuel.museum","vlaanderen.museum","volkenkunde.museum","wales.museum","wallonie.museum","war.museum","washingtondc.museum","watchandclock.museum","watch-and-clock.museum","western.museum","westfalen.museum","whaling.museum","wildlife.museum","williamsburg.museum","windmill.museum","workshop.museum","york.museum","yorkshire.museum","yosemite.museum","youth.museum","zoological.museum","zoology.museum","ירושלים.museum","иком.museum","mv","aero.mv","biz.mv","com.mv","coop.mv","edu.mv","gov.mv","info.mv","int.mv","mil.mv","museum.mv","name.mv","net.mv","org.mv","pro.mv","mw","ac.mw","biz.mw","co.mw","com.mw","coop.mw","edu.mw","gov.mw","int.mw","museum.mw","net.mw","org.mw","mx","com.mx","org.mx","gob.mx","edu.mx","net.mx","my","com.my","net.my","org.my","gov.my","edu.my","mil.my","name.my","mz","ac.mz","adv.mz","co.mz","edu.mz","gov.mz","mil.mz","net.mz","org.mz","na","info.na","pro.na","name.na","school.na","or.na","dr.na","us.na","mx.na","ca.na","in.na","cc.na","tv.na","ws.na","mobi.na","co.na","com.na","org.na","name","nc","asso.nc","nom.nc","ne","net","nf","com.nf","net.nf","per.nf","rec.nf","web.nf","arts.nf","firm.nf","info.nf","other.nf","store.nf","ng","com.ng","edu.ng","gov.ng","i.ng","mil.ng","mobi.ng","name.ng","net.ng","org.ng","sch.ng","ni","ac.ni","biz.ni","co.ni","com.ni","edu.ni","gob.ni","in.ni","info.ni","int.ni","mil.ni","net.ni","nom.ni","org.ni","web.ni","nl","bv.nl","no","fhs.no","vgs.no","fylkesbibl.no","folkebibl.no","museum.no","idrett.no","priv.no","mil.no","stat.no","dep.no","kommune.no","herad.no","aa.no","ah.no","bu.no","fm.no","hl.no","hm.no","jan-mayen.no","mr.no","nl.no","nt.no","of.no","ol.no","oslo.no","rl.no","sf.no","st.no","svalbard.no","tm.no","tr.no","va.no","vf.no","gs.aa.no","gs.ah.no","gs.bu.no","gs.fm.no","gs.hl.no","gs.hm.no","gs.jan-mayen.no","gs.mr.no","gs.nl.no","gs.nt.no","gs.of.no","gs.ol.no","gs.oslo.no","gs.rl.no","gs.sf.no","gs.st.no","gs.svalbard.no","gs.tm.no","gs.tr.no","gs.va.no","gs.vf.no","akrehamn.no","åkrehamn.no","algard.no","ålgård.no","arna.no","brumunddal.no","bryne.no","bronnoysund.no","brønnøysund.no","drobak.no","drøbak.no","egersund.no","fetsund.no","floro.no","florø.no","fredrikstad.no","hokksund.no","honefoss.no","hønefoss.no","jessheim.no","jorpeland.no","jørpeland.no","kirkenes.no","kopervik.no","krokstadelva.no","langevag.no","langevåg.no","leirvik.no","mjondalen.no","mjøndalen.no","mo-i-rana.no","mosjoen.no","mosjøen.no","nesoddtangen.no","orkanger.no","osoyro.no","osøyro.no","raholt.no","råholt.no","sandnessjoen.no","sandnessjøen.no","skedsmokorset.no","slattum.no","spjelkavik.no","stathelle.no","stavern.no","stjordalshalsen.no","stjørdalshalsen.no","tananger.no","tranby.no","vossevangen.no","afjord.no","åfjord.no","agdenes.no","al.no","ål.no","alesund.no","ålesund.no","alstahaug.no","alta.no","áltá.no","alaheadju.no","álaheadju.no","alvdal.no","amli.no","åmli.no","amot.no","åmot.no","andebu.no","andoy.no","andøy.no","andasuolo.no","ardal.no","årdal.no","aremark.no","arendal.no","ås.no","aseral.no","åseral.no","asker.no","askim.no","askvoll.no","askoy.no","askøy.no","asnes.no","åsnes.no","audnedaln.no","aukra.no","aure.no","aurland.no","aurskog-holand.no","aurskog-høland.no","austevoll.no","austrheim.no","averoy.no","averøy.no","balestrand.no","ballangen.no","balat.no","bálát.no","balsfjord.no","bahccavuotna.no","báhccavuotna.no","bamble.no","bardu.no","beardu.no","beiarn.no","bajddar.no","bájddar.no","baidar.no","báidár.no","berg.no","bergen.no","berlevag.no","berlevåg.no","bearalvahki.no","bearalváhki.no","bindal.no","birkenes.no","bjarkoy.no","bjarkøy.no","bjerkreim.no","bjugn.no","bodo.no","bodø.no","badaddja.no","bådåddjå.no","budejju.no","bokn.no","bremanger.no","bronnoy.no","brønnøy.no","bygland.no","bykle.no","barum.no","bærum.no","bo.telemark.no","bø.telemark.no","bo.nordland.no","bø.nordland.no","bievat.no","bievát.no","bomlo.no","bømlo.no","batsfjord.no","båtsfjord.no","bahcavuotna.no","báhcavuotna.no","dovre.no","drammen.no","drangedal.no","dyroy.no","dyrøy.no","donna.no","dønna.no","eid.no","eidfjord.no","eidsberg.no","eidskog.no","eidsvoll.no","eigersund.no","elverum.no","enebakk.no","engerdal.no","etne.no","etnedal.no","evenes.no","evenassi.no","evenášši.no","evje-og-hornnes.no","farsund.no","fauske.no","fuossko.no","fuoisku.no","fedje.no","fet.no","finnoy.no","finnøy.no","fitjar.no","fjaler.no","fjell.no","flakstad.no","flatanger.no","flekkefjord.no","flesberg.no","flora.no","fla.no","flå.no","folldal.no","forsand.no","fosnes.no","frei.no","frogn.no","froland.no","frosta.no","frana.no","fræna.no","froya.no","frøya.no","fusa.no","fyresdal.no","forde.no","førde.no","gamvik.no","gangaviika.no","gáŋgaviika.no","gaular.no","gausdal.no","gildeskal.no","gildeskål.no","giske.no","gjemnes.no","gjerdrum.no","gjerstad.no","gjesdal.no","gjovik.no","gjøvik.no","gloppen.no","gol.no","gran.no","grane.no","granvin.no","gratangen.no","grimstad.no","grong.no","kraanghke.no","kråanghke.no","grue.no","gulen.no","hadsel.no","halden.no","halsa.no","hamar.no","hamaroy.no","habmer.no","hábmer.no","hapmir.no","hápmir.no","hammerfest.no","hammarfeasta.no","hámmárfeasta.no","haram.no","hareid.no","harstad.no","hasvik.no","aknoluokta.no","ákŋoluokta.no","hattfjelldal.no","aarborte.no","haugesund.no","hemne.no","hemnes.no","hemsedal.no","heroy.more-og-romsdal.no","herøy.møre-og-romsdal.no","heroy.nordland.no","herøy.nordland.no","hitra.no","hjartdal.no","hjelmeland.no","hobol.no","hobøl.no","hof.no","hol.no","hole.no","holmestrand.no","holtalen.no","holtålen.no","hornindal.no","horten.no","hurdal.no","hurum.no","hvaler.no","hyllestad.no","hagebostad.no","hægebostad.no","hoyanger.no","høyanger.no","hoylandet.no","høylandet.no","ha.no","hå.no","ibestad.no","inderoy.no","inderøy.no","iveland.no","jevnaker.no","jondal.no","jolster.no","jølster.no","karasjok.no","karasjohka.no","kárášjohka.no","karlsoy.no","galsa.no","gálsá.no","karmoy.no","karmøy.no","kautokeino.no","guovdageaidnu.no","klepp.no","klabu.no","klæbu.no","kongsberg.no","kongsvinger.no","kragero.no","kragerø.no","kristiansand.no","kristiansund.no","krodsherad.no","krødsherad.no","kvalsund.no","rahkkeravju.no","ráhkkerávju.no","kvam.no","kvinesdal.no","kvinnherad.no","kviteseid.no","kvitsoy.no","kvitsøy.no","kvafjord.no","kvæfjord.no","giehtavuoatna.no","kvanangen.no","kvænangen.no","navuotna.no","návuotna.no","kafjord.no","kåfjord.no","gaivuotna.no","gáivuotna.no","larvik.no","lavangen.no","lavagis.no","loabat.no","loabát.no","lebesby.no","davvesiida.no","leikanger.no","leirfjord.no","leka.no","leksvik.no","lenvik.no","leangaviika.no","leaŋgaviika.no","lesja.no","levanger.no","lier.no","lierne.no","lillehammer.no","lillesand.no","lindesnes.no","lindas.no","lindås.no","lom.no","loppa.no","lahppi.no","láhppi.no","lund.no","lunner.no","luroy.no","lurøy.no","luster.no","lyngdal.no","lyngen.no","ivgu.no","lardal.no","lerdal.no","lærdal.no","lodingen.no","lødingen.no","lorenskog.no","lørenskog.no","loten.no","løten.no","malvik.no","masoy.no","måsøy.no","muosat.no","muosát.no","mandal.no","marker.no","marnardal.no","masfjorden.no","meland.no","meldal.no","melhus.no","meloy.no","meløy.no","meraker.no","meråker.no","moareke.no","moåreke.no","midsund.no","midtre-gauldal.no","modalen.no","modum.no","molde.no","moskenes.no","moss.no","mosvik.no","malselv.no","målselv.no","malatvuopmi.no","málatvuopmi.no","namdalseid.no","aejrie.no","namsos.no","namsskogan.no","naamesjevuemie.no","nååmesjevuemie.no","laakesvuemie.no","nannestad.no","narvik.no","narviika.no","naustdal.no","nedre-eiker.no","nes.akershus.no","nes.buskerud.no","nesna.no","nesodden.no","nesseby.no","unjarga.no","unjárga.no","nesset.no","nissedal.no","nittedal.no","nord-aurdal.no","nord-fron.no","nord-odal.no","norddal.no","nordkapp.no","davvenjarga.no","davvenjárga.no","nordre-land.no","nordreisa.no","raisa.no","ráisa.no","nore-og-uvdal.no","notodden.no","naroy.no","nærøy.no","notteroy.no","nøtterøy.no","odda.no","oksnes.no","øksnes.no","oppdal.no","oppegard.no","oppegård.no","orkdal.no","orland.no","ørland.no","orskog.no","ørskog.no","orsta.no","ørsta.no","os.hedmark.no","os.hordaland.no","osen.no","osteroy.no","osterøy.no","ostre-toten.no","østre-toten.no","overhalla.no","ovre-eiker.no","øvre-eiker.no","oyer.no","øyer.no","oygarden.no","øygarden.no","oystre-slidre.no","øystre-slidre.no","porsanger.no","porsangu.no","porsáŋgu.no","porsgrunn.no","radoy.no","radøy.no","rakkestad.no","rana.no","ruovat.no","randaberg.no","rauma.no","rendalen.no","rennebu.no","rennesoy.no","rennesøy.no","rindal.no","ringebu.no","ringerike.no","ringsaker.no","rissa.no","risor.no","risør.no","roan.no","rollag.no","rygge.no","ralingen.no","rælingen.no","rodoy.no","rødøy.no","romskog.no","rømskog.no","roros.no","røros.no","rost.no","røst.no","royken.no","røyken.no","royrvik.no","røyrvik.no","rade.no","råde.no","salangen.no","siellak.no","saltdal.no","salat.no","sálát.no","sálat.no","samnanger.no","sande.more-og-romsdal.no","sande.møre-og-romsdal.no","sande.vestfold.no","sandefjord.no","sandnes.no","sandoy.no","sandøy.no","sarpsborg.no","sauda.no","sauherad.no","sel.no","selbu.no","selje.no","seljord.no","sigdal.no","siljan.no","sirdal.no","skaun.no","skedsmo.no","ski.no","skien.no","skiptvet.no","skjervoy.no","skjervøy.no","skierva.no","skiervá.no","skjak.no","skjåk.no","skodje.no","skanland.no","skånland.no","skanit.no","skánit.no","smola.no","smøla.no","snillfjord.no","snasa.no","snåsa.no","snoasa.no","snaase.no","snåase.no","sogndal.no","sokndal.no","sola.no","solund.no","songdalen.no","sortland.no","spydeberg.no","stange.no","stavanger.no","steigen.no","steinkjer.no","stjordal.no","stjørdal.no","stokke.no","stor-elvdal.no","stord.no","stordal.no","storfjord.no","omasvuotna.no","strand.no","stranda.no","stryn.no","sula.no","suldal.no","sund.no","sunndal.no","surnadal.no","sveio.no","svelvik.no","sykkylven.no","sogne.no","søgne.no","somna.no","sømna.no","sondre-land.no","søndre-land.no","sor-aurdal.no","sør-aurdal.no","sor-fron.no","sør-fron.no","sor-odal.no","sør-odal.no","sor-varanger.no","sør-varanger.no","matta-varjjat.no","mátta-várjjat.no","sorfold.no","sørfold.no","sorreisa.no","sørreisa.no","sorum.no","sørum.no","tana.no","deatnu.no","time.no","tingvoll.no","tinn.no","tjeldsund.no","dielddanuorri.no","tjome.no","tjøme.no","tokke.no","tolga.no","torsken.no","tranoy.no","tranøy.no","tromso.no","tromsø.no","tromsa.no","romsa.no","trondheim.no","troandin.no","trysil.no","trana.no","træna.no","trogstad.no","trøgstad.no","tvedestrand.no","tydal.no","tynset.no","tysfjord.no","divtasvuodna.no","divttasvuotna.no","tysnes.no","tysvar.no","tysvær.no","tonsberg.no","tønsberg.no","ullensaker.no","ullensvang.no","ulvik.no","utsira.no","vadso.no","vadsø.no","cahcesuolo.no","čáhcesuolo.no","vaksdal.no","valle.no","vang.no","vanylven.no","vardo.no","vardø.no","varggat.no","várggát.no","vefsn.no","vaapste.no","vega.no","vegarshei.no","vegårshei.no","vennesla.no","verdal.no","verran.no","vestby.no","vestnes.no","vestre-slidre.no","vestre-toten.no","vestvagoy.no","vestvågøy.no","vevelstad.no","vik.no","vikna.no","vindafjord.no","volda.no","voss.no","varoy.no","værøy.no","vagan.no","vågan.no","voagat.no","vagsoy.no","vågsøy.no","vaga.no","vågå.no","valer.ostfold.no","våler.østfold.no","valer.hedmark.no","våler.hedmark.no","*.np","nr","biz.nr","info.nr","gov.nr","edu.nr","org.nr","net.nr","com.nr","nu","nz","ac.nz","co.nz","cri.nz","geek.nz","gen.nz","govt.nz","health.nz","iwi.nz","kiwi.nz","maori.nz","mil.nz","māori.nz","net.nz","org.nz","parliament.nz","school.nz","om","co.om","com.om","edu.om","gov.om","med.om","museum.om","net.om","org.om","pro.om","onion","org","pa","ac.pa","gob.pa","com.pa","org.pa","sld.pa","edu.pa","net.pa","ing.pa","abo.pa","med.pa","nom.pa","pe","edu.pe","gob.pe","nom.pe","mil.pe","org.pe","com.pe","net.pe","pf","com.pf","org.pf","edu.pf","*.pg","ph","com.ph","net.ph","org.ph","gov.ph","edu.ph","ngo.ph","mil.ph","i.ph","pk","com.pk","net.pk","edu.pk","org.pk","fam.pk","biz.pk","web.pk","gov.pk","gob.pk","gok.pk","gon.pk","gop.pk","gos.pk","info.pk","pl","com.pl","net.pl","org.pl","aid.pl","agro.pl","atm.pl","auto.pl","biz.pl","edu.pl","gmina.pl","gsm.pl","info.pl","mail.pl","miasta.pl","media.pl","mil.pl","nieruchomosci.pl","nom.pl","pc.pl","powiat.pl","priv.pl","realestate.pl","rel.pl","sex.pl","shop.pl","sklep.pl","sos.pl","szkola.pl","targi.pl","tm.pl","tourism.pl","travel.pl","turystyka.pl","gov.pl","ap.gov.pl","ic.gov.pl","is.gov.pl","us.gov.pl","kmpsp.gov.pl","kppsp.gov.pl","kwpsp.gov.pl","psp.gov.pl","wskr.gov.pl","kwp.gov.pl","mw.gov.pl","ug.gov.pl","um.gov.pl","umig.gov.pl","ugim.gov.pl","upow.gov.pl","uw.gov.pl","starostwo.gov.pl","pa.gov.pl","po.gov.pl","psse.gov.pl","pup.gov.pl","rzgw.gov.pl","sa.gov.pl","so.gov.pl","sr.gov.pl","wsa.gov.pl","sko.gov.pl","uzs.gov.pl","wiih.gov.pl","winb.gov.pl","pinb.gov.pl","wios.gov.pl","witd.gov.pl","wzmiuw.gov.pl","piw.gov.pl","wiw.gov.pl","griw.gov.pl","wif.gov.pl","oum.gov.pl","sdn.gov.pl","zp.gov.pl","uppo.gov.pl","mup.gov.pl","wuoz.gov.pl","konsulat.gov.pl","oirm.gov.pl","augustow.pl","babia-gora.pl","bedzin.pl","beskidy.pl","bialowieza.pl","bialystok.pl","bielawa.pl","bieszczady.pl","boleslawiec.pl","bydgoszcz.pl","bytom.pl","cieszyn.pl","czeladz.pl","czest.pl","dlugoleka.pl","elblag.pl","elk.pl","glogow.pl","gniezno.pl","gorlice.pl","grajewo.pl","ilawa.pl","jaworzno.pl","jelenia-gora.pl","jgora.pl","kalisz.pl","kazimierz-dolny.pl","karpacz.pl","kartuzy.pl","kaszuby.pl","katowice.pl","kepno.pl","ketrzyn.pl","klodzko.pl","kobierzyce.pl","kolobrzeg.pl","konin.pl","konskowola.pl","kutno.pl","lapy.pl","lebork.pl","legnica.pl","lezajsk.pl","limanowa.pl","lomza.pl","lowicz.pl","lubin.pl","lukow.pl","malbork.pl","malopolska.pl","mazowsze.pl","mazury.pl","mielec.pl","mielno.pl","mragowo.pl","naklo.pl","nowaruda.pl","nysa.pl","olawa.pl","olecko.pl","olkusz.pl","olsztyn.pl","opoczno.pl","opole.pl","ostroda.pl","ostroleka.pl","ostrowiec.pl","ostrowwlkp.pl","pila.pl","pisz.pl","podhale.pl","podlasie.pl","polkowice.pl","pomorze.pl","pomorskie.pl","prochowice.pl","pruszkow.pl","przeworsk.pl","pulawy.pl","radom.pl","rawa-maz.pl","rybnik.pl","rzeszow.pl","sanok.pl","sejny.pl","slask.pl","slupsk.pl","sosnowiec.pl","stalowa-wola.pl","skoczow.pl","starachowice.pl","stargard.pl","suwalki.pl","swidnica.pl","swiebodzin.pl","swinoujscie.pl","szczecin.pl","szczytno.pl","tarnobrzeg.pl","tgory.pl","turek.pl","tychy.pl","ustka.pl","walbrzych.pl","warmia.pl","warszawa.pl","waw.pl","wegrow.pl","wielun.pl","wlocl.pl","wloclawek.pl","wodzislaw.pl","wolomin.pl","wroclaw.pl","zachpomor.pl","zagan.pl","zarow.pl","zgora.pl","zgorzelec.pl","pm","pn","gov.pn","co.pn","org.pn","edu.pn","net.pn","post","pr","com.pr","net.pr","org.pr","gov.pr","edu.pr","isla.pr","pro.pr","biz.pr","info.pr","name.pr","est.pr","prof.pr","ac.pr","pro","aaa.pro","aca.pro","acct.pro","avocat.pro","bar.pro","cpa.pro","eng.pro","jur.pro","law.pro","med.pro","recht.pro","ps","edu.ps","gov.ps","sec.ps","plo.ps","com.ps","org.ps","net.ps","pt","net.pt","gov.pt","org.pt","edu.pt","int.pt","publ.pt","com.pt","nome.pt","pw","co.pw","ne.pw","or.pw","ed.pw","go.pw","belau.pw","py","com.py","coop.py","edu.py","gov.py","mil.py","net.py","org.py","qa","com.qa","edu.qa","gov.qa","mil.qa","name.qa","net.qa","org.qa","sch.qa","re","asso.re","com.re","nom.re","ro","arts.ro","com.ro","firm.ro","info.ro","nom.ro","nt.ro","org.ro","rec.ro","store.ro","tm.ro","www.ro","rs","ac.rs","co.rs","edu.rs","gov.rs","in.rs","org.rs","ru","ac.ru","edu.ru","gov.ru","int.ru","mil.ru","test.ru","rw","gov.rw","net.rw","edu.rw","ac.rw","com.rw","co.rw","int.rw","mil.rw","gouv.rw","sa","com.sa","net.sa","org.sa","gov.sa","med.sa","pub.sa","edu.sa","sch.sa","sb","com.sb","edu.sb","gov.sb","net.sb","org.sb","sc","com.sc","gov.sc","net.sc","org.sc","edu.sc","sd","com.sd","net.sd","org.sd","edu.sd","med.sd","tv.sd","gov.sd","info.sd","se","a.se","ac.se","b.se","bd.se","brand.se","c.se","d.se","e.se","f.se","fh.se","fhsk.se","fhv.se","g.se","h.se","i.se","k.se","komforb.se","kommunalforbund.se","komvux.se","l.se","lanbib.se","m.se","n.se","naturbruksgymn.se","o.se","org.se","p.se","parti.se","pp.se","press.se","r.se","s.se","t.se","tm.se","u.se","w.se","x.se","y.se","z.se","sg","com.sg","net.sg","org.sg","gov.sg","edu.sg","per.sg","sh","com.sh","net.sh","gov.sh","org.sh","mil.sh","si","sj","sk","sl","com.sl","net.sl","edu.sl","gov.sl","org.sl","sm","sn","art.sn","com.sn","edu.sn","gouv.sn","org.sn","perso.sn","univ.sn","so","com.so","net.so","org.so","sr","st","co.st","com.st","consulado.st","edu.st","embaixada.st","gov.st","mil.st","net.st","org.st","principe.st","saotome.st","store.st","su","sv","com.sv","edu.sv","gob.sv","org.sv","red.sv","sx","gov.sx","sy","edu.sy","gov.sy","net.sy","mil.sy","com.sy","org.sy","sz","co.sz","ac.sz","org.sz","tc","td","tel","tf","tg","th","ac.th","co.th","go.th","in.th","mi.th","net.th","or.th","tj","ac.tj","biz.tj","co.tj","com.tj","edu.tj","go.tj","gov.tj","int.tj","mil.tj","name.tj","net.tj","nic.tj","org.tj","test.tj","web.tj","tk","tl","gov.tl","tm","com.tm","co.tm","org.tm","net.tm","nom.tm","gov.tm","mil.tm","edu.tm","tn","com.tn","ens.tn","fin.tn","gov.tn","ind.tn","intl.tn","nat.tn","net.tn","org.tn","info.tn","perso.tn","tourism.tn","edunet.tn","rnrt.tn","rns.tn","rnu.tn","mincom.tn","agrinet.tn","defense.tn","turen.tn","to","com.to","gov.to","net.to","org.to","edu.to","mil.to","tr","com.tr","info.tr","biz.tr","net.tr","org.tr","web.tr","gen.tr","tv.tr","av.tr","dr.tr","bbs.tr","name.tr","tel.tr","gov.tr","bel.tr","pol.tr","mil.tr","k12.tr","edu.tr","kep.tr","nc.tr","gov.nc.tr","tt","co.tt","com.tt","org.tt","net.tt","biz.tt","info.tt","pro.tt","int.tt","coop.tt","jobs.tt","mobi.tt","travel.tt","museum.tt","aero.tt","name.tt","gov.tt","edu.tt","tv","tw","edu.tw","gov.tw","mil.tw","com.tw","net.tw","org.tw","idv.tw","game.tw","ebiz.tw","club.tw","網路.tw","組織.tw","商業.tw","tz","ac.tz","co.tz","go.tz","hotel.tz","info.tz","me.tz","mil.tz","mobi.tz","ne.tz","or.tz","sc.tz","tv.tz","ua","com.ua","edu.ua","gov.ua","in.ua","net.ua","org.ua","cherkassy.ua","cherkasy.ua","chernigov.ua","chernihiv.ua","chernivtsi.ua","chernovtsy.ua","ck.ua","cn.ua","cr.ua","crimea.ua","cv.ua","dn.ua","dnepropetrovsk.ua","dnipropetrovsk.ua","dominic.ua","donetsk.ua","dp.ua","if.ua","ivano-frankivsk.ua","kh.ua","kharkiv.ua","kharkov.ua","kherson.ua","khmelnitskiy.ua","khmelnytskyi.ua","kiev.ua","kirovograd.ua","km.ua","kr.ua","krym.ua","ks.ua","kv.ua","kyiv.ua","lg.ua","lt.ua","lugansk.ua","lutsk.ua","lv.ua","lviv.ua","mk.ua","mykolaiv.ua","nikolaev.ua","od.ua","odesa.ua","odessa.ua","pl.ua","poltava.ua","rivne.ua","rovno.ua","rv.ua","sb.ua","sebastopol.ua","sevastopol.ua","sm.ua","sumy.ua","te.ua","ternopil.ua","uz.ua","uzhgorod.ua","vinnica.ua","vinnytsia.ua","vn.ua","volyn.ua","yalta.ua","zaporizhzhe.ua","zaporizhzhia.ua","zhitomir.ua","zhytomyr.ua","zp.ua","zt.ua","ug","co.ug","or.ug","ac.ug","sc.ug","go.ug","ne.ug","com.ug","org.ug","uk","ac.uk","co.uk","gov.uk","ltd.uk","me.uk","net.uk","nhs.uk","org.uk","plc.uk","police.uk","*.sch.uk","us","dni.us","fed.us","isa.us","kids.us","nsn.us","ak.us","al.us","ar.us","as.us","az.us","ca.us","co.us","ct.us","dc.us","de.us","fl.us","ga.us","gu.us","hi.us","ia.us","id.us","il.us","in.us","ks.us","ky.us","la.us","ma.us","md.us","me.us","mi.us","mn.us","mo.us","ms.us","mt.us","nc.us","nd.us","ne.us","nh.us","nj.us","nm.us","nv.us","ny.us","oh.us","ok.us","or.us","pa.us","pr.us","ri.us","sc.us","sd.us","tn.us","tx.us","ut.us","vi.us","vt.us","va.us","wa.us","wi.us","wv.us","wy.us","k12.ak.us","k12.al.us","k12.ar.us","k12.as.us","k12.az.us","k12.ca.us","k12.co.us","k12.ct.us","k12.dc.us","k12.de.us","k12.fl.us","k12.ga.us","k12.gu.us","k12.ia.us","k12.id.us","k12.il.us","k12.in.us","k12.ks.us","k12.ky.us","k12.la.us","k12.ma.us","k12.md.us","k12.me.us","k12.mi.us","k12.mn.us","k12.mo.us","k12.ms.us","k12.mt.us","k12.nc.us","k12.ne.us","k12.nh.us","k12.nj.us","k12.nm.us","k12.nv.us","k12.ny.us","k12.oh.us","k12.ok.us","k12.or.us","k12.pa.us","k12.pr.us","k12.ri.us","k12.sc.us","k12.tn.us","k12.tx.us","k12.ut.us","k12.vi.us","k12.vt.us","k12.va.us","k12.wa.us","k12.wi.us","k12.wy.us","cc.ak.us","cc.al.us","cc.ar.us","cc.as.us","cc.az.us","cc.ca.us","cc.co.us","cc.ct.us","cc.dc.us","cc.de.us","cc.fl.us","cc.ga.us","cc.gu.us","cc.hi.us","cc.ia.us","cc.id.us","cc.il.us","cc.in.us","cc.ks.us","cc.ky.us","cc.la.us","cc.ma.us","cc.md.us","cc.me.us","cc.mi.us","cc.mn.us","cc.mo.us","cc.ms.us","cc.mt.us","cc.nc.us","cc.nd.us","cc.ne.us","cc.nh.us","cc.nj.us","cc.nm.us","cc.nv.us","cc.ny.us","cc.oh.us","cc.ok.us","cc.or.us","cc.pa.us","cc.pr.us","cc.ri.us","cc.sc.us","cc.sd.us","cc.tn.us","cc.tx.us","cc.ut.us","cc.vi.us","cc.vt.us","cc.va.us","cc.wa.us","cc.wi.us","cc.wv.us","cc.wy.us","lib.ak.us","lib.al.us","lib.ar.us","lib.as.us","lib.az.us","lib.ca.us","lib.co.us","lib.ct.us","lib.dc.us","lib.fl.us","lib.ga.us","lib.gu.us","lib.hi.us","lib.ia.us","lib.id.us","lib.il.us","lib.in.us","lib.ks.us","lib.ky.us","lib.la.us","lib.ma.us","lib.md.us","lib.me.us","lib.mi.us","lib.mn.us","lib.mo.us","lib.ms.us","lib.mt.us","lib.nc.us","lib.nd.us","lib.ne.us","lib.nh.us","lib.nj.us","lib.nm.us","lib.nv.us","lib.ny.us","lib.oh.us","lib.ok.us","lib.or.us","lib.pa.us","lib.pr.us","lib.ri.us","lib.sc.us","lib.sd.us","lib.tn.us","lib.tx.us","lib.ut.us","lib.vi.us","lib.vt.us","lib.va.us","lib.wa.us","lib.wi.us","lib.wy.us","pvt.k12.ma.us","chtr.k12.ma.us","paroch.k12.ma.us","ann-arbor.mi.us","cog.mi.us","dst.mi.us","eaton.mi.us","gen.mi.us","mus.mi.us","tec.mi.us","washtenaw.mi.us","uy","com.uy","edu.uy","gub.uy","mil.uy","net.uy","org.uy","uz","co.uz","com.uz","net.uz","org.uz","va","vc","com.vc","net.vc","org.vc","gov.vc","mil.vc","edu.vc","ve","arts.ve","co.ve","com.ve","e12.ve","edu.ve","firm.ve","gob.ve","gov.ve","info.ve","int.ve","mil.ve","net.ve","org.ve","rec.ve","store.ve","tec.ve","web.ve","vg","vi","co.vi","com.vi","k12.vi","net.vi","org.vi","vn","com.vn","net.vn","org.vn","edu.vn","gov.vn","int.vn","ac.vn","biz.vn","info.vn","name.vn","pro.vn","health.vn","vu","com.vu","edu.vu","net.vu","org.vu","wf","ws","com.ws","net.ws","org.ws","gov.ws","edu.ws","yt","امارات","հայ","বাংলা","бг","бел","中国","中國","الجزائر","مصر","ею","გე","ελ","香港","公司.香港","教育.香港","政府.香港","個人.香港","網絡.香港","組織.香港","ಭಾರತ","ଭାରତ","ভাৰত","भारतम्","भारोत","ڀارت","ഭാരതം","भारत","بارت","بھارت","భారత్","ભારત","ਭਾਰਤ","ভারত","இந்தியா","ایران","ايران","عراق","الاردن","한국","қаз","ලංකා","இலங்கை","المغرب","мкд","мон","澳門","澳门","مليسيا","عمان","پاکستان","پاكستان","فلسطين","срб","пр.срб","орг.срб","обр.срб","од.срб","упр.срб","ак.срб","рф","قطر","السعودية","السعودیة","السعودیۃ","السعوديه","سودان","新加坡","சிங்கப்பூர்","سورية","سوريا","ไทย","ศึกษา.ไทย","ธุรกิจ.ไทย","รัฐบาล.ไทย","ทหาร.ไทย","เน็ต.ไทย","องค์กร.ไทย","تونس","台灣","台湾","臺灣","укр","اليمن","xxx","*.ye","ac.za","agric.za","alt.za","co.za","edu.za","gov.za","grondar.za","law.za","mil.za","net.za","ngo.za","nis.za","nom.za","org.za","school.za","tm.za","web.za","zm","ac.zm","biz.zm","co.zm","com.zm","edu.zm","gov.zm","info.zm","mil.zm","net.zm","org.zm","sch.zm","zw","ac.zw","co.zw","gov.zw","mil.zw","org.zw","aaa","aarp","abarth","abb","abbott","abbvie","abc","able","abogado","abudhabi","academy","accenture","accountant","accountants","aco","active","actor","adac","ads","adult","aeg","aetna","afamilycompany","afl","africa","agakhan","agency","aig","aigo","airbus","airforce","airtel","akdn","alfaromeo","alibaba","alipay","allfinanz","allstate","ally","alsace","alstom","americanexpress","americanfamily","amex","amfam","amica","amsterdam","analytics","android","anquan","anz","aol","apartments","app","apple","aquarelle","arab","aramco","archi","army","art","arte","asda","associates","athleta","attorney","auction","audi","audible","audio","auspost","author","auto","autos","avianca","aws","axa","azure","baby","baidu","banamex","bananarepublic","band","bank","bar","barcelona","barclaycard","barclays","barefoot","bargains","baseball","basketball","bauhaus","bayern","bbc","bbt","bbva","bcg","bcn","beats","beauty","beer","bentley","berlin","best","bestbuy","bet","bharti","bible","bid","bike","bing","bingo","bio","black","blackfriday","blanco","blockbuster","blog","bloomberg","blue","bms","bmw","bnl","bnpparibas","boats","boehringer","bofa","bom","bond","boo","book","booking","bosch","bostik","boston","bot","boutique","box","bradesco","bridgestone","broadway","broker","brother","brussels","budapest","bugatti","build","builders","business","buy","buzz","bzh","cab","cafe","cal","call","calvinklein","cam","camera","camp","cancerresearch","canon","capetown","capital","capitalone","car","caravan","cards","care","career","careers","cars","cartier","casa","case","caseih","cash","casino","catering","catholic","cba","cbn","cbre","cbs","ceb","center","ceo","cern","cfa","cfd","chanel","channel","charity","chase","chat","cheap","chintai","christmas","chrome","chrysler","church","cipriani","circle","cisco","citadel","citi","citic","city","cityeats","claims","cleaning","click","clinic","clinique","clothing","cloud","club","clubmed","coach","codes","coffee","college","cologne","comcast","commbank","community","company","compare","computer","comsec","condos","construction","consulting","contact","contractors","cooking","cookingchannel","cool","corsica","country","coupon","coupons","courses","credit","creditcard","creditunion","cricket","crown","crs","cruise","cruises","csc","cuisinella","cymru","cyou","dabur","dad","dance","data","date","dating","datsun","day","dclk","dds","deal","dealer","deals","degree","delivery","dell","deloitte","delta","democrat","dental","dentist","desi","design","dev","dhl","diamonds","diet","digital","direct","directory","discount","discover","dish","diy","dnp","docs","doctor","dodge","dog","doha","domains","dot","download","drive","dtv","dubai","duck","dunlop","duns","dupont","durban","dvag","dvr","earth","eat","eco","edeka","education","email","emerck","energy","engineer","engineering","enterprises","epost","epson","equipment","ericsson","erni","esq","estate","esurance","etisalat","eurovision","eus","events","everbank","exchange","expert","exposed","express","extraspace","fage","fail","fairwinds","faith","family","fan","fans","farm","farmers","fashion","fast","fedex","feedback","ferrari","ferrero","fiat","fidelity","fido","film","final","finance","financial","fire","firestone","firmdale","fish","fishing","fit","fitness","flickr","flights","flir","florist","flowers","fly","foo","food","foodnetwork","football","ford","forex","forsale","forum","foundation","fox","free","fresenius","frl","frogans","frontdoor","frontier","ftr","fujitsu","fujixerox","fun","fund","furniture","futbol","fyi","gal","gallery","gallo","gallup","game","games","gap","garden","gbiz","gdn","gea","gent","genting","george","ggee","gift","gifts","gives","giving","glade","glass","gle","global","globo","gmail","gmbh","gmo","gmx","godaddy","gold","goldpoint","golf","goo","goodhands","goodyear","goog","google","gop","got","grainger","graphics","gratis","green","gripe","grocery","group","guardian","gucci","guge","guide","guitars","guru","hair","hamburg","hangout","haus","hbo","hdfc","hdfcbank","health","healthcare","help","helsinki","here","hermes","hgtv","hiphop","hisamitsu","hitachi","hiv","hkt","hockey","holdings","holiday","homedepot","homegoods","homes","homesense","honda","honeywell","horse","hospital","host","hosting","hot","hoteles","hotels","hotmail","house","how","hsbc","hughes","hyatt","hyundai","ibm","icbc","ice","icu","ieee","ifm","ikano","imamat","imdb","immo","immobilien","inc","industries","infiniti","ing","ink","institute","insurance","insure","intel","international","intuit","investments","ipiranga","irish","iselect","ismaili","ist","istanbul","itau","itv","iveco","jaguar","java","jcb","jcp","jeep","jetzt","jewelry","jio","jlc","jll","jmp","jnj","joburg","jot","joy","jpmorgan","jprs","juegos","juniper","kaufen","kddi","kerryhotels","kerrylogistics","kerryproperties","kfh","kia","kim","kinder","kindle","kitchen","kiwi","koeln","komatsu","kosher","kpmg","kpn","krd","kred","kuokgroup","kyoto","lacaixa","ladbrokes","lamborghini","lamer","lancaster","lancia","lancome","land","landrover","lanxess","lasalle","lat","latino","latrobe","law","lawyer","lds","lease","leclerc","lefrak","legal","lego","lexus","lgbt","liaison","lidl","life","lifeinsurance","lifestyle","lighting","like","lilly","limited","limo","lincoln","linde","link","lipsy","live","living","lixil","llc","loan","loans","locker","locus","loft","lol","london","lotte","lotto","love","lpl","lplfinancial","ltd","ltda","lundbeck","lupin","luxe","luxury","macys","madrid","maif","maison","makeup","man","management","mango","map","market","marketing","markets","marriott","marshalls","maserati","mattel","mba","mckinsey","med","media","meet","melbourne","meme","memorial","men","menu","merckmsd","metlife","miami","microsoft","mini","mint","mit","mitsubishi","mlb","mls","mma","mobile","mobily","moda","moe","moi","mom","monash","money","monster","mopar","mormon","mortgage","moscow","moto","motorcycles","mov","movie","movistar","msd","mtn","mtr","mutual","nab","nadex","nagoya","nationwide","natura","navy","nba","nec","netbank","netflix","network","neustar","new","newholland","news","next","nextdirect","nexus","nfl","ngo","nhk","nico","nike","nikon","ninja","nissan","nissay","nokia","northwesternmutual","norton","now","nowruz","nowtv","nra","nrw","ntt","nyc","obi","observer","off","office","okinawa","olayan","olayangroup","oldnavy","ollo","omega","one","ong","onl","online","onyourside","ooo","open","oracle","orange","organic","origins","osaka","otsuka","ott","ovh","page","panasonic","panerai","paris","pars","partners","parts","party","passagens","pay","pccw","pet","pfizer","pharmacy","phd","philips","phone","photo","photography","photos","physio","piaget","pics","pictet","pictures","pid","pin","ping","pink","pioneer","pizza","place","play","playstation","plumbing","plus","pnc","pohl","poker","politie","porn","pramerica","praxi","press","prime","prod","productions","prof","progressive","promo","properties","property","protection","pru","prudential","pub","pwc","qpon","quebec","quest","qvc","racing","radio","raid","read","realestate","realtor","realty","recipes","red","redstone","redumbrella","rehab","reise","reisen","reit","reliance","ren","rent","rentals","repair","report","republican","rest","restaurant","review","reviews","rexroth","rich","richardli","ricoh","rightathome","ril","rio","rip","rmit","rocher","rocks","rodeo","rogers","room","rsvp","rugby","ruhr","run","rwe","ryukyu","saarland","safe","safety","sakura","sale","salon","samsclub","samsung","sandvik","sandvikcoromant","sanofi","sap","sarl","sas","save","saxo","sbi","sbs","sca","scb","schaeffler","schmidt","scholarships","school","schule","schwarz","science","scjohnson","scor","scot","search","seat","secure","security","seek","select","sener","services","ses","seven","sew","sex","sexy","sfr","shangrila","sharp","shaw","shell","shia","shiksha","shoes","shop","shopping","shouji","show","showtime","shriram","silk","sina","singles","site","ski","skin","sky","skype","sling","smart","smile","sncf","soccer","social","softbank","software","sohu","solar","solutions","song","sony","soy","space","spiegel","sport","spot","spreadbetting","srl","srt","stada","staples","star","starhub","statebank","statefarm","statoil","stc","stcgroup","stockholm","storage","store","stream","studio","study","style","sucks","supplies","supply","support","surf","surgery","suzuki","swatch","swiftcover","swiss","sydney","symantec","systems","tab","taipei","talk","taobao","target","tatamotors","tatar","tattoo","tax","taxi","tci","tdk","team","tech","technology","telecity","telefonica","temasek","tennis","teva","thd","theater","theatre","tiaa","tickets","tienda","tiffany","tips","tires","tirol","tjmaxx","tjx","tkmaxx","tmall","today","tokyo","tools","top","toray","toshiba","total","tours","town","toyota","toys","trade","trading","training","travel","travelchannel","travelers","travelersinsurance","trust","trv","tube","tui","tunes","tushu","tvs","ubank","ubs","uconnect","unicom","university","uno","uol","ups","vacations","vana","vanguard","vegas","ventures","verisign","versicherung","vet","viajes","video","vig","viking","villas","vin","vip","virgin","visa","vision","vista","vistaprint","viva","vivo","vlaanderen","vodka","volkswagen","volvo","vote","voting","voto","voyage","vuelos","wales","walmart","walter","wang","wanggou","warman","watch","watches","weather","weatherchannel","webcam","weber","website","wed","wedding","weibo","weir","whoswho","wien","wiki","williamhill","win","windows","wine","winners","wme","wolterskluwer","woodside","work","works","world","wow","wtc","wtf","xbox","xerox","xfinity","xihuan","xin","कॉम","セール","佛山","慈善","集团","在线","大众汽车","点看","คอม","八卦","موقع","公益","公司","香格里拉","网站","移动","我爱你","москва","католик","онлайн","сайт","联通","קום","时尚","微博","淡马锡","ファッション","орг","नेट","ストア","삼성","商标","商店","商城","дети","ポイント","新闻","工行","家電","كوم","中文网","中信","娱乐","谷歌","電訊盈科","购物","クラウド","通販","网店","संगठन","餐厅","网络","ком","诺基亚","食品","飞利浦","手表","手机","ارامكو","العليان","اتصالات","بازار","موبايلي","ابوظبي","كاثوليك","همراه","닷컴","政府","شبكة","بيتك","عرب","机构","组织机构","健康","招聘","рус","珠宝","大拿","みんな","グーグル","世界","書籍","网址","닷넷","コム","天主教","游戏","vermögensberater","vermögensberatung","企业","信息","嘉里大酒店","嘉里","广东","政务","xyz","yachts","yahoo","yamaxun","yandex","yodobashi","yoga","yokohama","you","youtube","yun","zappos","zara","zero","zip","zippo","zone","zuerich","cc.ua","inf.ua","ltd.ua","beep.pl","*.compute.estate","*.alces.network","alwaysdata.net","cloudfront.net","*.compute.amazonaws.com","*.compute-1.amazonaws.com","*.compute.amazonaws.com.cn","us-east-1.amazonaws.com","cn-north-1.eb.amazonaws.com.cn","elasticbeanstalk.com","ap-northeast-1.elasticbeanstalk.com","ap-northeast-2.elasticbeanstalk.com","ap-northeast-3.elasticbeanstalk.com","ap-south-1.elasticbeanstalk.com","ap-southeast-1.elasticbeanstalk.com","ap-southeast-2.elasticbeanstalk.com","ca-central-1.elasticbeanstalk.com","eu-central-1.elasticbeanstalk.com","eu-west-1.elasticbeanstalk.com","eu-west-2.elasticbeanstalk.com","eu-west-3.elasticbeanstalk.com","sa-east-1.elasticbeanstalk.com","us-east-1.elasticbeanstalk.com","us-east-2.elasticbeanstalk.com","us-gov-west-1.elasticbeanstalk.com","us-west-1.elasticbeanstalk.com","us-west-2.elasticbeanstalk.com","*.elb.amazonaws.com","*.elb.amazonaws.com.cn","s3.amazonaws.com","s3-ap-northeast-1.amazonaws.com","s3-ap-northeast-2.amazonaws.com","s3-ap-south-1.amazonaws.com","s3-ap-southeast-1.amazonaws.com","s3-ap-southeast-2.amazonaws.com","s3-ca-central-1.amazonaws.com","s3-eu-central-1.amazonaws.com","s3-eu-west-1.amazonaws.com","s3-eu-west-2.amazonaws.com","s3-eu-west-3.amazonaws.com","s3-external-1.amazonaws.com","s3-fips-us-gov-west-1.amazonaws.com","s3-sa-east-1.amazonaws.com","s3-us-gov-west-1.amazonaws.com","s3-us-east-2.amazonaws.com","s3-us-west-1.amazonaws.com","s3-us-west-2.amazonaws.com","s3.ap-northeast-2.amazonaws.com","s3.ap-south-1.amazonaws.com","s3.cn-north-1.amazonaws.com.cn","s3.ca-central-1.amazonaws.com","s3.eu-central-1.amazonaws.com","s3.eu-west-2.amazonaws.com","s3.eu-west-3.amazonaws.com","s3.us-east-2.amazonaws.com","s3.dualstack.ap-northeast-1.amazonaws.com","s3.dualstack.ap-northeast-2.amazonaws.com","s3.dualstack.ap-south-1.amazonaws.com","s3.dualstack.ap-southeast-1.amazonaws.com","s3.dualstack.ap-southeast-2.amazonaws.com","s3.dualstack.ca-central-1.amazonaws.com","s3.dualstack.eu-central-1.amazonaws.com","s3.dualstack.eu-west-1.amazonaws.com","s3.dualstack.eu-west-2.amazonaws.com","s3.dualstack.eu-west-3.amazonaws.com","s3.dualstack.sa-east-1.amazonaws.com","s3.dualstack.us-east-1.amazonaws.com","s3.dualstack.us-east-2.amazonaws.com","s3-website-us-east-1.amazonaws.com","s3-website-us-west-1.amazonaws.com","s3-website-us-west-2.amazonaws.com","s3-website-ap-northeast-1.amazonaws.com","s3-website-ap-southeast-1.amazonaws.com","s3-website-ap-southeast-2.amazonaws.com","s3-website-eu-west-1.amazonaws.com","s3-website-sa-east-1.amazonaws.com","s3-website.ap-northeast-2.amazonaws.com","s3-website.ap-south-1.amazonaws.com","s3-website.ca-central-1.amazonaws.com","s3-website.eu-central-1.amazonaws.com","s3-website.eu-west-2.amazonaws.com","s3-website.eu-west-3.amazonaws.com","s3-website.us-east-2.amazonaws.com","t3l3p0rt.net","tele.amune.org","on-aptible.com","user.party.eus","pimienta.org","poivron.org","potager.org","sweetpepper.org","myasustor.com","myfritz.net","*.awdev.ca","*.advisor.ws","backplaneapp.io","betainabox.com","bnr.la","blackbaudcdn.net","boomla.net","boxfuse.io","square7.ch","bplaced.com","bplaced.de","square7.de","bplaced.net","square7.net","browsersafetymark.io","mycd.eu","ae.org","ar.com","br.com","cn.com","com.de","com.se","de.com","eu.com","gb.com","gb.net","hu.com","hu.net","jp.net","jpn.com","kr.com","mex.com","no.com","qc.com","ru.com","sa.com","se.net","uk.com","uk.net","us.com","uy.com","za.bz","za.com","africa.com","gr.com","in.net","us.org","co.com","c.la","certmgr.org","xenapponazure.com","virtueeldomein.nl","cleverapps.io","c66.me","cloud66.ws","jdevcloud.com","wpdevcloud.com","cloudaccess.host","freesite.host","cloudaccess.net","cloudcontrolled.com","cloudcontrolapp.com","co.ca","*.otap.co","co.cz","c.cdn77.org","cdn77-ssl.net","r.cdn77.net","rsc.cdn77.org","ssl.origin.cdn77-secure.org","cloudns.asia","cloudns.biz","cloudns.club","cloudns.cc","cloudns.eu","cloudns.in","cloudns.info","cloudns.org","cloudns.pro","cloudns.pw","cloudns.us","cloudeity.net","cnpy.gdn","co.nl","co.no","webhosting.be","hosting-cluster.nl","dyn.cosidns.de","dynamisches-dns.de","dnsupdater.de","internet-dns.de","l-o-g-i-n.de","dynamic-dns.info","feste-ip.net","knx-server.net","static-access.net","realm.cz","*.cryptonomic.net","cupcake.is","cyon.link","cyon.site","daplie.me","localhost.daplie.me","dattolocal.com","dattorelay.com","dattoweb.com","mydatto.com","dattolocal.net","mydatto.net","biz.dk","co.dk","firm.dk","reg.dk","store.dk","debian.net","dedyn.io","dnshome.de","drayddns.com","dreamhosters.com","mydrobo.com","drud.io","drud.us","duckdns.org","dy.fi","tunk.org","dyndns-at-home.com","dyndns-at-work.com","dyndns-blog.com","dyndns-free.com","dyndns-home.com","dyndns-ip.com","dyndns-mail.com","dyndns-office.com","dyndns-pics.com","dyndns-remote.com","dyndns-server.com","dyndns-web.com","dyndns-wiki.com","dyndns-work.com","dyndns.biz","dyndns.info","dyndns.org","dyndns.tv","at-band-camp.net","ath.cx","barrel-of-knowledge.info","barrell-of-knowledge.info","better-than.tv","blogdns.com","blogdns.net","blogdns.org","blogsite.org","boldlygoingnowhere.org","broke-it.net","buyshouses.net","cechire.com","dnsalias.com","dnsalias.net","dnsalias.org","dnsdojo.com","dnsdojo.net","dnsdojo.org","does-it.net","doesntexist.com","doesntexist.org","dontexist.com","dontexist.net","dontexist.org","doomdns.com","doomdns.org","dvrdns.org","dyn-o-saur.com","dynalias.com","dynalias.net","dynalias.org","dynathome.net","dyndns.ws","endofinternet.net","endofinternet.org","endoftheinternet.org","est-a-la-maison.com","est-a-la-masion.com","est-le-patron.com","est-mon-blogueur.com","for-better.biz","for-more.biz","for-our.info","for-some.biz","for-the.biz","forgot.her.name","forgot.his.name","from-ak.com","from-al.com","from-ar.com","from-az.net","from-ca.com","from-co.net","from-ct.com","from-dc.com","from-de.com","from-fl.com","from-ga.com","from-hi.com","from-ia.com","from-id.com","from-il.com","from-in.com","from-ks.com","from-ky.com","from-la.net","from-ma.com","from-md.com","from-me.org","from-mi.com","from-mn.com","from-mo.com","from-ms.com","from-mt.com","from-nc.com","from-nd.com","from-ne.com","from-nh.com","from-nj.com","from-nm.com","from-nv.com","from-ny.net","from-oh.com","from-ok.com","from-or.com","from-pa.com","from-pr.com","from-ri.com","from-sc.com","from-sd.com","from-tn.com","from-tx.com","from-ut.com","from-va.com","from-vt.com","from-wa.com","from-wi.com","from-wv.com","from-wy.com","ftpaccess.cc","fuettertdasnetz.de","game-host.org","game-server.cc","getmyip.com","gets-it.net","go.dyndns.org","gotdns.com","gotdns.org","groks-the.info","groks-this.info","ham-radio-op.net","here-for-more.info","hobby-site.com","hobby-site.org","home.dyndns.org","homedns.org","homeftp.net","homeftp.org","homeip.net","homelinux.com","homelinux.net","homelinux.org","homeunix.com","homeunix.net","homeunix.org","iamallama.com","in-the-band.net","is-a-anarchist.com","is-a-blogger.com","is-a-bookkeeper.com","is-a-bruinsfan.org","is-a-bulls-fan.com","is-a-candidate.org","is-a-caterer.com","is-a-celticsfan.org","is-a-chef.com","is-a-chef.net","is-a-chef.org","is-a-conservative.com","is-a-cpa.com","is-a-cubicle-slave.com","is-a-democrat.com","is-a-designer.com","is-a-doctor.com","is-a-financialadvisor.com","is-a-geek.com","is-a-geek.net","is-a-geek.org","is-a-green.com","is-a-guru.com","is-a-hard-worker.com","is-a-hunter.com","is-a-knight.org","is-a-landscaper.com","is-a-lawyer.com","is-a-liberal.com","is-a-libertarian.com","is-a-linux-user.org","is-a-llama.com","is-a-musician.com","is-a-nascarfan.com","is-a-nurse.com","is-a-painter.com","is-a-patsfan.org","is-a-personaltrainer.com","is-a-photographer.com","is-a-player.com","is-a-republican.com","is-a-rockstar.com","is-a-socialist.com","is-a-soxfan.org","is-a-student.com","is-a-teacher.com","is-a-techie.com","is-a-therapist.com","is-an-accountant.com","is-an-actor.com","is-an-actress.com","is-an-anarchist.com","is-an-artist.com","is-an-engineer.com","is-an-entertainer.com","is-by.us","is-certified.com","is-found.org","is-gone.com","is-into-anime.com","is-into-cars.com","is-into-cartoons.com","is-into-games.com","is-leet.com","is-lost.org","is-not-certified.com","is-saved.org","is-slick.com","is-uberleet.com","is-very-bad.org","is-very-evil.org","is-very-good.org","is-very-nice.org","is-very-sweet.org","is-with-theband.com","isa-geek.com","isa-geek.net","isa-geek.org","isa-hockeynut.com","issmarterthanyou.com","isteingeek.de","istmein.de","kicks-ass.net","kicks-ass.org","knowsitall.info","land-4-sale.us","lebtimnetz.de","leitungsen.de","likes-pie.com","likescandy.com","merseine.nu","mine.nu","misconfused.org","mypets.ws","myphotos.cc","neat-url.com","office-on-the.net","on-the-web.tv","podzone.net","podzone.org","readmyblog.org","saves-the-whales.com","scrapper-site.net","scrapping.cc","selfip.biz","selfip.com","selfip.info","selfip.net","selfip.org","sells-for-less.com","sells-for-u.com","sells-it.net","sellsyourhome.org","servebbs.com","servebbs.net","servebbs.org","serveftp.net","serveftp.org","servegame.org","shacknet.nu","simple-url.com","space-to-rent.com","stuff-4-sale.org","stuff-4-sale.us","teaches-yoga.com","thruhere.net","traeumtgerade.de","webhop.biz","webhop.info","webhop.net","webhop.org","worse-than.tv","writesthisblog.com","ddnss.de","dyn.ddnss.de","dyndns.ddnss.de","dyndns1.de","dyn-ip24.de","home-webserver.de","dyn.home-webserver.de","myhome-server.de","ddnss.org","definima.net","definima.io","bci.dnstrace.pro","ddnsfree.com","ddnsgeek.com","giize.com","gleeze.com","kozow.com","loseyourip.com","ooguy.com","theworkpc.com","casacam.net","dynu.net","accesscam.org","camdvr.org","freeddns.org","mywire.org","webredirect.org","myddns.rocks","blogsite.xyz","dynv6.net","e4.cz","mytuleap.com","enonic.io","customer.enonic.io","eu.org","al.eu.org","asso.eu.org","at.eu.org","au.eu.org","be.eu.org","bg.eu.org","ca.eu.org","cd.eu.org","ch.eu.org","cn.eu.org","cy.eu.org","cz.eu.org","de.eu.org","dk.eu.org","edu.eu.org","ee.eu.org","es.eu.org","fi.eu.org","fr.eu.org","gr.eu.org","hr.eu.org","hu.eu.org","ie.eu.org","il.eu.org","in.eu.org","int.eu.org","is.eu.org","it.eu.org","jp.eu.org","kr.eu.org","lt.eu.org","lu.eu.org","lv.eu.org","mc.eu.org","me.eu.org","mk.eu.org","mt.eu.org","my.eu.org","net.eu.org","ng.eu.org","nl.eu.org","no.eu.org","nz.eu.org","paris.eu.org","pl.eu.org","pt.eu.org","q-a.eu.org","ro.eu.org","ru.eu.org","se.eu.org","si.eu.org","sk.eu.org","tr.eu.org","uk.eu.org","us.eu.org","eu-1.evennode.com","eu-2.evennode.com","eu-3.evennode.com","eu-4.evennode.com","us-1.evennode.com","us-2.evennode.com","us-3.evennode.com","us-4.evennode.com","twmail.cc","twmail.net","twmail.org","mymailer.com.tw","url.tw","apps.fbsbx.com","ru.net","adygeya.ru","bashkiria.ru","bir.ru","cbg.ru","com.ru","dagestan.ru","grozny.ru","kalmykia.ru","kustanai.ru","marine.ru","mordovia.ru","msk.ru","mytis.ru","nalchik.ru","nov.ru","pyatigorsk.ru","spb.ru","vladikavkaz.ru","vladimir.ru","abkhazia.su","adygeya.su","aktyubinsk.su","arkhangelsk.su","armenia.su","ashgabad.su","azerbaijan.su","balashov.su","bashkiria.su","bryansk.su","bukhara.su","chimkent.su","dagestan.su","east-kazakhstan.su","exnet.su","georgia.su","grozny.su","ivanovo.su","jambyl.su","kalmykia.su","kaluga.su","karacol.su","karaganda.su","karelia.su","khakassia.su","krasnodar.su","kurgan.su","kustanai.su","lenug.su","mangyshlak.su","mordovia.su","msk.su","murmansk.su","nalchik.su","navoi.su","north-kazakhstan.su","nov.su","obninsk.su","penza.su","pokrovsk.su","sochi.su","spb.su","tashkent.su","termez.su","togliatti.su","troitsk.su","tselinograd.su","tula.su","tuva.su","vladikavkaz.su","vladimir.su","vologda.su","channelsdvr.net","fastlylb.net","map.fastlylb.net","freetls.fastly.net","map.fastly.net","a.prod.fastly.net","global.prod.fastly.net","a.ssl.fastly.net","b.ssl.fastly.net","global.ssl.fastly.net","fastpanel.direct","fastvps-server.com","fhapp.xyz","fedorainfracloud.org","fedorapeople.org","cloud.fedoraproject.org","app.os.fedoraproject.org","app.os.stg.fedoraproject.org","filegear.me","firebaseapp.com","flynnhub.com","flynnhosting.net","freebox-os.com","freeboxos.com","fbx-os.fr","fbxos.fr","freebox-os.fr","freeboxos.fr","freedesktop.org","*.futurecms.at","*.ex.futurecms.at","*.in.futurecms.at","futurehosting.at","futuremailing.at","*.ex.ortsinfo.at","*.kunden.ortsinfo.at","*.statics.cloud","service.gov.uk","github.io","githubusercontent.com","gitlab.io","homeoffice.gov.uk","ro.im","shop.ro","goip.de","*.0emm.com","appspot.com","blogspot.ae","blogspot.al","blogspot.am","blogspot.ba","blogspot.be","blogspot.bg","blogspot.bj","blogspot.ca","blogspot.cf","blogspot.ch","blogspot.cl","blogspot.co.at","blogspot.co.id","blogspot.co.il","blogspot.co.ke","blogspot.co.nz","blogspot.co.uk","blogspot.co.za","blogspot.com","blogspot.com.ar","blogspot.com.au","blogspot.com.br","blogspot.com.by","blogspot.com.co","blogspot.com.cy","blogspot.com.ee","blogspot.com.eg","blogspot.com.es","blogspot.com.mt","blogspot.com.ng","blogspot.com.tr","blogspot.com.uy","blogspot.cv","blogspot.cz","blogspot.de","blogspot.dk","blogspot.fi","blogspot.fr","blogspot.gr","blogspot.hk","blogspot.hr","blogspot.hu","blogspot.ie","blogspot.in","blogspot.is","blogspot.it","blogspot.jp","blogspot.kr","blogspot.li","blogspot.lt","blogspot.lu","blogspot.md","blogspot.mk","blogspot.mr","blogspot.mx","blogspot.my","blogspot.nl","blogspot.no","blogspot.pe","blogspot.pt","blogspot.qa","blogspot.re","blogspot.ro","blogspot.rs","blogspot.ru","blogspot.se","blogspot.sg","blogspot.si","blogspot.sk","blogspot.sn","blogspot.td","blogspot.tw","blogspot.ug","blogspot.vn","cloudfunctions.net","cloud.goog","codespot.com","googleapis.com","googlecode.com","pagespeedmobilizer.com","publishproxy.com","withgoogle.com","withyoutube.com","hashbang.sh","hasura.app","hasura-app.io","hepforge.org","herokuapp.com","herokussl.com","myravendb.com","ravendb.community","ravendb.me","development.run","ravendb.run","moonscale.net","iki.fi","biz.at","info.at","info.cx","ac.leg.br","al.leg.br","am.leg.br","ap.leg.br","ba.leg.br","ce.leg.br","df.leg.br","es.leg.br","go.leg.br","ma.leg.br","mg.leg.br","ms.leg.br","mt.leg.br","pa.leg.br","pb.leg.br","pe.leg.br","pi.leg.br","pr.leg.br","rj.leg.br","rn.leg.br","ro.leg.br","rr.leg.br","rs.leg.br","sc.leg.br","se.leg.br","sp.leg.br","to.leg.br","pixolino.com","ipifony.net","mein-iserv.de","test-iserv.de","myjino.ru","*.hosting.myjino.ru","*.landing.myjino.ru","*.spectrum.myjino.ru","*.vps.myjino.ru","*.triton.zone","*.cns.joyent.com","js.org","keymachine.de","knightpoint.systems","co.krd","edu.krd","git-repos.de","lcube-server.de","svn-repos.de","app.lmpm.com","linkitools.space","linkyard.cloud","linkyard-cloud.ch","we.bs","uklugs.org","glug.org.uk","lug.org.uk","lugs.org.uk","barsy.bg","barsy.co.uk","barsyonline.co.uk","barsycenter.com","barsyonline.com","barsy.club","barsy.de","barsy.eu","barsy.in","barsy.info","barsy.io","barsy.me","barsy.menu","barsy.mobi","barsy.net","barsy.online","barsy.org","barsy.pro","barsy.pub","barsy.shop","barsy.site","barsy.support","barsy.uk","*.magentosite.cloud","mayfirst.info","mayfirst.org","hb.cldmail.ru","miniserver.com","memset.net","cloud.metacentrum.cz","custom.metacentrum.cz","flt.cloud.muni.cz","usr.cloud.muni.cz","meteorapp.com","eu.meteorapp.com","co.pl","azurecontainer.io","azurewebsites.net","azure-mobile.net","cloudapp.net","mozilla-iot.org","bmoattachments.org","net.ru","org.ru","pp.ru","bitballoon.com","netlify.com","4u.com","ngrok.io","nh-serv.co.uk","nfshost.com","dnsking.ch","mypi.co","n4t.co","001www.com","ddnslive.com","myiphost.com","forumz.info","16-b.it","32-b.it","64-b.it","soundcast.me","tcp4.me","dnsup.net","hicam.net","now-dns.net","ownip.net","vpndns.net","dynserv.org","now-dns.org","x443.pw","now-dns.top","ntdll.top","freeddns.us","crafting.xyz","zapto.xyz","nsupdate.info","nerdpol.ovh","blogsyte.com","brasilia.me","cable-modem.org","ciscofreak.com","collegefan.org","couchpotatofries.org","damnserver.com","ddns.me","ditchyourip.com","dnsfor.me","dnsiskinky.com","dvrcam.info","dynns.com","eating-organic.net","fantasyleague.cc","geekgalaxy.com","golffan.us","health-carereform.com","homesecuritymac.com","homesecuritypc.com","hopto.me","ilovecollege.info","loginto.me","mlbfan.org","mmafan.biz","myactivedirectory.com","mydissent.net","myeffect.net","mymediapc.net","mypsx.net","mysecuritycamera.com","mysecuritycamera.net","mysecuritycamera.org","net-freaks.com","nflfan.org","nhlfan.net","no-ip.ca","no-ip.co.uk","no-ip.net","noip.us","onthewifi.com","pgafan.net","point2this.com","pointto.us","privatizehealthinsurance.net","quicksytes.com","read-books.org","securitytactics.com","serveexchange.com","servehumour.com","servep2p.com","servesarcasm.com","stufftoread.com","ufcfan.org","unusualperson.com","workisboring.com","3utilities.com","bounceme.net","ddns.net","ddnsking.com","gotdns.ch","hopto.org","myftp.biz","myftp.org","myvnc.com","no-ip.biz","no-ip.info","no-ip.org","noip.me","redirectme.net","servebeer.com","serveblog.net","servecounterstrike.com","serveftp.com","servegame.com","servehalflife.com","servehttp.com","serveirc.com","serveminecraft.net","servemp3.com","servepics.com","servequake.com","sytes.net","webhop.me","zapto.org","stage.nodeart.io","nodum.co","nodum.io","pcloud.host","nyc.mn","nom.ae","nom.af","nom.ai","nom.al","nym.by","nym.bz","nom.cl","nom.gd","nom.ge","nom.gl","nym.gr","nom.gt","nym.gy","nom.hn","nym.ie","nom.im","nom.ke","nym.kz","nym.la","nym.lc","nom.li","nym.li","nym.lt","nym.lu","nym.me","nom.mk","nym.mn","nym.mx","nom.nu","nym.nz","nym.pe","nym.pt","nom.pw","nom.qa","nym.ro","nom.rs","nom.si","nym.sk","nom.st","nym.su","nym.sx","nom.tj","nym.tw","nom.ug","nom.uy","nom.vc","nom.vg","cya.gg","cloudycluster.net","nid.io","opencraft.hosting","operaunite.com","outsystemscloud.com","ownprovider.com","own.pm","ox.rs","oy.lc","pgfog.com","pagefrontapp.com","art.pl","gliwice.pl","krakow.pl","poznan.pl","wroc.pl","zakopane.pl","pantheonsite.io","gotpantheon.com","mypep.link","on-web.fr","*.platform.sh","*.platformsh.site","xen.prgmr.com","priv.at","protonet.io","chirurgiens-dentistes-en-france.fr","byen.site","ras.ru","qa2.com","dev-myqnapcloud.com","alpha-myqnapcloud.com","myqnapcloud.com","*.quipelements.com","vapor.cloud","vaporcloud.io","rackmaze.com","rackmaze.net","rhcloud.com","resindevice.io","devices.resinstaging.io","hzc.io","wellbeingzone.eu","ptplus.fit","wellbeingzone.co.uk","sandcats.io","logoip.de","logoip.com","schokokeks.net","scrysec.com","firewall-gateway.com","firewall-gateway.de","my-gateway.de","my-router.de","spdns.de","spdns.eu","firewall-gateway.net","my-firewall.org","myfirewall.org","spdns.org","*.s5y.io","*.sensiosite.cloud","biz.ua","co.ua","pp.ua","shiftedit.io","myshopblocks.com","1kapp.com","appchizi.com","applinzi.com","sinaapp.com","vipsinaapp.com","bounty-full.com","alpha.bounty-full.com","beta.bounty-full.com","static.land","dev.static.land","sites.static.land","apps.lair.io","*.stolos.io","spacekit.io","customer.speedpartner.de","storj.farm","utwente.io","temp-dns.com","diskstation.me","dscloud.biz","dscloud.me","dscloud.mobi","dsmynas.com","dsmynas.net","dsmynas.org","familyds.com","familyds.net","familyds.org","i234.me","myds.me","synology.me","vpnplus.to","taifun-dns.de","gda.pl","gdansk.pl","gdynia.pl","med.pl","sopot.pl","gwiddle.co.uk","cust.dev.thingdust.io","cust.disrec.thingdust.io","cust.prod.thingdust.io","cust.testing.thingdust.io","bloxcms.com","townnews-staging.com","12hp.at","2ix.at","4lima.at","lima-city.at","12hp.ch","2ix.ch","4lima.ch","lima-city.ch","trafficplex.cloud","de.cool","12hp.de","2ix.de","4lima.de","lima-city.de","1337.pictures","clan.rip","lima-city.rocks","webspace.rocks","lima.zone","*.transurl.be","*.transurl.eu","*.transurl.nl","tuxfamily.org","dd-dns.de","diskstation.eu","diskstation.org","dray-dns.de","draydns.de","dyn-vpn.de","dynvpn.de","mein-vigor.de","my-vigor.de","my-wan.de","syno-ds.de","synology-diskstation.de","synology-ds.de","uber.space","*.uberspace.de","hk.com","hk.org","ltd.hk","inc.hk","virtualuser.de","virtual-user.de","lib.de.us","2038.io","router.management","v-info.info","wedeploy.io","wedeploy.me","wedeploy.sh","remotewd.com","wmflabs.org","half.host","xnbay.com","u2.xnbay.com","u2-local.xnbay.com","cistron.nl","demon.nl","xs4all.space","official.academy","yolasite.com","ybo.faith","yombo.me","homelink.one","ybo.party","ybo.review","ybo.science","ybo.trade","nohost.me","noho.st","za.net","za.org","now.sh","zone.id"]
+
+/***/ }),
+/* 17 */
+/***/ (function(module, exports) {
+
+	/*!
+	 * Copyright (c) 2015, Salesforce.com, Inc.
+	 * All rights reserved.
+	 *
+	 * Redistribution and use in source and binary forms, with or without
+	 * modification, are permitted provided that the following conditions are met:
+	 *
+	 * 1. Redistributions of source code must retain the above copyright notice,
+	 * this list of conditions and the following disclaimer.
+	 *
+	 * 2. Redistributions in binary form must reproduce the above copyright notice,
+	 * this list of conditions and the following disclaimer in the documentation
+	 * and/or other materials provided with the distribution.
+	 *
+	 * 3. Neither the name of Salesforce.com nor the names of its contributors may
+	 * be used to endorse or promote products derived from this software without
+	 * specific prior written permission.
+	 *
+	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+	 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+	 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+	 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+	 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+	 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	 * POSSIBILITY OF SUCH DAMAGE.
+	 */
+	'use strict';
+	/*jshint unused:false */
+
+	function Store() {
+	}
+	exports.Store = Store;
+
+	// Stores may be synchronous, but are still required to use a
+	// Continuation-Passing Style API.  The CookieJar itself will expose a "*Sync"
+	// API that converts from synchronous-callbacks to imperative style.
+	Store.prototype.synchronous = false;
+
+	Store.prototype.findCookie = function(domain, path, key, cb) {
+	  throw new Error('findCookie is not implemented');
+	};
+
+	Store.prototype.findCookies = function(domain, path, cb) {
+	  throw new Error('findCookies is not implemented');
+	};
+
+	Store.prototype.putCookie = function(cookie, cb) {
+	  throw new Error('putCookie is not implemented');
+	};
+
+	Store.prototype.updateCookie = function(oldCookie, newCookie, cb) {
+	  // recommended default implementation:
+	  // return this.putCookie(newCookie, cb);
+	  throw new Error('updateCookie is not implemented');
+	};
+
+	Store.prototype.removeCookie = function(domain, path, key, cb) {
+	  throw new Error('removeCookie is not implemented');
+	};
+
+	Store.prototype.removeCookies = function(domain, path, cb) {
+	  throw new Error('removeCookies is not implemented');
+	};
+
+	Store.prototype.getAllCookies = function(cb) {
+	  throw new Error('getAllCookies is not implemented (therefore jar cannot be serialized)');
+	};
+
+
+/***/ }),
+/* 18 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/*!
+	 * Copyright (c) 2015, Salesforce.com, Inc.
+	 * All rights reserved.
+	 *
+	 * Redistribution and use in source and binary forms, with or without
+	 * modification, are permitted provided that the following conditions are met:
+	 *
+	 * 1. Redistributions of source code must retain the above copyright notice,
+	 * this list of conditions and the following disclaimer.
+	 *
+	 * 2. Redistributions in binary form must reproduce the above copyright notice,
+	 * this list of conditions and the following disclaimer in the documentation
+	 * and/or other materials provided with the distribution.
+	 *
+	 * 3. Neither the name of Salesforce.com nor the names of its contributors may
+	 * be used to endorse or promote products derived from this software without
+	 * specific prior written permission.
+	 *
+	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+	 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+	 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+	 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+	 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+	 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	 * POSSIBILITY OF SUCH DAMAGE.
+	 */
+	'use strict';
+	var Store = __webpack_require__(17).Store;
+	var permuteDomain = __webpack_require__(19).permuteDomain;
+	var pathMatch = __webpack_require__(20).pathMatch;
+	var util = __webpack_require__(9);
+
+	function MemoryCookieStore() {
+	  Store.call(this);
+	  this.idx = {};
+	}
+	util.inherits(MemoryCookieStore, Store);
+	exports.MemoryCookieStore = MemoryCookieStore;
+	MemoryCookieStore.prototype.idx = null;
+
+	// Since it's just a struct in RAM, this Store is synchronous
+	MemoryCookieStore.prototype.synchronous = true;
+
+	// force a default depth:
+	MemoryCookieStore.prototype.inspect = function() {
+	  return "{ idx: "+util.inspect(this.idx, false, 2)+' }';
+	};
+
+	// Use the new custom inspection symbol to add the custom inspect function if
+	// available.
+	if (util.inspect.custom) {
+	  MemoryCookieStore.prototype[util.inspect.custom] = MemoryCookieStore.prototype.inspect;
+	}
+
+	MemoryCookieStore.prototype.findCookie = function(domain, path, key, cb) {
+	  if (!this.idx[domain]) {
+	    return cb(null,undefined);
+	  }
+	  if (!this.idx[domain][path]) {
+	    return cb(null,undefined);
+	  }
+	  return cb(null,this.idx[domain][path][key]||null);
+	};
+
+	MemoryCookieStore.prototype.findCookies = function(domain, path, cb) {
+	  var results = [];
+	  if (!domain) {
+	    return cb(null,[]);
+	  }
+
+	  var pathMatcher;
+	  if (!path) {
+	    // null means "all paths"
+	    pathMatcher = function matchAll(domainIndex) {
+	      for (var curPath in domainIndex) {
+	        var pathIndex = domainIndex[curPath];
+	        for (var key in pathIndex) {
+	          results.push(pathIndex[key]);
+	        }
+	      }
+	    };
+
+	  } else {
+	    pathMatcher = function matchRFC(domainIndex) {
+	       //NOTE: we should use path-match algorithm from S5.1.4 here
+	       //(see : https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/canonical_cookie.cc#L299)
+	       Object.keys(domainIndex).forEach(function (cookiePath) {
+	         if (pathMatch(path, cookiePath)) {
+	           var pathIndex = domainIndex[cookiePath];
+
+	           for (var key in pathIndex) {
+	             results.push(pathIndex[key]);
+	           }
+	         }
+	       });
+	     };
+	  }
+
+	  var domains = permuteDomain(domain) || [domain];
+	  var idx = this.idx;
+	  domains.forEach(function(curDomain) {
+	    var domainIndex = idx[curDomain];
+	    if (!domainIndex) {
+	      return;
+	    }
+	    pathMatcher(domainIndex);
+	  });
+
+	  cb(null,results);
+	};
+
+	MemoryCookieStore.prototype.putCookie = function(cookie, cb) {
+	  if (!this.idx[cookie.domain]) {
+	    this.idx[cookie.domain] = {};
+	  }
+	  if (!this.idx[cookie.domain][cookie.path]) {
+	    this.idx[cookie.domain][cookie.path] = {};
+	  }
+	  this.idx[cookie.domain][cookie.path][cookie.key] = cookie;
+	  cb(null);
+	};
+
+	MemoryCookieStore.prototype.updateCookie = function(oldCookie, newCookie, cb) {
+	  // updateCookie() may avoid updating cookies that are identical.  For example,
+	  // lastAccessed may not be important to some stores and an equality
+	  // comparison could exclude that field.
+	  this.putCookie(newCookie,cb);
+	};
+
+	MemoryCookieStore.prototype.removeCookie = function(domain, path, key, cb) {
+	  if (this.idx[domain] && this.idx[domain][path] && this.idx[domain][path][key]) {
+	    delete this.idx[domain][path][key];
+	  }
+	  cb(null);
+	};
+
+	MemoryCookieStore.prototype.removeCookies = function(domain, path, cb) {
+	  if (this.idx[domain]) {
+	    if (path) {
+	      delete this.idx[domain][path];
+	    } else {
+	      delete this.idx[domain];
+	    }
+	  }
+	  return cb(null);
+	};
+
+	MemoryCookieStore.prototype.getAllCookies = function(cb) {
+	  var cookies = [];
+	  var idx = this.idx;
+
+	  var domains = Object.keys(idx);
+	  domains.forEach(function(domain) {
+	    var paths = Object.keys(idx[domain]);
+	    paths.forEach(function(path) {
+	      var keys = Object.keys(idx[domain][path]);
+	      keys.forEach(function(key) {
+	        if (key !== null) {
+	          cookies.push(idx[domain][path][key]);
+	        }
+	      });
+	    });
+	  });
+
+	  // Sort by creationIndex so deserializing retains the creation order.
+	  // When implementing your own store, this SHOULD retain the order too
+	  cookies.sort(function(a,b) {
+	    return (a.creationIndex||0) - (b.creationIndex||0);
+	  });
+
+	  cb(null, cookies);
+	};
+
+
+/***/ }),
+/* 19 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/*!
+	 * Copyright (c) 2015, Salesforce.com, Inc.
+	 * All rights reserved.
+	 *
+	 * Redistribution and use in source and binary forms, with or without
+	 * modification, are permitted provided that the following conditions are met:
+	 *
+	 * 1. Redistributions of source code must retain the above copyright notice,
+	 * this list of conditions and the following disclaimer.
+	 *
+	 * 2. Redistributions in binary form must reproduce the above copyright notice,
+	 * this list of conditions and the following disclaimer in the documentation
+	 * and/or other materials provided with the distribution.
+	 *
+	 * 3. Neither the name of Salesforce.com nor the names of its contributors may
+	 * be used to endorse or promote products derived from this software without
+	 * specific prior written permission.
+	 *
+	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+	 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+	 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+	 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+	 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+	 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	 * POSSIBILITY OF SUCH DAMAGE.
+	 */
+	"use strict";
+	var pubsuffix = __webpack_require__(13);
+
+	// Gives the permutation of all possible domainMatch()es of a given domain. The
+	// array is in shortest-to-longest order.  Handy for indexing.
+	function permuteDomain (domain) {
+	  var pubSuf = pubsuffix.getPublicSuffix(domain);
+	  if (!pubSuf) {
+	    return null;
+	  }
+	  if (pubSuf == domain) {
+	    return [domain];
+	  }
+
+	  var prefix = domain.slice(0, -(pubSuf.length + 1)); // ".example.com"
+	  var parts = prefix.split('.').reverse();
+	  var cur = pubSuf;
+	  var permutations = [cur];
+	  while (parts.length) {
+	    cur = parts.shift() + '.' + cur;
+	    permutations.push(cur);
+	  }
+	  return permutations;
+	}
+
+	exports.permuteDomain = permuteDomain;
+
+
+/***/ }),
+/* 20 */
+/***/ (function(module, exports) {
+
+	/*!
+	 * Copyright (c) 2015, Salesforce.com, Inc.
+	 * All rights reserved.
+	 *
+	 * Redistribution and use in source and binary forms, with or without
+	 * modification, are permitted provided that the following conditions are met:
+	 *
+	 * 1. Redistributions of source code must retain the above copyright notice,
+	 * this list of conditions and the following disclaimer.
+	 *
+	 * 2. Redistributions in binary form must reproduce the above copyright notice,
+	 * this list of conditions and the following disclaimer in the documentation
+	 * and/or other materials provided with the distribution.
+	 *
+	 * 3. Neither the name of Salesforce.com nor the names of its contributors may
+	 * be used to endorse or promote products derived from this software without
+	 * specific prior written permission.
+	 *
+	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+	 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+	 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+	 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+	 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+	 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	 * POSSIBILITY OF SUCH DAMAGE.
+	 */
+	"use strict";
+	/*
+	 * "A request-path path-matches a given cookie-path if at least one of the
+	 * following conditions holds:"
+	 */
+	function pathMatch (reqPath, cookiePath) {
+	  // "o  The cookie-path and the request-path are identical."
+	  if (cookiePath === reqPath) {
+	    return true;
+	  }
+
+	  var idx = reqPath.indexOf(cookiePath);
+	  if (idx === 0) {
+	    // "o  The cookie-path is a prefix of the request-path, and the last
+	    // character of the cookie-path is %x2F ("/")."
+	    if (cookiePath.substr(-1) === "/") {
+	      return true;
+	    }
+
+	    // " o  The cookie-path is a prefix of the request-path, and the first
+	    // character of the request-path that is not included in the cookie- path
+	    // is a %x2F ("/") character."
+	    if (reqPath.substr(cookiePath.length, 1) === "/") {
+	      return true;
+	    }
+	  }
+
+	  return false;
+	}
+
+	exports.pathMatch = pathMatch;
+
+
+/***/ }),
+/* 21 */
+/***/ (function(module, exports) {
+
+	module.exports = {"_from":"tough-cookie@2.4.3","_id":"tough-cookie@2.4.3","_inBundle":false,"_integrity":"sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==","_location":"/tough-cookie","_phantomChildren":{},"_requested":{"type":"version","registry":true,"raw":"tough-cookie@2.4.3","name":"tough-cookie","escapedName":"tough-cookie","rawSpec":"2.4.3","saveSpec":null,"fetchSpec":"2.4.3"},"_requiredBy":["#DEV:/"],"_resolved":"https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz","_shasum":"53f36da3f47783b0925afa06ff9f3b165280f781","_spec":"tough-cookie@2.4.3","_where":"/Users/sefa/Entwicklung/umd-tough-cookie","author":{"name":"Jeremy Stashewsky","email":"jstash@gmail.com"},"bugs":{"url":"https://github.com/salesforce/tough-cookie/issues"},"bundleDependencies":false,"contributors":[{"name":"Alexander Savin"},{"name":"Ian Livingstone"},{"name":"Ivan Nikulin"},{"name":"Lalit Kapoor"},{"name":"Sam Thompson"},{"name":"Sebastian Mayr"}],"dependencies":{"psl":"^1.1.24","punycode":"^1.4.1"},"deprecated":false,"description":"RFC6265 Cookies and Cookie Jar for node.js","devDependencies":{"async":"^1.4.2","nyc":"^11.6.0","string.prototype.repeat":"^0.2.0","vows":"^0.8.1"},"engines":{"node":">=0.8"},"files":["lib"],"homepage":"https://github.com/salesforce/tough-cookie","keywords":["HTTP","cookie","cookies","set-cookie","cookiejar","jar","RFC6265","RFC2965"],"license":"BSD-3-Clause","main":"./lib/cookie","name":"tough-cookie","repository":{"type":"git","url":"git://github.com/salesforce/tough-cookie.git"},"scripts":{"cover":"nyc --reporter=lcov --reporter=html vows test/*_test.js","test":"vows test/*_test.js"},"version":"2.4.3"}
+
+/***/ })
+/******/ ])
+});
+;
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/url-util.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/url-util.js
new file mode 100644
index 0000000..8d9228a
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-advanced-http/www/url-util.js
@@ -0,0 +1,106 @@
+cordova.define("cordova-plugin-advanced-http.url-util", function(require, exports, module) {
+module.exports = function init(jsUtil) {
+  return {
+    parseUrl: parseUrl,
+    appendQueryParamsString: appendQueryParamsString,
+    serializeQueryParams: serializeQueryParams
+  }
+
+  function parseUrl(url) {
+    var match = url.match(/^(https?\:)\/\/(([^:\/?#]*)(?:\:([0-9]+))?)([\/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/);
+
+    return match && {
+        protocol: match[1],
+        host: match[2],
+        hostname: match[3],
+        port: match[4] || '',
+        pathname: match[5],
+        search: match[6],
+        hash: match[7]
+    }
+  }
+
+  function appendQueryParamsString(url, params) {
+    if (!url.length || !params.length) {
+      return url;
+    }
+
+    var parsed = parseUrl(url);
+
+    return parsed.protocol
+      + '//'
+      + parsed.host
+      + parsed.pathname
+      + (parsed.search.length ? parsed.search + '&' + params : '?' + params)
+      + parsed.hash;
+  }
+
+  function serializeQueryParams(params, encode) {
+    return serializeObject('', params, encode);
+  }
+
+  function serializeObject(parentKey, object, encode) {
+    var parts = [];
+
+    for (var key in object) {
+      if (!object.hasOwnProperty(key)) {
+        continue;
+      }
+
+      var identifier = parentKey.length ? parentKey + '[' + key + ']' : key;
+
+      if (jsUtil.getTypeOf(object[key]) === 'Array') {
+        parts.push(serializeArray(identifier, object[key], encode));
+        continue;
+      } else if (jsUtil.getTypeOf(object[key]) === 'Object') {
+        parts.push(serializeObject(identifier, object[key], encode));
+        continue;
+      }
+
+      parts.push(serializeIdentifier(parentKey, key, encode) + '=' + serializeValue(object[key], encode));
+    }
+
+    return parts.join('&');
+  }
+
+  function serializeArray(parentKey, array, encode) {
+    var parts = [];
+
+    for (var i = 0; i < array.length; ++i) {
+      if (jsUtil.getTypeOf(array[i]) === 'Array') {
+        parts.push(serializeArray(parentKey + '[]', array[i], encode));
+        continue;
+      } else if (jsUtil.getTypeOf(array[i]) === 'Object') {
+        parts.push(serializeObject(parentKey + '[]' + array[i], encode));
+        continue;
+      }
+
+      parts.push(serializeIdentifier(parentKey, '', encode) + '=' + serializeValue(array[i], encode));
+    }
+
+    return parts.join('&');
+  }
+
+  function serializeIdentifier(parentKey, key, encode) {
+    if (!parentKey.length) {
+      return encode ? encodeURIComponent(key) : key;
+    }
+
+    if (encode) {
+      return encodeURIComponent(parentKey) + '[' + encodeURIComponent(key) + ']';
+    } else {
+      return parentKey + '[' + key + ']';
+    }
+  }
+
+  function serializeValue(value, encode) {
+    if (encode) {
+      return encodeURIComponent(value);
+    } else {
+      return value;
+    }
+  }
+};
+
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-camera/www/Camera.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-camera/www/Camera.js
new file mode 100644
index 0000000..3f614ec
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-camera/www/Camera.js
@@ -0,0 +1,188 @@
+cordova.define("cordova-plugin-camera.camera", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var argscheck = require('cordova/argscheck');
+var exec = require('cordova/exec');
+var Camera = require('./Camera');
+// XXX: commented out
+// CameraPopoverHandle = require('./CameraPopoverHandle');
+
+/**
+ * @namespace navigator
+ */
+
+/**
+ * @exports camera
+ */
+var cameraExport = {};
+
+// Tack on the Camera Constants to the base camera plugin.
+for (var key in Camera) {
+    cameraExport[key] = Camera[key];
+}
+
+/**
+ * Callback function that provides an error message.
+ * @callback module:camera.onError
+ * @param {string} message - The message is provided by the device's native code.
+ */
+
+/**
+ * Callback function that provides the image data.
+ * @callback module:camera.onSuccess
+ * @param {string} imageData - Base64 encoding of the image data, _or_ the image file URI, depending on [`cameraOptions`]{@link module:camera.CameraOptions} in effect.
+ * @example
+ * // Show image
+ * //
+ * function cameraCallback(imageData) {
+ *    var image = document.getElementById('myImage');
+ *    image.src = "data:image/jpeg;base64," + imageData;
+ * }
+ */
+
+/**
+ * Optional parameters to customize the camera settings.
+ * * [Quirks](#CameraOptions-quirks)
+ * @typedef module:camera.CameraOptions
+ * @type {Object}
+ * @property {number} [quality=50] - Quality of the saved image, expressed as a range of 0-100, where 100 is typically full resolution with no loss from file compression. (Note that information about the camera's resolution is unavailable.)
+ * @property {module:Camera.DestinationType} [destinationType=FILE_URI] - Choose the format of the return value.
+ * @property {module:Camera.PictureSourceType} [sourceType=CAMERA] - Set the source of the picture.
+ * @property {Boolean} [allowEdit=false] - Allow simple editing of image before selection.
+ * @property {module:Camera.EncodingType} [encodingType=JPEG] - Choose the  returned image file's encoding.
+ * @property {number} [targetWidth] - Width in pixels to scale image. Must be used with `targetHeight`. Aspect ratio remains constant.
+ * @property {number} [targetHeight] - Height in pixels to scale image. Must be used with `targetWidth`. Aspect ratio remains constant.
+ * @property {module:Camera.MediaType} [mediaType=PICTURE] - Set the type of media to select from.  Only works when `PictureSourceType` is `PHOTOLIBRARY` or `SAVEDPHOTOALBUM`.
+ * @property {Boolean} [correctOrientation] - Rotate the image to correct for the orientation of the device during capture.
+ * @property {Boolean} [saveToPhotoAlbum] - Save the image to the photo album on the device after capture.
+ * @property {module:CameraPopoverOptions} [popoverOptions] - iOS-only options that specify popover location in iPad.
+ * @property {module:Camera.Direction} [cameraDirection=BACK] - Choose the camera to use (front- or back-facing).
+ */
+
+/**
+ * @description Takes a photo using the camera, or retrieves a photo from the device's
+ * image gallery.  The image is passed to the success callback as a
+ * Base64-encoded `String`, or as the URI for the image file.
+ *
+ * The `camera.getPicture` function opens the device's default camera
+ * application that allows users to snap pictures by default - this behavior occurs,
+ * when `Camera.sourceType` equals [`Camera.PictureSourceType.CAMERA`]{@link module:Camera.PictureSourceType}.
+ * Once the user snaps the photo, the camera application closes and the application is restored.
+ *
+ * If `Camera.sourceType` is `Camera.PictureSourceType.PHOTOLIBRARY` or
+ * `Camera.PictureSourceType.SAVEDPHOTOALBUM`, then a dialog displays
+ * that allows users to select an existing image.
+ *
+ * The return value is sent to the [`cameraSuccess`]{@link module:camera.onSuccess} callback function, in
+ * one of the following formats, depending on the specified
+ * `cameraOptions`:
+ *
+ * - A `String` containing the Base64-encoded photo image.
+ * - A `String` representing the image file location on local storage (default).
+ *
+ * You can do whatever you want with the encoded image or URI, for
+ * example:
+ *
+ * - Render the image in an `<img>` tag, as in the example below
+ * - Save the data locally (`LocalStorage`, [Lawnchair](http://brianleroux.github.com/lawnchair/), etc.)
+ * - Post the data to a remote server
+ *
+ * __NOTE__: Photo resolution on newer devices is quite good. Photos
+ * selected from the device's gallery are not downscaled to a lower
+ * quality, even if a `quality` parameter is specified.  To avoid common
+ * memory problems, set `Camera.destinationType` to `FILE_URI` rather
+ * than `DATA_URL`.
+ *
+ * __Supported Platforms__
+ *
+ * - Android
+ * - BlackBerry
+ * - Browser
+ * - Firefox
+ * - FireOS
+ * - iOS
+ * - Windows
+ * - WP8
+ * - Ubuntu
+ *
+ * More examples [here](#camera-getPicture-examples). Quirks [here](#camera-getPicture-quirks).
+ *
+ * @example
+ * navigator.camera.getPicture(cameraSuccess, cameraError, cameraOptions);
+ * @param {module:camera.onSuccess} successCallback
+ * @param {module:camera.onError} errorCallback
+ * @param {module:camera.CameraOptions} options CameraOptions
+ */
+cameraExport.getPicture = function (successCallback, errorCallback, options) {
+    argscheck.checkArgs('fFO', 'Camera.getPicture', arguments);
+    options = options || {};
+    var getValue = argscheck.getValue;
+
+    var quality = getValue(options.quality, 50);
+    var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI);
+    var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA);
+    var targetWidth = getValue(options.targetWidth, -1);
+    var targetHeight = getValue(options.targetHeight, -1);
+    var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG);
+    var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE);
+    var allowEdit = !!options.allowEdit;
+    var correctOrientation = !!options.correctOrientation;
+    var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
+    var popoverOptions = getValue(options.popoverOptions, null);
+    var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
+
+    var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
+        mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
+
+    exec(successCallback, errorCallback, 'Camera', 'takePicture', args);
+    // XXX: commented out
+    // return new CameraPopoverHandle();
+};
+
+/**
+ * Removes intermediate image files that are kept in temporary storage
+ * after calling [`camera.getPicture`]{@link module:camera.getPicture}. Applies only when the value of
+ * `Camera.sourceType` equals `Camera.PictureSourceType.CAMERA` and the
+ * `Camera.destinationType` equals `Camera.DestinationType.FILE_URI`.
+ *
+ * __Supported Platforms__
+ *
+ * - iOS
+ *
+ * @example
+ * navigator.camera.cleanup(onSuccess, onFail);
+ *
+ * function onSuccess() {
+ *     console.log("Camera cleanup success.")
+ * }
+ *
+ * function onFail(message) {
+ *     alert('Failed because: ' + message);
+ * }
+ */
+cameraExport.cleanup = function (successCallback, errorCallback) {
+    exec(successCallback, errorCallback, 'Camera', 'cleanup', []);
+};
+
+module.exports = cameraExport;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-camera/www/CameraConstants.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-camera/www/CameraConstants.js
new file mode 100644
index 0000000..4f4b046
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-camera/www/CameraConstants.js
@@ -0,0 +1,104 @@
+cordova.define("cordova-plugin-camera.Camera", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * @module Camera
+ */
+module.exports = {
+    /**
+     * @description
+     * Defines the output format of `Camera.getPicture` call.
+     * _Note:_ On iOS passing `DestinationType.NATIVE_URI` along with
+     * `PictureSourceType.PHOTOLIBRARY` or `PictureSourceType.SAVEDPHOTOALBUM` will
+     * disable any image modifications (resize, quality change, cropping, etc.) due
+     * to implementation specific.
+     *
+     * @enum {number}
+     */
+    DestinationType: {
+        /** Return base64 encoded string. DATA_URL can be very memory intensive and cause app crashes or out of memory errors. Use FILE_URI or NATIVE_URI if possible */
+        DATA_URL: 0,
+        /** Return file uri (content://media/external/images/media/2 for Android) */
+        FILE_URI: 1,
+        /** Return native uri (eg. asset-library://... for iOS) */
+        NATIVE_URI: 2
+    },
+    /**
+     * @enum {number}
+     */
+    EncodingType: {
+        /** Return JPEG encoded image */
+        JPEG: 0,
+        /** Return PNG encoded image */
+        PNG: 1
+    },
+    /**
+     * @enum {number}
+     */
+    MediaType: {
+        /** Allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType */
+        PICTURE: 0,
+        /** Allow selection of video only, ONLY RETURNS URL */
+        VIDEO: 1,
+        /** Allow selection from all media types */
+        ALLMEDIA: 2
+    },
+    /**
+     * @description
+     * Defines the output format of `Camera.getPicture` call.
+     * _Note:_ On iOS passing `PictureSourceType.PHOTOLIBRARY` or `PictureSourceType.SAVEDPHOTOALBUM`
+     * along with `DestinationType.NATIVE_URI` will disable any image modifications (resize, quality
+     * change, cropping, etc.) due to implementation specific.
+     *
+     * @enum {number}
+     */
+    PictureSourceType: {
+        /** Choose image from the device's photo library (same as SAVEDPHOTOALBUM for Android) */
+        PHOTOLIBRARY: 0,
+        /** Take picture from camera */
+        CAMERA: 1,
+        /** Choose image only from the device's Camera Roll album (same as PHOTOLIBRARY for Android) */
+        SAVEDPHOTOALBUM: 2
+    },
+    /**
+     * Matches iOS UIPopoverArrowDirection constants to specify arrow location on popover.
+     * @enum {number}
+     */
+    PopoverArrowDirection: {
+        ARROW_UP: 1,
+        ARROW_DOWN: 2,
+        ARROW_LEFT: 4,
+        ARROW_RIGHT: 8,
+        ARROW_ANY: 15
+    },
+    /**
+     * @enum {number}
+     */
+    Direction: {
+        /** Use the back-facing camera */
+        BACK: 0,
+        /** Use the front-facing camera */
+        FRONT: 1
+    }
+};
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-camera/www/CameraPopoverHandle.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-camera/www/CameraPopoverHandle.js
new file mode 100644
index 0000000..c970f55
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-camera/www/CameraPopoverHandle.js
@@ -0,0 +1,35 @@
+cordova.define("cordova-plugin-camera.CameraPopoverHandle", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * @ignore in favour of iOS' one
+ * A handle to an image picker popover.
+ */
+var CameraPopoverHandle = function () {
+    this.setPosition = function (popoverOptions) {
+        console.log('CameraPopoverHandle.setPosition is only supported on iOS.');
+    };
+};
+
+module.exports = CameraPopoverHandle;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-camera/www/CameraPopoverOptions.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-camera/www/CameraPopoverOptions.js
new file mode 100644
index 0000000..81d7d20
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-camera/www/CameraPopoverOptions.js
@@ -0,0 +1,55 @@
+cordova.define("cordova-plugin-camera.CameraPopoverOptions", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var Camera = require('./Camera');
+
+/**
+ * @namespace navigator
+ */
+
+/**
+ * iOS-only parameters that specify the anchor element location and arrow
+ * direction of the popover when selecting images from an iPad's library
+ * or album.
+ * Note that the size of the popover may change to adjust to the
+ * direction of the arrow and orientation of the screen.  Make sure to
+ * account for orientation changes when specifying the anchor element
+ * location.
+ * @module CameraPopoverOptions
+ * @param {Number} [x=0] - x pixel coordinate of screen element onto which to anchor the popover.
+ * @param {Number} [y=32] - y pixel coordinate of screen element onto which to anchor the popover.
+ * @param {Number} [width=320] - width, in pixels, of the screen element onto which to anchor the popover.
+ * @param {Number} [height=480] - height, in pixels, of the screen element onto which to anchor the popover.
+ * @param {module:Camera.PopoverArrowDirection} [arrowDir=ARROW_ANY] - Direction the arrow on the popover should point.
+ */
+var CameraPopoverOptions = function (x, y, width, height, arrowDir) {
+    // information of rectangle that popover should be anchored to
+    this.x = x || 0;
+    this.y = y || 32;
+    this.width = width || 320;
+    this.height = height || 480;
+    this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY;
+};
+
+module.exports = CameraPopoverOptions;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-device/www/device.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-device/www/device.js
new file mode 100644
index 0000000..ae48e35
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-device/www/device.js
@@ -0,0 +1,86 @@
+cordova.define("cordova-plugin-device.device", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var argscheck = require('cordova/argscheck');
+var channel = require('cordova/channel');
+var utils = require('cordova/utils');
+var exec = require('cordova/exec');
+var cordova = require('cordova');
+
+channel.createSticky('onCordovaInfoReady');
+// Tell cordova channel to wait on the CordovaInfoReady event
+channel.waitForInitialization('onCordovaInfoReady');
+
+/**
+ * This represents the mobile device, and provides properties for inspecting the model, version, UUID of the
+ * phone, etc.
+ * @constructor
+ */
+function Device () {
+    this.available = false;
+    this.platform = null;
+    this.version = null;
+    this.uuid = null;
+    this.cordova = null;
+    this.model = null;
+    this.manufacturer = null;
+    this.isVirtual = null;
+    this.serial = null;
+
+    var me = this;
+
+    channel.onCordovaReady.subscribe(function () {
+        me.getInfo(function (info) {
+            // ignoring info.cordova returning from native, we should use value from cordova.version defined in cordova.js
+            // TODO: CB-5105 native implementations should not return info.cordova
+            var buildLabel = cordova.version;
+            me.available = true;
+            me.platform = info.platform;
+            me.version = info.version;
+            me.uuid = info.uuid;
+            me.cordova = buildLabel;
+            me.model = info.model;
+            me.isVirtual = info.isVirtual;
+            me.manufacturer = info.manufacturer || 'unknown';
+            me.serial = info.serial || 'unknown';
+            channel.onCordovaInfoReady.fire();
+        }, function (e) {
+            me.available = false;
+            utils.alert('[ERROR] Error initializing Cordova: ' + e);
+        });
+    });
+}
+
+/**
+ * Get device info
+ *
+ * @param {Function} successCallback The function to call when the heading data is available
+ * @param {Function} errorCallback The function to call when there is an error getting the heading data. (OPTIONAL)
+ */
+Device.prototype.getInfo = function (successCallback, errorCallback) {
+    argscheck.checkArgs('fF', 'Device.getInfo', arguments);
+    exec(successCallback, errorCallback, 'Device', 'getDeviceInfo', []);
+};
+
+module.exports = new Device();
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/DirectoryEntry.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/DirectoryEntry.js
new file mode 100644
index 0000000..bb676eb
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/DirectoryEntry.js
@@ -0,0 +1,120 @@
+cordova.define("cordova-plugin-file.DirectoryEntry", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var argscheck = require('cordova/argscheck');
+var utils = require('cordova/utils');
+var exec = require('cordova/exec');
+var Entry = require('./Entry');
+var FileError = require('./FileError');
+var DirectoryReader = require('./DirectoryReader');
+
+/**
+ * An interface representing a directory on the file system.
+ *
+ * {boolean} isFile always false (readonly)
+ * {boolean} isDirectory always true (readonly)
+ * {DOMString} name of the directory, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the directory (readonly)
+ * {FileSystem} filesystem on which the directory resides (readonly)
+ */
+var DirectoryEntry = function (name, fullPath, fileSystem, nativeURL) {
+
+    // add trailing slash if it is missing
+    if ((fullPath) && !/\/$/.test(fullPath)) {
+        fullPath += '/';
+    }
+    // add trailing slash if it is missing
+    if (nativeURL && !/\/$/.test(nativeURL)) {
+        nativeURL += '/';
+    }
+    DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath, fileSystem, nativeURL);
+};
+
+utils.extend(DirectoryEntry, Entry);
+
+/**
+ * Creates a new DirectoryReader to read entries from this directory
+ */
+DirectoryEntry.prototype.createReader = function () {
+    return new DirectoryReader(this.toInternalURL());
+};
+
+/**
+ * Creates or looks up a directory
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory
+ * @param {Flags} options to create or exclusively create the directory
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getDirectory = function (path, options, successCallback, errorCallback) {
+    argscheck.checkArgs('sOFF', 'DirectoryEntry.getDirectory', arguments);
+    var fs = this.filesystem;
+    var win = successCallback && function (result) {
+        var entry = new DirectoryEntry(result.name, result.fullPath, fs, result.nativeURL);
+        successCallback(entry);
+    };
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, 'File', 'getDirectory', [this.toInternalURL(), path, options]);
+};
+
+/**
+ * Deletes a directory and all of it's contents
+ *
+ * @param {Function} successCallback is called with no parameters
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.removeRecursively = function (successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'DirectoryEntry.removeRecursively', arguments);
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    exec(successCallback, fail, 'File', 'removeRecursively', [this.toInternalURL()]);
+};
+
+/**
+ * Creates or looks up a file
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file
+ * @param {Flags} options to create or exclusively create the file
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getFile = function (path, options, successCallback, errorCallback) {
+    argscheck.checkArgs('sOFF', 'DirectoryEntry.getFile', arguments);
+    var fs = this.filesystem;
+    var win = successCallback && function (result) {
+        var FileEntry = require('./FileEntry');
+        var entry = new FileEntry(result.name, result.fullPath, fs, result.nativeURL);
+        successCallback(entry);
+    };
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, 'File', 'getFile', [this.toInternalURL(), path, options]);
+};
+
+module.exports = DirectoryEntry;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/DirectoryReader.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/DirectoryReader.js
new file mode 100644
index 0000000..417c85f
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/DirectoryReader.js
@@ -0,0 +1,75 @@
+cordova.define("cordova-plugin-file.DirectoryReader", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var exec = require('cordova/exec');
+var FileError = require('./FileError');
+
+/**
+ * An interface that lists the files and directories in a directory.
+ */
+function DirectoryReader (localURL) {
+    this.localURL = localURL || null;
+    this.hasReadEntries = false;
+}
+
+/**
+ * Returns a list of entries from a directory.
+ *
+ * @param {Function} successCallback is called with a list of entries
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryReader.prototype.readEntries = function (successCallback, errorCallback) {
+    // If we've already read and passed on this directory's entries, return an empty list.
+    if (this.hasReadEntries) {
+        successCallback([]);
+        return;
+    }
+    var reader = this;
+    var win = typeof successCallback !== 'function' ? null : function (result) {
+        var retVal = [];
+        for (var i = 0; i < result.length; i++) {
+            var entry = null;
+            if (result[i].isDirectory) {
+                entry = new (require('./DirectoryEntry'))();
+            } else if (result[i].isFile) {
+                entry = new (require('./FileEntry'))();
+            }
+            entry.isDirectory = result[i].isDirectory;
+            entry.isFile = result[i].isFile;
+            entry.name = result[i].name;
+            entry.fullPath = result[i].fullPath;
+            entry.filesystem = new (require('./FileSystem'))(result[i].filesystemName);
+            entry.nativeURL = result[i].nativeURL;
+            retVal.push(entry);
+        }
+        reader.hasReadEntries = true;
+        successCallback(retVal);
+    };
+    var fail = typeof errorCallback !== 'function' ? null : function (code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, 'File', 'readEntries', [this.localURL]);
+};
+
+module.exports = DirectoryReader;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/Entry.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/Entry.js
new file mode 100644
index 0000000..b296d99
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/Entry.js
@@ -0,0 +1,263 @@
+cordova.define("cordova-plugin-file.Entry", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var argscheck = require('cordova/argscheck');
+var exec = require('cordova/exec');
+var FileError = require('./FileError');
+var Metadata = require('./Metadata');
+
+/**
+ * Represents a file or directory on the local file system.
+ *
+ * @param isFile
+ *            {boolean} true if Entry is a file (readonly)
+ * @param isDirectory
+ *            {boolean} true if Entry is a directory (readonly)
+ * @param name
+ *            {DOMString} name of the file or directory, excluding the path
+ *            leading to it (readonly)
+ * @param fullPath
+ *            {DOMString} the absolute full path to the file or directory
+ *            (readonly)
+ * @param fileSystem
+ *            {FileSystem} the filesystem on which this entry resides
+ *            (readonly)
+ * @param nativeURL
+ *            {DOMString} an alternate URL which can be used by native
+ *            webview controls, for example media players.
+ *            (optional, readonly)
+ */
+function Entry (isFile, isDirectory, name, fullPath, fileSystem, nativeURL) {
+    this.isFile = !!isFile;
+    this.isDirectory = !!isDirectory;
+    this.name = name || '';
+    this.fullPath = fullPath || '';
+    this.filesystem = fileSystem || null;
+    this.nativeURL = nativeURL || null;
+}
+
+/**
+ * Look up the metadata of the entry.
+ *
+ * @param successCallback
+ *            {Function} is called with a Metadata object
+ * @param errorCallback
+ *            {Function} is called with a FileError
+ */
+Entry.prototype.getMetadata = function (successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'Entry.getMetadata', arguments);
+    var success = successCallback && function (entryMetadata) {
+        var metadata = new Metadata({
+            size: entryMetadata.size,
+            modificationTime: entryMetadata.lastModifiedDate
+        });
+        successCallback(metadata);
+    };
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    exec(success, fail, 'File', 'getFileMetadata', [this.toInternalURL()]);
+};
+
+/**
+ * Set the metadata of the entry.
+ *
+ * @param successCallback
+ *            {Function} is called with a Metadata object
+ * @param errorCallback
+ *            {Function} is called with a FileError
+ * @param metadataObject
+ *            {Object} keys and values to set
+ */
+Entry.prototype.setMetadata = function (successCallback, errorCallback, metadataObject) {
+    argscheck.checkArgs('FFO', 'Entry.setMetadata', arguments);
+    exec(successCallback, errorCallback, 'File', 'setMetadata', [this.toInternalURL(), metadataObject]);
+};
+
+/**
+ * Move a file or directory to a new location.
+ *
+ * @param parent
+ *            {DirectoryEntry} the directory to which to move this entry
+ * @param newName
+ *            {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ *            {Function} called with the new DirectoryEntry object
+ * @param errorCallback
+ *            {Function} called with a FileError
+ */
+Entry.prototype.moveTo = function (parent, newName, successCallback, errorCallback) {
+    argscheck.checkArgs('oSFF', 'Entry.moveTo', arguments);
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    var srcURL = this.toInternalURL();
+    // entry name
+    var name = newName || this.name;
+    var success = function (entry) {
+        if (entry) {
+            if (successCallback) {
+                // create appropriate Entry object
+                var newFSName = entry.filesystemName || (entry.filesystem && entry.filesystem.name);
+                var fs = newFSName ? new FileSystem(newFSName, { name: '', fullPath: '/' }) : new FileSystem(parent.filesystem.name, { name: '', fullPath: '/' }); // eslint-disable-line no-undef
+                var result = (entry.isDirectory) ? new (require('./DirectoryEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL) : new (require('cordova-plugin-file.FileEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL);
+                successCallback(result);
+            }
+        } else {
+            // no Entry object returned
+            if (fail) {
+                fail(FileError.NOT_FOUND_ERR);
+            }
+        }
+    };
+
+    // copy
+    exec(success, fail, 'File', 'moveTo', [srcURL, parent.toInternalURL(), name]);
+};
+
+/**
+ * Copy a directory to a different location.
+ *
+ * @param parent
+ *            {DirectoryEntry} the directory to which to copy the entry
+ * @param newName
+ *            {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ *            {Function} called with the new Entry object
+ * @param errorCallback
+ *            {Function} called with a FileError
+ */
+Entry.prototype.copyTo = function (parent, newName, successCallback, errorCallback) {
+    argscheck.checkArgs('oSFF', 'Entry.copyTo', arguments);
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    var srcURL = this.toInternalURL();
+        // entry name
+    var name = newName || this.name;
+    // success callback
+    var success = function (entry) {
+        if (entry) {
+            if (successCallback) {
+                // create appropriate Entry object
+                var newFSName = entry.filesystemName || (entry.filesystem && entry.filesystem.name);
+                var fs = newFSName ? new FileSystem(newFSName, { name: '', fullPath: '/' }) : new FileSystem(parent.filesystem.name, { name: '', fullPath: '/' }); // eslint-disable-line no-undef
+                var result = (entry.isDirectory) ? new (require('./DirectoryEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL) : new (require('cordova-plugin-file.FileEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL);
+                successCallback(result);
+            }
+        } else {
+            // no Entry object returned
+            if (fail) {
+                fail(FileError.NOT_FOUND_ERR);
+            }
+        }
+    };
+
+    // copy
+    exec(success, fail, 'File', 'copyTo', [srcURL, parent.toInternalURL(), name]);
+};
+
+/**
+ * Return a URL that can be passed across the bridge to identify this entry.
+ */
+Entry.prototype.toInternalURL = function () {
+    if (this.filesystem && this.filesystem.__format__) {
+        return this.filesystem.__format__(this.fullPath, this.nativeURL);
+    }
+};
+
+/**
+ * Return a URL that can be used to identify this entry.
+ * Use a URL that can be used to as the src attribute of a <video> or
+ * <audio> tag. If that is not possible, construct a cdvfile:// URL.
+ */
+Entry.prototype.toURL = function () {
+    if (this.nativeURL) {
+        return this.nativeURL;
+    }
+    // fullPath attribute may contain the full URL in the case that
+    // toInternalURL fails.
+    return this.toInternalURL() || 'file://localhost' + this.fullPath;
+};
+
+/**
+ * Backwards-compatibility: In v1.0.0 - 1.0.2, .toURL would only return a
+ * cdvfile:// URL, and this method was necessary to obtain URLs usable by the
+ * webview.
+ * See CB-6051, CB-6106, CB-6117, CB-6152, CB-6199, CB-6201, CB-6243, CB-6249,
+ * and CB-6300.
+ */
+Entry.prototype.toNativeURL = function () {
+    console.log("DEPRECATED: Update your code to use 'toURL'");
+    return this.toURL();
+};
+
+/**
+ * Returns a URI that can be used to identify this entry.
+ *
+ * @param {DOMString} mimeType for a FileEntry, the mime type to be used to interpret the file, when loaded through this URI.
+ * @return uri
+ */
+Entry.prototype.toURI = function (mimeType) {
+    console.log("DEPRECATED: Update your code to use 'toURL'");
+    return this.toURL();
+};
+
+/**
+ * Remove a file or directory. It is an error to attempt to delete a
+ * directory that is not empty. It is an error to attempt to delete a
+ * root directory of a file system.
+ *
+ * @param successCallback {Function} called with no parameters
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.remove = function (successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'Entry.remove', arguments);
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    exec(successCallback, fail, 'File', 'remove', [this.toInternalURL()]);
+};
+
+/**
+ * Look up the parent DirectoryEntry of this entry.
+ *
+ * @param successCallback {Function} called with the parent DirectoryEntry object
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.getParent = function (successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'Entry.getParent', arguments);
+    var fs = this.filesystem;
+    var win = successCallback && function (result) {
+        var DirectoryEntry = require('./DirectoryEntry');
+        var entry = new DirectoryEntry(result.name, result.fullPath, fs, result.nativeURL);
+        successCallback(entry);
+    };
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, 'File', 'getParent', [this.toInternalURL()]);
+};
+
+module.exports = Entry;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/File.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/File.js
new file mode 100644
index 0000000..c771786
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/File.js
@@ -0,0 +1,81 @@
+cordova.define("cordova-plugin-file.File", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * Constructor.
+ * name {DOMString} name of the file, without path information
+ * fullPath {DOMString} the full path of the file, including the name
+ * type {DOMString} mime type
+ * lastModifiedDate {Date} last modified date
+ * size {Number} size of the file in bytes
+ */
+
+var File = function (name, localURL, type, lastModifiedDate, size) {
+    this.name = name || '';
+    this.localURL = localURL || null;
+    this.type = type || null;
+    this.lastModified = lastModifiedDate || null;
+    // For backwards compatibility, store the timestamp in lastModifiedDate as well
+    this.lastModifiedDate = lastModifiedDate || null;
+    this.size = size || 0;
+
+    // These store the absolute start and end for slicing the file.
+    this.start = 0;
+    this.end = this.size;
+};
+
+/**
+ * Returns a "slice" of the file. Since Cordova Files don't contain the actual
+ * content, this really returns a File with adjusted start and end.
+ * Slices of slices are supported.
+ * start {Number} The index at which to start the slice (inclusive).
+ * end {Number} The index at which to end the slice (exclusive).
+ */
+File.prototype.slice = function (start, end) {
+    var size = this.end - this.start;
+    var newStart = 0;
+    var newEnd = size;
+    if (arguments.length) {
+        if (start < 0) {
+            newStart = Math.max(size + start, 0);
+        } else {
+            newStart = Math.min(size, start);
+        }
+    }
+
+    if (arguments.length >= 2) {
+        if (end < 0) {
+            newEnd = Math.max(size + end, 0);
+        } else {
+            newEnd = Math.min(end, size);
+        }
+    }
+
+    var newFile = new File(this.name, this.localURL, this.type, this.lastModified, this.size);
+    newFile.start = this.start + newStart;
+    newFile.end = this.start + newEnd;
+    return newFile;
+};
+
+module.exports = File;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileEntry.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileEntry.js
new file mode 100644
index 0000000..6651b55
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileEntry.js
@@ -0,0 +1,95 @@
+cordova.define("cordova-plugin-file.FileEntry", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var utils = require('cordova/utils');
+var exec = require('cordova/exec');
+var Entry = require('./Entry');
+var FileWriter = require('./FileWriter');
+var File = require('./File');
+var FileError = require('./FileError');
+
+/**
+ * An interface representing a file on the file system.
+ *
+ * {boolean} isFile always true (readonly)
+ * {boolean} isDirectory always false (readonly)
+ * {DOMString} name of the file, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the file (readonly)
+ * {FileSystem} filesystem on which the file resides (readonly)
+ */
+var FileEntry = function (name, fullPath, fileSystem, nativeURL) {
+    // remove trailing slash if it is present
+    if (fullPath && /\/$/.test(fullPath)) {
+        fullPath = fullPath.substring(0, fullPath.length - 1);
+    }
+    if (nativeURL && /\/$/.test(nativeURL)) {
+        nativeURL = nativeURL.substring(0, nativeURL.length - 1);
+    }
+
+    FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath, fileSystem, nativeURL]);
+};
+
+utils.extend(FileEntry, Entry);
+
+/**
+ * Creates a new FileWriter associated with the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new FileWriter
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.createWriter = function (successCallback, errorCallback) {
+    this.file(function (filePointer) {
+        var writer = new FileWriter(filePointer);
+
+        if (writer.localURL === null || writer.localURL === '') {
+            if (errorCallback) {
+                errorCallback(new FileError(FileError.INVALID_STATE_ERR));
+            }
+        } else {
+            if (successCallback) {
+                successCallback(writer);
+            }
+        }
+    }, errorCallback);
+};
+
+/**
+ * Returns a File that represents the current state of the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new File object
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.file = function (successCallback, errorCallback) {
+    var localURL = this.toInternalURL();
+    var win = successCallback && function (f) {
+        var file = new File(f.name, localURL, f.type, f.lastModifiedDate, f.size);
+        successCallback(file);
+    };
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, 'File', 'getFileMetadata', [localURL]);
+};
+
+module.exports = FileEntry;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileError.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileError.js
new file mode 100644
index 0000000..f378c38
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileError.js
@@ -0,0 +1,49 @@
+cordova.define("cordova-plugin-file.FileError", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * FileError
+ */
+function FileError (error) {
+    this.code = error || null;
+}
+
+// File error codes
+// Found in DOMException
+FileError.NOT_FOUND_ERR = 1;
+FileError.SECURITY_ERR = 2;
+FileError.ABORT_ERR = 3;
+
+// Added by File API specification
+FileError.NOT_READABLE_ERR = 4;
+FileError.ENCODING_ERR = 5;
+FileError.NO_MODIFICATION_ALLOWED_ERR = 6;
+FileError.INVALID_STATE_ERR = 7;
+FileError.SYNTAX_ERR = 8;
+FileError.INVALID_MODIFICATION_ERR = 9;
+FileError.QUOTA_EXCEEDED_ERR = 10;
+FileError.TYPE_MISMATCH_ERR = 11;
+FileError.PATH_EXISTS_ERR = 12;
+
+module.exports = FileError;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileReader.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileReader.js
new file mode 100644
index 0000000..5c03091
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileReader.js
@@ -0,0 +1,301 @@
+cordova.define("cordova-plugin-file.FileReader", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var exec = require('cordova/exec');
+var modulemapper = require('cordova/modulemapper');
+var utils = require('cordova/utils');
+var FileError = require('./FileError');
+var ProgressEvent = require('./ProgressEvent');
+var origFileReader = modulemapper.getOriginalSymbol(window, 'FileReader');
+
+/**
+ * This class reads the mobile device file system.
+ *
+ * For Android:
+ *      The root directory is the root of the file system.
+ *      To read from the SD card, the file name is "sdcard/my_file.txt"
+ * @constructor
+ */
+var FileReader = function () {
+    this._readyState = 0;
+    this._error = null;
+    this._result = null;
+    this._progress = null;
+    this._localURL = '';
+    this._realReader = origFileReader ? new origFileReader() : {}; // eslint-disable-line new-cap
+};
+
+/**
+ * Defines the maximum size to read at a time via the native API. The default value is a compromise between
+ * minimizing the overhead of many exec() calls while still reporting progress frequently enough for large files.
+ * (Note attempts to allocate more than a few MB of contiguous memory on the native side are likely to cause
+ * OOM exceptions, while the JS engine seems to have fewer problems managing large strings or ArrayBuffers.)
+ */
+FileReader.READ_CHUNK_SIZE = 256 * 1024;
+
+// States
+FileReader.EMPTY = 0;
+FileReader.LOADING = 1;
+FileReader.DONE = 2;
+
+utils.defineGetter(FileReader.prototype, 'readyState', function () {
+    return this._localURL ? this._readyState : this._realReader.readyState;
+});
+
+utils.defineGetter(FileReader.prototype, 'error', function () {
+    return this._localURL ? this._error : this._realReader.error;
+});
+
+utils.defineGetter(FileReader.prototype, 'result', function () {
+    return this._localURL ? this._result : this._realReader.result;
+});
+
+function defineEvent (eventName) {
+    utils.defineGetterSetter(FileReader.prototype, eventName, function () {
+        return this._realReader[eventName] || null;
+    }, function (value) {
+        this._realReader[eventName] = value;
+    });
+}
+defineEvent('onloadstart');    // When the read starts.
+defineEvent('onprogress');     // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total)
+defineEvent('onload');         // When the read has successfully completed.
+defineEvent('onerror');        // When the read has failed (see errors).
+defineEvent('onloadend');      // When the request has completed (either in success or failure).
+defineEvent('onabort');        // When the read has been aborted. For instance, by invoking the abort() method.
+
+function initRead (reader, file) {
+    // Already loading something
+    if (reader.readyState === FileReader.LOADING) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    reader._result = null;
+    reader._error = null;
+    reader._progress = 0;
+    reader._readyState = FileReader.LOADING;
+
+    if (typeof file.localURL === 'string') {
+        reader._localURL = file.localURL;
+    } else {
+        reader._localURL = '';
+        return true;
+    }
+
+    if (reader.onloadstart) {
+        reader.onloadstart(new ProgressEvent('loadstart', {target: reader}));
+    }
+}
+
+/**
+ * Callback used by the following read* functions to handle incremental or final success.
+ * Must be bound to the FileReader's this along with all but the last parameter,
+ * e.g. readSuccessCallback.bind(this, "readAsText", "UTF-8", offset, totalSize, accumulate)
+ * @param readType The name of the read function to call.
+ * @param encoding Text encoding, or null if this is not a text type read.
+ * @param offset Starting offset of the read.
+ * @param totalSize Total number of bytes or chars to read.
+ * @param accumulate A function that takes the callback result and accumulates it in this._result.
+ * @param r Callback result returned by the last read exec() call, or null to begin reading.
+ */
+function readSuccessCallback (readType, encoding, offset, totalSize, accumulate, r) {
+    if (this._readyState === FileReader.DONE) {
+        return;
+    }
+
+    var CHUNK_SIZE = FileReader.READ_CHUNK_SIZE;
+    if (readType === 'readAsDataURL') {
+        // Windows proxy does not support reading file slices as Data URLs
+        // so read the whole file at once.
+        CHUNK_SIZE = cordova.platformId === 'windows' ? totalSize : // eslint-disable-line no-undef
+            // Calculate new chunk size for data URLs to be multiply of 3
+            // Otherwise concatenated base64 chunks won't be valid base64 data
+            FileReader.READ_CHUNK_SIZE - (FileReader.READ_CHUNK_SIZE % 3) + 3;
+    }
+
+    if (typeof r !== 'undefined') {
+        accumulate(r);
+        this._progress = Math.min(this._progress + CHUNK_SIZE, totalSize);
+
+        if (typeof this.onprogress === 'function') {
+            this.onprogress(new ProgressEvent('progress', {loaded: this._progress, total: totalSize}));
+        }
+    }
+
+    if (typeof r === 'undefined' || this._progress < totalSize) {
+        var execArgs = [
+            this._localURL,
+            offset + this._progress,
+            offset + this._progress + Math.min(totalSize - this._progress, CHUNK_SIZE)];
+        if (encoding) {
+            execArgs.splice(1, 0, encoding);
+        }
+        exec(
+            readSuccessCallback.bind(this, readType, encoding, offset, totalSize, accumulate),
+            readFailureCallback.bind(this),
+            'File', readType, execArgs);
+    } else {
+        this._readyState = FileReader.DONE;
+
+        if (typeof this.onload === 'function') {
+            this.onload(new ProgressEvent('load', {target: this}));
+        }
+
+        if (typeof this.onloadend === 'function') {
+            this.onloadend(new ProgressEvent('loadend', {target: this}));
+        }
+    }
+}
+
+/**
+ * Callback used by the following read* functions to handle errors.
+ * Must be bound to the FileReader's this, e.g. readFailureCallback.bind(this)
+ */
+function readFailureCallback (e) {
+    if (this._readyState === FileReader.DONE) {
+        return;
+    }
+
+    this._readyState = FileReader.DONE;
+    this._result = null;
+    this._error = new FileError(e);
+
+    if (typeof this.onerror === 'function') {
+        this.onerror(new ProgressEvent('error', {target: this}));
+    }
+
+    if (typeof this.onloadend === 'function') {
+        this.onloadend(new ProgressEvent('loadend', {target: this}));
+    }
+}
+
+/**
+ * Abort reading file.
+ */
+FileReader.prototype.abort = function () {
+    if (origFileReader && !this._localURL) {
+        return this._realReader.abort();
+    }
+    this._result = null;
+
+    if (this._readyState === FileReader.DONE || this._readyState === FileReader.EMPTY) {
+        return;
+    }
+
+    this._readyState = FileReader.DONE;
+
+    // If abort callback
+    if (typeof this.onabort === 'function') {
+        this.onabort(new ProgressEvent('abort', {target: this}));
+    }
+    // If load end callback
+    if (typeof this.onloadend === 'function') {
+        this.onloadend(new ProgressEvent('loadend', {target: this}));
+    }
+};
+
+/**
+ * Read text file.
+ *
+ * @param file          {File} File object containing file properties
+ * @param encoding      [Optional] (see http://www.iana.org/assignments/character-sets)
+ */
+FileReader.prototype.readAsText = function (file, encoding) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsText(file, encoding);
+    }
+
+    // Default encoding is UTF-8
+    var enc = encoding || 'UTF-8';
+
+    var totalSize = file.end - file.start;
+    readSuccessCallback.bind(this)('readAsText', enc, file.start, totalSize, function (r) {
+        if (this._progress === 0) {
+            this._result = '';
+        }
+        this._result += r;
+    }.bind(this));
+};
+
+/**
+ * Read file and return data as a base64 encoded data url.
+ * A data url is of the form:
+ *      data:[<mediatype>][;base64],<data>
+ *
+ * @param file          {File} File object containing file properties
+ */
+FileReader.prototype.readAsDataURL = function (file) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsDataURL(file);
+    }
+
+    var totalSize = file.end - file.start;
+    readSuccessCallback.bind(this)('readAsDataURL', null, file.start, totalSize, function (r) {
+        var commaIndex = r.indexOf(',');
+        if (this._progress === 0) {
+            this._result = r;
+        } else {
+            this._result += r.substring(commaIndex + 1);
+        }
+    }.bind(this));
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file          {File} File object containing file properties
+ */
+FileReader.prototype.readAsBinaryString = function (file) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsBinaryString(file);
+    }
+
+    var totalSize = file.end - file.start;
+    readSuccessCallback.bind(this)('readAsBinaryString', null, file.start, totalSize, function (r) {
+        if (this._progress === 0) {
+            this._result = '';
+        }
+        this._result += r;
+    }.bind(this));
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file          {File} File object containing file properties
+ */
+FileReader.prototype.readAsArrayBuffer = function (file) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsArrayBuffer(file);
+    }
+
+    var totalSize = file.end - file.start;
+    readSuccessCallback.bind(this)('readAsArrayBuffer', null, file.start, totalSize, function (r) {
+        var resultArray = (this._progress === 0 ? new Uint8Array(totalSize) : new Uint8Array(this._result));
+        resultArray.set(new Uint8Array(r), this._progress);
+        this._result = resultArray.buffer;
+    }.bind(this));
+};
+
+module.exports = FileReader;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileSystem.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileSystem.js
new file mode 100644
index 0000000..ad9ea78
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileSystem.js
@@ -0,0 +1,58 @@
+cordova.define("cordova-plugin-file.FileSystem", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var DirectoryEntry = require('./DirectoryEntry');
+
+/**
+ * An interface representing a file system
+ *
+ * @constructor
+ * {DOMString} name the unique name of the file system (readonly)
+ * {DirectoryEntry} root directory of the file system (readonly)
+ */
+var FileSystem = function (name, root) {
+    this.name = name;
+    if (root) {
+        this.root = new DirectoryEntry(root.name, root.fullPath, this, root.nativeURL);
+    } else {
+        this.root = new DirectoryEntry(this.name, '/', this);
+    }
+};
+
+FileSystem.prototype.__format__ = function (fullPath, nativeUrl) {
+    return fullPath;
+};
+
+FileSystem.prototype.toJSON = function () {
+    return '<FileSystem: ' + this.name + '>';
+};
+
+// Use instead of encodeURI() when encoding just the path part of a URI rather than an entire URI.
+FileSystem.encodeURIPath = function (path) {
+    // Because # is a valid filename character, it must be encoded to prevent part of the
+    // path from being parsed as a URI fragment.
+    return encodeURI(path).replace(/#/g, '%23');
+};
+
+module.exports = FileSystem;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileUploadOptions.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileUploadOptions.js
new file mode 100644
index 0000000..6acd093
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileUploadOptions.js
@@ -0,0 +1,44 @@
+cordova.define("cordova-plugin-file.FileUploadOptions", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * Options to customize the HTTP request used to upload files.
+ * @constructor
+ * @param fileKey {String}   Name of file request parameter.
+ * @param fileName {String}  Filename to be used by the server. Defaults to image.jpg.
+ * @param mimeType {String}  Mimetype of the uploaded file. Defaults to image/jpeg.
+ * @param params {Object}    Object with key: value params to send to the server.
+ * @param headers {Object}   Keys are header names, values are header values. Multiple
+ *                           headers of the same name are not supported.
+ */
+var FileUploadOptions = function (fileKey, fileName, mimeType, params, headers, httpMethod) {
+    this.fileKey = fileKey || null;
+    this.fileName = fileName || null;
+    this.mimeType = mimeType || null;
+    this.params = params || null;
+    this.headers = headers || null;
+    this.httpMethod = httpMethod || null;
+};
+
+module.exports = FileUploadOptions;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileUploadResult.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileUploadResult.js
new file mode 100644
index 0000000..e3c3a74
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileUploadResult.js
@@ -0,0 +1,33 @@
+cordova.define("cordova-plugin-file.FileUploadResult", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * FileUploadResult
+ * @constructor
+ */
+module.exports = function FileUploadResult (size, code, content) {
+    this.bytesSent = size;
+    this.responseCode = code;
+    this.response = content;
+};
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileWriter.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileWriter.js
new file mode 100644
index 0000000..d48a089
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/FileWriter.js
@@ -0,0 +1,327 @@
+cordova.define("cordova-plugin-file.FileWriter", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var exec = require('cordova/exec');
+var FileError = require('./FileError');
+var ProgressEvent = require('./ProgressEvent');
+
+/**
+ * This class writes to the mobile device file system.
+ *
+ * For Android:
+ *      The root directory is the root of the file system.
+ *      To write to the SD card, the file name is "sdcard/my_file.txt"
+ *
+ * @constructor
+ * @param file {File} File object containing file properties
+ * @param append if true write to the end of the file, otherwise overwrite the file
+ */
+var FileWriter = function (file) {
+    this.fileName = '';
+    this.length = 0;
+    if (file) {
+        this.localURL = file.localURL || file;
+        this.length = file.size || 0;
+    }
+    // default is to write at the beginning of the file
+    this.position = 0;
+
+    this.readyState = 0; // EMPTY
+
+    this.result = null;
+
+    // Error
+    this.error = null;
+
+    // Event handlers
+    this.onwritestart = null;   // When writing starts
+    this.onprogress = null;     // While writing the file, and reporting partial file data
+    this.onwrite = null;        // When the write has successfully completed.
+    this.onwriteend = null;     // When the request has completed (either in success or failure).
+    this.onabort = null;        // When the write has been aborted. For instance, by invoking the abort() method.
+    this.onerror = null;        // When the write has failed (see errors).
+};
+
+// States
+FileWriter.INIT = 0;
+FileWriter.WRITING = 1;
+FileWriter.DONE = 2;
+
+/**
+ * Abort writing file.
+ */
+FileWriter.prototype.abort = function () {
+    // check for invalid state
+    if (this.readyState === FileWriter.DONE || this.readyState === FileWriter.INIT) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    // set error
+    this.error = new FileError(FileError.ABORT_ERR);
+
+    this.readyState = FileWriter.DONE;
+
+    // If abort callback
+    if (typeof this.onabort === 'function') {
+        this.onabort(new ProgressEvent('abort', {'target': this}));
+    }
+
+    // If write end callback
+    if (typeof this.onwriteend === 'function') {
+        this.onwriteend(new ProgressEvent('writeend', {'target': this}));
+    }
+};
+
+/**
+ * Writes data to the file
+ *
+ * @param data text or blob to be written
+ * @param isPendingBlobReadResult {Boolean} true if the data is the pending blob read operation result
+ */
+FileWriter.prototype.write = function (data, isPendingBlobReadResult) {
+
+    var that = this;
+    var supportsBinary = (typeof window.Blob !== 'undefined' && typeof window.ArrayBuffer !== 'undefined');
+    /* eslint-disable no-undef */
+    var isProxySupportBlobNatively = (cordova.platformId === 'windows8' || cordova.platformId === 'windows');
+    var isBinary;
+
+    // Check to see if the incoming data is a blob
+    if (data instanceof File || (!isProxySupportBlobNatively && supportsBinary && data instanceof Blob)) {
+        var fileReader = new FileReader();
+        /* eslint-enable no-undef */
+        fileReader.onload = function () {
+            // Call this method again, with the arraybuffer as argument
+            FileWriter.prototype.write.call(that, this.result, true /* isPendingBlobReadResult */);
+        };
+        fileReader.onerror = function () {
+            // DONE state
+            that.readyState = FileWriter.DONE;
+
+            // Save error
+            that.error = this.error;
+
+            // If onerror callback
+            if (typeof that.onerror === 'function') {
+                that.onerror(new ProgressEvent('error', {'target': that}));
+            }
+
+            // If onwriteend callback
+            if (typeof that.onwriteend === 'function') {
+                that.onwriteend(new ProgressEvent('writeend', {'target': that}));
+            }
+        };
+
+        // WRITING state
+        this.readyState = FileWriter.WRITING;
+
+        if (supportsBinary) {
+            fileReader.readAsArrayBuffer(data);
+        } else {
+            fileReader.readAsText(data);
+        }
+        return;
+    }
+
+    // Mark data type for safer transport over the binary bridge
+    isBinary = supportsBinary && (data instanceof ArrayBuffer);
+    if (isBinary && cordova.platformId === 'windowsphone') { // eslint-disable-line no-undef
+        // create a plain array, using the keys from the Uint8Array view so that we can serialize it
+        data = Array.apply(null, new Uint8Array(data));
+    }
+
+    // Throw an exception if we are already writing a file
+    if (this.readyState === FileWriter.WRITING && !isPendingBlobReadResult) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    // WRITING state
+    this.readyState = FileWriter.WRITING;
+
+    var me = this;
+
+    // If onwritestart callback
+    if (typeof me.onwritestart === 'function') {
+        me.onwritestart(new ProgressEvent('writestart', {'target': me}));
+    }
+
+    // Write file
+    exec(
+        // Success callback
+        function (r) {
+            // If DONE (cancelled), then don't do anything
+            if (me.readyState === FileWriter.DONE) {
+                return;
+            }
+
+            // position always increases by bytes written because file would be extended
+            me.position += r;
+            // The length of the file is now where we are done writing.
+
+            me.length = me.position;
+
+            // DONE state
+            me.readyState = FileWriter.DONE;
+
+            // If onwrite callback
+            if (typeof me.onwrite === 'function') {
+                me.onwrite(new ProgressEvent('write', {'target': me}));
+            }
+
+            // If onwriteend callback
+            if (typeof me.onwriteend === 'function') {
+                me.onwriteend(new ProgressEvent('writeend', {'target': me}));
+            }
+        },
+        // Error callback
+        function (e) {
+            // If DONE (cancelled), then don't do anything
+            if (me.readyState === FileWriter.DONE) {
+                return;
+            }
+
+            // DONE state
+            me.readyState = FileWriter.DONE;
+
+            // Save error
+            me.error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === 'function') {
+                me.onerror(new ProgressEvent('error', {'target': me}));
+            }
+
+            // If onwriteend callback
+            if (typeof me.onwriteend === 'function') {
+                me.onwriteend(new ProgressEvent('writeend', {'target': me}));
+            }
+        }, 'File', 'write', [this.localURL, data, this.position, isBinary]);
+};
+
+/**
+ * Moves the file pointer to the location specified.
+ *
+ * If the offset is a negative number the position of the file
+ * pointer is rewound.  If the offset is greater than the file
+ * size the position is set to the end of the file.
+ *
+ * @param offset is the location to move the file pointer to.
+ */
+FileWriter.prototype.seek = function (offset) {
+    // Throw an exception if we are already writing a file
+    if (this.readyState === FileWriter.WRITING) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    if (!offset && offset !== 0) {
+        return;
+    }
+
+    // See back from end of file.
+    if (offset < 0) {
+        this.position = Math.max(offset + this.length, 0);
+    // Offset is bigger than file size so set position
+    // to the end of the file.
+    } else if (offset > this.length) {
+        this.position = this.length;
+    // Offset is between 0 and file size so set the position
+    // to start writing.
+    } else {
+        this.position = offset;
+    }
+};
+
+/**
+ * Truncates the file to the size specified.
+ *
+ * @param size to chop the file at.
+ */
+FileWriter.prototype.truncate = function (size) {
+    // Throw an exception if we are already writing a file
+    if (this.readyState === FileWriter.WRITING) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    // WRITING state
+    this.readyState = FileWriter.WRITING;
+
+    var me = this;
+
+    // If onwritestart callback
+    if (typeof me.onwritestart === 'function') {
+        me.onwritestart(new ProgressEvent('writestart', {'target': this}));
+    }
+
+    // Write file
+    exec(
+        // Success callback
+        function (r) {
+            // If DONE (cancelled), then don't do anything
+            if (me.readyState === FileWriter.DONE) {
+                return;
+            }
+
+            // DONE state
+            me.readyState = FileWriter.DONE;
+
+            // Update the length of the file
+            me.length = r;
+            me.position = Math.min(me.position, r);
+
+            // If onwrite callback
+            if (typeof me.onwrite === 'function') {
+                me.onwrite(new ProgressEvent('write', {'target': me}));
+            }
+
+            // If onwriteend callback
+            if (typeof me.onwriteend === 'function') {
+                me.onwriteend(new ProgressEvent('writeend', {'target': me}));
+            }
+        },
+        // Error callback
+        function (e) {
+            // If DONE (cancelled), then don't do anything
+            if (me.readyState === FileWriter.DONE) {
+                return;
+            }
+
+            // DONE state
+            me.readyState = FileWriter.DONE;
+
+            // Save error
+            me.error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === 'function') {
+                me.onerror(new ProgressEvent('error', {'target': me}));
+            }
+
+            // If onwriteend callback
+            if (typeof me.onwriteend === 'function') {
+                me.onwriteend(new ProgressEvent('writeend', {'target': me}));
+            }
+        }, 'File', 'truncate', [this.localURL, size]);
+};
+
+module.exports = FileWriter;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/Flags.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/Flags.js
new file mode 100644
index 0000000..cdb12bb
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/Flags.js
@@ -0,0 +1,39 @@
+cordova.define("cordova-plugin-file.Flags", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * Supplies arguments to methods that lookup or create files and directories.
+ *
+ * @param create
+ *            {boolean} file or directory if it doesn't exist
+ * @param exclusive
+ *            {boolean} used with create; if true the command will fail if
+ *            target path exists
+ */
+function Flags (create, exclusive) {
+    this.create = create || false;
+    this.exclusive = exclusive || false;
+}
+
+module.exports = Flags;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/LocalFileSystem.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/LocalFileSystem.js
new file mode 100644
index 0000000..4ce6848
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/LocalFileSystem.js
@@ -0,0 +1,26 @@
+cordova.define("cordova-plugin-file.LocalFileSystem", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+exports.TEMPORARY = 0;
+exports.PERSISTENT = 1;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/Metadata.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/Metadata.js
new file mode 100644
index 0000000..22366e1
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/Metadata.js
@@ -0,0 +1,43 @@
+cordova.define("cordova-plugin-file.Metadata", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * Information about the state of the file or directory
+ *
+ * {Date} modificationTime (readonly)
+ */
+var Metadata = function (metadata) {
+    if (typeof metadata === 'object') {
+        this.modificationTime = new Date(metadata.modificationTime);
+        this.size = metadata.size || 0;
+    } else if (typeof metadata === 'undefined') {
+        this.modificationTime = null;
+        this.size = 0;
+    } else {
+        /* Backwards compatiblity with platforms that only return a timestamp */
+        this.modificationTime = new Date(metadata);
+    }
+};
+
+module.exports = Metadata;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/ProgressEvent.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/ProgressEvent.js
new file mode 100644
index 0000000..cbecdb1
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/ProgressEvent.js
@@ -0,0 +1,70 @@
+cordova.define("cordova-plugin-file.ProgressEvent", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+// If ProgressEvent exists in global context, use it already, otherwise use our own polyfill
+// Feature test: See if we can instantiate a native ProgressEvent;
+// if so, use that approach,
+// otherwise fill-in with our own implementation.
+//
+// NOTE: right now we always fill in with our own. Down the road would be nice if we can use whatever is native in the webview.
+var ProgressEvent = (function () {
+    /*
+    var createEvent = function(data) {
+        var event = document.createEvent('Events');
+        event.initEvent('ProgressEvent', false, false);
+        if (data) {
+            for (var i in data) {
+                if (data.hasOwnProperty(i)) {
+                    event[i] = data[i];
+                }
+            }
+            if (data.target) {
+                // TODO: cannot call <some_custom_object>.dispatchEvent
+                // need to first figure out how to implement EventTarget
+            }
+        }
+        return event;
+    };
+    try {
+        var ev = createEvent({type:"abort",target:document});
+        return function ProgressEvent(type, data) {
+            data.type = type;
+            return createEvent(data);
+        };
+    } catch(e){
+    */
+    return function ProgressEvent (type, dict) {
+        this.type = type;
+        this.bubbles = false;
+        this.cancelBubble = false;
+        this.cancelable = false;
+        this.lengthComputable = false;
+        this.loaded = dict && dict.loaded ? dict.loaded : 0;
+        this.total = dict && dict.total ? dict.total : 0;
+        this.target = dict && dict.target ? dict.target : null;
+    };
+    // }
+})();
+
+module.exports = ProgressEvent;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/android/FileSystem.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/android/FileSystem.js
new file mode 100644
index 0000000..0124fa6
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/android/FileSystem.js
@@ -0,0 +1,51 @@
+cordova.define("cordova-plugin-file.androidFileSystem", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+FILESYSTEM_PROTOCOL = 'cdvfile'; // eslint-disable-line no-undef
+
+module.exports = {
+    __format__: function (fullPath, nativeUrl) {
+        var path;
+        var contentUrlMatch = /^content:\/\//.exec(nativeUrl);
+        if (contentUrlMatch) {
+            // When available, use the path from a native content URL, which was already encoded by Android.
+            // This is necessary because JavaScript's encodeURI() does not encode as many characters as
+            // Android, which can result in permission exceptions when the encoding of a content URI
+            // doesn't match the string for which permission was originally granted.
+            path = nativeUrl.substring(contentUrlMatch[0].length - 1);
+        } else {
+            path = FileSystem.encodeURIPath(fullPath); // eslint-disable-line no-undef
+            if (!/^\//.test(path)) {
+                path = '/' + path;
+            }
+
+            var m = /\?.*/.exec(nativeUrl);
+            if (m) {
+                path += m[0];
+            }
+        }
+
+        return FILESYSTEM_PROTOCOL + '://localhost/' + this.name + path; // eslint-disable-line no-undef
+    }
+};
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/browser/isChrome.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/browser/isChrome.js
new file mode 100644
index 0000000..c74fd9c
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/browser/isChrome.js
@@ -0,0 +1,29 @@
+cordova.define("cordova-plugin-file.isChrome", function(require, exports, module) {
+/*

+ *

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ *

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ *

+ */

+

+module.exports = function () {

+    // window.webkitRequestFileSystem and window.webkitResolveLocalFileSystemURL are available only in Chrome and

+    // possibly a good flag to indicate that we're running in Chrome

+    return window.webkitRequestFileSystem && window.webkitResolveLocalFileSystemURL;

+};

+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/fileSystemPaths.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/fileSystemPaths.js
new file mode 100644
index 0000000..4bfc0f6
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/fileSystemPaths.js
@@ -0,0 +1,65 @@
+cordova.define("cordova-plugin-file.fileSystemPaths", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var exec = require('cordova/exec');
+var channel = require('cordova/channel');
+
+exports.file = {
+    // Read-only directory where the application is installed.
+    applicationDirectory: null,
+    // Root of app's private writable storage
+    applicationStorageDirectory: null,
+    // Where to put app-specific data files.
+    dataDirectory: null,
+    // Cached files that should survive app restarts.
+    // Apps should not rely on the OS to delete files in here.
+    cacheDirectory: null,
+    // Android: the application space on external storage.
+    externalApplicationStorageDirectory: null,
+    // Android: Where to put app-specific data files on external storage.
+    externalDataDirectory: null,
+    // Android: the application cache on external storage.
+    externalCacheDirectory: null,
+    // Android: the external storage (SD card) root.
+    externalRootDirectory: null,
+    // iOS: Temp directory that the OS can clear at will.
+    tempDirectory: null,
+    // iOS: Holds app-specific files that should be synced (e.g. to iCloud).
+    syncedDataDirectory: null,
+    // iOS: Files private to the app, but that are meaningful to other applications (e.g. Office files)
+    documentsDirectory: null,
+    // BlackBerry10: Files globally available to all apps
+    sharedDirectory: null
+};
+
+channel.waitForInitialization('onFileSystemPathsReady');
+channel.onCordovaReady.subscribe(function () {
+    function after (paths) {
+        for (var k in paths) {
+            exports.file[k] = paths[k];
+        }
+        channel.initializationComplete('onFileSystemPathsReady');
+    }
+    exec(after, null, 'File', 'requestAllPaths', []);
+});
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/fileSystems-roots.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/fileSystems-roots.js
new file mode 100644
index 0000000..9351132
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/fileSystems-roots.js
@@ -0,0 +1,47 @@
+cordova.define("cordova-plugin-file.fileSystems-roots", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+// Map of fsName -> FileSystem.
+var fsMap = null;
+var FileSystem = require('./FileSystem');
+var exec = require('cordova/exec');
+
+// Overridden by Android, BlackBerry 10 and iOS to populate fsMap.
+require('./fileSystems').getFs = function (name, callback) {
+    function success (response) {
+        fsMap = {};
+        for (var i = 0; i < response.length; ++i) {
+            var fsRoot = response[i];
+            var fs = new FileSystem(fsRoot.filesystemName, fsRoot);
+            fsMap[fs.name] = fs;
+        }
+        callback(fsMap[name]);
+    }
+
+    if (fsMap) {
+        callback(fsMap[name]);
+    } else {
+        exec(success, null, 'File', 'requestAllFileSystems', []);
+    }
+};
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/fileSystems.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/fileSystems.js
new file mode 100644
index 0000000..e61ceaf
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/fileSystems.js
@@ -0,0 +1,28 @@
+cordova.define("cordova-plugin-file.fileSystems", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+// Overridden by Android, BlackBerry 10 and iOS to populate fsMap.
+module.exports.getFs = function (name, callback) {
+    callback(null);
+};
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/requestFileSystem.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/requestFileSystem.js
new file mode 100644
index 0000000..7f65219
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/requestFileSystem.js
@@ -0,0 +1,84 @@
+cordova.define("cordova-plugin-file.requestFileSystem", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+(function () {
+    // For browser platform: not all browsers use this file.
+    function checkBrowser () {
+        if (cordova.platformId === 'browser' && require('./isChrome')()) { // eslint-disable-line no-undef
+            module.exports = window.requestFileSystem || window.webkitRequestFileSystem;
+            return true;
+        }
+        return false;
+    }
+    if (checkBrowser()) {
+        return;
+    }
+
+    var argscheck = require('cordova/argscheck');
+    var FileError = require('./FileError');
+    var FileSystem = require('./FileSystem');
+    var exec = require('cordova/exec');
+    var fileSystems = require('./fileSystems');
+
+    /**
+     * Request a file system in which to store application data.
+     * @param type  local file system type
+     * @param size  indicates how much storage space, in bytes, the application expects to need
+     * @param successCallback  invoked with a FileSystem object
+     * @param errorCallback  invoked if error occurs retrieving file system
+     */
+    var requestFileSystem = function (type, size, successCallback, errorCallback) {
+        argscheck.checkArgs('nnFF', 'requestFileSystem', arguments);
+        var fail = function (code) {
+            if (errorCallback) {
+                errorCallback(new FileError(code));
+            }
+        };
+
+        if (type < 0) {
+            fail(FileError.SYNTAX_ERR);
+        } else {
+            // if successful, return a FileSystem object
+            var success = function (file_system) {
+                if (file_system) {
+                    if (successCallback) {
+                        fileSystems.getFs(file_system.name, function (fs) {
+                            // This should happen only on platforms that haven't implemented requestAllFileSystems (windows)
+                            if (!fs) {
+                                fs = new FileSystem(file_system.name, file_system.root);
+                            }
+                            successCallback(fs);
+                        });
+                    }
+                } else {
+                    // no FileSystem object returned
+                    fail(FileError.NOT_FOUND_ERR);
+                }
+            };
+            exec(success, fail, 'File', 'requestFileSystem', [type, size]);
+        }
+    };
+
+    module.exports = requestFileSystem;
+})();
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/resolveLocalFileSystemURI.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/resolveLocalFileSystemURI.js
new file mode 100644
index 0000000..73715bc
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-file/www/resolveLocalFileSystemURI.js
@@ -0,0 +1,94 @@
+cordova.define("cordova-plugin-file.resolveLocalFileSystemURI", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+(function () {
+    // For browser platform: not all browsers use overrided `resolveLocalFileSystemURL`.
+    function checkBrowser () {
+        if (cordova.platformId === 'browser' && require('./isChrome')()) { // eslint-disable-line no-undef
+            module.exports.resolveLocalFileSystemURL = window.resolveLocalFileSystemURL || window.webkitResolveLocalFileSystemURL;
+            return true;
+        }
+        return false;
+    }
+    if (checkBrowser()) {
+        return;
+    }
+
+    var argscheck = require('cordova/argscheck');
+    var DirectoryEntry = require('./DirectoryEntry');
+    var FileEntry = require('./FileEntry');
+    var FileError = require('./FileError');
+    var exec = require('cordova/exec');
+    var fileSystems = require('./fileSystems');
+
+    /**
+     * Look up file system Entry referred to by local URI.
+     * @param {DOMString} uri  URI referring to a local file or directory
+     * @param successCallback  invoked with Entry object corresponding to URI
+     * @param errorCallback    invoked if error occurs retrieving file system entry
+     */
+    module.exports.resolveLocalFileSystemURL = module.exports.resolveLocalFileSystemURL || function (uri, successCallback, errorCallback) {
+        argscheck.checkArgs('sFF', 'resolveLocalFileSystemURI', arguments);
+        // error callback
+        var fail = function (error) {
+            if (errorCallback) {
+                errorCallback(new FileError(error));
+            }
+        };
+        // sanity check for 'not:valid:filename' or '/not:valid:filename'
+        // file.spec.12 window.resolveLocalFileSystemURI should error (ENCODING_ERR) when resolving invalid URI with leading /.
+        if (!uri || uri.split(':').length > 2) {
+            setTimeout(function () {
+                fail(FileError.ENCODING_ERR);
+            }, 0);
+            return;
+        }
+        // if successful, return either a file or directory entry
+        var success = function (entry) {
+            if (entry) {
+                if (successCallback) {
+                    // create appropriate Entry object
+                    var fsName = entry.filesystemName || (entry.filesystem && entry.filesystem.name) || (entry.filesystem === window.PERSISTENT ? 'persistent' : 'temporary'); // eslint-disable-line no-undef
+                    fileSystems.getFs(fsName, function (fs) {
+                        // This should happen only on platforms that haven't implemented requestAllFileSystems (windows)
+                        if (!fs) {
+                            fs = new FileSystem(fsName, {name: '', fullPath: '/'}); // eslint-disable-line no-undef
+                        }
+                        var result = (entry.isDirectory) ? new DirectoryEntry(entry.name, entry.fullPath, fs, entry.nativeURL) : new FileEntry(entry.name, entry.fullPath, fs, entry.nativeURL);
+                        successCallback(result);
+                    });
+                }
+            } else {
+                // no Entry object returned
+                fail(FileError.NOT_FOUND_ERR);
+            }
+        };
+
+        exec(success, fail, 'File', 'resolveLocalFileSystemURI', [uri]);
+    };
+
+    module.exports.resolveLocalFileSystemURI = function () {
+        console.log('resolveLocalFileSystemURI is deprecated. Please call resolveLocalFileSystemURL instead.');
+        module.exports.resolveLocalFileSystemURL.apply(this, arguments);
+    };
+})();
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-fingerprint-aio/www/Fingerprint.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-fingerprint-aio/www/Fingerprint.js
new file mode 100644
index 0000000..3982139
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-fingerprint-aio/www/Fingerprint.js
@@ -0,0 +1,29 @@
+cordova.define("cordova-plugin-fingerprint-aio.Fingerprint", function(require, exports, module) {
+/*global cordova */
+
+function Fingerprint() {
+}
+
+Fingerprint.prototype.show = function (params, successCallback, errorCallback) {
+  cordova.exec(
+    successCallback,
+    errorCallback,
+    "Fingerprint",
+    "authenticate",
+    [params]
+  );
+};
+
+Fingerprint.prototype.isAvailable = function (successCallback, errorCallback) {
+  cordova.exec(
+    successCallback,
+    errorCallback,
+    "Fingerprint",
+    "isAvailable",
+    [{}]
+  );
+};
+
+module.exports = new Fingerprint();
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-inappbrowser/www/inappbrowser.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-inappbrowser/www/inappbrowser.js
new file mode 100644
index 0000000..a3021c2
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-inappbrowser/www/inappbrowser.js
@@ -0,0 +1,118 @@
+cordova.define("cordova-plugin-inappbrowser.inappbrowser", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+(function () {
+    // special patch to correctly work on Ripple emulator (CB-9760)
+    if (window.parent && !!window.parent.ripple) { // https://gist.github.com/triceam/4658021
+        module.exports = window.open.bind(window); // fallback to default window.open behaviour
+        return;
+    }
+
+    var exec = require('cordova/exec');
+    var channel = require('cordova/channel');
+    var modulemapper = require('cordova/modulemapper');
+    var urlutil = require('cordova/urlutil');
+
+    function InAppBrowser () {
+        this.channels = {
+            'loadstart': channel.create('loadstart'),
+            'loadstop': channel.create('loadstop'),
+            'loaderror': channel.create('loaderror'),
+            'exit': channel.create('exit'),
+            'customscheme': channel.create('customscheme')
+        };
+    }
+
+    InAppBrowser.prototype = {
+        _eventHandler: function (event) {
+            if (event && (event.type in this.channels)) {
+                this.channels[event.type].fire(event);
+            }
+        },
+        close: function (eventname) {
+            exec(null, null, 'InAppBrowser', 'close', []);
+        },
+        show: function (eventname) {
+            exec(null, null, 'InAppBrowser', 'show', []);
+        },
+        hide: function (eventname) {
+            exec(null, null, 'InAppBrowser', 'hide', []);
+        },
+        addEventListener: function (eventname, f) {
+            if (eventname in this.channels) {
+                this.channels[eventname].subscribe(f);
+            }
+        },
+        removeEventListener: function (eventname, f) {
+            if (eventname in this.channels) {
+                this.channels[eventname].unsubscribe(f);
+            }
+        },
+
+        executeScript: function (injectDetails, cb) {
+            if (injectDetails.code) {
+                exec(cb, null, 'InAppBrowser', 'injectScriptCode', [injectDetails.code, !!cb]);
+            } else if (injectDetails.file) {
+                exec(cb, null, 'InAppBrowser', 'injectScriptFile', [injectDetails.file, !!cb]);
+            } else {
+                throw new Error('executeScript requires exactly one of code or file to be specified');
+            }
+        },
+
+        insertCSS: function (injectDetails, cb) {
+            if (injectDetails.code) {
+                exec(cb, null, 'InAppBrowser', 'injectStyleCode', [injectDetails.code, !!cb]);
+            } else if (injectDetails.file) {
+                exec(cb, null, 'InAppBrowser', 'injectStyleFile', [injectDetails.file, !!cb]);
+            } else {
+                throw new Error('insertCSS requires exactly one of code or file to be specified');
+            }
+        }
+    };
+
+    module.exports = function (strUrl, strWindowName, strWindowFeatures, callbacks) {
+        // Don't catch calls that write to existing frames (e.g. named iframes).
+        if (window.frames && window.frames[strWindowName]) {
+            var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open');
+            return origOpenFunc.apply(window, arguments);
+        }
+
+        strUrl = urlutil.makeAbsolute(strUrl);
+        var iab = new InAppBrowser();
+
+        callbacks = callbacks || {};
+        for (var callbackName in callbacks) {
+            iab.addEventListener(callbackName, callbacks[callbackName]);
+        }
+
+        var cb = function (eventname) {
+            iab._eventHandler(eventname);
+        };
+
+        strWindowFeatures = strWindowFeatures || '';
+
+        exec(cb, cb, 'InAppBrowser', 'open', [strUrl, strWindowName, strWindowFeatures]);
+        return iab;
+    };
+})();
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-qrscanner/www/www.min.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-qrscanner/www/www.min.js
new file mode 100644
index 0000000..2469e9e
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-qrscanner/www/www.min.js
@@ -0,0 +1,344 @@
+cordova.define("cordova-plugin-qrscanner.QRScanner", function(require, exports, module) {
+// This file is generated by `npm run build`.
+
+/*global exports:false*/
+/*jshint unused:false */
+// remap parameter names from cordova.define
+// see `externals` in webpack.cordova.config.js
+var cordovaRequire = require;
+var cordovaExports = exports;
+var cordovaModule = module;
+/******/ (function(modules) { // webpackBootstrap
+/******/ 	// The module cache
+/******/ 	var installedModules = {};
+/******/
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+/******/
+/******/ 		// Check if module is in cache
+/******/ 		if(installedModules[moduleId]) {
+/******/ 			return installedModules[moduleId].exports;
+/******/ 		}
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = installedModules[moduleId] = {
+/******/ 			i: moduleId,
+/******/ 			l: false,
+/******/ 			exports: {}
+/******/ 		};
+/******/
+/******/ 		// Execute the module function
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ 		// Flag the module as loaded
+/******/ 		module.l = true;
+/******/
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+/******/
+/******/
+/******/ 	// expose the modules object (__webpack_modules__)
+/******/ 	__webpack_require__.m = modules;
+/******/
+/******/ 	// expose the module cache
+/******/ 	__webpack_require__.c = installedModules;
+/******/
+/******/ 	// identity function for calling harmony imports with the correct context
+/******/ 	__webpack_require__.i = function(value) { return value; };
+/******/
+/******/ 	// define getter function for harmony exports
+/******/ 	__webpack_require__.d = function(exports, name, getter) {
+/******/ 		if(!__webpack_require__.o(exports, name)) {
+/******/ 			Object.defineProperty(exports, name, {
+/******/ 				configurable: false,
+/******/ 				enumerable: true,
+/******/ 				get: getter
+/******/ 			});
+/******/ 		}
+/******/ 	};
+/******/
+/******/ 	// getDefaultExport function for compatibility with non-harmony modules
+/******/ 	__webpack_require__.n = function(module) {
+/******/ 		var getter = module && module.__esModule ?
+/******/ 			function getDefault() { return module['default']; } :
+/******/ 			function getModuleExports() { return module; };
+/******/ 		__webpack_require__.d(getter, 'a', getter);
+/******/ 		return getter;
+/******/ 	};
+/******/
+/******/ 	// Object.prototype.hasOwnProperty.call
+/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+/******/
+/******/ 	// __webpack_public_path__
+/******/ 	__webpack_require__.p = "";
+/******/
+/******/ 	// Load entry module and return exports
+/******/ 	return __webpack_require__(__webpack_require__.s = 18);
+/******/ })
+/************************************************************************/
+/******/ ({
+
+/***/ 1:
+/***/ (function(module, exports) {
+
+module.exports = cordovaModule;
+
+/***/ }),
+
+/***/ 18:
+/***/ (function(module, exports, __webpack_require__) {
+
+var globalCordova = __webpack_require__(4);
+var cordovaModule = __webpack_require__(1);
+
+var createQRScannerAdapter = __webpack_require__(3);
+
+// pass in global cordova object to expose cordova.exec
+var QRScannerAdapter = createQRScannerAdapter(globalCordova);
+cordovaModule.exports = QRScannerAdapter;
+
+
+/***/ }),
+
+/***/ 3:
+/***/ (function(module, exports) {
+
+module.exports = function createQRScanner(cordova){
+// The native implementations should return their status as ['string':'string']
+// dictionaries. Boolean values are encoded to '0' and '1', respectively.
+function stringToBool(string) {
+  switch (string) {
+    case '1':
+      return true;
+    case '0':
+      return false;
+    default:
+    throw new Error('QRScanner plugin returned an invalid boolean number-string: ' + string);
+  }
+}
+
+// Converts the returned ['string':'string'] dictionary to a status object.
+function convertStatus(statusDictionary) {
+  return {
+    authorized: stringToBool(statusDictionary.authorized),
+    denied: stringToBool(statusDictionary.denied),
+    restricted: stringToBool(statusDictionary.restricted),
+    prepared: stringToBool(statusDictionary.prepared),
+    scanning: stringToBool(statusDictionary.scanning),
+    previewing: stringToBool(statusDictionary.previewing),
+    showing: stringToBool(statusDictionary.showing),
+    lightEnabled: stringToBool(statusDictionary.lightEnabled),
+    canOpenSettings: stringToBool(statusDictionary.canOpenSettings),
+    canEnableLight: stringToBool(statusDictionary.canEnableLight),
+    canChangeCamera: stringToBool(statusDictionary.canChangeCamera),
+    currentCamera: parseInt(statusDictionary.currentCamera)
+  };
+}
+
+// Simple utility method to ensure the background is transparent. Used by the
+// plugin to force re-rendering immediately after the native webview background
+// is made transparent.
+function clearBackground() {
+  var body = document.body;
+  if (body.style) {
+    body.style.backgroundColor = 'rgba(0,0,0,0.01)';
+    body.style.backgroundImage = '';
+    setTimeout(function() {
+      body.style.backgroundColor = 'transparent';
+    }, 1);
+    if (body.parentNode && body.parentNode.style) {
+      body.parentNode.style.backgroundColor = 'transparent';
+      body.parentNode.style.backgroundImage = '';
+    }
+  }
+}
+
+function errorCallback(callback) {
+  if (!callback) {
+    return null;
+  }
+  return function(error) {
+    var errorCode = parseInt(error);
+    var QRScannerError = {};
+    switch (errorCode) {
+      case 0:
+        QRScannerError = {
+          name: 'UNEXPECTED_ERROR',
+          code: 0,
+          _message: 'QRScanner experienced an unexpected error.'
+        };
+        break;
+      case 1:
+        QRScannerError = {
+          name: 'CAMERA_ACCESS_DENIED',
+          code: 1,
+          _message: 'The user denied camera access.'
+        };
+        break;
+      case 2:
+        QRScannerError = {
+          name: 'CAMERA_ACCESS_RESTRICTED',
+          code: 2,
+          _message: 'Camera access is restricted.'
+        };
+        break;
+      case 3:
+        QRScannerError = {
+          name: 'BACK_CAMERA_UNAVAILABLE',
+          code: 3,
+          _message: 'The back camera is unavailable.'
+        };
+        break;
+      case 4:
+        QRScannerError = {
+          name: 'FRONT_CAMERA_UNAVAILABLE',
+          code: 4,
+          _message: 'The front camera is unavailable.'
+        };
+        break;
+      case 5:
+        QRScannerError = {
+          name: 'CAMERA_UNAVAILABLE',
+          code: 5,
+          _message: 'The camera is unavailable.'
+        };
+        break;
+      case 6:
+        QRScannerError = {
+          name: 'SCAN_CANCELED',
+          code: 6,
+          _message: 'Scan was canceled.'
+        };
+        break;
+      case 7:
+        QRScannerError = {
+          name: 'LIGHT_UNAVAILABLE',
+          code: 7,
+          _message: 'The device light is unavailable.'
+        };
+        break;
+      case 8:
+        // Open settings is only available on iOS 8.0+.
+        QRScannerError = {
+          name: 'OPEN_SETTINGS_UNAVAILABLE',
+          code: 8,
+          _message: 'The device is unable to open settings.'
+        };
+        break;
+      default:
+        QRScannerError = {
+          name: 'UNEXPECTED_ERROR',
+          code: 0,
+          _message: 'QRScanner returned an invalid error code.'
+        };
+        break;
+    }
+    callback(QRScannerError);
+  };
+}
+
+function successCallback(callback) {
+  if (!callback) {
+    return null;
+  }
+  return function(statusDict) {
+    callback(null, convertStatus(statusDict));
+  };
+}
+
+function doneCallback(callback, clear) {
+  if (!callback) {
+    return null;
+  }
+  return function(statusDict) {
+    if (clear) {
+      clearBackground();
+    }
+    callback(convertStatus(statusDict));
+  };
+}
+
+return {
+  prepare: function(callback) {
+    cordova.exec(successCallback(callback), errorCallback(callback), 'QRScanner', 'prepare', []);
+  },
+  destroy: function(callback) {
+    cordova.exec(doneCallback(callback, true), null, 'QRScanner', 'destroy', []);
+  },
+  scan: function(callback) {
+    if (!callback) {
+      throw new Error('No callback provided to scan method.');
+    }
+    var success = function(result) {
+      callback(null, result);
+    };
+    cordova.exec(success, errorCallback(callback), 'QRScanner', 'scan', []);
+  },
+  cancelScan: function(callback) {
+    cordova.exec(doneCallback(callback), null, 'QRScanner', 'cancelScan', []);
+  },
+  show: function(callback) {
+    cordova.exec(doneCallback(callback, true), null, 'QRScanner', 'show', []);
+  },
+  hide: function(callback) {
+    cordova.exec(doneCallback(callback, true), null, 'QRScanner', 'hide', []);
+  },
+  pausePreview: function(callback) {
+    cordova.exec(doneCallback(callback), null, 'QRScanner', 'pausePreview', []);
+  },
+  resumePreview: function(callback) {
+    cordova.exec(doneCallback(callback), null, 'QRScanner', 'resumePreview', []);
+  },
+  enableLight: function(callback) {
+    cordova.exec(successCallback(callback), errorCallback(callback), 'QRScanner', 'enableLight', []);
+  },
+  disableLight: function(callback) {
+    cordova.exec(successCallback(callback), errorCallback(callback), 'QRScanner', 'disableLight', []);
+  },
+  useCamera: function(index, callback) {
+    cordova.exec(successCallback(callback), errorCallback(callback), 'QRScanner', 'useCamera', [index]);
+  },
+  useFrontCamera: function(callback) {
+    var frontCamera = 1;
+    if (callback) {
+      this.useCamera(frontCamera, callback);
+    } else {
+      cordova.exec(null, null, 'QRScanner', 'useCamera', [frontCamera]);
+    }
+  },
+  useBackCamera: function(callback) {
+    var backCamera = 0;
+    if (callback) {
+      this.useCamera(backCamera, callback);
+    } else {
+      cordova.exec(null, null, 'QRScanner', 'useCamera', [backCamera]);
+    }
+  },
+  openSettings: function(callback) {
+    if (callback) {
+      cordova.exec(successCallback(callback), errorCallback(callback), 'QRScanner', 'openSettings', []);
+    } else {
+      cordova.exec(null, null, 'QRScanner', 'openSettings', []);
+    }
+  },
+  getStatus: function(callback) {
+    if (!callback) {
+      throw new Error('No callback provided to getStatus method.');
+    }
+    cordova.exec(doneCallback(callback), null, 'QRScanner', 'getStatus', []);
+  }
+};
+};
+
+
+/***/ }),
+
+/***/ 4:
+/***/ (function(module, exports) {
+
+module.exports = cordova;
+
+/***/ })
+
+/******/ });
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-splashscreen/www/splashscreen.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-splashscreen/www/splashscreen.js
new file mode 100644
index 0000000..911ad50
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-splashscreen/www/splashscreen.js
@@ -0,0 +1,36 @@
+cordova.define("cordova-plugin-splashscreen.SplashScreen", function(require, exports, module) {
+/*

+ *

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ *

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ *

+*/

+

+var exec = require('cordova/exec');

+

+var splashscreen = {

+    show:function() {

+        exec(null, null, "SplashScreen", "show", []);

+    },

+    hide:function() {

+        exec(null, null, "SplashScreen", "hide", []);

+    }

+};

+

+module.exports = splashscreen;

+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-statusbar/www/statusbar.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-statusbar/www/statusbar.js
new file mode 100644
index 0000000..708186f
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-statusbar/www/statusbar.js
@@ -0,0 +1,116 @@
+cordova.define("cordova-plugin-statusbar.statusbar", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/* global cordova */
+
+var exec = require('cordova/exec');
+
+var namedColors = {
+    "black": "#000000",
+    "darkGray": "#A9A9A9",
+    "lightGray": "#D3D3D3",
+    "white": "#FFFFFF",
+    "gray": "#808080",
+    "red": "#FF0000",
+    "green": "#00FF00",
+    "blue": "#0000FF",
+    "cyan": "#00FFFF",
+    "yellow": "#FFFF00",
+    "magenta": "#FF00FF",
+    "orange": "#FFA500",
+    "purple": "#800080",
+    "brown": "#A52A2A"
+};
+
+var StatusBar = {
+
+    isVisible: true,
+
+    overlaysWebView: function (doOverlay) {
+        exec(null, null, "StatusBar", "overlaysWebView", [doOverlay]);
+    },
+
+    styleDefault: function () {
+        // dark text ( to be used on a light background )
+        exec(null, null, "StatusBar", "styleDefault", []);
+    },
+
+    styleLightContent: function () {
+        // light text ( to be used on a dark background )
+        exec(null, null, "StatusBar", "styleLightContent", []);
+    },
+
+    styleBlackTranslucent: function () {
+        // #88000000 ? Apple says to use lightContent instead
+        exec(null, null, "StatusBar", "styleBlackTranslucent", []);
+    },
+
+    styleBlackOpaque: function () {
+        // #FF000000 ? Apple says to use lightContent instead
+        exec(null, null, "StatusBar", "styleBlackOpaque", []);
+    },
+
+    backgroundColorByName: function (colorname) {
+        return StatusBar.backgroundColorByHexString(namedColors[colorname]);
+    },
+
+    backgroundColorByHexString: function (hexString) {
+        if (hexString.charAt(0) !== "#") {
+            hexString = "#" + hexString;
+        }
+
+        if (hexString.length === 4) {
+            var split = hexString.split("");
+            hexString = "#" + split[1] + split[1] + split[2] + split[2] + split[3] + split[3];
+        }
+
+        exec(null, null, "StatusBar", "backgroundColorByHexString", [hexString]);
+    },
+
+    hide: function () {
+        exec(null, null, "StatusBar", "hide", []);
+        StatusBar.isVisible = false;
+    },
+
+    show: function () {
+        exec(null, null, "StatusBar", "show", []);
+        StatusBar.isVisible = true;
+    }
+
+};
+
+// prime it. setTimeout so that proxy gets time to init
+window.setTimeout(function () {
+    exec(function (res) {
+        if (typeof res == 'object') {
+            if (res.type == 'tap') {
+                cordova.fireWindowEvent('statusTap');
+            }
+        } else {
+            StatusBar.isVisible = res;
+        }
+    }, null, "StatusBar", "_ready", []);
+}, 0);
+
+module.exports = StatusBar;
+
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-themeablebrowser/www/themeablebrowser.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-themeablebrowser/www/themeablebrowser.js
new file mode 100644
index 0000000..9c935cb
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-themeablebrowser/www/themeablebrowser.js
@@ -0,0 +1,121 @@
+cordova.define("cordova-plugin-themeablebrowser.themeablebrowser", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var exec = require('cordova/exec');
+var channel = require('cordova/channel');
+var modulemapper = require('cordova/modulemapper');
+var urlutil = require('cordova/urlutil');
+
+function ThemeableBrowser() {
+   this.channels = {};
+}
+
+ThemeableBrowser.prototype = {
+    _eventHandler: function (event) {
+        if (event && (event.type in this.channels)) {
+            this.channels[event.type].fire(event);
+        }
+    },
+    close: function (eventname) {
+        exec(null, null, 'ThemeableBrowser', 'close', []);
+        return this;
+    },
+    show: function (eventname) {
+        exec(null, null, 'ThemeableBrowser', 'show', []);
+        return this;
+    },
+    reload: function (eventname) {
+        exec(null, null, 'ThemeableBrowser', 'reload', []);
+        return this;
+    },
+    addEventListener: function (eventname,f) {
+        if (!(eventname in this.channels)) {
+            this.channels[eventname] = channel.create(eventname);
+        }
+        this.channels[eventname].subscribe(f);
+        return this;
+    },
+    removeEventListener: function(eventname, f) {
+        if (eventname in this.channels) {
+            this.channels[eventname].unsubscribe(f);
+        }
+        return this;
+    },
+
+    executeScript: function(injectDetails, cb) {
+        if (injectDetails.code) {
+            exec(cb, null, 'ThemeableBrowser', 'injectScriptCode', [injectDetails.code, !!cb]);
+        } else if (injectDetails.file) {
+            exec(cb, null, 'ThemeableBrowser', 'injectScriptFile', [injectDetails.file, !!cb]);
+        } else {
+            throw new Error('executeScript requires exactly one of code or file to be specified');
+        }
+        return this;
+    },
+
+    insertCSS: function(injectDetails, cb) {
+        if (injectDetails.code) {
+            exec(cb, null, 'ThemeableBrowser', 'injectStyleCode', [injectDetails.code, !!cb]);
+        } else if (injectDetails.file) {
+            exec(cb, null, 'ThemeableBrowser', 'injectStyleFile', [injectDetails.file, !!cb]);
+        } else {
+            throw new Error('insertCSS requires exactly one of code or file to be specified');
+        }
+        return this;
+    }
+};
+
+exports.open = function(strUrl, strWindowName, strWindowFeatures, callbacks) {
+    // Don't catch calls that write to existing frames (e.g. named iframes).
+    if (window.frames && window.frames[strWindowName]) {
+        var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open');
+        return origOpenFunc.apply(window, arguments);
+    }
+
+    strUrl = urlutil.makeAbsolute(strUrl);
+    var iab = new ThemeableBrowser();
+
+    callbacks = callbacks || {};
+    for (var callbackName in callbacks) {
+        iab.addEventListener(callbackName, callbacks[callbackName]);
+    }
+
+    var cb = function(eventname) {
+       iab._eventHandler(eventname);
+    };
+
+    strWindowFeatures = strWindowFeatures && JSON.stringify(strWindowFeatures);
+    // Slightly delay the actual native call to give the user a chance to
+    // register event listeners first, otherwise some warnings or errors may be missed.
+    setTimeout(function() {
+        exec(cb, cb, 'ThemeableBrowser', 'open', [strUrl, strWindowName, strWindowFeatures || '']);
+    }, 0);
+    return iab;
+};
+
+exports.EVT_ERR = 'ThemeableBrowserError';
+exports.EVT_WRN = 'ThemeableBrowserWarning';
+exports.ERR_CRITICAL = 'critical';
+exports.ERR_LOADFAIL = 'loadfail';
+exports.WRN_UNEXPECTED = 'unexpected';
+exports.WRN_UNDEFINED = 'undefined';
+});
diff --git a/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-touch-id/www/TouchID.js b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-touch-id/www/TouchID.js
new file mode 100644
index 0000000..38a3a85
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/plugins/cordova-plugin-touch-id/www/TouchID.js
@@ -0,0 +1,36 @@
+cordova.define("cordova-plugin-touch-id.TouchID", function(require, exports, module) {
+function TouchID() {
+}
+
+TouchID.prototype.isAvailable = function (successCallback, errorCallback) {
+  cordova.exec(successCallback, errorCallback, "TouchID", "isAvailable", []);
+};
+
+TouchID.prototype.didFingerprintDatabaseChange = function (successCallback, errorCallback) {
+  cordova.exec(successCallback, errorCallback, "TouchID", "didFingerprintDatabaseChange", []);
+};
+
+TouchID.prototype.verifyFingerprint = function (message, successCallback, errorCallback) {
+  cordova.exec(successCallback, errorCallback, "TouchID", "verifyFingerprint", [message]);
+};
+
+TouchID.prototype.verifyFingerprintWithCustomPasswordFallback = function (message, successCallback, errorCallback) {
+  cordova.exec(successCallback, errorCallback, "TouchID", "verifyFingerprintWithCustomPasswordFallback", [message]);
+};
+
+TouchID.prototype.verifyFingerprintWithCustomPasswordFallbackAndEnterPasswordLabel = function (message, enterPasswordLabel, successCallback, errorCallback) {
+  cordova.exec(successCallback, errorCallback, "TouchID", "verifyFingerprintWithCustomPasswordFallbackAndEnterPasswordLabel", [message, enterPasswordLabel]);
+};
+
+TouchID.install = function () {
+  if (!window.plugins) {
+    window.plugins = {};
+  }
+
+  window.plugins.touchid = new TouchID();
+  return window.plugins.touchid;
+};
+
+cordova.addConstructor(TouchID.install);
+
+});
diff --git a/platforms/android/app/src/main/assets/www/pwdset.html b/platforms/android/app/src/main/assets/www/pwdset.html
new file mode 100644
index 0000000..fc201aa
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/pwdset.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <link rel="stylesheet" type="text/css" href="mobileui/style.css">
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="viewport-fit=cover, initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <link rel="stylesheet" type="text/css" href="css/aui.css">
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <title>设置登录密码</title>
+</head>
+<body>
+    <header class="aui-bar aui-bar-nav" style="padding-top:25px;">
+        <a class="aui-pull-left" href="login.html">
+            <span class="aui-iconfont aui-icon-left"></span>
+        </a>
+        <div class="aui-title">设置登录密码</div>
+    </header>
+    <div>
+        <div class="weui-cells weui-cells_form">
+            <div class="weui-cell">
+                <div class="weui-cell__hd"><label class="weui-label">登录密码</label></div>
+                <div class="weui-cell__bd">
+                    <input class="weui-input" type="password" id="pwd" placeholder="6位以上字符">
+                </div>
+            </div>
+            <div class="weui-cell">
+                <div class="weui-cell__hd"><label class="weui-label">确认密码</label></div>
+                <div class="weui-cell__bd">
+                    <input class="weui-input" type="password" id="repwd" placeholder="请再次确认密码">
+                </div>
+            </div>
+        </div>
+        <div style="padding: 20px;">
+            <a href="javascript:app.doRegister();" class="weui-btn weui-btn_primary">保存</a>
+        </div>
+    </div>
+</body>
+</html>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/lib/jquery-weui.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
+<script type="text/javascript" src="js/pwdset.js"></script>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/qrcode.html b/platforms/android/app/src/main/assets/www/qrcode.html
new file mode 100644
index 0000000..3391537
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/qrcode.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <link rel="stylesheet" type="text/css" href="mobileui/style.css">
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="viewport-fit=cover, initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <link rel="stylesheet" type="text/css" href="css/aui.css">
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <title>付款码</title>
+</head>
+<body style="background: #fff"  >
+    <header class="aui-bar aui-bar-nav" style="padding-top:25px;">
+        <a class="aui-pull-left" href="main.html">
+            <span class="aui-iconfont aui-icon-left"></span>
+        </a>
+        <div class="aui-title">付款码</div>
+    </header>
+    <div style="display: flex;flex-direction: row;justify-content: center;align-items: center;margin-top: 50px;">
+        <div style="background: #fff;text-align: center;" id="qrcode"></div>
+    </div>
+    <p style="text-align: center;margin-top:20px;color:#999">请将二维码对准扫描设备</p>
+    <div style="padding: 30px;">
+        <div class="aui-btn aui-btn-block aui-btn-info" tapmode onclick="app.refresh()">手动刷新二维码</div>
+    </div>
+</body>
+</html>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/lib/jquery-weui.js"></script>
+<script type="text/javascript" src="js/lib/qrcode.min.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
+<script type="text/javascript" src="js/qrcode.js"></script>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/register.html b/platforms/android/app/src/main/assets/www/register.html
new file mode 100644
index 0000000..34e5998
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/register.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <link rel="stylesheet" type="text/css" href="mobileui/style.css">
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="viewport-fit=cover, initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <link rel="stylesheet" type="text/css" href="css/aui.css">
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <title>注册绑定</title>
+</head>
+<body>
+    <header class="aui-bar aui-bar-nav" style="padding-top:25px;">
+        <a class="aui-pull-left" href="login.html">
+            <span class="aui-iconfont aui-icon-left"></span>
+        </a>
+        <div class="aui-title">注册</div>
+    </header>
+    <div>
+        <div class="weui-cells weui-cells_form">
+            <div class="weui-cell" style="padding:0 10px; "> 
+                <div class="weui-cell__hd"><label class="weui-label" style="width: 80px;font-size: 14px;">手机号</label></div>
+                <div class="weui-cell__bd">
+                    <input class="weui-input" type="tel" id="phone" style="font-size: 14px;" placeholder="请输入市民卡预留的手机号" maxlength="11">
+                </div>
+            </div>
+            <div class="weui-cell weui-cell_vcode" style="padding:0 10px; ">
+                <div class="weui-cell__hd">
+                    <label class="weui-label" style="width: 80px;font-size: 14px;">验证码</label>
+                </div>
+                <div class="weui-cell__bd">
+                    <input class="weui-input" type="tel" id="code" style="font-size: 14px;" placeholder="请输入验证码" maxlength="6">
+                </div>
+                <div class="weui-cell__ft">
+                    <button class="weui-vcode-btn" onclick="app.getCode()" id="codebtn" style="width: 100px;height: 1rem;font-size: 14px;">获取验证码</button>
+                </div>
+            </div>
+        </div>
+        <div>
+            <label for="agree" class="weui-agree" style="padding: .5em 5px .5em 15px;display: inline-block;">
+                <input id="agree" type="checkbox" class="weui-agree__checkbox" value="1">
+                <span class="weui-agree__text">
+                    我已阅读并同意
+                </span>
+            </label>
+            <a href="uxy.html" style="font-size: 13px;">《用户协议与隐私条款》</a>
+        </div>
+        <section class="aui-content-padded" style="margin-top: 30px;">
+            <div class="aui-btn aui-btn-block aui-btn-info" tapmode onclick="app.doRegister()">注册</div>
+        </section>
+    </div>
+</body>
+
+</html>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/register.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/lib/jquery-weui.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/scan.html b/platforms/android/app/src/main/assets/www/scan.html
new file mode 100644
index 0000000..80b62bb
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/scan.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <link rel="stylesheet" type="text/css" href="mobileui/style.css">
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="viewport-fit=cover, initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <link rel="stylesheet" type="text/css" href="css/aui.css">
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <title>大理市民卡</title>
+</head>
+
+<body style="background: transparent none !important;">
+    <header class="aui-bar aui-bar-nav" style="padding-top:25px;">
+        <a class="aui-pull-left" href="javascript:app.goPage()">
+            <span class="aui-iconfont aui-icon-left"></span>
+        </a>
+        <div class="aui-title">扫一扫</div>
+        <a class="aui-pull-right aui-btn aui-btn-outlined">
+            <span class="aui-iconfont aui-icon-search" id="lightBtn" ></span>
+        </a>
+    </header>
+    <div class="qrscanner">
+        <div class="qrscanner-area">
+        </div>
+        <div class="through-line"></div>
+    </div>
+    <!--<div class="footer ">
+        <div class="align-center">
+            <button class="icon ion-flash" id="lightBtn"></button>
+        </div>
+    </div>-->
+</body>
+</html>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/lib/jquery-weui.js"></script>
+<script type="text/javascript" src="js/lib/aui-dialog.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
+<script type="text/javascript" src="js/scan.js"></script>
diff --git a/platforms/android/app/src/main/assets/www/security.html b/platforms/android/app/src/main/assets/www/security.html
new file mode 100644
index 0000000..9cc54d3
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/security.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <link rel="stylesheet" type="text/css" href="mobileui/style.css">
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="viewport-fit=cover, initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <link rel="stylesheet" type="text/css" href="css/aui.css">
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <title>账户安全</title>
+</head>
+<body>
+    <header class="aui-bar aui-bar-nav" style="padding-top:25px;">
+        <a class="aui-pull-left" href="main.html">
+            <span class="aui-iconfont aui-icon-left"></span>
+        </a>
+        <div class="aui-title">账户安全</div>
+    </header>
+    <section class="aui-content aui-margin-b-15 aui-margin-t-10">
+        <ul class="aui-list aui-list-in aui-margin-t-10 ">
+            <li class="aui-list-item">
+                <div class="aui-list-item-label-icon">
+                    <i class="aui-iconfont aui-icon-lock aui-text-info"></i>
+                </div>
+                <div class="aui-list-item-inner aui-list-item-arrow">
+                    <div class="aui-list-item-title">登录密码</div>
+                    <div class="aui-list-item-right"></div>
+                </div>
+            </li>
+            <li class="aui-list-item">
+                <div class="aui-list-item-label-icon">
+                    <i class="aui-iconfont aui-icon-pencil aui-text-danger"></i>
+                </div>
+                <div class="aui-list-item-inner aui-list-item-arrow">
+                    <div class="aui-list-item-title">支付密码</div>
+                    <div class="aui-list-item-right"></div>
+                </div>
+            </li>
+        </ul>
+    </section>
+</body>
+
+</html>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/lib/jquery-weui.js"></script>
+<script type="text/javascript" src="js/lib/aui-dialog.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
+<script type="text/javascript" src="js/security.js"></script>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/signxy.html b/platforms/android/app/src/main/assets/www/signxy.html
new file mode 100644
index 0000000..cb0f1ba
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/signxy.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <link rel="stylesheet" type="text/css" href="mobileui/style.css">
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="viewport-fit=cover, initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <link rel="stylesheet" type="text/css" href="css/aui.css">
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <title>签约代扣免密支付协议</title>
+</head>
+<body>
+    <header class="aui-bar aui-bar-nav" style="padding-top:25px;">
+        <a class="aui-pull-left" href="main.html">
+            <span class="aui-iconfont aui-icon-left"></span>
+        </a>
+        <div class="aui-title">签约代扣免密支付协议</div>
+    </header>
+    <div style="padding:10px;overflow: scroll;position: absolute;top:74px;bottom:135px;left: 0;right: 0" id="content">
+        
+    </div>
+    <div class="weui-footer weui-footer_fixed-bottom" style="background: #fff;display: none;" id="btn">
+            <div style="margin-top: 10px;">
+                <label for="agree" class="weui-agree" style="padding: .5em 5px .5em 15px;display: inline-block;">
+                    <input id="agree" type="checkbox" class="weui-agree__checkbox" value="yes">
+                    <span class="weui-agree__text">
+                        我已阅读并同意该协议
+                    </span>
+                </label>
+            </div>
+            <section class="aui-content-padded" style="margin-top: 20px;">
+                <div class="aui-btn aui-btn-block aui-btn-info"  tapmode onclick="app.agreeXY()">签约代扣协议</div>
+            </section>
+    </div>
+</body>
+
+</html>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/lib/jquery-weui.js"></script>
+<script type="text/javascript" src="js/signxy.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/assets/www/uxy.html b/platforms/android/app/src/main/assets/www/uxy.html
new file mode 100644
index 0000000..319f8fc
--- /dev/null
+++ b/platforms/android/app/src/main/assets/www/uxy.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <link rel="stylesheet" type="text/css" href="mobileui/style.css">
+    <meta name="format-detection" content="telephone=no">
+    <meta charset="utf-8">
+    <meta name="msapplication-tap-highlight" content="no">
+    <meta name="viewport" content="viewport-fit=cover, initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
+    <link rel="stylesheet" type="text/css" href="css/index.css">
+    <link rel="stylesheet" type="text/css" href="css/aui.css">
+    <link rel="stylesheet" type="text/css" href="css/weui.min.css">
+    <link rel="stylesheet" type="text/css" href="css/jquery-weui.min.css">
+    <title>用户协议与隐私条款</title>
+</head>
+<body>
+    <header class="aui-bar aui-bar-nav" style="padding-top:25px;">
+        <a class="aui-pull-left" href="register.html">
+            <span class="aui-iconfont aui-icon-close"></span>
+        </a>
+        <div class="aui-title">用户协议与隐私条款</div>
+    </header>
+    <div style="padding:10px;overflow: scroll;position: absolute;top:74px;bottom:5px;left: 0;right: 0" id="content">
+本应用尊重并保护所有使用服务用户的个人隐私权。为了给您提供更准确、更有个性化的服务,本应用会按照本隐私权政策的规定使用和披露您的个人信息。但本应用将以高度的勤勉、审慎义务对待这些信息。除本隐私权政策另有规定外,在未征得您事先许可的情况下,本应用不会将这些信息对外披露或向第三方提供。本应用会不时更新本隐私权政策。 您在同意本应用服务使用协议之时,即视为您已经同意本隐私权政策全部内容。本隐私权政策属于本应用服务使用协议不可分割的一部分。
+<br>
+1. 适用范围<br>
+
+(a) 在您注册本应用帐号时,您根据本应用要求提供的个人注册信息;<br>
+
+(b) 在您使用本应用网络服务,或访问本应用平台网页时,本应用自动接收并记录的您的浏览器和计算机上的信息,包括但不限于您的IP地址、浏览器的类型、使用的语言、访问日期和时间、软硬件特征信息及您需求的网页记录等数据;
+<br>
+(c) 本应用通过合法途径从商业伙伴处取得的用户个人数据。<br>
+
+您了解并同意,以下信息不适用本隐私权政策:<br>
+
+(a) 您在使用本应用平台提供的搜索服务时输入的关键字信息;<br>
+
+(b) 本应用收集到的您在本应用发布的有关信息数据,包括但不限于参与活动、成交信息及评价详情;<br>
+
+(c) 违反法律规定或违反本应用规则行为及本应用已对您采取的措施。<br>
+
+2. 信息使用<br>
+(a)本应用不会向任何无关第三方提供、出售、出租、分享或交易您的个人信息,除非事先得到您的许可,或该第三方和本应用(含本应用关联公司)单独或共同为您提供服务,且在该服务结束后,其将被禁止访问包括其以前能够访问的所有这些资料。
+<br>
+(b) 本应用亦不允许任何第三方以任何手段收集、编辑、出售或者无偿传播您的个人信息。任何本应用平台用户如从事上述活动,一经发现,本应用有权立即终止与该用户的服务协议。
+<br>
+(c) 为服务用户的目的,本应用可能通过使用您的个人信息,向您提供您感兴趣的信息,包括但不限于向您发出产品和服务信息,或者与本应用合作伙伴共享信息以便他们向您发送有关其产品和服务的信息(后者需要您的事先同意)。
+<br>
+3. 信息披露<br>
+
+在如下情况下,本应用将依据您的个人意愿或法律的规定全部或部分的披露您的个人信息:
+<br>
+(a) 经您事先同意,向第三方披露;
+<br>
+(b)为提供您所要求的产品和服务,而必须和第三方分享您的个人信息;
+<br>
+(c) 根据法律的有关规定,或者行政或司法机构的要求,向第三方或者行政、司法机构披露;
+<br>
+(d) 如您出现违反中国有关法律、法规或者本应用服务协议或相关规则的情况,需要向第三方披露;
+<br>
+(e) 如您是适格的知识产权投诉人并已提起投诉,应被投诉人要求,向被投诉人披露,以便双方处理可能的权利纠纷;
+<br>
+(f) 在本应用平台上创建的某一交易中,如交易任何一方履行或部分履行了交易义务并提出信息披露请求的,本应用有权决定向该用户提供其交易对方的联络方式等必要信息,以促成交易的完成或纠纷的解决。
+<br>
+(g) 其它本应用根据法律、法规或者网站政策认为合适的披露。
+<br>
+4. 信息存储和交换
+<br>
+本应用收集的有关您的信息和资料将保存在本应用及(或)其关联公司的服务器上,这些信息和资料可能传送至您所在国家、地区或本应用收集信息和资料所在地的境外并在境外被访问、存储和展示。
+<br>
+5. Cookie的使用
+<br>
+(a) 在您未拒绝接受cookies的情况下,本应用会在您的计算机上设定或取用cookies ,以便您能登录或使用依赖于cookies的本应用平台服务或功能。本应用使用cookies可为您提供更加周到的个性化服务,包括推广服务。
+<br>
+(b) 您有权选择接受或拒绝接受cookies。您可以通过修改浏览器设置的方式拒绝接受cookies。但如果您选择拒绝接受cookies,则您可能无法登录或使用依赖于cookies的本应用网络服务或功能。
+<br>
+(c) 通过本应用所设cookies所取得的有关信息,将适用本政策。
+<br>
+6. 信息安全
+<br>
+(a) 本应用帐号均有安全保护功能,请妥善保管您的用户名及密码信息。本应用将通过对用户密码进行加密等安全措施确保您的信息不丢失,不被滥用和变造。尽管有前述安全措施,但同时也请您注意在信息网络上不存在“完善的安全措施”。
+<br>
+(b) 在使用本应用网络服务进行网上交易时,您不可避免的要向交易对方或潜在的交易对
+<br>
+7.本隐私政策的更改
+<br>
+(a)如果决定更改隐私政策,我们会在本政策中、本公司网站中以及我们认为适当的位置发布这些更改,以便您了解我们如何收集、使用您的个人信息,哪些人可以访问这些信息,以及在什么情况下我们会透露这些信息。
+<br>
+(b)本公司保留随时修改本政策的权利,因此请经常查看。如对本政策作出重大更改,本公司会通过网站通知的形式告知。
+<br>
+方披露自己的个人信息,如联络方式或者邮政地址。请您妥善保护自己的个人信息,仅在必要的情形下向他人提供。如您发现自己的个人信息泄密,尤其是本应用用户名及密码发生泄露,请您立即联络本应用客服,以便本应用采取相应措施。
+<br>
+
+
+    </div>
+</body>
+</html>
+<script type="text/javascript" src="cordova.js"></script>
+<script type="text/javascript" src="js/lib/jquery-2.1.4.js"></script>
+<script type="text/javascript" src="js/lib/jquery-weui.js"></script>
+<script type="text/javascript" src="js/uxy.js"></script>
+<script type="text/javascript" src="js/server.js"></script>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/java/com/bitpay/cordova/qrscanner/QRScanner.java b/platforms/android/app/src/main/java/com/bitpay/cordova/qrscanner/QRScanner.java
new file mode 100755
index 0000000..f2e37d7
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/bitpay/cordova/qrscanner/QRScanner.java
@@ -0,0 +1,793 @@
+package com.bitpay.cordova.qrscanner;
+
+import android.Manifest;
+import android.content.Intent;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageManager;
+import android.graphics.Color;
+import android.hardware.camera2.CameraAccessException;
+import android.net.Uri;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.ResultPoint;
+import com.journeyapps.barcodescanner.BarcodeCallback;
+import com.journeyapps.barcodescanner.BarcodeResult;
+import com.journeyapps.barcodescanner.BarcodeView;
+import com.journeyapps.barcodescanner.DefaultDecoderFactory;
+import com.journeyapps.barcodescanner.camera.CameraSettings;
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.PluginResult;
+import org.apache.cordova.PermissionHelper;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import android.hardware.Camera;
+import android.provider.Settings;
+import android.support.v4.app.ActivityCompat;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.List;
+
+
+@SuppressWarnings("deprecation")
+public class QRScanner extends CordovaPlugin implements BarcodeCallback {
+
+    private CallbackContext callbackContext;
+    private boolean cameraClosing;
+    private static Boolean flashAvailable;
+    private boolean lightOn = false;
+    private boolean showing = false;
+    private boolean prepared = false;
+    private int currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
+    private String[] permissions = {Manifest.permission.CAMERA};
+    //Preview started or paused
+    private boolean previewing = false;
+    private BarcodeView  mBarcodeView;
+    private boolean switchFlashOn = false;
+    private boolean switchFlashOff = false;
+    private boolean cameraPreviewing;
+    private boolean scanning = false;
+    private CallbackContext nextScanCallback;
+    private boolean shouldScanAgain;
+    private boolean denied;
+    private boolean authorized;
+    private boolean restricted;
+    private boolean oneTime = true;
+    private boolean keepDenied = false;
+    private boolean appPausedWithActivePreview = false;
+    
+    static class QRScannerError {
+        private static final int UNEXPECTED_ERROR = 0,
+                CAMERA_ACCESS_DENIED = 1,
+                CAMERA_ACCESS_RESTRICTED = 2,
+                BACK_CAMERA_UNAVAILABLE = 3,
+                FRONT_CAMERA_UNAVAILABLE = 4,
+                CAMERA_UNAVAILABLE = 5,
+                SCAN_CANCELED = 6,
+                LIGHT_UNAVAILABLE = 7,
+                OPEN_SETTINGS_UNAVAILABLE = 8;
+    }
+
+    @Override
+    public boolean execute(final String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException {
+        this.callbackContext = callbackContext;
+        try {
+            if (action.equals("show")) {
+                cordova.getThreadPool().execute(new Runnable() {
+                    public void run() {
+                        show(callbackContext);
+                    }
+                });
+                return true;
+            }
+            else if(action.equals("scan")) {
+                cordova.getThreadPool().execute(new Runnable() {
+                    public void run() {
+                        scan(callbackContext);
+                    }
+                });
+                return true;
+            }
+            else if(action.equals("cancelScan")) {
+                cordova.getThreadPool().execute(new Runnable() {
+                    public void run() {
+                        cancelScan(callbackContext);
+                    }
+                });
+                return true;
+            }
+            else if(action.equals("openSettings")) {
+                cordova.getThreadPool().execute(new Runnable() {
+                    public void run() {
+                        openSettings(callbackContext);
+                    }
+                });
+                return true;
+            }
+            else if(action.equals("pausePreview")) {
+                cordova.getThreadPool().execute(new Runnable() {
+                    public void run() {
+                        pausePreview(callbackContext);
+                    }
+                });
+                return true;
+            }
+            else if(action.equals("useCamera")) {
+                cordova.getThreadPool().execute(new Runnable() {
+                    public void run() {
+                        switchCamera(callbackContext, args);
+                    }
+                });
+                return true;
+            }
+            else if(action.equals("resumePreview")) {
+                cordova.getThreadPool().execute(new Runnable() {
+                    public void run() {
+                        resumePreview(callbackContext);
+                    }
+                });
+                return true;
+            }
+            else if(action.equals("hide")) {
+                cordova.getThreadPool().execute(new Runnable() {
+                    public void run() {
+                        hide(callbackContext);
+                    }
+                });
+                return true;
+            }
+            else if (action.equals("enableLight")) {
+                cordova.getThreadPool().execute(new Runnable() {
+                    public void run() {
+                        while (cameraClosing) {
+                            try {
+                                Thread.sleep(10);
+                            } catch (InterruptedException ignore) {
+                            }
+                        }
+                        switchFlashOn = true;
+                        if (hasFlash()) {
+                            if (!hasPermission()) {
+                                requestPermission(33);
+                            } else
+                                enableLight(callbackContext);
+                        } else {
+                            callbackContext.error(QRScannerError.LIGHT_UNAVAILABLE);
+                        }
+                    }
+                });
+                return true;
+            }
+            else if (action.equals("disableLight")) {
+                cordova.getThreadPool().execute(new Runnable() {
+                    public void run() {
+                        switchFlashOff = true;
+                        if (hasFlash()) {
+                            if (!hasPermission()) {
+                                requestPermission(33);
+                            } else
+                                disableLight(callbackContext);
+                        } else {
+                            callbackContext.error(QRScannerError.LIGHT_UNAVAILABLE);
+                        }
+                    }
+                });
+                return true;
+            }
+            else if (action.equals("prepare")) {
+                cordova.getThreadPool().execute(new Runnable() {
+                    public void run() {
+                        cordova.getActivity().runOnUiThread(new Runnable() {
+                            @Override
+                            public void run() {
+                                try {
+                                    currentCameraId = args.getInt(0);
+                                } catch (JSONException e) {
+                                }
+                                prepare(callbackContext);
+                            }
+                        });
+                    }
+                });
+                return true;
+            }
+            else if (action.equals("destroy")) {
+                cordova.getThreadPool().execute(new Runnable() {
+                    public void run() {
+                        destroy(callbackContext);
+                    }
+                });
+                return true;
+            }
+            else if (action.equals("getStatus")) {
+                cordova.getThreadPool().execute(new Runnable() {
+                    public void run() {
+                        getStatus(callbackContext);
+                    }
+                });
+                return true;
+            }
+            else {
+                return false;
+            }
+        } catch (Exception e) {
+            callbackContext.error(QRScannerError.UNEXPECTED_ERROR);
+            return false;
+        }
+    }
+
+    @Override
+    public void onPause(boolean multitasking) {
+        if (previewing) {
+            this.appPausedWithActivePreview = true;
+            this.pausePreview(null);
+        }
+    }
+
+    @Override
+    public void onResume(boolean multitasking) {
+        if (this.appPausedWithActivePreview) {
+            this.appPausedWithActivePreview = false;
+            this.resumePreview(null);
+        }
+    }
+
+    private boolean hasFlash() {
+        if (flashAvailable == null) {
+            flashAvailable = false;
+            final PackageManager packageManager = this.cordova.getActivity().getPackageManager();
+            for (final FeatureInfo feature : packageManager.getSystemAvailableFeatures()) {
+                if (PackageManager.FEATURE_CAMERA_FLASH.equalsIgnoreCase(feature.name)) {
+                    flashAvailable = true;
+                    break;
+                }
+            }
+        }
+        return flashAvailable;
+    }
+
+    private void switchFlash(boolean toggleLight, CallbackContext callbackContext) {
+        try {
+            if (hasFlash()) {
+                doswitchFlash(toggleLight, callbackContext);
+            } else {
+                callbackContext.error(QRScannerError.LIGHT_UNAVAILABLE);
+            }
+        } catch (Exception e) {
+            lightOn = false;
+            callbackContext.error(QRScannerError.LIGHT_UNAVAILABLE);
+        }
+    }
+
+    private String boolToNumberString(Boolean bool) {
+        if(bool)
+            return "1";
+        else
+            return "0";
+    }
+
+    private void doswitchFlash(final boolean toggleLight, final CallbackContext callbackContext) throws IOException, CameraAccessException {        //No flash for front facing cameras
+        if (getCurrentCameraId() == Camera.CameraInfo.CAMERA_FACING_FRONT) {
+            callbackContext.error(QRScannerError.LIGHT_UNAVAILABLE);
+            return;
+        }
+        if (!prepared) {
+            if (toggleLight)
+                lightOn = true;
+            else
+                lightOn = false;
+            prepare(callbackContext);
+        }
+        cordova.getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (mBarcodeView != null) {
+                    mBarcodeView.setTorch(toggleLight);
+                    if (toggleLight)
+                        lightOn = true;
+                    else
+                        lightOn = false;
+                }
+                getStatus(callbackContext);
+            }
+        });
+    }
+
+    public int getCurrentCameraId() {
+        return this.currentCameraId;
+    }
+
+    private boolean canChangeCamera() {
+        int numCameras= Camera.getNumberOfCameras();
+        for(int i=0;i<numCameras;i++){
+            Camera.CameraInfo info = new Camera.CameraInfo();
+            Camera.getCameraInfo(i, info);
+            if(info.CAMERA_FACING_FRONT == info.facing){
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void switchCamera(CallbackContext callbackContext, JSONArray args) {
+        int cameraId = 0;
+
+        try {
+            cameraId = args.getInt(0);
+        } catch (JSONException d) {
+            callbackContext.error(QRScannerError.UNEXPECTED_ERROR);
+        }
+        currentCameraId = cameraId;
+        if(scanning) {
+            scanning = false;
+            prepared = false;
+            if(cameraPreviewing) {
+                this.cordova.getActivity().runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        ((ViewGroup) mBarcodeView.getParent()).removeView(mBarcodeView);
+                        cameraPreviewing = false;
+                    }
+                });
+            }
+            closeCamera();
+            prepare(callbackContext);
+            scan(this.nextScanCallback);
+        }
+        else
+            prepare(callbackContext);
+    }
+
+    public void onRequestPermissionResult(int requestCode, String[] permissions,
+                                          int[] grantResults) throws JSONException {
+        oneTime = false;
+        if (requestCode == 33) {
+            // for each permission check if the user granted/denied them
+            // you may want to group the rationale in a single dialog,
+            // this is just an example
+            for (int i = 0; i < permissions.length; i++) {
+                String permission = permissions[i];
+                if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
+                    boolean showRationale = ActivityCompat.shouldShowRequestPermissionRationale(cordova.getActivity(), permission);
+                    if (! showRationale) {
+                        // user denied flagging NEVER ASK AGAIN
+                        denied = true;
+                        authorized = false;
+                        callbackContext.error(QRScannerError.CAMERA_ACCESS_DENIED);
+                        return;
+                    } else {
+                        authorized = false;
+                        denied = false;
+                        callbackContext.error(QRScannerError.CAMERA_ACCESS_DENIED);
+                        return;
+                    }
+                } else if (grantResults[i] == PackageManager.PERMISSION_GRANTED){
+                    authorized = true;
+                    denied = false;
+                    switch (requestCode) {
+                        case 33:
+                            if(switchFlashOn && !scanning && !switchFlashOff)
+                                switchFlash(true, callbackContext);
+                            else if(switchFlashOff && !scanning)
+                                switchFlash(false, callbackContext);
+                            else {
+                                setupCamera(callbackContext);
+                                if(!scanning)
+                                    getStatus(callbackContext);
+                            }
+                            break;
+                    }
+                }
+                else {
+                    authorized = false;
+                    denied = false;
+                    restricted = false;
+                }
+            }
+        }
+    }
+
+    public boolean hasPermission() {
+        for(String p : permissions)
+        {
+            if(!PermissionHelper.hasPermission(this, p))
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void requestPermission(int requestCode) {
+        PermissionHelper.requestPermissions(this, requestCode, permissions);
+    }
+
+    private void closeCamera() {
+        cameraClosing = true;
+        cordova.getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (mBarcodeView != null) {
+                    mBarcodeView.pause();
+                }
+
+                cameraClosing = false;
+            }
+        });
+    }
+
+    private void makeOpaque() {
+        this.cordova.getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                webView.getView().setBackgroundColor(Color.TRANSPARENT);
+            }
+        });
+        showing = false;
+    }
+
+    private boolean hasCamera() {
+        if (this.cordova.getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private boolean hasFrontCamera() {
+        if (this.cordova.getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)){
+            return true;
+        } else {
+            return false;
+        }
+    }
+    private void setupCamera(CallbackContext callbackContext) {
+        cordova.getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Create our Preview view and set it as the content of our activity.
+                mBarcodeView = new BarcodeView(cordova.getActivity());
+
+                //Configure the decoder
+                ArrayList<BarcodeFormat> formatList = new ArrayList<BarcodeFormat>();
+                formatList.add(BarcodeFormat.QR_CODE);
+                mBarcodeView.setDecoderFactory(new DefaultDecoderFactory(formatList, null, null));
+
+                //Configure the camera (front/back)
+                CameraSettings settings = new CameraSettings();
+                settings.setRequestedCameraId(getCurrentCameraId());
+                mBarcodeView.setCameraSettings(settings);
+
+                FrameLayout.LayoutParams cameraPreviewParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
+                ((ViewGroup) webView.getView().getParent()).addView(mBarcodeView, cameraPreviewParams);
+
+                cameraPreviewing = true;
+                webView.getView().bringToFront();
+
+                mBarcodeView.resume();
+            }
+        });
+        prepared = true;
+        previewing = true;
+        if(shouldScanAgain)
+            scan(callbackContext);
+
+    }
+
+    @Override
+    public void barcodeResult(BarcodeResult barcodeResult) {
+        if (this.nextScanCallback == null) {
+            return;
+        }
+
+        if(barcodeResult.getText() != null) {
+            scanning = false;
+            this.nextScanCallback.success(barcodeResult.getText());
+            this.nextScanCallback = null;
+        }
+        else {
+            scan(this.nextScanCallback);
+        }
+    }
+
+    @Override
+    public void possibleResultPoints(List<ResultPoint> list) {
+    }
+
+    // ---- BEGIN EXTERNAL API ----
+    private void prepare(final CallbackContext callbackContext) {
+        if(!prepared) {
+            if(currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
+                if (hasCamera()) {
+                    if (!hasPermission()) {
+                        requestPermission(33);
+                    }
+                    else {
+                        setupCamera(callbackContext);
+                        if (!scanning)
+                            getStatus(callbackContext);
+                    }
+                }
+                else {
+                    callbackContext.error(QRScannerError.BACK_CAMERA_UNAVAILABLE);
+                }
+            }
+            else if(currentCameraId == Camera.CameraInfo.CAMERA_FACING_FRONT) {
+                if (hasFrontCamera()) {
+                    if (!hasPermission()) {
+                        requestPermission(33);
+                    }
+                    else {
+                        setupCamera(callbackContext);
+                        if (!scanning)
+                            getStatus(callbackContext);
+                    }
+                }
+                else {
+                    callbackContext.error(QRScannerError.FRONT_CAMERA_UNAVAILABLE);
+                }
+            }
+            else {
+                callbackContext.error(QRScannerError.CAMERA_UNAVAILABLE);
+            }
+        }
+        else {
+            prepared = false;
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    mBarcodeView.pause();
+                }
+            });
+            if(cameraPreviewing) {
+                this.cordova.getActivity().runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        ((ViewGroup) mBarcodeView.getParent()).removeView(mBarcodeView);
+                        cameraPreviewing = false;
+                    }
+                });
+
+                previewing = true;
+                lightOn = false;
+            }
+            setupCamera(callbackContext);
+            getStatus(callbackContext);
+        }
+    }
+
+    private void scan(final CallbackContext callbackContext) {
+        scanning = true;
+        if (!prepared) {
+            shouldScanAgain = true;
+            if (hasCamera()) {
+                if (!hasPermission()) {
+                    requestPermission(33);
+                } else {
+                    setupCamera(callbackContext);
+                }
+            }
+        } else {
+            if(!previewing) {
+                this.cordova.getActivity().runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        if(mBarcodeView != null) {
+                            mBarcodeView.resume();
+                            previewing = true;
+                            if(switchFlashOn)
+                                lightOn = true;
+                        }
+                    }
+                });
+            }
+            shouldScanAgain = false;
+            this.nextScanCallback = callbackContext;
+            final BarcodeCallback b = this;
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    if (mBarcodeView != null) {
+                        mBarcodeView.decodeSingle(b);
+                    }
+                }
+            });
+        }
+    }
+
+    private void cancelScan(final CallbackContext callbackContext) {
+        this.cordova.getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                scanning = false;
+                if (mBarcodeView != null) {
+                    mBarcodeView.stopDecoding();
+                }
+            }
+        });
+        if(this.nextScanCallback != null)
+            this.nextScanCallback.error(QRScannerError.SCAN_CANCELED);
+        this.nextScanCallback = null;
+    }
+
+    private void show(final CallbackContext callbackContext) {
+        this.cordova.getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                webView.getView().setBackgroundColor(Color.argb(1, 0, 0, 0));
+                showing = true;
+                getStatus(callbackContext);
+            }
+        });
+    }
+
+    private void hide(final CallbackContext callbackContext) {
+        makeOpaque();
+        getStatus(callbackContext);
+    }
+
+    private void pausePreview(final CallbackContext callbackContext) {
+        this.cordova.getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if(mBarcodeView != null) {
+                    mBarcodeView.pause();
+                    previewing = false;
+                    if(lightOn)
+                        lightOn = false;
+                }
+                
+                if (callbackContext != null)
+                    getStatus(callbackContext);
+            }
+        });
+
+    }
+
+    private void resumePreview(final CallbackContext callbackContext) {
+        this.cordova.getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if(mBarcodeView != null) {
+                    mBarcodeView.resume();
+                    previewing = true;
+                    if(switchFlashOn)
+                        lightOn = true;
+                }
+                
+                if (callbackContext != null)
+                    getStatus(callbackContext);
+            }
+        });
+    }
+
+    private void enableLight(CallbackContext callbackContext) {
+        lightOn = true;
+        if(hasPermission())
+            switchFlash(true, callbackContext);
+        else callbackContext.error(QRScannerError.CAMERA_ACCESS_DENIED);
+    }
+
+    private void disableLight(CallbackContext callbackContext) {
+        lightOn = false;
+        switchFlashOn = false;
+        if(hasPermission())
+            switchFlash(false, callbackContext);
+        else callbackContext.error(QRScannerError.CAMERA_ACCESS_DENIED);
+    }
+
+    private void openSettings(CallbackContext callbackContext) {
+        oneTime = true;
+        if(denied)
+            keepDenied = true;
+        try {
+            denied = false;
+            authorized = false;
+            boolean shouldPrepare = prepared;
+            boolean shouldFlash = lightOn;
+            boolean shouldShow = showing;
+            if(prepared)
+                destroy(callbackContext);
+            lightOn = false;
+            Intent intent = new Intent();
+            intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            Uri uri = Uri.fromParts("package", this.cordova.getActivity().getPackageName(), null);
+            intent.setData(uri);
+            this.cordova.getActivity().getApplicationContext().startActivity(intent);
+            getStatus(callbackContext);
+            if (shouldPrepare)
+                prepare(callbackContext);
+            if (shouldFlash)
+                enableLight(callbackContext);
+            if (shouldShow)
+                show(callbackContext);
+        } catch (Exception e) {
+            callbackContext.error(QRScannerError.OPEN_SETTINGS_UNAVAILABLE);
+        }
+
+    }
+
+    private void getStatus(CallbackContext callbackContext) {
+
+        if(oneTime) {
+            boolean authorizationStatus = hasPermission();
+
+            authorized = false;
+            if (authorizationStatus)
+                authorized = true;
+
+            if(keepDenied && !authorized)
+                denied = true;
+            else
+                denied = false;
+
+            //No applicable API
+            restricted = false;
+        }
+        boolean canOpenSettings = true;
+
+        boolean canEnableLight = hasFlash();
+
+        if(currentCameraId == Camera.CameraInfo.CAMERA_FACING_FRONT)
+            canEnableLight = false;
+
+        HashMap status = new HashMap();
+        status.put("authorized",boolToNumberString(authorized));
+        status.put("denied",boolToNumberString(denied));
+        status.put("restricted",boolToNumberString(restricted));
+        status.put("prepared",boolToNumberString(prepared));
+        status.put("scanning",boolToNumberString(scanning));
+        status.put("previewing",boolToNumberString(previewing));
+        status.put("showing",boolToNumberString(showing));
+        status.put("lightEnabled",boolToNumberString(lightOn));
+        status.put("canOpenSettings",boolToNumberString(canOpenSettings));
+        status.put("canEnableLight",boolToNumberString(canEnableLight));
+        status.put("canChangeCamera",boolToNumberString(canChangeCamera()));
+        status.put("currentCamera",Integer.toString(getCurrentCameraId()));
+
+        JSONObject obj = new JSONObject(status);
+        PluginResult result = new PluginResult(PluginResult.Status.OK, obj);
+        callbackContext.sendPluginResult(result);
+    }
+
+    private void destroy(CallbackContext callbackContext) {
+        prepared = false;
+        makeOpaque();
+        previewing = false;
+        if(scanning) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    scanning = false;
+                    if (mBarcodeView != null) {
+                        mBarcodeView.stopDecoding();
+                    }
+                }
+            });
+            this.nextScanCallback = null;
+        }
+
+        if(cameraPreviewing) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    ((ViewGroup) mBarcodeView.getParent()).removeView(mBarcodeView);
+                    cameraPreviewing = false;
+                }
+            });
+        }
+        if(currentCameraId != Camera.CameraInfo.CAMERA_FACING_FRONT) {
+            if (lightOn)
+                switchFlash(false, callbackContext);
+        }
+        closeCamera();
+        currentCameraId = 0;
+        getStatus(callbackContext);
+    }
+}
diff --git a/platforms/android/app/src/main/java/com/initialxy/cordova/themeablebrowser/InAppChromeClient.java b/platforms/android/app/src/main/java/com/initialxy/cordova/themeablebrowser/InAppChromeClient.java
new file mode 100644
index 0000000..74456a4
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/initialxy/cordova/themeablebrowser/InAppChromeClient.java
@@ -0,0 +1,132 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package com.initialxy.cordova.themeablebrowser;
+
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.LOG;
+import org.apache.cordova.PluginResult;
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import android.webkit.JsPromptResult;
+import android.webkit.WebChromeClient;
+import android.webkit.WebStorage;
+import android.webkit.WebView;
+import android.webkit.GeolocationPermissions.Callback;
+
+public class InAppChromeClient extends WebChromeClient {
+
+    private CordovaWebView webView;
+    private String LOG_TAG = "InAppChromeClient";
+    private long MAX_QUOTA = 100 * 1024 * 1024;
+
+    public InAppChromeClient(CordovaWebView webView) {
+        super();
+        this.webView = webView;
+    }
+    /**
+     * Handle database quota exceeded notification.
+     *
+     * @param url
+     * @param databaseIdentifier
+     * @param currentQuota
+     * @param estimatedSize
+     * @param totalUsedQuota
+     * @param quotaUpdater
+     */
+    @Override
+    public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize,
+            long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater)
+    {
+        LOG.d(LOG_TAG, "onExceededDatabaseQuota estimatedSize: %d  currentQuota: %d  totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota);
+        quotaUpdater.updateQuota(MAX_QUOTA);
+    }
+
+    /**
+     * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin.
+     *
+     * @param origin
+     * @param callback
+     */
+    @Override
+    public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
+        super.onGeolocationPermissionsShowPrompt(origin, callback);
+        callback.invoke(origin, true, false);
+    }
+
+    /**
+     * Tell the client to display a prompt dialog to the user.
+     * If the client returns true, WebView will assume that the client will
+     * handle the prompt dialog and call the appropriate JsPromptResult method.
+     *
+     * The prompt bridge provided for the ThemeableBrowser is capable of executing any
+     * oustanding callback belonging to the ThemeableBrowser plugin. Care has been
+     * taken that other callbacks cannot be triggered, and that no other code
+     * execution is possible.
+     *
+     * To trigger the bridge, the prompt default value should be of the form:
+     *
+     * gap-iab://<callbackId>
+     *
+     * where <callbackId> is the string id of the callback to trigger (something
+     * like "ThemeableBrowser0123456789")
+     *
+     * If present, the prompt message is expected to be a JSON-encoded value to
+     * pass to the callback. A JSON_EXCEPTION is returned if the JSON is invalid.
+     *
+     * @param view
+     * @param url
+     * @param message
+     * @param defaultValue
+     * @param result
+     */
+    @Override
+    public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
+        // See if the prompt string uses the 'gap-iab' protocol. If so, the remainder should be the id of a callback to execute.
+        if (defaultValue != null && defaultValue.startsWith("gap")) {
+            if(defaultValue.startsWith("gap-iab://")) {
+                PluginResult scriptResult;
+                String scriptCallbackId = defaultValue.substring(10);
+                if (scriptCallbackId.startsWith("ThemeableBrowser")) {
+                    if(message == null || message.length() == 0) {
+                        scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray());
+                    } else {
+                        try {
+                            scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray(message));
+                        } catch(JSONException e) {
+                            scriptResult = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
+                        }
+                    }
+                    this.webView.sendPluginResult(scriptResult, scriptCallbackId);
+                    result.confirm("");
+                    return true;
+                }
+            }
+            else
+            {
+                // Anything else with a gap: prefix should get this message
+                LOG.w(LOG_TAG, "ThemeableBrowser does not support Cordova API calls: " + url + " " + defaultValue); 
+                result.cancel();
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/platforms/android/app/src/main/java/com/initialxy/cordova/themeablebrowser/ThemeableBrowser.java b/platforms/android/app/src/main/java/com/initialxy/cordova/themeablebrowser/ThemeableBrowser.java
new file mode 100644
index 0000000..673e0d8
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/initialxy/cordova/themeablebrowser/ThemeableBrowser.java
@@ -0,0 +1,1447 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package com.initialxy.cordova.themeablebrowser;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.provider.Browser;
+import android.text.InputType;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.webkit.CookieManager;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaArgs;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.PluginManager;
+import org.apache.cordova.PluginResult;
+import org.apache.cordova.Whitelist;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+@SuppressLint("SetJavaScriptEnabled")
+public class ThemeableBrowser extends CordovaPlugin {
+
+    private static final String NULL = "null";
+    protected static final String LOG_TAG = "ThemeableBrowser";
+    private static final String SELF = "_self";
+    private static final String SYSTEM = "_system";
+    // private static final String BLANK = "_blank";
+    private static final String EXIT_EVENT = "exit";
+    private static final String LOAD_START_EVENT = "loadstart";
+    private static final String LOAD_STOP_EVENT = "loadstop";
+    private static final String LOAD_ERROR_EVENT = "loaderror";
+
+    private static final String ALIGN_LEFT = "left";
+    private static final String ALIGN_RIGHT = "right";
+
+    private static final int TOOLBAR_DEF_HEIGHT = 44;
+    private static final int DISABLED_ALPHA = 127;  // 50% AKA 127/255.
+
+    private static final String EVT_ERR = "ThemeableBrowserError";
+    private static final String EVT_WRN = "ThemeableBrowserWarning";
+    private static final String ERR_CRITICAL = "critical";
+    private static final String ERR_LOADFAIL = "loadfail";
+    private static final String WRN_UNEXPECTED = "unexpected";
+    private static final String WRN_UNDEFINED = "undefined";
+
+    private ThemeableBrowserDialog dialog;
+    private WebView inAppWebView;
+    private EditText edittext;
+    private CallbackContext callbackContext;
+
+    /**
+     * Executes the request and returns PluginResult.
+     *
+     * @param action          The action to execute.
+     * @param args            The exec() arguments, wrapped with some Cordova helpers.
+     * @param callbackContext The callback context used when calling back into JavaScript.
+     * @return
+     * @throws JSONException
+     */
+    public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
+        if (action.equals("open")) {
+            this.callbackContext = callbackContext;
+            final String url = args.getString(0);
+            String t = args.optString(1);
+            if (t == null || t.equals("") || t.equals(NULL)) {
+                t = SELF;
+            }
+            final String target = t;
+            final Options features = parseFeature(args.optString(2));
+
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    String result = "";
+                    // SELF
+                    if (SELF.equals(target)) {
+                        /* This code exists for compatibility between 3.x and 4.x versions of Cordova.
+                         * Previously the Config class had a static method, isUrlWhitelisted(). That
+                         * responsibility has been moved to the plugins, with an aggregating method in
+                         * PluginManager.
+                         */
+                        Boolean shouldAllowNavigation = null;
+                        if (url.startsWith("javascript:")) {
+                            shouldAllowNavigation = true;
+                        }
+                        if (shouldAllowNavigation == null) {
+                            shouldAllowNavigation = new Whitelist().isUrlWhiteListed(url);
+                        }
+                        if (shouldAllowNavigation == null) {
+                            try {
+                                Method gpm = webView.getClass().getMethod("getPluginManager");
+                                PluginManager pm = (PluginManager)gpm.invoke(webView);
+                                Method san = pm.getClass().getMethod("shouldAllowNavigation", String.class);
+                                shouldAllowNavigation = (Boolean)san.invoke(pm, url);
+                            } catch (NoSuchMethodException e) {
+                            } catch (IllegalAccessException e) {
+                            } catch (InvocationTargetException e) {
+                            }
+                        }
+                        // load in webview
+                        if (Boolean.TRUE.equals(shouldAllowNavigation)) {
+                            webView.loadUrl(url);
+                        }
+                        //Load the dialer
+                        else if (url.startsWith(WebView.SCHEME_TEL))
+                        {
+                            try {
+                                Intent intent = new Intent(Intent.ACTION_DIAL);
+                                intent.setData(Uri.parse(url));
+                                cordova.getActivity().startActivity(intent);
+                            } catch (android.content.ActivityNotFoundException e) {
+                                emitError(ERR_CRITICAL,
+                                        String.format("Error dialing %s: %s", url, e.toString()));
+                            }
+                        }
+                        // load in ThemeableBrowser
+                        else {
+                            result = showWebPage(url, features);
+                        }
+                    }
+                    // SYSTEM
+                    else if (SYSTEM.equals(target)) {
+                        result = openExternal(url);
+                    }
+                    // BLANK - or anything else
+                    else {
+                        result = showWebPage(url, features);
+                    }
+
+                    PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, result);
+                    pluginResult.setKeepCallback(true);
+                    callbackContext.sendPluginResult(pluginResult);
+                }
+            });
+        }
+        else if (action.equals("close")) {
+            closeDialog();
+        }
+        else if (action.equals("injectScriptCode")) {
+            String jsWrapper = null;
+            if (args.getBoolean(1)) {
+                jsWrapper = String.format("prompt(JSON.stringify([eval(%%s)]), 'gap-iab://%s')", callbackContext.getCallbackId());
+            }
+            injectDeferredObject(args.getString(0), jsWrapper);
+        }
+        else if (action.equals("injectScriptFile")) {
+            String jsWrapper;
+            if (args.getBoolean(1)) {
+                jsWrapper = String.format("(function(d) { var c = d.createElement('script'); c.src = %%s; c.onload = function() { prompt('', 'gap-iab://%s'); }; d.body.appendChild(c); })(document)", callbackContext.getCallbackId());
+            } else {
+                jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)";
+            }
+            injectDeferredObject(args.getString(0), jsWrapper);
+        }
+        else if (action.equals("injectStyleCode")) {
+            String jsWrapper;
+            if (args.getBoolean(1)) {
+                jsWrapper = String.format("(function(d) { var c = d.createElement('style'); c.innerHTML = %%s; d.body.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
+            } else {
+                jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)";
+            }
+            injectDeferredObject(args.getString(0), jsWrapper);
+        }
+        else if (action.equals("injectStyleFile")) {
+            String jsWrapper;
+            if (args.getBoolean(1)) {
+                jsWrapper = String.format("(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%s; d.head.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
+            } else {
+                jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document)";
+            }
+            injectDeferredObject(args.getString(0), jsWrapper);
+        }
+        else if (action.equals("show")) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    dialog.show();
+                }
+            });
+            PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
+            pluginResult.setKeepCallback(true);
+            this.callbackContext.sendPluginResult(pluginResult);
+        }
+        else if (action.equals("reload")) {
+            if (inAppWebView != null) {
+                this.cordova.getActivity().runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        inAppWebView.reload();
+                    }
+                });
+            }
+        }
+        else {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Called when the view navigates.
+     */
+    @Override
+    public void onReset() {
+        closeDialog();
+    }
+
+    /**
+     * Called by AccelBroker when listener is to be shut down.
+     * Stop listener.
+     */
+    public void onDestroy() {
+        closeDialog();
+    }
+
+    /**
+     * Inject an object (script or style) into the ThemeableBrowser WebView.
+     *
+     * This is a helper method for the inject{Script|Style}{Code|File} API calls, which
+     * provides a consistent method for injecting JavaScript code into the document.
+     *
+     * If a wrapper string is supplied, then the source string will be JSON-encoded (adding
+     * quotes) and wrapped using string formatting. (The wrapper string should have a single
+     * '%s' marker)
+     *
+     * @param source      The source object (filename or script/style text) to inject into
+     *                    the document.
+     * @param jsWrapper   A JavaScript string to wrap the source string in, so that the object
+     *                    is properly injected, or null if the source string is JavaScript text
+     *                    which should be executed directly.
+     */
+    private void injectDeferredObject(String source, String jsWrapper) {
+        String scriptToInject;
+        if (jsWrapper != null) {
+            org.json.JSONArray jsonEsc = new org.json.JSONArray();
+            jsonEsc.put(source);
+            String jsonRepr = jsonEsc.toString();
+            String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
+            scriptToInject = String.format(jsWrapper, jsonSourceString);
+        } else {
+            scriptToInject = source;
+        }
+        final String finalScriptToInject = scriptToInject;
+        this.cordova.getActivity().runOnUiThread(new Runnable() {
+            @SuppressLint("NewApi")
+            @Override
+            public void run() {
+                if (inAppWebView != null) {
+                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+                        // This action will have the side-effect of blurring the currently focused
+                        // element
+                        inAppWebView.loadUrl("javascript:" + finalScriptToInject);
+                    } else {
+                        inAppWebView.evaluateJavascript(finalScriptToInject, null);
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Put the list of features into a hash map
+     *
+     * @param optString
+     * @return
+     */
+    private Options parseFeature(String optString) {
+        Options result = null;
+        if (optString != null && !optString.isEmpty()) {
+            try {
+                result = ThemeableBrowserUnmarshaller.JSONToObj(
+                        optString, Options.class);
+            } catch (Exception e) {
+                emitError(ERR_CRITICAL,
+                        String.format("Invalid JSON @s", e.toString()));
+            }
+        } else {
+            emitWarning(WRN_UNDEFINED,
+                    "No config was given, defaults will be used, "
+                    + "which is quite boring.");
+        }
+
+        if (result == null) {
+            result = new Options();
+        }
+
+        // Always show location, this property is overwritten.
+        result.location = true;
+
+        return result;
+    }
+
+    /**
+     * Display a new browser with the specified URL.
+     *
+     * @param url
+     * @return
+     */
+    public String openExternal(String url) {
+        try {
+            Intent intent = null;
+            intent = new Intent(Intent.ACTION_VIEW);
+            // Omitting the MIME type for file: URLs causes "No Activity found to handle Intent".
+            // Adding the MIME type to http: URLs causes them to not be handled by the downloader.
+            Uri uri = Uri.parse(url);
+            if ("file".equals(uri.getScheme())) {
+                intent.setDataAndType(uri, webView.getResourceApi().getMimeType(uri));
+            } else {
+                intent.setData(uri);
+            }
+            intent.putExtra(Browser.EXTRA_APPLICATION_ID, cordova.getActivity().getPackageName());
+            this.cordova.getActivity().startActivity(intent);
+            return "";
+        } catch (android.content.ActivityNotFoundException e) {
+            Log.d(LOG_TAG, "ThemeableBrowser: Error loading url "+url+":"+ e.toString());
+            return e.toString();
+        }
+    }
+
+    /**
+     * Closes the dialog
+     */
+    public void closeDialog() {
+        this.cordova.getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // The JS protects against multiple calls, so this should happen only when
+                // closeDialog() is called by other native code.
+                if (inAppWebView == null) {
+                    emitWarning(WRN_UNEXPECTED, "Close called but already closed.");
+                    return;
+                }
+
+                inAppWebView.setWebViewClient(new WebViewClient() {
+                    // NB: wait for about:blank before dismissing
+                    public void onPageFinished(WebView view, String url) {
+                        if (dialog != null) {
+                            dialog.dismiss();
+                        }
+
+                        // Clean up.
+                        dialog = null;
+                        inAppWebView = null;
+                        edittext = null;
+                        callbackContext = null;
+                    }
+                });
+
+                // NB: From SDK 19: "If you call methods on WebView from any
+                // thread other than your app's UI thread, it can cause
+                // unexpected results."
+                // http://developer.android.com/guide/webapps/migrating.html#Threads
+                inAppWebView.loadUrl("about:blank");
+
+                try {
+                    JSONObject obj = new JSONObject();
+                    obj.put("type", EXIT_EVENT);
+                    sendUpdate(obj, false);
+                } catch (JSONException ex) {
+                }
+            }
+        });
+    }
+
+    private void emitButtonEvent(Event event, String url) {
+        emitButtonEvent(event, url, null);
+    }
+
+    private void emitButtonEvent(Event event, String url, Integer index) {
+        if (event != null && event.event != null) {
+            try {
+                JSONObject obj = new JSONObject();
+                obj.put("type", event.event);
+                obj.put("url", url);
+                if (index != null) {
+                    obj.put("index", index.intValue());
+                }
+                sendUpdate(obj, true);
+            } catch (JSONException e) {
+                // Ignore, should never happen.
+            }
+        } else {
+            emitWarning(WRN_UNDEFINED,
+                    "Button clicked, but event property undefined. "
+                    + "No event will be raised.");
+        }
+    }
+
+    private void emitError(String code, String message) {
+        emitLog(EVT_ERR, code, message);
+    }
+
+    private void emitWarning(String code, String message) {
+        emitLog(EVT_WRN, code, message);
+    }
+
+    private void emitLog(String type, String code, String message) {
+        if (type != null) {
+            try {
+                JSONObject obj = new JSONObject();
+                obj.put("type", type);
+                obj.put("code", code);
+                obj.put("message", message);
+                sendUpdate(obj, true);
+            } catch (JSONException e) {
+                // Ignore, should never happen.
+            }
+        }
+    }
+
+    /**
+     * Checks to see if it is possible to go back one page in history, then does so.
+     */
+    public void goBack() {
+        if (this.inAppWebView != null && this.inAppWebView.canGoBack()) {
+            this.inAppWebView.goBack();
+        }
+    }
+
+    /**
+     * Can the web browser go back?
+     * @return boolean
+     */
+    public boolean canGoBack() {
+        return this.inAppWebView != null && this.inAppWebView.canGoBack();
+    }
+
+    /**
+     * Checks to see if it is possible to go forward one page in history, then does so.
+     */
+    private void goForward() {
+        if (this.inAppWebView != null && this.inAppWebView.canGoForward()) {
+            this.inAppWebView.goForward();
+        }
+    }
+
+    /**
+     * Navigate to the new page
+     *
+     * @param url to load
+     */
+    private void navigate(String url) {
+        InputMethodManager imm = (InputMethodManager)this.cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
+        imm.hideSoftInputFromWindow(edittext.getWindowToken(), 0);
+
+        if (!url.startsWith("http") && !url.startsWith("file:")) {
+            this.inAppWebView.loadUrl("http://" + url);
+        } else {
+            this.inAppWebView.loadUrl(url);
+        }
+        this.inAppWebView.requestFocus();
+    }
+
+    private ThemeableBrowser getThemeableBrowser() {
+        return this;
+    }
+
+    /**
+     * Display a new browser with the specified URL.
+     *
+     * @param url
+     * @param features
+     * @return
+     */
+    public String showWebPage(final String url, final Options features) {
+        final CordovaWebView thatWebView = this.webView;
+
+        // Create dialog in new thread
+        Runnable runnable = new Runnable() {
+            @SuppressLint("NewApi")
+            public void run() {
+                // Let's create the main dialog
+                dialog = new ThemeableBrowserDialog(cordova.getActivity(),
+                        android.R.style.Theme_Black_NoTitleBar,
+                        features.hardwareback);
+                if (!features.disableAnimation) {
+                    dialog.getWindow().getAttributes().windowAnimations
+                            = android.R.style.Animation_Dialog;
+                }
+                dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+                dialog.setCancelable(true);
+                dialog.setThemeableBrowser(getThemeableBrowser());
+
+                // Main container layout
+                ViewGroup main = null;
+
+                if (features.fullscreen) {
+                    main = new FrameLayout(cordova.getActivity());
+                } else {
+                    main = new LinearLayout(cordova.getActivity());
+                    ((LinearLayout) main).setOrientation(LinearLayout.VERTICAL);
+                }
+
+                // Toolbar layout
+                Toolbar toolbarDef = features.toolbar;
+                FrameLayout toolbar = new FrameLayout(cordova.getActivity());
+                toolbar.setBackgroundColor(hexStringToColor(
+                        toolbarDef != null && toolbarDef.color != null
+                                ? toolbarDef.color : "#ffffffff"));
+                toolbar.setLayoutParams(new ViewGroup.LayoutParams(
+                        LayoutParams.MATCH_PARENT,
+                        dpToPixels(toolbarDef != null
+                                ? toolbarDef.height : TOOLBAR_DEF_HEIGHT)));
+
+                if (toolbarDef != null
+                        && (toolbarDef.image != null || toolbarDef.wwwImage != null)) {
+                    try {
+                        Drawable background = getImage(toolbarDef.image
+                                , toolbarDef.wwwImage, toolbarDef.wwwImageDensity);
+                        setBackground(toolbar, background);
+                    } catch (Resources.NotFoundException e) {
+                        emitError(ERR_LOADFAIL,
+                                String.format("Image for toolbar, %s, failed to load",
+                                        toolbarDef.image));
+                    } catch (IOException ioe) {
+                        emitError(ERR_LOADFAIL,
+                                String.format("Image for toolbar, %s, failed to load",
+                                        toolbarDef.wwwImage));
+                    }
+                }
+
+                // Left Button Container layout
+                LinearLayout leftButtonContainer = new LinearLayout(cordova.getActivity());
+                FrameLayout.LayoutParams leftButtonContainerParams = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+                leftButtonContainerParams.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
+                leftButtonContainer.setLayoutParams(leftButtonContainerParams);
+                leftButtonContainer.setVerticalGravity(Gravity.CENTER_VERTICAL);
+
+                // Right Button Container layout
+                LinearLayout rightButtonContainer = new LinearLayout(cordova.getActivity());
+                FrameLayout.LayoutParams rightButtonContainerParams = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+                rightButtonContainerParams.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
+                rightButtonContainer.setLayoutParams(rightButtonContainerParams);
+                rightButtonContainer.setVerticalGravity(Gravity.CENTER_VERTICAL);
+
+                // Edit Text Box
+                edittext = new EditText(cordova.getActivity());
+                RelativeLayout.LayoutParams textLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+                textLayoutParams.addRule(RelativeLayout.RIGHT_OF, 1);
+                textLayoutParams.addRule(RelativeLayout.LEFT_OF, 5);
+                edittext.setLayoutParams(textLayoutParams);
+                edittext.setSingleLine(true);
+                edittext.setText(url);
+                edittext.setInputType(InputType.TYPE_TEXT_VARIATION_URI);
+                edittext.setImeOptions(EditorInfo.IME_ACTION_GO);
+                edittext.setInputType(InputType.TYPE_NULL); // Will not except input... Makes the text NON-EDITABLE
+                edittext.setOnKeyListener(new View.OnKeyListener() {
+                    public boolean onKey(View v, int keyCode, KeyEvent event) {
+                        // If the event is a key-down event on the "enter" button
+                        if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
+                            navigate(edittext.getText().toString());
+                            return true;
+                        }
+                        return false;
+                    }
+                });
+
+                // Back button
+                final Button back = createButton(
+                    features.backButton,
+                    "back button",
+                    new View.OnClickListener() {
+                        public void onClick(View v) {
+                            emitButtonEvent(
+                                    features.backButton,
+                                    inAppWebView.getUrl());
+
+                            if (features.backButtonCanClose && !canGoBack()) {
+                                closeDialog();
+                            } else {
+                                goBack();
+                            }
+                        }
+                    }
+                );
+
+                if (back != null) {
+                    back.setEnabled(features.backButtonCanClose);
+                }
+
+                // Forward button
+                final Button forward = createButton(
+                    features.forwardButton,
+                    "forward button",
+                    new View.OnClickListener() {
+                        public void onClick(View v) {
+                            emitButtonEvent(
+                                    features.forwardButton,
+                                    inAppWebView.getUrl());
+
+                            goForward();
+                        }
+                    }
+                );
+
+                if (back != null) {
+                    back.setEnabled(false);
+                }
+
+
+                // Close/Done button
+                Button close = createButton(
+                    features.closeButton,
+                    "close button",
+                    new View.OnClickListener() {
+                        public void onClick(View v) {
+                            emitButtonEvent(
+                                    features.closeButton,
+                                    inAppWebView.getUrl());
+                            closeDialog();
+                        }
+                    }
+                );
+
+                // Menu button
+                Spinner menu = features.menu != null
+                        ? new MenuSpinner(cordova.getActivity()) : null;
+                if (menu != null) {
+                    menu.setLayoutParams(new LinearLayout.LayoutParams(
+                            LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+                    menu.setContentDescription("menu button");
+                    setButtonImages(menu, features.menu, DISABLED_ALPHA);
+
+                    // We are not allowed to use onClickListener for Spinner, so we will use
+                    // onTouchListener as a fallback.
+                    menu.setOnTouchListener(new View.OnTouchListener() {
+                        @Override
+                        public boolean onTouch(View v, MotionEvent event) {
+                            if (event.getAction() == MotionEvent.ACTION_UP) {
+                                emitButtonEvent(
+                                        features.menu,
+                                        inAppWebView.getUrl());
+                            }
+                            return false;
+                        }
+                    });
+
+                    if (features.menu.items != null) {
+                        HideSelectedAdapter<EventLabel> adapter
+                                = new HideSelectedAdapter<EventLabel>(
+                                cordova.getActivity(),
+                                android.R.layout.simple_spinner_item,
+                                features.menu.items);
+                        adapter.setDropDownViewResource(
+                                android.R.layout.simple_spinner_dropdown_item);
+                        menu.setAdapter(adapter);
+                        menu.setOnItemSelectedListener(
+                                new AdapterView.OnItemSelectedListener() {
+                                    @Override
+                                    public void onItemSelected(
+                                            AdapterView<?> adapterView,
+                                            View view, int i, long l) {
+                                        if (inAppWebView != null
+                                                && i < features.menu.items.length) {
+                                            emitButtonEvent(
+                                                    features.menu.items[i],
+                                                    inAppWebView.getUrl(), i);
+                                        }
+                                    }
+
+                                    @Override
+                                    public void onNothingSelected(
+                                            AdapterView<?> adapterView) {
+                                    }
+                                }
+                        );
+                    }
+                }
+
+                // Title
+                final TextView title = features.title != null
+                        ? new TextView(cordova.getActivity()) : null;
+                if (title != null) {
+                    FrameLayout.LayoutParams titleParams
+                            = new FrameLayout.LayoutParams(
+                            LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+                    titleParams.gravity = Gravity.CENTER;
+                    title.setLayoutParams(titleParams);
+                    title.setSingleLine();
+                    title.setEllipsize(TextUtils.TruncateAt.END);
+                    title.setGravity(Gravity.CENTER);
+                    title.setTextColor(hexStringToColor(
+                            features.title.color != null
+                                    ? features.title.color : "#000000ff"));
+                    if (features.title.staticText != null) {
+                        title.setText(features.title.staticText);
+                    }
+                }
+
+                // WebView
+                inAppWebView = new WebView(cordova.getActivity());
+                final ViewGroup.LayoutParams inAppWebViewParams = features.fullscreen
+                        ? new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
+                        : new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 0);
+                if (!features.fullscreen) {
+                    ((LinearLayout.LayoutParams) inAppWebViewParams).weight = 1;
+                }
+                inAppWebView.setLayoutParams(inAppWebViewParams);
+                inAppWebView.setWebChromeClient(new InAppChromeClient(thatWebView));
+                WebViewClient client = new ThemeableBrowserClient(thatWebView, new PageLoadListener() {
+                    @Override
+                    public void onPageFinished(String url, boolean canGoBack, boolean canGoForward) {
+                        if (inAppWebView != null
+                                && title != null && features.title != null
+                                && features.title.staticText == null
+                                && features.title.showPageTitle) {
+                            title.setText(inAppWebView.getTitle());
+                        }
+
+                        if (back != null) {
+                            back.setEnabled(canGoBack || features.backButtonCanClose);
+                        }
+
+                        if (forward != null) {
+                            forward.setEnabled(canGoForward);
+                        }
+                    }
+                });
+                inAppWebView.setWebViewClient(client);
+                WebSettings settings = inAppWebView.getSettings();
+                settings.setJavaScriptEnabled(true);
+                settings.setJavaScriptCanOpenWindowsAutomatically(true);
+                settings.setBuiltInZoomControls(features.zoom);
+                settings.setDisplayZoomControls(false);
+                settings.setPluginState(android.webkit.WebSettings.PluginState.ON);
+
+                //Toggle whether this is enabled or not!
+                Bundle appSettings = cordova.getActivity().getIntent().getExtras();
+                boolean enableDatabase = appSettings == null || appSettings.getBoolean("ThemeableBrowserStorageEnabled", true);
+                if (enableDatabase) {
+                    String databasePath = cordova.getActivity().getApplicationContext().getDir("themeableBrowserDB", Context.MODE_PRIVATE).getPath();
+                    settings.setDatabasePath(databasePath);
+                    settings.setDatabaseEnabled(true);
+                }
+                settings.setDomStorageEnabled(true);
+
+                if (features.clearcache) {
+                    CookieManager.getInstance().removeAllCookie();
+                } else if (features.clearsessioncache) {
+                    CookieManager.getInstance().removeSessionCookie();
+                }
+
+                inAppWebView.loadUrl(url);
+                inAppWebView.getSettings().setLoadWithOverviewMode(true);
+                inAppWebView.getSettings().setUseWideViewPort(true);
+                inAppWebView.requestFocus();
+                inAppWebView.requestFocusFromTouch();
+
+                // Add buttons to either leftButtonsContainer or
+                // rightButtonsContainer according to user's alignment
+                // configuration.
+                int leftContainerWidth = 0;
+                int rightContainerWidth = 0;
+
+                if (features.customButtons != null) {
+                    for (int i = 0; i < features.customButtons.length; i++) {
+                        final BrowserButton buttonProps = features.customButtons[i];
+                        final int index = i;
+                        Button button = createButton(
+                            buttonProps,
+                            String.format("custom button at %d", i),
+                            new View.OnClickListener() {
+                                @Override
+                                public void onClick(View view) {
+                                    if (inAppWebView != null) {
+                                        emitButtonEvent(buttonProps,
+                                                inAppWebView.getUrl(), index);
+                                    }
+                                }
+                            }
+                        );
+
+                        if (ALIGN_RIGHT.equals(buttonProps.align)) {
+                            rightButtonContainer.addView(button);
+                            rightContainerWidth
+                                    += button.getLayoutParams().width;
+                        } else {
+                            leftButtonContainer.addView(button, 0);
+                            leftContainerWidth
+                                    += button.getLayoutParams().width;
+                        }
+                    }
+                }
+
+                // Back and forward buttons must be added with special ordering logic such
+                // that back button is always on the left of forward button if both buttons
+                // are on the same side.
+                if (forward != null && features.forwardButton != null
+                        && !ALIGN_RIGHT.equals(features.forwardButton.align)) {
+                    leftButtonContainer.addView(forward, 0);
+                    leftContainerWidth
+                            += forward.getLayoutParams().width;
+                }
+
+                if (back != null && features.backButton != null
+                        && ALIGN_RIGHT.equals(features.backButton.align)) {
+                    rightButtonContainer.addView(back);
+                    rightContainerWidth
+                            += back.getLayoutParams().width;
+                }
+
+                if (back != null && features.backButton != null
+                        && !ALIGN_RIGHT.equals(features.backButton.align)) {
+                    leftButtonContainer.addView(back, 0);
+                    leftContainerWidth
+                            += back.getLayoutParams().width;
+                }
+
+                if (forward != null && features.forwardButton != null
+                        && ALIGN_RIGHT.equals(features.forwardButton.align)) {
+                    rightButtonContainer.addView(forward);
+                    rightContainerWidth
+                            += forward.getLayoutParams().width;
+                }
+
+                if (menu != null) {
+                    if (features.menu != null
+                            && ALIGN_RIGHT.equals(features.menu.align)) {
+                        rightButtonContainer.addView(menu);
+                        rightContainerWidth
+                                += menu.getLayoutParams().width;
+                    } else {
+                        leftButtonContainer.addView(menu, 0);
+                        leftContainerWidth
+                                += menu.getLayoutParams().width;
+                    }
+                }
+
+                if (close != null) {
+                    if (features.closeButton != null
+                            && ALIGN_RIGHT.equals(features.closeButton.align)) {
+                        rightButtonContainer.addView(close);
+                        rightContainerWidth
+                                += close.getLayoutParams().width;
+                    } else {
+                        leftButtonContainer.addView(close, 0);
+                        leftContainerWidth
+                                += close.getLayoutParams().width;
+                    }
+                }
+
+                // Add the views to our toolbar
+                toolbar.addView(leftButtonContainer);
+                // Don't show address bar.
+                // toolbar.addView(edittext);
+                toolbar.addView(rightButtonContainer);
+
+                if (title != null) {
+                    int titleMargin = Math.max(
+                            leftContainerWidth, rightContainerWidth);
+
+                    FrameLayout.LayoutParams titleParams
+                            = (FrameLayout.LayoutParams) title.getLayoutParams();
+                    titleParams.setMargins(titleMargin, 0, titleMargin, 0);
+                    toolbar.addView(title);
+                }
+
+                if (features.fullscreen) {
+                    // If full screen mode, we have to add inAppWebView before adding toolbar.
+                    main.addView(inAppWebView);
+                }
+
+                // Don't add the toolbar if its been disabled
+                if (features.location) {
+                    // Add our toolbar to our main view/layout
+                    main.addView(toolbar);
+                }
+
+                if (!features.fullscreen) {
+                    // If not full screen, we add inAppWebView after adding toolbar.
+                    main.addView(inAppWebView);
+                }
+
+                WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
+                lp.copyFrom(dialog.getWindow().getAttributes());
+                lp.width = WindowManager.LayoutParams.MATCH_PARENT;
+                lp.height = WindowManager.LayoutParams.MATCH_PARENT;
+
+                dialog.setContentView(main);
+                dialog.show();
+                dialog.getWindow().setAttributes(lp);
+                // the goal of openhidden is to load the url and not display it
+                // Show() needs to be called to cause the URL to be loaded
+                if(features.hidden) {
+                    dialog.hide();
+                }
+            }
+        };
+        this.cordova.getActivity().runOnUiThread(runnable);
+        return "";
+    }
+
+    /**
+     * Convert our DIP units to Pixels
+     *
+     * @return int
+     */
+    private int dpToPixels(int dipValue) {
+        int value = (int) TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP,
+                (float) dipValue,
+                cordova.getActivity().getResources().getDisplayMetrics()
+        );
+
+        return value;
+    }
+
+    private int hexStringToColor(String hex) {
+        int result = 0;
+
+        if (hex != null && !hex.isEmpty()) {
+            if (hex.charAt(0) == '#') {
+                hex = hex.substring(1);
+            }
+
+            // No alpha, that's fine, we will just attach ff.
+            if (hex.length() < 8) {
+                hex += "ff";
+            }
+
+            result = (int) Long.parseLong(hex, 16);
+
+            // Almost done, but Android color code is in form of ARGB instead of
+            // RGBA, so we gotta shift it a bit.
+            int alpha = (result & 0xff) << 24;
+            result = result >> 8 & 0xffffff | alpha;
+        }
+
+        return result;
+    }
+
+    /**
+    * This is a rather unintuitive helper method to load images. The reason why this method exists
+    * is because due to some service limitations, one may not be able to add images to native
+    * resource bundle. So this method offers a way to load image from www contents instead.
+    * However loading from native resource bundle is already preferred over loading from www. So
+    * if name is given, then it simply loads from resource bundle and the other two parameters are
+    * ignored. If name is not given, then altPath is assumed to be a file path _under_ www and
+    * altDensity is the desired density of the given image file, because without native resource
+    * bundle, we can't tell what density the image is supposed to be so it needs to be given
+    * explicitly.
+    */
+    private Drawable getImage(String name, String altPath, double altDensity) throws IOException {
+        Drawable result = null;
+        Resources activityRes = cordova.getActivity().getResources();
+
+        if (name != null) {
+            int id = activityRes.getIdentifier(name, "drawable",
+                    cordova.getActivity().getPackageName());
+            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+                result = activityRes.getDrawable(id);
+            } else {
+                result = activityRes.getDrawable(id, cordova.getActivity().getTheme());
+            }
+        } else if (altPath != null) {
+            File file = new File("www", altPath);
+            InputStream is = null;
+            try {
+                is = cordova.getActivity().getAssets().open(file.getPath());
+                Bitmap bitmap = BitmapFactory.decodeStream(is);
+                bitmap.setDensity((int) (DisplayMetrics.DENSITY_MEDIUM * altDensity));
+                result = new BitmapDrawable(activityRes, bitmap);
+            } finally {
+                // Make sure we close this input stream to prevent resource leak.
+                try {
+                    is.close();
+                } catch (Exception e) {}
+            }
+        }
+        return result;
+    }
+
+    private void setButtonImages(View view, BrowserButton buttonProps, int disabledAlpha) {
+        Drawable normalDrawable = null;
+        Drawable disabledDrawable = null;
+        Drawable pressedDrawable = null;
+
+        CharSequence description = view.getContentDescription();
+
+        if (buttonProps.image != null || buttonProps.wwwImage != null) {
+            try {
+                normalDrawable = getImage(buttonProps.image, buttonProps.wwwImage,
+                        buttonProps.wwwImageDensity);
+                ViewGroup.LayoutParams params = view.getLayoutParams();
+                params.width = normalDrawable.getIntrinsicWidth();
+                params.height = normalDrawable.getIntrinsicHeight();
+            } catch (Resources.NotFoundException e) {
+                emitError(ERR_LOADFAIL,
+                        String.format("Image for %s, %s, failed to load",
+                                description, buttonProps.image));
+            } catch (IOException ioe) {
+                emitError(ERR_LOADFAIL,
+                        String.format("Image for %s, %s, failed to load",
+                                description, buttonProps.wwwImage));
+            }
+        } else {
+            emitWarning(WRN_UNDEFINED,
+                    String.format("Image for %s is not defined. Button will not be shown",
+                            description));
+        }
+
+        if (buttonProps.imagePressed != null || buttonProps.wwwImagePressed != null) {
+            try {
+                pressedDrawable = getImage(buttonProps.imagePressed, buttonProps.wwwImagePressed,
+                        buttonProps.wwwImageDensity);
+            } catch (Resources.NotFoundException e) {
+                emitError(ERR_LOADFAIL,
+                        String.format("Pressed image for %s, %s, failed to load",
+                                description, buttonProps.imagePressed));
+            } catch (IOException e) {
+                emitError(ERR_LOADFAIL,
+                        String.format("Pressed image for %s, %s, failed to load",
+                                description, buttonProps.wwwImagePressed));
+            }
+        } else {
+            emitWarning(WRN_UNDEFINED,
+                    String.format("Pressed image for %s is not defined.",
+                            description));
+        }
+
+        if (normalDrawable != null) {
+            // Create the disabled state drawable by fading the normal state
+            // drawable. Drawable.setAlpha() stopped working above Android 4.4
+            // so we gotta bring out some bitmap magic. Credit goes to:
+            // http://stackoverflow.com/a/7477572
+            Bitmap enabledBitmap = ((BitmapDrawable) normalDrawable).getBitmap();
+            Bitmap disabledBitmap = Bitmap.createBitmap(
+                    normalDrawable.getIntrinsicWidth(),
+                    normalDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(disabledBitmap);
+
+            Paint paint = new Paint();
+            paint.setAlpha(disabledAlpha);
+            canvas.drawBitmap(enabledBitmap, 0, 0, paint);
+
+            Resources activityRes = cordova.getActivity().getResources();
+            disabledDrawable = new BitmapDrawable(activityRes, disabledBitmap);
+        }
+
+        StateListDrawable states = new StateListDrawable();
+        if (pressedDrawable != null) {
+            states.addState(
+                new int[] {
+                    android.R.attr.state_pressed
+                },
+                pressedDrawable
+            );
+        }
+        if (normalDrawable != null) {
+            states.addState(
+                new int[] {
+                    android.R.attr.state_enabled
+                },
+                normalDrawable
+            );
+        }
+        if (disabledDrawable != null) {
+            states.addState(
+                new int[] {},
+                disabledDrawable
+            );
+        }
+
+        setBackground(view, states);
+    }
+
+    private void setBackground(View view, Drawable drawable) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
+            view.setBackgroundDrawable(drawable);
+        } else {
+            view.setBackground(drawable);
+        }
+    }
+
+    private Button createButton(BrowserButton buttonProps, String description,
+            View.OnClickListener listener) {
+        Button result = null;
+        if (buttonProps != null) {
+            result = new Button(cordova.getActivity());
+            result.setContentDescription(description);
+            result.setLayoutParams(new LinearLayout.LayoutParams(
+                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+            setButtonImages(result, buttonProps, DISABLED_ALPHA);
+            if (listener != null) {
+                result.setOnClickListener(listener);
+            }
+        } else {
+            emitWarning(WRN_UNDEFINED,
+                    String.format("%s is not defined. Button will not be shown.",
+                            description));
+        }
+        return result;
+    }
+
+    /**
+     * Create a new plugin success result and send it back to JavaScript
+     *
+     * @param obj a JSONObject contain event payload information
+     */
+    private void sendUpdate(JSONObject obj, boolean keepCallback) {
+        sendUpdate(obj, keepCallback, PluginResult.Status.OK);
+    }
+
+    /**
+     * Create a new plugin result and send it back to JavaScript
+     *
+     * @param obj a JSONObject contain event payload information
+     * @param status the status code to return to the JavaScript environment
+     */
+    private void sendUpdate(JSONObject obj, boolean keepCallback, PluginResult.Status status) {
+        if (callbackContext != null) {
+            PluginResult result = new PluginResult(status, obj);
+            result.setKeepCallback(keepCallback);
+            callbackContext.sendPluginResult(result);
+            if (!keepCallback) {
+                callbackContext = null;
+            }
+        }
+    }
+
+    public static interface PageLoadListener {
+        public void onPageFinished(String url, boolean canGoBack,
+                boolean canGoForward);
+    }
+
+    /**
+     * The webview client receives notifications about appView
+     */
+    public class ThemeableBrowserClient extends WebViewClient {
+        PageLoadListener callback;
+        CordovaWebView webView;
+
+        /**
+         * Constructor.
+         *
+         * @param webView
+         * @param callback
+         */
+        public ThemeableBrowserClient(CordovaWebView webView,
+                PageLoadListener callback) {
+            this.webView = webView;
+            this.callback = callback;
+        }
+
+        /**
+         * Override the URL that should be loaded
+         *
+         * This handles a small subset of all the URIs that would be encountered.
+         *
+         * @param webView
+         * @param url
+         */
+        @Override
+        public boolean shouldOverrideUrlLoading(WebView webView, String url) {
+            if (url.startsWith(WebView.SCHEME_TEL)) {
+                try {
+                    Intent intent = new Intent(Intent.ACTION_DIAL);
+                    intent.setData(Uri.parse(url));
+                    cordova.getActivity().startActivity(intent);
+                    return true;
+                } catch (android.content.ActivityNotFoundException e) {
+                    Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
+                }
+            } else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:")) {
+                try {
+                    Intent intent = new Intent(Intent.ACTION_VIEW);
+                    intent.setData(Uri.parse(url));
+                    cordova.getActivity().startActivity(intent);
+                    return true;
+                } catch (android.content.ActivityNotFoundException e) {
+                    Log.e(LOG_TAG, "Error with " + url + ": " + e.toString());
+                }
+            }
+            // If sms:5551212?body=This is the message
+            else if (url.startsWith("sms:")) {
+                try {
+                    Intent intent = new Intent(Intent.ACTION_VIEW);
+
+                    // Get address
+                    String address = null;
+                    int parmIndex = url.indexOf('?');
+                    if (parmIndex == -1) {
+                        address = url.substring(4);
+                    } else {
+                        address = url.substring(4, parmIndex);
+
+                        // If body, then set sms body
+                        Uri uri = Uri.parse(url);
+                        String query = uri.getQuery();
+                        if (query != null) {
+                            if (query.startsWith("body=")) {
+                                intent.putExtra("sms_body", query.substring(5));
+                            }
+                        }
+                    }
+                    intent.setData(Uri.parse("sms:" + address));
+                    intent.putExtra("address", address);
+                    intent.setType("vnd.android-dir/mms-sms");
+                    cordova.getActivity().startActivity(intent);
+                    return true;
+                } catch (android.content.ActivityNotFoundException e) {
+                    Log.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
+                }
+            }
+            return false;
+        }
+
+
+        /*
+         * onPageStarted fires the LOAD_START_EVENT
+         *
+         * @param view
+         * @param url
+         * @param favicon
+         */
+        @Override
+        public void onPageStarted(WebView view, String url, Bitmap favicon) {
+            super.onPageStarted(view, url, favicon);
+            String newloc = "";
+            if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:")) {
+                newloc = url;
+            }
+            else
+            {
+                // Assume that everything is HTTP at this point, because if we don't specify,
+                // it really should be.  Complain loudly about this!!!
+                Log.e(LOG_TAG, "Possible Uncaught/Unknown URI");
+                newloc = "http://" + url;
+            }
+
+            // Update the UI if we haven't already
+            if (!newloc.equals(edittext.getText().toString())) {
+                edittext.setText(newloc);
+            }
+
+            try {
+                JSONObject obj = new JSONObject();
+                obj.put("type", LOAD_START_EVENT);
+                obj.put("url", newloc);
+                sendUpdate(obj, true);
+            } catch (JSONException ex) {
+                Log.e(LOG_TAG, "URI passed in has caused a JSON error.");
+            }
+        }
+
+        public void onPageFinished(WebView view, String url) {
+            super.onPageFinished(view, url);
+
+            try {
+                JSONObject obj = new JSONObject();
+                obj.put("type", LOAD_STOP_EVENT);
+                obj.put("url", url);
+
+                sendUpdate(obj, true);
+
+                if (this.callback != null) {
+                    this.callback.onPageFinished(url, view.canGoBack(),
+                            view.canGoForward());
+                }
+            } catch (JSONException ex) {
+            }
+        }
+
+        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+            super.onReceivedError(view, errorCode, description, failingUrl);
+
+            try {
+                JSONObject obj = new JSONObject();
+                obj.put("type", LOAD_ERROR_EVENT);
+                obj.put("url", failingUrl);
+                obj.put("code", errorCode);
+                obj.put("message", description);
+
+                sendUpdate(obj, true, PluginResult.Status.ERROR);
+            } catch (JSONException ex) {
+            }
+        }
+    }
+
+    /**
+     * Like Spinner but will always trigger onItemSelected even if a selected
+     * item is selected, and always ignore default selection.
+     */
+    public class MenuSpinner extends Spinner {
+        private OnItemSelectedListener listener;
+
+        public MenuSpinner(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void setSelection(int position) {
+            super.setSelection(position);
+
+            if (listener != null) {
+                listener.onItemSelected(null, this, position, 0);
+            }
+        }
+
+        @Override
+        public void setOnItemSelectedListener(OnItemSelectedListener listener) {
+            this.listener = listener;
+        }
+    }
+
+    /**
+     * Extension of ArrayAdapter. The only difference is that it hides the
+     * selected text that's shown inside spinner.
+     * @param <T>
+     */
+    private static class HideSelectedAdapter<T> extends ArrayAdapter {
+
+        public HideSelectedAdapter(Context context, int resource, T[] objects) {
+            super(context, resource, objects);
+        }
+
+        public View getView (int position, View convertView, ViewGroup parent) {
+            View v = super.getView(position, convertView, parent);
+            v.setVisibility(View.GONE);
+            return v;
+        }
+    }
+
+
+    /**
+     * A class to hold parsed option properties.
+     */
+    private static class Options {
+        public boolean location = true;
+        public boolean hidden = false;
+        public boolean clearcache = false;
+        public boolean clearsessioncache = false;
+        public boolean zoom = true;
+        public boolean hardwareback = true;
+
+        public Toolbar toolbar;
+        public Title title;
+        public BrowserButton backButton;
+        public BrowserButton forwardButton;
+        public BrowserButton closeButton;
+        public BrowserMenu menu;
+        public BrowserButton[] customButtons;
+        public boolean backButtonCanClose;
+        public boolean disableAnimation;
+        public boolean fullscreen;
+    }
+
+    private static class Event {
+        public String event;
+    }
+
+    private static class EventLabel extends Event {
+        public String label;
+
+        public String toString() {
+            return label;
+        }
+    }
+
+    private static class BrowserButton extends Event {
+        public String image;
+        public String wwwImage;
+        public String imagePressed;
+        public String wwwImagePressed;
+        public double wwwImageDensity = 1;
+        public String align = ALIGN_LEFT;
+    }
+
+    private static class BrowserMenu extends BrowserButton {
+        public EventLabel[] items;
+    }
+
+    private static class Toolbar {
+        public int height = TOOLBAR_DEF_HEIGHT;
+        public String color;
+        public String image;
+        public String wwwImage;
+        public double wwwImageDensity = 1;
+    }
+
+    private static class Title {
+        public String color;
+        public String staticText;
+        public boolean showPageTitle;
+    }
+}
diff --git a/platforms/android/app/src/main/java/com/initialxy/cordova/themeablebrowser/ThemeableBrowserDialog.java b/platforms/android/app/src/main/java/com/initialxy/cordova/themeablebrowser/ThemeableBrowserDialog.java
new file mode 100644
index 0000000..210c258
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/initialxy/cordova/themeablebrowser/ThemeableBrowserDialog.java
@@ -0,0 +1,61 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package com.initialxy.cordova.themeablebrowser;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Created by Oliver on 22/11/2013.
+ */
+public class ThemeableBrowserDialog extends Dialog {
+    Context context;
+    ThemeableBrowser themeableBrowser = null;
+    boolean hardwareBack;
+
+    public ThemeableBrowserDialog(Context context, int theme,
+          boolean hardwareBack) {
+        super(context, theme);
+        this.context = context;
+        this.hardwareBack = hardwareBack;
+    }
+
+    public void setThemeableBrowser(ThemeableBrowser browser) {
+        this.themeableBrowser = browser;
+    }
+
+    public void onBackPressed () {
+        if (this.themeableBrowser == null) {
+            this.dismiss();
+        } else {
+            // better to go through in themeableBrowser because it does a clean
+            // up
+            if (this.hardwareBack && this.themeableBrowser.canGoBack()) {
+                this.themeableBrowser.goBack();
+            }  else {
+                this.themeableBrowser.closeDialog();
+            }
+        }
+    }
+}
diff --git a/platforms/android/app/src/main/java/com/initialxy/cordova/themeablebrowser/ThemeableBrowserUnmarshaller.java b/platforms/android/app/src/main/java/com/initialxy/cordova/themeablebrowser/ThemeableBrowserUnmarshaller.java
new file mode 100644
index 0000000..beff5d5
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/initialxy/cordova/themeablebrowser/ThemeableBrowserUnmarshaller.java
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.initialxy.cordova.themeablebrowser;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This is a simple and half decent JSON to POJO unmarshaller inspired by
+ * Jackson. It is only a unmarshaller without a marshaller. It is intended to
+ * parse JSON passed to a plugin as options to a POJO. It is nowhere as powerful
+ * as Jackson is, but for most use cases, it will do a pretty decent job since
+ * it is designed to be used for general purpose unmarshalling. This avoid
+ * having to import Jackson or JAXB for merely a Cordova plugin. ~350 lines
+ * isn't too big right?
+ */
+public class ThemeableBrowserUnmarshaller {
+    /**
+     * Runtime exception to notify type mismatch between expected class
+     * structure and JSON.
+     */
+    public static class TypeMismatchException extends RuntimeException {
+        public TypeMismatchException(Type expected, Type got) {
+            super(String.format("Expected %s but got %s.", expected, got));
+        }
+
+        public TypeMismatchException(String message) {
+            super(message);
+        }
+    }
+
+    /**
+     * Runtime exception to notify errors during class initialization.
+     */
+    public static class ClassInstantiationException extends RuntimeException {
+        public ClassInstantiationException(Class<?> cls) {
+            super(String.format("Failed to instantiate %s", cls));
+        }
+
+        public ClassInstantiationException(String message) {
+            super(message);
+        }
+    }
+
+    /**
+     * Runtime exception to notify parser errors.
+     */
+    public static class ParserException extends RuntimeException {
+        public ParserException(Exception e) {
+            super(e);
+        }
+    }
+
+    /**
+     * Given a JSON string, unmarhall it to an instance of the given class.
+     *
+     * @param json JSON string to unmarshall.
+     * @param cls Return an instance of this class. Must be either public class
+     *            or private static class. Inner class will not work.
+     * @param <T> Same type as cls.
+     * @return An instance of class given by cls.
+     * @throws com.initialxy.cordova.themeablebrowser.ThemeableBrowserUnmarshaller.TypeMismatchException
+     */
+    public static <T> T JSONToObj(String json, Class<T> cls) {
+        T result = null;
+
+        if (json != null && !json.isEmpty()) {
+            try {
+                JSONObject jsonObj = new JSONObject(json);
+                result = JSONToObj(jsonObj, cls);
+            } catch (JSONException e) {
+                throw new ParserException(e);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Given a JSONObject, unmarhall it to an instance of the given class.
+     *
+     * @param jsonObj JSON string to unmarshall.
+     * @param cls Return an instance of this class. Must be either public class
+     *            or private static class. Inner class will not work.
+     * @param <T> Same type as cls.
+     * @return An instance of class given by cls.
+     * @throws com.initialxy.cordova.themeablebrowser.ThemeableBrowserUnmarshaller.TypeMismatchException
+     */
+    public static <T> T JSONToObj(JSONObject jsonObj, Class<T> cls) {
+        T result = null;
+
+        try {
+            Constructor<T> constructor = cls.getDeclaredConstructor();
+            constructor.setAccessible(true);
+            result = (T) constructor.newInstance();
+            Iterator<?> i = jsonObj.keys();
+
+            while (i.hasNext()) {
+                String k = (String) i.next();
+                Object val = jsonObj.get(k);
+
+                try {
+                    Field field = cls.getField(k);
+                    Object converted = valToType(val, field.getGenericType());
+
+                    if (converted == null) {
+                        if (!field.getType().isPrimitive()) {
+                            field.set(result, null);
+                        } else {
+                            throw new TypeMismatchException(String.format(
+                                    "Type %s cannot be set to null.",
+                                    field.getType()));
+                        }
+                    } else {
+                        if (converted instanceof List
+                                && field.getType()
+                                .isAssignableFrom(List.class)) {
+                            // Class can define their own favorite
+                            // implementation of List. In which case the field
+                            // still need to be defined as List, but it can be
+                            // initialized with a placeholder instance of any of
+                            // the List implementations (eg. ArrayList).
+                            Object existing = field.get(result);
+                            if (existing != null) {
+                                ((List<?>) existing).clear();
+
+                                // Just because I don't want javac to complain
+                                // about unsafe operations. So I'm gonna use
+                                // more reflection, HA!
+                                Method addAll = existing.getClass()
+                                        .getMethod("addAll", Collection.class);
+                                addAll.invoke(existing, converted);
+                            } else {
+                                field.set(result, converted);
+                            }
+                        } else {
+                            field.set(result, converted);
+                        }
+                    }
+                } catch (NoSuchFieldException e) {
+                    // Ignore.
+                } catch (IllegalAccessException e) {
+                    // Ignore.
+                } catch (IllegalArgumentException e) {
+                    // Ignore.
+                }
+            }
+        } catch (JSONException e) {
+            throw new ParserException(e);
+        } catch (NoSuchMethodException e) {
+            throw new ClassInstantiationException(
+                    "Failed to retrieve constructor for "
+                    + cls.toString() + ", make sure it's not an inner class.");
+        } catch (InstantiationException e) {
+            throw new ClassInstantiationException(cls);
+        } catch (IllegalAccessException e) {
+            throw new ClassInstantiationException(cls);
+        } catch (InvocationTargetException e) {
+            throw new ClassInstantiationException(cls);
+        }
+
+        return result;
+    }
+
+    /**
+     * Given an object extracted from JSONObject field, convert it to an
+     * appropriate object with type appropriate for given type so that it can be
+     * assigned to the associated field of the ummarshalled object. eg.
+     * JSONObject value from a JSONObject field probably needs to be
+     * unmarshalled to a class instance. Double from JSONObject may need to be
+     * converted to Float. etc.
+     *
+     * @param val Value extracted from JSONObject field.
+     * @param genericType Type to convert to. Must be generic type. ie. From
+     *                    field.getGenericType().
+     * @return Object of the given type so it can be assinged to field with
+     * field.set().
+     * @throws com.initialxy.cordova.themeablebrowser.ThemeableBrowserUnmarshaller.TypeMismatchException
+     */
+    private static Object valToType(Object val, Type genericType) {
+        Object result = null;
+        boolean isArray = false;
+
+        Class<?> rawType = null;
+        if (genericType instanceof ParameterizedType) {
+            rawType = (Class<?>) ((ParameterizedType) genericType).getRawType();
+        } else if (genericType instanceof GenericArrayType) {
+            rawType = List.class;
+            isArray = true;
+        } else {
+            rawType = (Class<?>) genericType;
+        }
+
+        isArray = isArray || rawType.isArray();
+ 
+        if (val != null && val != JSONObject.NULL) {
+            if (rawType.isAssignableFrom(String.class)) {
+                if (val instanceof String) {
+                    result = val;
+                } else {
+                    throw new TypeMismatchException(rawType, val.getClass());
+                }
+            } else if (isPrimitive(rawType)) {
+                result = convertToPrimitiveFieldObj(val, rawType);
+            } else if (isArray || rawType.isAssignableFrom(List.class)) {
+                if (val instanceof JSONArray) {
+                    Type itemType = getListItemType(genericType);
+                    result = JSONToList((JSONArray) val, itemType);
+
+                    if (isArray) {
+                        List<?> list = (List<?>) result;
+
+                        Class<?> itemClass = null;
+                        if (itemType instanceof ParameterizedType) {
+                            itemClass = (Class<?>) ((ParameterizedType) itemType).getRawType();
+                        } else {
+                            itemClass = (Class<?>) itemType;
+                        }
+
+                        result = Array.newInstance(itemClass, list.size());
+                        int cnt = 0;
+                        for (Object i : list) {
+                            Array.set(result, cnt, i);
+                            cnt += 1;
+                        }
+                    }
+                } else {
+                    throw new TypeMismatchException(
+                            JSONArray.class, val.getClass());
+                }
+            } else if (val instanceof JSONObject) {
+                result = JSONToObj((JSONObject) val, rawType);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Given a generic type representing a List or array, retrieve list or array
+     * item type.
+     *
+     * @param type
+     * @return
+     */
+    private static Type getListItemType(Type type) {
+        Type result = null;
+        
+        if (type instanceof GenericArrayType) {
+            result = ((GenericArrayType) type).getGenericComponentType();
+        } else if (type instanceof ParameterizedType){
+            result = ((ParameterizedType) type).getActualTypeArguments()[0];
+        } else {
+            result = ((Class<?>) type).getComponentType();
+        }
+
+        return result;
+    }
+
+    /**
+     * Given an JSONArray retrieved from JSONObject, and the destination item
+     * type, unmarshall this list to a List of given item type.
+     *
+     * @param jsonArr
+     * @param itemType
+     * @return
+     */
+    private static List<?> JSONToList(JSONArray jsonArr, Type itemType) {
+        List<Object> result = new ArrayList<Object>();
+
+        Class<?> rawType = null;
+        ParameterizedType pType = null;
+
+        if (itemType instanceof ParameterizedType) {
+            pType = (ParameterizedType) itemType;
+            rawType = (Class<?>) pType.getRawType();
+        } else {
+            rawType = (Class<?>) itemType;
+        }
+
+        int len = jsonArr.length();
+        for (int i = 0; i < len; i++) {
+            try {
+                Object item = jsonArr.get(i);
+                Object converted = valToType(item, itemType);
+                if (converted != null) {
+                    result.add(converted);
+                }
+            } catch (JSONException e) {
+                throw new ParserException(e);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Checks if given class is one of the primitive types or more importantly,
+     * one of the classes associated with a primitive type. eg. Integer, Double
+     * etc.
+     *
+     * @param cls
+     * @return
+     */
+    private static boolean isPrimitive(Class<?> cls) {
+        return cls.isPrimitive()
+                || cls.isAssignableFrom(Byte.class)
+                || cls.isAssignableFrom(Short.class)
+                || cls.isAssignableFrom(Integer.class)
+                || cls.isAssignableFrom(Long.class)
+                || cls.isAssignableFrom(Float.class)
+                || cls.isAssignableFrom(Double.class)
+                || cls.isAssignableFrom(Boolean.class)
+                || cls.isAssignableFrom(Character.class);
+    }
+
+    /**
+     * Gracefully convert given Object to given class given the precondition
+     * that both are primitives or one of the classes associated with
+     * primitives. eg. If val is of type Double and cls is of type int, return
+     * Integer type with appropriate value truncation so that it can be assigned
+     * to field with field.set().
+     *
+     * @param cls
+     * @param val
+     * @return
+     * @throws com.initialxy.cordova.themeablebrowser.ThemeableBrowserUnmarshaller.TypeMismatchException
+     */
+    private static Object convertToPrimitiveFieldObj(Object val, Class<?> cls) {
+        Class<?> valClass = val.getClass();
+        Object result = null;
+
+        try {
+            Method getter = null;
+            if (cls.isAssignableFrom(Byte.class)
+                    || cls.isAssignableFrom(Byte.TYPE)) {
+                getter = valClass.getMethod("byteValue");
+            } else if (cls.isAssignableFrom(Short.class)
+                    || cls.isAssignableFrom(Short.TYPE)) {
+                getter = valClass.getMethod("shortValue");
+            } else if (cls.isAssignableFrom(Integer.class)
+                    || cls.isAssignableFrom(Integer.TYPE)) {
+                getter = valClass.getMethod("intValue");
+            } else if (cls.isAssignableFrom(Long.class)
+                    || cls.isAssignableFrom(Long.TYPE)) {
+                getter = valClass.getMethod("longValue");
+            } else if (cls.isAssignableFrom(Float.class)
+                    || cls.isAssignableFrom(Float.TYPE)) {
+                getter = valClass.getMethod("floatValue");
+            } else if (cls.isAssignableFrom(Double.class)
+                    || cls.isAssignableFrom(Double.TYPE)) {
+                getter = valClass.getMethod("doubleValue");
+            } else if (cls.isAssignableFrom(Boolean.class)
+                    || cls.isAssignableFrom(Boolean.TYPE)) {
+                if (val instanceof Boolean) {
+                    result = val;
+                } else {
+                    throw new TypeMismatchException(cls, val.getClass());
+                }
+            } else if (cls.isAssignableFrom(Character.class)
+                    || cls.isAssignableFrom(Character.TYPE)) {
+                if (val instanceof String && ((String) val).length() == 1) {
+                    char c = ((String) val).charAt(0);
+                    result = Character.valueOf(c);
+                } else if (val instanceof String) {
+                    throw new TypeMismatchException(
+                            "Expected Character, "
+                            + "but received String with length other than 1.");
+                } else {
+                    throw new TypeMismatchException(String.format(
+                            "Expected Character, accept String, but got %s.",
+                            val.getClass()));
+                }
+            }
+
+            if (getter != null) {
+                result = getter.invoke(val);
+            }
+        } catch (NoSuchMethodException e) {
+            throw new TypeMismatchException(String.format(
+                    "Cannot convert %s to %s.", val.getClass(), cls));
+        } catch (SecurityException e) {
+            throw new TypeMismatchException(String.format(
+                    "Cannot convert %s to %s.", val.getClass(), cls));
+        } catch (IllegalAccessException e) {
+            throw new TypeMismatchException(String.format(
+                    "Cannot convert %s to %s.", val.getClass(), cls));
+        } catch (InvocationTargetException e) {
+            throw new TypeMismatchException(String.format(
+                    "Cannot convert %s to %s.", val.getClass(), cls));
+        }
+
+        return result;
+    }
+}
diff --git a/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaClientAuth.java b/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaClientAuth.java
new file mode 100644
index 0000000..b01ac93
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaClientAuth.java
@@ -0,0 +1,113 @@
+package com.silkimen.cordovahttp;
+
+import android.app.Activity;
+import android.content.Context;
+import android.security.KeyChain;
+import android.security.KeyChainAliasCallback;
+import android.util.Log;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.net.URI;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+
+import org.apache.cordova.CallbackContext;
+
+import com.silkimen.http.KeyChainKeyManager;
+import com.silkimen.http.TLSConfiguration;
+
+class CordovaClientAuth implements Runnable, KeyChainAliasCallback {
+  private static final String TAG = "Cordova-Plugin-HTTP";
+
+  private String mode;
+  private String aliasString;
+  private byte[] rawPkcs;
+  private String pkcsPassword;
+  private Activity activity;
+  private Context context;
+  private TLSConfiguration tlsConfiguration;
+  private CallbackContext callbackContext;
+
+  public CordovaClientAuth(final String mode, final String aliasString, final byte[] rawPkcs,
+      final String pkcsPassword, final Activity activity, final Context context, final TLSConfiguration configContainer,
+      final CallbackContext callbackContext) {
+
+    this.mode = mode;
+    this.aliasString = aliasString;
+    this.rawPkcs = rawPkcs;
+    this.pkcsPassword = pkcsPassword;
+    this.activity = activity;
+    this.tlsConfiguration = configContainer;
+    this.context = context;
+    this.callbackContext = callbackContext;
+  }
+
+  @Override
+  public void run() {
+    if ("systemstore".equals(this.mode)) {
+      this.loadFromSystemStore();
+    } else if ("buffer".equals(this.mode)) {
+      this.loadFromBuffer();
+    } else {
+      this.disableClientAuth();
+    }
+  }
+
+  private void loadFromSystemStore() {
+    if (this.aliasString == null) {
+      KeyChain.choosePrivateKeyAlias(this.activity, this, null, null, null, -1, null);
+    } else {
+      this.alias(this.aliasString);
+    }
+  }
+
+  private void loadFromBuffer() {
+    try {
+      KeyStore keyStore = KeyStore.getInstance("PKCS12");
+      String keyManagerFactoryAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
+      KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(keyManagerFactoryAlgorithm);
+      ByteArrayInputStream stream = new ByteArrayInputStream(this.rawPkcs);
+
+      keyStore.load(stream, this.pkcsPassword.toCharArray());
+      keyManagerFactory.init(keyStore, this.pkcsPassword.toCharArray());
+
+      this.tlsConfiguration.setKeyManagers(keyManagerFactory.getKeyManagers());
+      this.callbackContext.success();
+    } catch (Exception e) {
+      Log.e(TAG, "Couldn't load given PKCS12 container for authentication", e);
+      this.callbackContext.error("Couldn't load given PKCS12 container for authentication");
+    }
+  }
+
+  private void disableClientAuth() {
+    this.tlsConfiguration.setKeyManagers(null);
+    this.callbackContext.success();
+  }
+
+  @Override
+  public void alias(final String alias) {
+    try {
+      if (alias == null) {
+        throw new Exception("Couldn't get a consent for private key access");
+      }
+
+      PrivateKey key = KeyChain.getPrivateKey(this.context, alias);
+      X509Certificate[] chain = KeyChain.getCertificateChain(this.context, alias);
+      KeyManager keyManager = new KeyChainKeyManager(alias, key, chain);
+
+      this.tlsConfiguration.setKeyManagers(new KeyManager[] { keyManager });
+
+      this.callbackContext.success(alias);
+    } catch (Exception e) {
+      Log.e(TAG, "Couldn't load private key and certificate pair with given alias \"" + alias + "\" for authentication",
+          e);
+      this.callbackContext.error(
+          "Couldn't load private key and certificate pair with given alias \"" + alias + "\" for authentication");
+    }
+  }
+}
diff --git a/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpBase.java b/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpBase.java
new file mode 100644
index 0000000..011b0dc
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpBase.java
@@ -0,0 +1,180 @@
+package com.silkimen.cordovahttp;
+
+import java.io.IOException;
+import java.io.ByteArrayOutputStream;
+
+import java.net.SocketTimeoutException;
+import java.net.UnknownHostException;
+
+import java.nio.ByteBuffer;
+
+import javax.net.ssl.SSLException;
+
+import com.silkimen.http.HttpBodyDecoder;
+import com.silkimen.http.HttpRequest;
+import com.silkimen.http.HttpRequest.HttpRequestException;
+import com.silkimen.http.JsonUtils;
+import com.silkimen.http.OkConnectionFactory;
+import com.silkimen.http.TLSConfiguration;
+
+import org.apache.cordova.CallbackContext;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.util.Log;
+
+abstract class CordovaHttpBase implements Runnable {
+  protected static final String TAG = "Cordova-Plugin-HTTP";
+
+  protected String method;
+  protected String url;
+  protected String serializer = "none";
+  protected String responseType;
+  protected Object data;
+  protected JSONObject headers;
+  protected int timeout;
+  protected boolean followRedirects;
+  protected TLSConfiguration tlsConfiguration;
+  protected CallbackContext callbackContext;
+
+  public CordovaHttpBase(String method, String url, String serializer, Object data, JSONObject headers, int timeout,
+      boolean followRedirects, String responseType, TLSConfiguration tlsConfiguration,
+      CallbackContext callbackContext) {
+
+    this.method = method;
+    this.url = url;
+    this.serializer = serializer;
+    this.data = data;
+    this.headers = headers;
+    this.timeout = timeout;
+    this.followRedirects = followRedirects;
+    this.responseType = responseType;
+    this.tlsConfiguration = tlsConfiguration;
+    this.callbackContext = callbackContext;
+  }
+
+  public CordovaHttpBase(String method, String url, JSONObject headers, int timeout, boolean followRedirects,
+      String responseType, TLSConfiguration tlsConfiguration, CallbackContext callbackContext) {
+
+    this.method = method;
+    this.url = url;
+    this.headers = headers;
+    this.timeout = timeout;
+    this.followRedirects = followRedirects;
+    this.responseType = responseType;
+    this.tlsConfiguration = tlsConfiguration;
+    this.callbackContext = callbackContext;
+  }
+
+  @Override
+  public void run() {
+    CordovaHttpResponse response = new CordovaHttpResponse();
+
+    try {
+      HttpRequest request = this.createRequest();
+      this.prepareRequest(request);
+      this.sendBody(request);
+      this.processResponse(request, response);
+    } catch (HttpRequestException e) {
+      if (e.getCause() instanceof SSLException) {
+        response.setStatus(-2);
+        response.setErrorMessage("TLS connection could not be established: " + e.getMessage());
+        Log.w(TAG, "TLS connection could not be established", e);
+      } else if (e.getCause() instanceof UnknownHostException) {
+        response.setStatus(-3);
+        response.setErrorMessage("Host could not be resolved: " + e.getMessage());
+        Log.w(TAG, "Host could not be resolved", e);
+      } else if (e.getCause() instanceof SocketTimeoutException) {
+        response.setStatus(-4);
+        response.setErrorMessage("Request timed out: " + e.getMessage());
+        Log.w(TAG, "Request timed out", e);
+      } else {
+        response.setStatus(-1);
+        response.setErrorMessage("There was an error with the request: " + e.getCause().getMessage());
+        Log.w(TAG, "Generic request error", e);
+      }
+    } catch (Exception e) {
+      response.setStatus(-1);
+      response.setErrorMessage(e.getMessage());
+      Log.e(TAG, "An unexpected error occured", e);
+    }
+
+    try {
+      if (response.hasFailed()) {
+        this.callbackContext.error(response.toJSON());
+      } else {
+        this.callbackContext.success(response.toJSON());
+      }
+    } catch (JSONException e) {
+      Log.e(TAG, "An unexpected error occured while creating HTTP response object", e);
+    }
+  }
+
+  protected HttpRequest createRequest() throws JSONException {
+    return new HttpRequest(this.url, this.method);
+  }
+
+  protected void prepareRequest(HttpRequest request) throws JSONException, IOException {
+    request.followRedirects(this.followRedirects);
+    request.readTimeout(this.timeout);
+    request.acceptCharset("UTF-8");
+    request.uncompress(true);
+    request.setConnectionFactory(new OkConnectionFactory());
+
+    if (this.tlsConfiguration.getHostnameVerifier() != null) {
+      request.setHostnameVerifier(this.tlsConfiguration.getHostnameVerifier());
+    }
+
+    request.setSSLSocketFactory(this.tlsConfiguration.getTLSSocketFactory());
+
+    // setup content type before applying headers, so user can override it
+    this.setContentType(request);
+
+    request.headers(JsonUtils.getStringMap(this.headers));
+  }
+
+  protected void setContentType(HttpRequest request) {
+    if ("json".equals(this.serializer)) {
+      request.contentType("application/json", "UTF-8");
+    } else if ("utf8".equals(this.serializer)) {
+      request.contentType("text/plain", "UTF-8");
+    } else if ("urlencoded".equals(this.serializer)) {
+      // intentionally left blank, because content type is set in HttpRequest.form()
+    }
+  }
+
+  protected void sendBody(HttpRequest request) throws Exception {
+    if (this.data == null) {
+      return;
+    }
+
+    if ("json".equals(this.serializer)) {
+      request.send(this.data.toString());
+    } else if ("utf8".equals(this.serializer)) {
+      request.send(((JSONObject) this.data).getString("text"));
+    } else if ("urlencoded".equals(this.serializer)) {
+      request.form(JsonUtils.getObjectMap((JSONObject) this.data));
+    }
+  }
+
+  protected void processResponse(HttpRequest request, CordovaHttpResponse response) throws Exception {
+    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+    request.receive(outputStream);
+
+    response.setStatus(request.code());
+    response.setUrl(request.url().toString());
+    response.setHeaders(request.headers());
+
+    if (request.code() >= 200 && request.code() < 300) {
+      if ("text".equals(this.responseType)) {
+        String decoded = HttpBodyDecoder.decodeBody(outputStream.toByteArray(), request.charset());
+        response.setBody(decoded);
+      } else {
+        response.setData(outputStream.toByteArray());
+      }
+    } else {
+      response.setErrorMessage(HttpBodyDecoder.decodeBody(outputStream.toByteArray(), request.charset()));
+    }
+  }
+}
diff --git a/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpDownload.java b/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpDownload.java
new file mode 100644
index 0000000..d89db82
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpDownload.java
@@ -0,0 +1,42 @@
+package com.silkimen.cordovahttp;
+
+import java.io.File;
+import java.net.URI;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLSocketFactory;
+
+import com.silkimen.http.HttpRequest;
+import com.silkimen.http.TLSConfiguration;
+
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.file.FileUtils;
+import org.json.JSONObject;
+
+class CordovaHttpDownload extends CordovaHttpBase {
+  private String filePath;
+
+  public CordovaHttpDownload(String url, JSONObject headers, String filePath, int timeout, boolean followRedirects,
+      TLSConfiguration tlsConfiguration, CallbackContext callbackContext) {
+
+    super("GET", url, headers, timeout, followRedirects, "text", tlsConfiguration, callbackContext);
+    this.filePath = filePath;
+  }
+
+  @Override
+  protected void processResponse(HttpRequest request, CordovaHttpResponse response) throws Exception {
+    response.setStatus(request.code());
+    response.setUrl(request.url().toString());
+    response.setHeaders(request.headers());
+
+    if (request.code() >= 200 && request.code() < 300) {
+      File file = new File(new URI(this.filePath));
+      JSONObject fileEntry = FileUtils.getFilePlugin().getEntryForFile(file);
+
+      request.receive(file);
+      response.setFileEntry(fileEntry);
+    } else {
+      response.setErrorMessage("There was an error downloading the file");
+    }
+  }
+}
diff --git a/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpOperation.java b/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpOperation.java
new file mode 100644
index 0000000..5f17e5d
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpOperation.java
@@ -0,0 +1,25 @@
+package com.silkimen.cordovahttp;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLSocketFactory;
+
+import com.silkimen.http.TLSConfiguration;
+
+import org.apache.cordova.CallbackContext;
+import org.json.JSONObject;
+
+class CordovaHttpOperation extends CordovaHttpBase {
+  public CordovaHttpOperation(String method, String url, String serializer, Object data, JSONObject headers,
+      int timeout, boolean followRedirects, String responseType, TLSConfiguration tlsConfiguration,
+      CallbackContext callbackContext) {
+
+    super(method, url, serializer, data, headers, timeout, followRedirects, responseType, tlsConfiguration,
+        callbackContext);
+  }
+
+  public CordovaHttpOperation(String method, String url, JSONObject headers, int timeout, boolean followRedirects,
+      String responseType, TLSConfiguration tlsConfiguration, CallbackContext callbackContext) {
+
+    super(method, url, headers, timeout, followRedirects, responseType, tlsConfiguration, callbackContext);
+  }
+}
diff --git a/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpPlugin.java b/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpPlugin.java
new file mode 100644
index 0000000..b7ea1b3
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpPlugin.java
@@ -0,0 +1,167 @@
+package com.silkimen.cordovahttp;
+
+import java.security.KeyStore;
+
+import com.silkimen.http.TLSConfiguration;
+
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.CordovaWebView;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.util.Log;
+import android.util.Base64;
+
+import javax.net.ssl.TrustManagerFactory;
+
+public class CordovaHttpPlugin extends CordovaPlugin {
+  private static final String TAG = "Cordova-Plugin-HTTP";
+
+  private TLSConfiguration tlsConfiguration;
+
+  @Override
+  public void initialize(CordovaInterface cordova, CordovaWebView webView) {
+    super.initialize(cordova, webView);
+
+    this.tlsConfiguration = new TLSConfiguration();
+
+    try {
+      KeyStore store = KeyStore.getInstance("AndroidCAStore");
+      String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
+      TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
+
+      store.load(null);
+      tmf.init(store);
+
+      this.tlsConfiguration.setHostnameVerifier(null);
+      this.tlsConfiguration.setTrustManagers(tmf.getTrustManagers());
+    } catch (Exception e) {
+      Log.e(TAG, "An error occured while loading system's CA certificates", e);
+    }
+  }
+
+  @Override
+  public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext)
+      throws JSONException {
+
+    if (action == null) {
+      return false;
+    }
+
+    if ("get".equals(action)) {
+      return this.executeHttpRequestWithoutData(action, args, callbackContext);
+    } else if ("head".equals(action)) {
+      return this.executeHttpRequestWithoutData(action, args, callbackContext);
+    } else if ("delete".equals(action)) {
+      return this.executeHttpRequestWithoutData(action, args, callbackContext);
+    } else if ("post".equals(action)) {
+      return this.executeHttpRequestWithData(action, args, callbackContext);
+    } else if ("put".equals(action)) {
+      return this.executeHttpRequestWithData(action, args, callbackContext);
+    } else if ("patch".equals(action)) {
+      return this.executeHttpRequestWithData(action, args, callbackContext);
+    } else if ("uploadFile".equals(action)) {
+      return this.uploadFile(args, callbackContext);
+    } else if ("downloadFile".equals(action)) {
+      return this.downloadFile(args, callbackContext);
+    } else if ("setServerTrustMode".equals(action)) {
+      return this.setServerTrustMode(args, callbackContext);
+    } else if ("setClientAuthMode".equals(action)) {
+      return this.setClientAuthMode(args, callbackContext);
+    } else {
+      return false;
+    }
+  }
+
+  private boolean executeHttpRequestWithoutData(final String method, final JSONArray args,
+      final CallbackContext callbackContext) throws JSONException {
+
+    String url = args.getString(0);
+    JSONObject headers = args.getJSONObject(1);
+    int timeout = args.getInt(2) * 1000;
+    boolean followRedirect = args.getBoolean(3);
+    String responseType = args.getString(4);
+
+    CordovaHttpOperation request = new CordovaHttpOperation(method.toUpperCase(), url, headers, timeout, followRedirect,
+        responseType, this.tlsConfiguration, callbackContext);
+
+    cordova.getThreadPool().execute(request);
+
+    return true;
+  }
+
+  private boolean executeHttpRequestWithData(final String method, final JSONArray args,
+      final CallbackContext callbackContext) throws JSONException {
+
+    String url = args.getString(0);
+    Object data = args.get(1);
+    String serializer = args.getString(2);
+    JSONObject headers = args.getJSONObject(3);
+    int timeout = args.getInt(4) * 1000;
+    boolean followRedirect = args.getBoolean(5);
+    String responseType = args.getString(6);
+
+    CordovaHttpOperation request = new CordovaHttpOperation(method.toUpperCase(), url, serializer, data, headers,
+        timeout, followRedirect, responseType, this.tlsConfiguration, callbackContext);
+
+    cordova.getThreadPool().execute(request);
+
+    return true;
+  }
+
+  private boolean uploadFile(final JSONArray args, final CallbackContext callbackContext) throws JSONException {
+    String url = args.getString(0);
+    JSONObject headers = args.getJSONObject(1);
+    String filePath = args.getString(2);
+    String uploadName = args.getString(3);
+    int timeout = args.getInt(4) * 1000;
+    boolean followRedirect = args.getBoolean(5);
+    String responseType = args.getString(6);
+
+    CordovaHttpUpload upload = new CordovaHttpUpload(url, headers, filePath, uploadName, timeout, followRedirect,
+        responseType, this.tlsConfiguration, callbackContext);
+
+    cordova.getThreadPool().execute(upload);
+
+    return true;
+  }
+
+  private boolean downloadFile(final JSONArray args, final CallbackContext callbackContext) throws JSONException {
+    String url = args.getString(0);
+    JSONObject headers = args.getJSONObject(1);
+    String filePath = args.getString(2);
+    int timeout = args.getInt(3) * 1000;
+    boolean followRedirect = args.getBoolean(4);
+
+    CordovaHttpDownload download = new CordovaHttpDownload(url, headers, filePath, timeout, followRedirect,
+        this.tlsConfiguration, callbackContext);
+
+    cordova.getThreadPool().execute(download);
+
+    return true;
+  }
+
+  private boolean setServerTrustMode(final JSONArray args, final CallbackContext callbackContext) throws JSONException {
+    CordovaServerTrust runnable = new CordovaServerTrust(args.getString(0), this.cordova.getActivity(),
+        this.tlsConfiguration, callbackContext);
+
+    cordova.getThreadPool().execute(runnable);
+
+    return true;
+  }
+
+  private boolean setClientAuthMode(final JSONArray args, final CallbackContext callbackContext) throws JSONException {
+    byte[] pkcs = args.isNull(2) ? null : Base64.decode(args.getString(2), Base64.DEFAULT);
+
+    CordovaClientAuth runnable = new CordovaClientAuth(args.getString(0), args.isNull(1) ? null : args.getString(1),
+        pkcs, args.getString(3), this.cordova.getActivity(), this.cordova.getActivity().getApplicationContext(),
+        this.tlsConfiguration, callbackContext);
+
+    cordova.getThreadPool().execute(runnable);
+
+    return true;
+  }
+}
diff --git a/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpResponse.java b/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpResponse.java
new file mode 100644
index 0000000..e6051bf
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpResponse.java
@@ -0,0 +1,100 @@
+package com.silkimen.cordovahttp;
+
+import java.nio.ByteBuffer;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Base64;
+
+class CordovaHttpResponse {
+  private int status;
+  private String url;
+  private Map<String, List<String>> headers;
+  private String body;
+  private byte[] rawData;
+  private JSONObject fileEntry;
+  private boolean hasFailed;
+  private boolean isFileOperation;
+  private boolean isRawResponse;
+  private String error;
+
+  public void setStatus(int status) {
+    this.status = status;
+  }
+
+  public void setUrl(String url) {
+    this.url = url;
+  }
+
+  public void setHeaders(Map<String, List<String>> headers) {
+    this.headers = headers;
+  }
+
+  public void setBody(String body) {
+    this.body = body;
+  }
+
+  public void setData(byte[] rawData) {
+    this.isRawResponse = true;
+    this.rawData = rawData;
+  }
+
+  public void setFileEntry(JSONObject entry) {
+    this.isFileOperation = true;
+    this.fileEntry = entry;
+  }
+
+  public void setErrorMessage(String message) {
+    this.hasFailed = true;
+    this.error = message;
+  }
+
+  public boolean hasFailed() {
+    return this.hasFailed;
+  }
+
+  public JSONObject toJSON() throws JSONException {
+    JSONObject json = new JSONObject();
+
+    json.put("status", this.status);
+    json.put("url", this.url);
+
+    if (this.headers != null && !this.headers.isEmpty()) {
+      json.put("headers", new JSONObject(getFilteredHeaders()));
+    }
+
+    if (this.hasFailed) {
+      json.put("error", this.error);
+    } else if (this.isFileOperation) {
+      json.put("file", this.fileEntry);
+    } else if (this.isRawResponse) {
+      json.put("data", Base64.encodeToString(this.rawData, Base64.DEFAULT));
+    } else {
+      json.put("data", this.body);
+    }
+
+    return json;
+  }
+
+  private Map<String, String> getFilteredHeaders() throws JSONException {
+    Map<String, String> filteredHeaders = new HashMap<String, String>();
+
+    for (Map.Entry<String, List<String>> entry : this.headers.entrySet()) {
+      String key = entry.getKey();
+      List<String> value = entry.getValue();
+
+      if ((key != null) && (!value.isEmpty())) {
+        filteredHeaders.put(key.toLowerCase(), TextUtils.join(", ", value));
+      }
+    }
+
+    return filteredHeaders;
+  }
+}
diff --git a/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpUpload.java b/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpUpload.java
new file mode 100644
index 0000000..9d74736
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaHttpUpload.java
@@ -0,0 +1,44 @@
+package com.silkimen.cordovahttp;
+
+import android.webkit.MimeTypeMap;
+
+import com.silkimen.http.HttpRequest;
+
+import java.io.File;
+import java.net.URI;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLSocketFactory;
+
+import com.silkimen.http.TLSConfiguration;
+
+import org.apache.cordova.CallbackContext;
+import org.json.JSONObject;
+
+class CordovaHttpUpload extends CordovaHttpBase {
+  private String filePath;
+  private String uploadName;
+
+  public CordovaHttpUpload(String url, JSONObject headers, String filePath, String uploadName, int timeout,
+      boolean followRedirects, String responseType, TLSConfiguration tlsConfiguration,
+      CallbackContext callbackContext) {
+
+    super("POST", url, headers, timeout, followRedirects, responseType, tlsConfiguration, callbackContext);
+    this.filePath = filePath;
+    this.uploadName = uploadName;
+  }
+
+  @Override
+  protected void sendBody(HttpRequest request) throws Exception {
+    int filenameIndex = this.filePath.lastIndexOf('/');
+    String filename = this.filePath.substring(filenameIndex + 1);
+
+    int extIndex = this.filePath.lastIndexOf('.');
+    String ext = this.filePath.substring(extIndex + 1);
+
+    MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
+    String mimeType = mimeTypeMap.getMimeTypeFromExtension(ext);
+
+    request.part(this.uploadName, filename, mimeType, new File(new URI(this.filePath)));
+  }
+}
diff --git a/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaServerTrust.java b/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaServerTrust.java
new file mode 100644
index 0000000..822079e
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/silkimen/cordovahttp/CordovaServerTrust.java
@@ -0,0 +1,124 @@
+package com.silkimen.cordovahttp;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import com.silkimen.http.TLSConfiguration;
+
+import org.apache.cordova.CallbackContext;
+
+import android.app.Activity;
+import android.util.Log;
+import android.content.res.AssetManager;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+class CordovaServerTrust implements Runnable {
+  private static final String TAG = "Cordova-Plugin-HTTP";
+
+  private final TrustManager[] noOpTrustManagers;
+  private final HostnameVerifier noOpVerifier;
+
+  private String mode;
+  private Activity activity;
+  private TLSConfiguration tlsConfiguration;
+  private CallbackContext callbackContext;
+
+  public CordovaServerTrust(final String mode, final Activity activity, final TLSConfiguration configContainer,
+      final CallbackContext callbackContext) {
+
+    this.mode = mode;
+    this.activity = activity;
+    this.tlsConfiguration = configContainer;
+    this.callbackContext = callbackContext;
+
+    this.noOpTrustManagers = new TrustManager[] { new X509TrustManager() {
+      public X509Certificate[] getAcceptedIssuers() {
+        return new X509Certificate[0];
+      }
+
+      public void checkClientTrusted(X509Certificate[] chain, String authType) {
+        // intentionally left blank
+      }
+
+      public void checkServerTrusted(X509Certificate[] chain, String authType) {
+        // intentionally left blank
+      }
+    } };
+
+    this.noOpVerifier = new HostnameVerifier() {
+      public boolean verify(String hostname, SSLSession session) {
+        return true;
+      }
+    };
+  }
+
+  @Override
+  public void run() {
+    try {
+      if ("legacy".equals(this.mode)) {
+        this.tlsConfiguration.setHostnameVerifier(null);
+        this.tlsConfiguration.setTrustManagers(null);
+      } else if ("nocheck".equals(this.mode)) {
+        this.tlsConfiguration.setHostnameVerifier(this.noOpVerifier);
+        this.tlsConfiguration.setTrustManagers(this.noOpTrustManagers);
+      } else if ("pinned".equals(this.mode)) {
+        this.tlsConfiguration.setHostnameVerifier(null);
+        this.tlsConfiguration.setTrustManagers(this.getTrustManagers(this.getCertsFromBundle("www/certificates")));
+      } else {
+        this.tlsConfiguration.setHostnameVerifier(null);
+        this.tlsConfiguration.setTrustManagers(this.getTrustManagers(this.getCertsFromKeyStore("AndroidCAStore")));
+      }
+
+      callbackContext.success();
+    } catch (Exception e) {
+      Log.e(TAG, "An error occured while configuring SSL cert mode", e);
+      callbackContext.error("An error occured while configuring SSL cert mode");
+    }
+  }
+
+  private TrustManager[] getTrustManagers(KeyStore store) throws GeneralSecurityException {
+    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
+    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
+    tmf.init(store);
+
+    return tmf.getTrustManagers();
+  }
+
+  private KeyStore getCertsFromBundle(String path) throws GeneralSecurityException, IOException {
+    AssetManager assetManager = this.activity.getAssets();
+    String[] files = assetManager.list(path);
+
+    CertificateFactory cf = CertificateFactory.getInstance("X.509");
+    String keyStoreType = KeyStore.getDefaultType();
+    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
+
+    keyStore.load(null, null);
+
+    for (int i = 0; i < files.length; i++) {
+      int index = files[i].lastIndexOf('.');
+
+      if (index == -1 || !files[i].substring(index).equals(".cer")) {
+        continue;
+      }
+
+      keyStore.setCertificateEntry("CA" + i, cf.generateCertificate(assetManager.open(path + "/" + files[i])));
+    }
+
+    return keyStore;
+  }
+
+  private KeyStore getCertsFromKeyStore(String storeType) throws GeneralSecurityException, IOException {
+    KeyStore store = KeyStore.getInstance(storeType);
+    store.load(null);
+
+    return store;
+  }
+}
diff --git a/platforms/android/app/src/main/java/com/silkimen/http/HttpBodyDecoder.java b/platforms/android/app/src/main/java/com/silkimen/http/HttpBodyDecoder.java
new file mode 100644
index 0000000..92d69e2
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/silkimen/http/HttpBodyDecoder.java
@@ -0,0 +1,55 @@
+package com.silkimen.http;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.MalformedInputException;
+
+public class HttpBodyDecoder {
+  private static final String[] ACCEPTED_CHARSETS = new String[] { "UTF-8", "ISO-8859-1" };
+
+  public static String decodeBody(byte[] body, String charsetName)
+      throws CharacterCodingException, MalformedInputException {
+
+    return decodeBody(ByteBuffer.wrap(body), charsetName);
+  }
+
+  public static String decodeBody(ByteBuffer body, String charsetName)
+      throws CharacterCodingException, MalformedInputException {
+
+    if (charsetName == null) {
+      return tryDecodeByteBuffer(body);
+    } else {
+      return decodeByteBuffer(body, charsetName);
+    }
+  }
+
+  private static String tryDecodeByteBuffer(ByteBuffer buffer)
+      throws CharacterCodingException, MalformedInputException {
+
+    for (int i = 0; i < ACCEPTED_CHARSETS.length - 1; i++) {
+      try {
+        return decodeByteBuffer(buffer, ACCEPTED_CHARSETS[i]);
+      } catch (MalformedInputException e) {
+        continue;
+      } catch (CharacterCodingException e) {
+        continue;
+      }
+    }
+
+    return decodeBody(buffer, ACCEPTED_CHARSETS[ACCEPTED_CHARSETS.length - 1]);
+  }
+
+  private static String decodeByteBuffer(ByteBuffer buffer, String charsetName)
+      throws CharacterCodingException, MalformedInputException {
+
+    return createCharsetDecoder(charsetName).decode(buffer).toString();
+  }
+
+  private static CharsetDecoder createCharsetDecoder(String charsetName) {
+    return Charset.forName(charsetName).newDecoder().onMalformedInput(CodingErrorAction.REPORT)
+        .onUnmappableCharacter(CodingErrorAction.REPORT);
+  }
+}
diff --git a/platforms/android/app/src/main/java/com/silkimen/http/HttpRequest.java b/platforms/android/app/src/main/java/com/silkimen/http/HttpRequest.java
new file mode 100644
index 0000000..7e638bb
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/silkimen/http/HttpRequest.java
@@ -0,0 +1,3095 @@
+/*
+ * Copyright (c) 2014 Kevin Sawicki <kevinsawicki@gmail.com>
+ * modified by contributors of cordova-plugin-advanced-http
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+package com.silkimen.http;
+
+import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
+import static java.net.HttpURLConnection.HTTP_CREATED;
+import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR;
+import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
+import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
+import static java.net.HttpURLConnection.HTTP_NOT_MODIFIED;
+import static java.net.HttpURLConnection.HTTP_OK;
+import static java.net.Proxy.Type.HTTP;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+import java.net.MalformedURLException;
+import java.net.Proxy;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.security.AccessController;
+import java.security.GeneralSecurityException;
+import java.security.PrivilegedAction;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.zip.GZIPInputStream;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * A fluid interface for making HTTP requests using an underlying
+ * {@link HttpURLConnection} (or sub-class).
+ * <p>
+ * Each instance supports making a single request and cannot be reused for
+ * further requests.
+ */
+public class HttpRequest {
+
+  /**
+   * 'UTF-8' charset name
+   */
+  public static final String CHARSET_UTF8 = "UTF-8";
+
+  /**
+   * 'application/x-www-form-urlencoded' content type header value
+   */
+  public static final String CONTENT_TYPE_FORM = "application/x-www-form-urlencoded";
+
+  /**
+   * 'application/json' content type header value
+   */
+  public static final String CONTENT_TYPE_JSON = "application/json";
+
+  /**
+   * 'gzip' encoding header value
+   */
+  public static final String ENCODING_GZIP = "gzip";
+
+  /**
+   * 'Accept' header name
+   */
+  public static final String HEADER_ACCEPT = "Accept";
+
+  /**
+   * 'Accept-Charset' header name
+   */
+  public static final String HEADER_ACCEPT_CHARSET = "Accept-Charset";
+
+  /**
+   * 'Accept-Encoding' header name
+   */
+  public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
+
+  /**
+   * 'Authorization' header name
+   */
+  public static final String HEADER_AUTHORIZATION = "Authorization";
+
+  /**
+   * 'Cache-Control' header name
+   */
+  public static final String HEADER_CACHE_CONTROL = "Cache-Control";
+
+  /**
+   * 'Content-Encoding' header name
+   */
+  public static final String HEADER_CONTENT_ENCODING = "Content-Encoding";
+
+  /**
+   * 'Content-Length' header name
+   */
+  public static final String HEADER_CONTENT_LENGTH = "Content-Length";
+
+  /**
+   * 'Content-Type' header name
+   */
+  public static final String HEADER_CONTENT_TYPE = "Content-Type";
+
+  /**
+   * 'Date' header name
+   */
+  public static final String HEADER_DATE = "Date";
+
+  /**
+   * 'ETag' header name
+   */
+  public static final String HEADER_ETAG = "ETag";
+
+  /**
+   * 'Expires' header name
+   */
+  public static final String HEADER_EXPIRES = "Expires";
+
+  /**
+   * 'If-None-Match' header name
+   */
+  public static final String HEADER_IF_NONE_MATCH = "If-None-Match";
+
+  /**
+   * 'Last-Modified' header name
+   */
+  public static final String HEADER_LAST_MODIFIED = "Last-Modified";
+
+  /**
+   * 'Location' header name
+   */
+  public static final String HEADER_LOCATION = "Location";
+
+  /**
+   * 'Proxy-Authorization' header name
+   */
+  public static final String HEADER_PROXY_AUTHORIZATION = "Proxy-Authorization";
+
+  /**
+   * 'Referer' header name
+   */
+  public static final String HEADER_REFERER = "Referer";
+
+  /**
+   * 'Server' header name
+   */
+  public static final String HEADER_SERVER = "Server";
+
+  /**
+   * 'User-Agent' header name
+   */
+  public static final String HEADER_USER_AGENT = "User-Agent";
+
+  /**
+   * 'DELETE' request method
+   */
+  public static final String METHOD_DELETE = "DELETE";
+
+  /**
+   * 'GET' request method
+   */
+  public static final String METHOD_GET = "GET";
+
+  /**
+   * 'HEAD' request method
+   */
+  public static final String METHOD_HEAD = "HEAD";
+
+  /**
+   * 'OPTIONS' options method
+   */
+  public static final String METHOD_OPTIONS = "OPTIONS";
+
+  /**
+   * 'POST' request method
+   */
+  public static final String METHOD_POST = "POST";
+
+  /**
+   * 'PUT' request method
+   */
+  public static final String METHOD_PUT = "PUT";
+
+  /**
+   * 'TRACE' request method
+   */
+  public static final String METHOD_TRACE = "TRACE";
+
+  /**
+   * 'charset' header value parameter
+   */
+  public static final String PARAM_CHARSET = "charset";
+
+  private static final String BOUNDARY = "00content0boundary00";
+
+  private static final String CONTENT_TYPE_MULTIPART = "multipart/form-data; boundary=" + BOUNDARY;
+
+  private static final String CRLF = "\r\n";
+
+  private static final String[] EMPTY_STRINGS = new String[0];
+
+  private static String getValidCharset(final String charset) {
+    if (charset != null && charset.length() > 0)
+      return charset;
+    else
+      return CHARSET_UTF8;
+  }
+
+  private static StringBuilder addPathSeparator(final String baseUrl, final StringBuilder result) {
+    // Add trailing slash if the base URL doesn't have any path segments.
+    //
+    // The following test is checking for the last slash not being part of
+    // the protocol to host separator: '://'.
+    if (baseUrl.indexOf(':') + 2 == baseUrl.lastIndexOf('/'))
+      result.append('/');
+    return result;
+  }
+
+  private static StringBuilder addParamPrefix(final String baseUrl, final StringBuilder result) {
+    // Add '?' if missing and add '&' if params already exist in base url
+    final int queryStart = baseUrl.indexOf('?');
+    final int lastChar = result.length() - 1;
+    if (queryStart == -1)
+      result.append('?');
+    else if (queryStart < lastChar && baseUrl.charAt(lastChar) != '&')
+      result.append('&');
+    return result;
+  }
+
+  private static StringBuilder addParam(final Object key, Object value, final StringBuilder result) {
+    if (value != null && value.getClass().isArray())
+      value = arrayToList(value);
+
+    if (value instanceof Iterable<?>) {
+      Iterator<?> iterator = ((Iterable<?>) value).iterator();
+      while (iterator.hasNext()) {
+        result.append(key);
+        result.append("[]=");
+        Object element = iterator.next();
+        if (element != null)
+          result.append(element);
+        if (iterator.hasNext())
+          result.append("&");
+      }
+    } else {
+      result.append(key);
+      result.append("=");
+      if (value != null)
+        result.append(value);
+    }
+
+    return result;
+  }
+
+  /**
+   * Creates {@link HttpURLConnection HTTP connections} for {@link URL urls}.
+   */
+  public interface ConnectionFactory {
+    /**
+     * Open an {@link HttpURLConnection} for the specified {@link URL}.
+     *
+     * @throws IOException
+     */
+    HttpURLConnection create(URL url) throws IOException;
+
+    /**
+     * Open an {@link HttpURLConnection} for the specified {@link URL} and
+     * {@link Proxy}.
+     *
+     * @throws IOException
+     */
+    HttpURLConnection create(URL url, Proxy proxy) throws IOException;
+
+    /**
+     * A {@link ConnectionFactory} which uses the built-in
+     * {@link URL#openConnection()}
+     */
+    ConnectionFactory DEFAULT = new ConnectionFactory() {
+      public HttpURLConnection create(URL url) throws IOException {
+        return (HttpURLConnection) url.openConnection();
+      }
+
+      public HttpURLConnection create(URL url, Proxy proxy) throws IOException {
+        return (HttpURLConnection) url.openConnection(proxy);
+      }
+    };
+  }
+
+  private static ConnectionFactory CONNECTION_FACTORY = ConnectionFactory.DEFAULT;
+
+  /**
+   * Specify the {@link ConnectionFactory} used to create new requests.
+   */
+  public static void setConnectionFactory(final ConnectionFactory connectionFactory) {
+    if (connectionFactory == null)
+      CONNECTION_FACTORY = ConnectionFactory.DEFAULT;
+    else
+      CONNECTION_FACTORY = connectionFactory;
+  }
+
+  /**
+   * Callback interface for reporting upload progress for a request.
+   */
+  public interface UploadProgress {
+    /**
+     * Callback invoked as data is uploaded by the request.
+     *
+     * @param uploaded The number of bytes already uploaded
+     * @param total    The total number of bytes that will be uploaded or -1 if the
+     *                 length is unknown.
+     */
+    void onUpload(long uploaded, long total);
+
+    UploadProgress DEFAULT = new UploadProgress() {
+      public void onUpload(long uploaded, long total) {
+      }
+    };
+  }
+
+  /**
+   * <p>
+   * Encodes and decodes to and from Base64 notation.
+   * </p>
+   * <p>
+   * I am placing this code in the Public Domain. Do with it as you will. This
+   * software comes with no guarantees or warranties but with plenty of
+   * well-wishing instead! Please visit
+   * <a href="http://iharder.net/base64">http://iharder.net/base64</a>
+   * periodically to check for updates or to contribute improvements.
+   * </p>
+   *
+   * @author Robert Harder
+   * @author rob@iharder.net
+   * @version 2.3.7
+   */
+  public static class Base64 {
+
+    /** The equals sign (=) as a byte. */
+    private final static byte EQUALS_SIGN = (byte) '=';
+
+    /** Preferred encoding. */
+    private final static String PREFERRED_ENCODING = "US-ASCII";
+
+    /** The 64 valid Base64 values. */
+    private final static byte[] _STANDARD_ALPHABET = { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E',
+        (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
+        (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W',
+        (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f',
+        (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o',
+        (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x',
+        (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6',
+        (byte) '7', (byte) '8', (byte) '9', (byte) '+', (byte) '/' };
+
+    /** Defeats instantiation. */
+    private Base64() {
+    }
+
+    /**
+     * <p>
+     * Encodes up to three bytes of the array <var>source</var> and writes the
+     * resulting four Base64 bytes to <var>destination</var>. The source and
+     * destination arrays can be manipulated anywhere along their length by
+     * specifying <var>srcOffset</var> and <var>destOffset</var>. This method does
+     * not check to make sure your arrays are large enough to accomodate
+     * <var>srcOffset</var> + 3 for the <var>source</var> array or
+     * <var>destOffset</var> + 4 for the <var>destination</var> array. The actual
+     * number of significant bytes in your array is given by <var>numSigBytes</var>.
+     * </p>
+     * <p>
+     * This is the lowest level of the encoding methods with all possible
+     * parameters.
+     * </p>
+     *
+     * @param source      the array to convert
+     * @param srcOffset   the index where conversion begins
+     * @param numSigBytes the number of significant bytes in your array
+     * @param destination the array to hold the conversion
+     * @param destOffset  the index where output will be put
+     * @return the <var>destination</var> array
+     * @since 1.3
+     */
+    private static byte[] encode3to4(byte[] source, int srcOffset, int numSigBytes, byte[] destination,
+        int destOffset) {
+
+      byte[] ALPHABET = _STANDARD_ALPHABET;
+
+      int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0)
+          | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0)
+          | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0);
+
+      switch (numSigBytes) {
+      case 3:
+        destination[destOffset] = ALPHABET[(inBuff >>> 18)];
+        destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
+        destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
+        destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f];
+        return destination;
+
+      case 2:
+        destination[destOffset] = ALPHABET[(inBuff >>> 18)];
+        destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
+        destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
+        destination[destOffset + 3] = EQUALS_SIGN;
+        return destination;
+
+      case 1:
+        destination[destOffset] = ALPHABET[(inBuff >>> 18)];
+        destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
+        destination[destOffset + 2] = EQUALS_SIGN;
+        destination[destOffset + 3] = EQUALS_SIGN;
+        return destination;
+
+      default:
+        return destination;
+      }
+    }
+
+    /**
+     * Encode string as a byte array in Base64 annotation.
+     *
+     * @param string
+     * @return The Base64-encoded data as a string
+     */
+    public static String encode(String string) {
+      byte[] bytes;
+      try {
+        bytes = string.getBytes(PREFERRED_ENCODING);
+      } catch (UnsupportedEncodingException e) {
+        bytes = string.getBytes();
+      }
+      return encodeBytes(bytes);
+    }
+
+    /**
+     * Encodes a byte array into Base64 notation.
+     *
+     * @param source The data to convert
+     * @return The Base64-encoded data as a String
+     * @throws NullPointerException     if source array is null
+     * @throws IllegalArgumentException if source array, offset, or length are
+     *                                  invalid
+     * @since 2.0
+     */
+    public static String encodeBytes(byte[] source) {
+      return encodeBytes(source, 0, source.length);
+    }
+
+    /**
+     * Encodes a byte array into Base64 notation.
+     *
+     * @param source The data to convert
+     * @param off    Offset in array where conversion should begin
+     * @param len    Length of data to convert
+     * @return The Base64-encoded data as a String
+     * @throws NullPointerException     if source array is null
+     * @throws IllegalArgumentException if source array, offset, or length are
+     *                                  invalid
+     * @since 2.0
+     */
+    public static String encodeBytes(byte[] source, int off, int len) {
+      byte[] encoded = encodeBytesToBytes(source, off, len);
+      try {
+        return new String(encoded, PREFERRED_ENCODING);
+      } catch (UnsupportedEncodingException uue) {
+        return new String(encoded);
+      }
+    }
+
+    /**
+     * Similar to {@link #encodeBytes(byte[], int, int)} but returns a byte array
+     * instead of instantiating a String. This is more efficient if you're working
+     * with I/O streams and have large data sets to encode.
+     *
+     *
+     * @param source The data to convert
+     * @param off    Offset in array where conversion should begin
+     * @param len    Length of data to convert
+     * @return The Base64-encoded data as a String if there is an error
+     * @throws NullPointerException     if source array is null
+     * @throws IllegalArgumentException if source array, offset, or length are
+     *                                  invalid
+     * @since 2.3.1
+     */
+    public static byte[] encodeBytesToBytes(byte[] source, int off, int len) {
+
+      if (source == null)
+        throw new NullPointerException("Cannot serialize a null array.");
+
+      if (off < 0)
+        throw new IllegalArgumentException("Cannot have negative offset: " + off);
+
+      if (len < 0)
+        throw new IllegalArgumentException("Cannot have length offset: " + len);
+
+      if (off + len > source.length)
+        throw new IllegalArgumentException(String
+            .format("Cannot have offset of %d and length of %d with array of length %d", off, len, source.length));
+
+      // Bytes needed for actual encoding
+      int encLen = (len / 3) * 4 + (len % 3 > 0 ? 4 : 0);
+
+      byte[] outBuff = new byte[encLen];
+
+      int d = 0;
+      int e = 0;
+      int len2 = len - 2;
+      for (; d < len2; d += 3, e += 4)
+        encode3to4(source, d + off, 3, outBuff, e);
+
+      if (d < len) {
+        encode3to4(source, d + off, len - d, outBuff, e);
+        e += 4;
+      }
+
+      if (e <= outBuff.length - 1) {
+        byte[] finalOut = new byte[e];
+        System.arraycopy(outBuff, 0, finalOut, 0, e);
+        return finalOut;
+      } else
+        return outBuff;
+    }
+  }
+
+  /**
+   * HTTP request exception whose cause is always an {@link IOException}
+   */
+  public static class HttpRequestException extends RuntimeException {
+
+    private static final long serialVersionUID = -1170466989781746231L;
+
+    /**
+     * Create a new HttpRequestException with the given cause
+     *
+     * @param cause
+     */
+    public HttpRequestException(final IOException cause) {
+      super(cause);
+    }
+
+    /**
+     * Get {@link IOException} that triggered this request exception
+     *
+     * @return {@link IOException} cause
+     */
+    @Override
+    public IOException getCause() {
+      return (IOException) super.getCause();
+    }
+  }
+
+  /**
+   * Operation that handles executing a callback once complete and handling nested
+   * exceptions
+   *
+   * @param <V>
+   */
+  protected static abstract class Operation<V> implements Callable<V> {
+
+    /**
+     * Run operation
+     *
+     * @return result
+     * @throws HttpRequestException
+     * @throws IOException
+     */
+    protected abstract V run() throws HttpRequestException, IOException;
+
+    /**
+     * Operation complete callback
+     *
+     * @throws IOException
+     */
+    protected abstract void done() throws IOException;
+
+    public V call() throws HttpRequestException {
+      boolean thrown = false;
+      try {
+        return run();
+      } catch (HttpRequestException e) {
+        thrown = true;
+        throw e;
+      } catch (IOException e) {
+        thrown = true;
+        throw new HttpRequestException(e);
+      } finally {
+        try {
+          done();
+        } catch (IOException e) {
+          if (!thrown)
+            throw new HttpRequestException(e);
+        }
+      }
+    }
+  }
+
+  /**
+   * Class that ensures a {@link Closeable} gets closed with proper exception
+   * handling.
+   *
+   * @param <V>
+   */
+  protected static abstract class CloseOperation<V> extends Operation<V> {
+
+    private final Closeable closeable;
+
+    private final boolean ignoreCloseExceptions;
+
+    /**
+     * Create closer for operation
+     *
+     * @param closeable
+     * @param ignoreCloseExceptions
+     */
+    protected CloseOperation(final Closeable closeable, final boolean ignoreCloseExceptions) {
+      this.closeable = closeable;
+      this.ignoreCloseExceptions = ignoreCloseExceptions;
+    }
+
+    @Override
+    protected void done() throws IOException {
+      if (closeable instanceof Flushable)
+        ((Flushable) closeable).flush();
+      if (ignoreCloseExceptions)
+        try {
+          closeable.close();
+        } catch (IOException e) {
+          // Ignored
+        }
+      else
+        closeable.close();
+    }
+  }
+
+  /**
+   * Class that and ensures a {@link Flushable} gets flushed with proper exception
+   * handling.
+   *
+   * @param <V>
+   */
+  protected static abstract class FlushOperation<V> extends Operation<V> {
+
+    private final Flushable flushable;
+
+    /**
+     * Create flush operation
+     *
+     * @param flushable
+     */
+    protected FlushOperation(final Flushable flushable) {
+      this.flushable = flushable;
+    }
+
+    @Override
+    protected void done() throws IOException {
+      flushable.flush();
+    }
+  }
+
+  /**
+   * Request output stream
+   */
+  public static class RequestOutputStream extends BufferedOutputStream {
+
+    private final CharsetEncoder encoder;
+
+    /**
+     * Create request output stream
+     *
+     * @param stream
+     * @param charset
+     * @param bufferSize
+     */
+    public RequestOutputStream(final OutputStream stream, final String charset, final int bufferSize) {
+      super(stream, bufferSize);
+
+      encoder = Charset.forName(getValidCharset(charset)).newEncoder();
+    }
+
+    /**
+     * Write string to stream
+     *
+     * @param value
+     * @return this stream
+     * @throws IOException
+     */
+    public RequestOutputStream write(final String value) throws IOException {
+      final ByteBuffer bytes = encoder.encode(CharBuffer.wrap(value));
+
+      super.write(bytes.array(), 0, bytes.limit());
+
+      return this;
+    }
+  }
+
+  /**
+   * Represents array of any type as list of objects so we can easily iterate over
+   * it
+   *
+   * @param array of elements
+   * @return list with the same elements
+   */
+  private static List<Object> arrayToList(final Object array) {
+    if (array instanceof Object[])
+      return Arrays.asList((Object[]) array);
+
+    List<Object> result = new ArrayList<Object>();
+    // Arrays of the primitive types can't be cast to array of Object, so this:
+    if (array instanceof int[])
+      for (int value : (int[]) array)
+        result.add(value);
+    else if (array instanceof boolean[])
+      for (boolean value : (boolean[]) array)
+        result.add(value);
+    else if (array instanceof long[])
+      for (long value : (long[]) array)
+        result.add(value);
+    else if (array instanceof float[])
+      for (float value : (float[]) array)
+        result.add(value);
+    else if (array instanceof double[])
+      for (double value : (double[]) array)
+        result.add(value);
+    else if (array instanceof short[])
+      for (short value : (short[]) array)
+        result.add(value);
+    else if (array instanceof byte[])
+      for (byte value : (byte[]) array)
+        result.add(value);
+    else if (array instanceof char[])
+      for (char value : (char[]) array)
+        result.add(value);
+    return result;
+  }
+
+  /**
+   * Encode the given URL as an ASCII {@link String}
+   * <p>
+   * This method ensures the path and query segments of the URL are properly
+   * encoded such as ' ' characters being encoded to '%20' or any UTF-8 characters
+   * that are non-ASCII. No encoding of URLs is done by default by the
+   * {@link HttpRequest} constructors and so if URL encoding is needed this method
+   * should be called before calling the {@link HttpRequest} constructor.
+   *
+   * @param url
+   * @return encoded URL
+   * @throws HttpRequestException
+   */
+  public static String encode(final CharSequence url) throws HttpRequestException {
+    URL parsed;
+    try {
+      parsed = new URL(url.toString());
+    } catch (IOException e) {
+      throw new HttpRequestException(e);
+    }
+
+    String host = parsed.getHost();
+    int port = parsed.getPort();
+    if (port != -1)
+      host = host + ':' + Integer.toString(port);
+
+    try {
+      String encoded = new URI(parsed.getProtocol(), host, parsed.getPath(), parsed.getQuery(), null).toASCIIString();
+      int paramsStart = encoded.indexOf('?');
+      if (paramsStart > 0 && paramsStart + 1 < encoded.length())
+        encoded = encoded.substring(0, paramsStart + 1) + encoded.substring(paramsStart + 1).replace("+", "%2B");
+      return encoded;
+    } catch (URISyntaxException e) {
+      IOException io = new IOException("Parsing URI failed");
+      io.initCause(e);
+      throw new HttpRequestException(io);
+    }
+  }
+
+  /**
+   * Append given map as query parameters to the base URL
+   * <p>
+   * Each map entry's key will be a parameter name and the value's
+   * {@link Object#toString()} will be the parameter value.
+   *
+   * @param url
+   * @param params
+   * @return URL with appended query params
+   */
+  public static String append(final CharSequence url, final Map<?, ?> params) {
+    final String baseUrl = url.toString();
+    if (params == null || params.isEmpty())
+      return baseUrl;
+
+    final StringBuilder result = new StringBuilder(baseUrl);
+
+    addPathSeparator(baseUrl, result);
+    addParamPrefix(baseUrl, result);
+
+    Entry<?, ?> entry;
+    Iterator<?> iterator = params.entrySet().iterator();
+    entry = (Entry<?, ?>) iterator.next();
+    addParam(entry.getKey().toString(), entry.getValue(), result);
+
+    while (iterator.hasNext()) {
+      result.append('&');
+      entry = (Entry<?, ?>) iterator.next();
+      addParam(entry.getKey().toString(), entry.getValue(), result);
+    }
+
+    return result.toString();
+  }
+
+  /**
+   * Append given name/value pairs as query parameters to the base URL
+   * <p>
+   * The params argument is interpreted as a sequence of name/value pairs so the
+   * given number of params must be divisible by 2.
+   *
+   * @param url
+   * @param params name/value pairs
+   * @return URL with appended query params
+   */
+  public static String append(final CharSequence url, final Object... params) {
+    final String baseUrl = url.toString();
+    if (params == null || params.length == 0)
+      return baseUrl;
+
+    if (params.length % 2 != 0)
+      throw new IllegalArgumentException("Must specify an even number of parameter names/values");
+
+    final StringBuilder result = new StringBuilder(baseUrl);
+
+    addPathSeparator(baseUrl, result);
+    addParamPrefix(baseUrl, result);
+
+    addParam(params[0], params[1], result);
+
+    for (int i = 2; i < params.length; i += 2) {
+      result.append('&');
+      addParam(params[i], params[i + 1], result);
+    }
+
+    return result.toString();
+  }
+
+  /**
+   * Start a 'GET' request to the given URL
+   *
+   * @param url
+   * @return request
+   * @throws HttpRequestException
+   */
+  public static HttpRequest get(final CharSequence url) throws HttpRequestException {
+    return new HttpRequest(url, METHOD_GET);
+  }
+
+  /**
+   * Start a 'GET' request to the given URL
+   *
+   * @param url
+   * @return request
+   * @throws HttpRequestException
+   */
+  public static HttpRequest get(final URL url) throws HttpRequestException {
+    return new HttpRequest(url, METHOD_GET);
+  }
+
+  /**
+   * Start a 'GET' request to the given URL along with the query params
+   *
+   * @param baseUrl
+   * @param params  The query parameters to include as part of the baseUrl
+   * @param encode  true to encode the full URL
+   *
+   * @see #append(CharSequence, Map)
+   * @see #encode(CharSequence)
+   *
+   * @return request
+   */
+  public static HttpRequest get(final CharSequence baseUrl, final Map<?, ?> params, final boolean encode) {
+    String url = append(baseUrl, params);
+    return get(encode ? encode(url) : url);
+  }
+
+  /**
+   * Start a 'GET' request to the given URL along with the query params
+   *
+   * @param baseUrl
+   * @param encode  true to encode the full URL
+   * @param params  the name/value query parameter pairs to include as part of the
+   *                baseUrl
+   *
+   * @see #append(CharSequence, Object...)
+   * @see #encode(CharSequence)
+   *
+   * @return request
+   */
+  public static HttpRequest get(final CharSequence baseUrl, final boolean encode, final Object... params) {
+    String url = append(baseUrl, params);
+    return get(encode ? encode(url) : url);
+  }
+
+  /**
+   * Start a 'POST' request to the given URL
+   *
+   * @param url
+   * @return request
+   * @throws HttpRequestException
+   */
+  public static HttpRequest post(final CharSequence url) throws HttpRequestException {
+    return new HttpRequest(url, METHOD_POST);
+  }
+
+  /**
+   * Start a 'POST' request to the given URL
+   *
+   * @param url
+   * @return request
+   * @throws HttpRequestException
+   */
+  public static HttpRequest post(final URL url) throws HttpRequestException {
+    return new HttpRequest(url, METHOD_POST);
+  }
+
+  /**
+   * Start a 'POST' request to the given URL along with the query params
+   *
+   * @param baseUrl
+   * @param params  the query parameters to include as part of the baseUrl
+   * @param encode  true to encode the full URL
+   *
+   * @see #append(CharSequence, Map)
+   * @see #encode(CharSequence)
+   *
+   * @return request
+   */
+  public static HttpRequest post(final CharSequence baseUrl, final Map<?, ?> params, final boolean encode) {
+    String url = append(baseUrl, params);
+    return post(encode ? encode(url) : url);
+  }
+
+  /**
+   * Start a 'POST' request to the given URL along with the query params
+   *
+   * @param baseUrl
+   * @param encode  true to encode the full URL
+   * @param params  the name/value query parameter pairs to include as part of the
+   *                baseUrl
+   *
+   * @see #append(CharSequence, Object...)
+   * @see #encode(CharSequence)
+   *
+   * @return request
+   */
+  public static HttpRequest post(final CharSequence baseUrl, final boolean encode, final Object... params) {
+    String url = append(baseUrl, params);
+    return post(encode ? encode(url) : url);
+  }
+
+  /**
+   * Start a 'PUT' request to the given URL
+   *
+   * @param url
+   * @return request
+   * @throws HttpRequestException
+   */
+  public static HttpRequest put(final CharSequence url) throws HttpRequestException {
+    return new HttpRequest(url, METHOD_PUT);
+  }
+
+  /**
+   * Start a 'PUT' request to the given URL
+   *
+   * @param url
+   * @return request
+   * @throws HttpRequestException
+   */
+  public static HttpRequest put(final URL url) throws HttpRequestException {
+    return new HttpRequest(url, METHOD_PUT);
+  }
+
+  /**
+   * Start a 'PUT' request to the given URL along with the query params
+   *
+   * @param baseUrl
+   * @param params  the query parameters to include as part of the baseUrl
+   * @param encode  true to encode the full URL
+   *
+   * @see #append(CharSequence, Map)
+   * @see #encode(CharSequence)
+   *
+   * @return request
+   */
+  public static HttpRequest put(final CharSequence baseUrl, final Map<?, ?> params, final boolean encode) {
+    String url = append(baseUrl, params);
+    return put(encode ? encode(url) : url);
+  }
+
+  /**
+   * Start a 'PUT' request to the given URL along with the query params
+   *
+   * @param baseUrl
+   * @param encode  true to encode the full URL
+   * @param params  the name/value query parameter pairs to include as part of the
+   *                baseUrl
+   *
+   * @see #append(CharSequence, Object...)
+   * @see #encode(CharSequence)
+   *
+   * @return request
+   */
+  public static HttpRequest put(final CharSequence baseUrl, final boolean encode, final Object... params) {
+    String url = append(baseUrl, params);
+    return put(encode ? encode(url) : url);
+  }
+
+  /**
+   * Start a 'DELETE' request to the given URL
+   *
+   * @param url
+   * @return request
+   * @throws HttpRequestException
+   */
+  public static HttpRequest delete(final CharSequence url) throws HttpRequestException {
+    return new HttpRequest(url, METHOD_DELETE);
+  }
+
+  /**
+   * Start a 'DELETE' request to the given URL
+   *
+   * @param url
+   * @return request
+   * @throws HttpRequestException
+   */
+  public static HttpRequest delete(final URL url) throws HttpRequestException {
+    return new HttpRequest(url, METHOD_DELETE);
+  }
+
+  /**
+   * Start a 'DELETE' request to the given URL along with the query params
+   *
+   * @param baseUrl
+   * @param params  The query parameters to include as part of the baseUrl
+   * @param encode  true to encode the full URL
+   *
+   * @see #append(CharSequence, Map)
+   * @see #encode(CharSequence)
+   *
+   * @return request
+   */
+  public static HttpRequest delete(final CharSequence baseUrl, final Map<?, ?> params, final boolean encode) {
+    String url = append(baseUrl, params);
+    return delete(encode ? encode(url) : url);
+  }
+
+  /**
+   * Start a 'DELETE' request to the given URL along with the query params
+   *
+   * @param baseUrl
+   * @param encode  true to encode the full URL
+   * @param params  the name/value query parameter pairs to include as part of the
+   *                baseUrl
+   *
+   * @see #append(CharSequence, Object...)
+   * @see #encode(CharSequence)
+   *
+   * @return request
+   */
+  public static HttpRequest delete(final CharSequence baseUrl, final boolean encode, final Object... params) {
+    String url = append(baseUrl, params);
+    return delete(encode ? encode(url) : url);
+  }
+
+  /**
+   * Start a 'HEAD' request to the given URL
+   *
+   * @param url
+   * @return request
+   * @throws HttpRequestException
+   */
+  public static HttpRequest head(final CharSequence url) throws HttpRequestException {
+    return new HttpRequest(url, METHOD_HEAD);
+  }
+
+  /**
+   * Start a 'HEAD' request to the given URL
+   *
+   * @param url
+   * @return request
+   * @throws HttpRequestException
+   */
+  public static HttpRequest head(final URL url) throws HttpRequestException {
+    return new HttpRequest(url, METHOD_HEAD);
+  }
+
+  /**
+   * Start a 'HEAD' request to the given URL along with the query params
+   *
+   * @param baseUrl
+   * @param params  The query parameters to include as part of the baseUrl
+   * @param encode  true to encode the full URL
+   *
+   * @see #append(CharSequence, Map)
+   * @see #encode(CharSequence)
+   *
+   * @return request
+   */
+  public static HttpRequest head(final CharSequence baseUrl, final Map<?, ?> params, final boolean encode) {
+    String url = append(baseUrl, params);
+    return head(encode ? encode(url) : url);
+  }
+
+  /**
+   * Start a 'GET' request to the given URL along with the query params
+   *
+   * @param baseUrl
+   * @param encode  true to encode the full URL
+   * @param params  the name/value query parameter pairs to include as part of the
+   *                baseUrl
+   *
+   * @see #append(CharSequence, Object...)
+   * @see #encode(CharSequence)
+   *
+   * @return request
+   */
+  public static HttpRequest head(final CharSequence baseUrl, final boolean encode, final Object... params) {
+    String url = append(baseUrl, params);
+    return head(encode ? encode(url) : url);
+  }
+
+  /**
+   * Start an 'OPTIONS' request to the given URL
+   *
+   * @param url
+   * @return request
+   * @throws HttpRequestException
+   */
+  public static HttpRequest options(final CharSequence url) throws HttpRequestException {
+    return new HttpRequest(url, METHOD_OPTIONS);
+  }
+
+  /**
+   * Start an 'OPTIONS' request to the given URL
+   *
+   * @param url
+   * @return request
+   * @throws HttpRequestException
+   */
+  public static HttpRequest options(final URL url) throws HttpRequestException {
+    return new HttpRequest(url, METHOD_OPTIONS);
+  }
+
+  /**
+   * Start a 'TRACE' request to the given URL
+   *
+   * @param url
+   * @return request
+   * @throws HttpRequestException
+   */
+  public static HttpRequest trace(final CharSequence url) throws HttpRequestException {
+    return new HttpRequest(url, METHOD_TRACE);
+  }
+
+  /**
+   * Start a 'TRACE' request to the given URL
+   *
+   * @param url
+   * @return request
+   * @throws HttpRequestException
+   */
+  public static HttpRequest trace(final URL url) throws HttpRequestException {
+    return new HttpRequest(url, METHOD_TRACE);
+  }
+
+  /**
+   * Set the 'http.keepAlive' property to the given value.
+   * <p>
+   * This setting will apply to all requests.
+   *
+   * @param keepAlive
+   */
+  public static void keepAlive(final boolean keepAlive) {
+    setProperty("http.keepAlive", Boolean.toString(keepAlive));
+  }
+
+  /**
+   * Set the 'http.maxConnections' property to the given value.
+   * <p>
+   * This setting will apply to all requests.
+   *
+   * @param maxConnections
+   */
+  public static void maxConnections(final int maxConnections) {
+    setProperty("http.maxConnections", Integer.toString(maxConnections));
+  }
+
+  /**
+   * Set the 'http.proxyHost' and 'https.proxyHost' properties to the given host
+   * value.
+   * <p>
+   * This setting will apply to all requests.
+   *
+   * @param host
+   */
+  public static void proxyHost(final String host) {
+    setProperty("http.proxyHost", host);
+    setProperty("https.proxyHost", host);
+  }
+
+  /**
+   * Set the 'http.proxyPort' and 'https.proxyPort' properties to the given port
+   * number.
+   * <p>
+   * This setting will apply to all requests.
+   *
+   * @param port
+   */
+  public static void proxyPort(final int port) {
+    final String portValue = Integer.toString(port);
+    setProperty("http.proxyPort", portValue);
+    setProperty("https.proxyPort", portValue);
+  }
+
+  /**
+   * Set the 'http.nonProxyHosts' property to the given host values.
+   * <p>
+   * Hosts will be separated by a '|' character.
+   * <p>
+   * This setting will apply to all requests.
+   *
+   * @param hosts
+   */
+  public static void nonProxyHosts(final String... hosts) {
+    if (hosts != null && hosts.length > 0) {
+      StringBuilder separated = new StringBuilder();
+      int last = hosts.length - 1;
+      for (int i = 0; i < last; i++)
+        separated.append(hosts[i]).append('|');
+      separated.append(hosts[last]);
+      setProperty("http.nonProxyHosts", separated.toString());
+    } else
+      setProperty("http.nonProxyHosts", null);
+  }
+
+  /**
+   * Set property to given value.
+   * <p>
+   * Specifying a null value will cause the property to be cleared
+   *
+   * @param name
+   * @param value
+   * @return previous value
+   */
+  private static String setProperty(final String name, final String value) {
+    final PrivilegedAction<String> action;
+    if (value != null)
+      action = new PrivilegedAction<String>() {
+
+        public String run() {
+          return System.setProperty(name, value);
+        }
+      };
+    else
+      action = new PrivilegedAction<String>() {
+
+        public String run() {
+          return System.clearProperty(name);
+        }
+      };
+    return AccessController.doPrivileged(action);
+  }
+
+  private HttpURLConnection connection = null;
+
+  private final URL url;
+
+  private final String requestMethod;
+
+  private RequestOutputStream output;
+
+  private boolean multipart;
+
+  private boolean form;
+
+  private boolean ignoreCloseExceptions = true;
+
+  private boolean uncompress = false;
+
+  private int bufferSize = 8192;
+
+  private long totalSize = -1;
+
+  private long totalWritten = 0;
+
+  private String httpProxyHost;
+
+  private int httpProxyPort;
+
+  private UploadProgress progress = UploadProgress.DEFAULT;
+
+  /**
+   * Create HTTP connection wrapper
+   *
+   * @param url    Remote resource URL.
+   * @param method HTTP request method (e.g., "GET", "POST").
+   * @throws HttpRequestException
+   */
+  public HttpRequest(final CharSequence url, final String method) throws HttpRequestException {
+    try {
+      this.url = new URL(url.toString());
+    } catch (MalformedURLException e) {
+      throw new HttpRequestException(e);
+    }
+    this.requestMethod = method;
+  }
+
+  /**
+   * Create HTTP connection wrapper
+   *
+   * @param url    Remote resource URL.
+   * @param method HTTP request method (e.g., "GET", "POST").
+   * @throws HttpRequestException
+   */
+  public HttpRequest(final URL url, final String method) throws HttpRequestException {
+    this.url = url;
+    this.requestMethod = method;
+  }
+
+  private Proxy createProxy() {
+    return new Proxy(HTTP, new InetSocketAddress(httpProxyHost, httpProxyPort));
+  }
+
+  private HttpURLConnection createConnection() {
+    try {
+      final HttpURLConnection connection;
+      if (httpProxyHost != null)
+        connection = CONNECTION_FACTORY.create(url, createProxy());
+      else
+        connection = CONNECTION_FACTORY.create(url);
+      connection.setRequestMethod(requestMethod);
+      return connection;
+    } catch (IOException e) {
+      throw new HttpRequestException(e);
+    }
+  }
+
+  @Override
+  public String toString() {
+    return method() + ' ' + url();
+  }
+
+  /**
+   * Get underlying connection
+   *
+   * @return connection
+   */
+  public HttpURLConnection getConnection() {
+    if (connection == null)
+      connection = createConnection();
+    return connection;
+  }
+
+  /**
+   * Set whether or not to ignore exceptions that occur from calling
+   * {@link Closeable#close()}
+   * <p>
+   * The default value of this setting is <code>true</code>
+   *
+   * @param ignore
+   * @return this request
+   */
+  public HttpRequest ignoreCloseExceptions(final boolean ignore) {
+    ignoreCloseExceptions = ignore;
+    return this;
+  }
+
+  /**
+   * Get whether or not exceptions thrown by {@link Closeable#close()} are ignored
+   *
+   * @return true if ignoring, false if throwing
+   */
+  public boolean ignoreCloseExceptions() {
+    return ignoreCloseExceptions;
+  }
+
+  /**
+   * Get the status code of the response
+   *
+   * @return the response code
+   * @throws HttpRequestException
+   */
+  public int code() throws HttpRequestException {
+    try {
+      closeOutput();
+      return getConnection().getResponseCode();
+    } catch (IOException e) {
+      throw new HttpRequestException(e);
+    }
+  }
+
+  /**
+   * Set the value of the given {@link AtomicInteger} to the status code of the
+   * response
+   *
+   * @param output
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest code(final AtomicInteger output) throws HttpRequestException {
+    output.set(code());
+    return this;
+  }
+
+  /**
+   * Is the response code a 200 OK?
+   *
+   * @return true if 200, false otherwise
+   * @throws HttpRequestException
+   */
+  public boolean ok() throws HttpRequestException {
+    return HTTP_OK == code();
+  }
+
+  /**
+   * Is the response code a 201 Created?
+   *
+   * @return true if 201, false otherwise
+   * @throws HttpRequestException
+   */
+  public boolean created() throws HttpRequestException {
+    return HTTP_CREATED == code();
+  }
+
+  /**
+   * Is the response code a 204 No Content?
+   *
+   * @return true if 204, false otherwise
+   * @throws HttpRequestException
+   */
+  public boolean noContent() throws HttpRequestException {
+    return HTTP_NO_CONTENT == code();
+  }
+
+  /**
+   * Is the response code a 500 Internal Server Error?
+   *
+   * @return true if 500, false otherwise
+   * @throws HttpRequestException
+   */
+  public boolean serverError() throws HttpRequestException {
+    return HTTP_INTERNAL_ERROR == code();
+  }
+
+  /**
+   * Is the response code a 400 Bad Request?
+   *
+   * @return true if 400, false otherwise
+   * @throws HttpRequestException
+   */
+  public boolean badRequest() throws HttpRequestException {
+    return HTTP_BAD_REQUEST == code();
+  }
+
+  /**
+   * Is the response code a 404 Not Found?
+   *
+   * @return true if 404, false otherwise
+   * @throws HttpRequestException
+   */
+  public boolean notFound() throws HttpRequestException {
+    return HTTP_NOT_FOUND == code();
+  }
+
+  /**
+   * Is the response code a 304 Not Modified?
+   *
+   * @return true if 304, false otherwise
+   * @throws HttpRequestException
+   */
+  public boolean notModified() throws HttpRequestException {
+    return HTTP_NOT_MODIFIED == code();
+  }
+
+  /**
+   * Get status message of the response
+   *
+   * @return message
+   * @throws HttpRequestException
+   */
+  public String message() throws HttpRequestException {
+    try {
+      closeOutput();
+      return getConnection().getResponseMessage();
+    } catch (IOException e) {
+      throw new HttpRequestException(e);
+    }
+  }
+
+  /**
+   * Disconnect the connection
+   *
+   * @return this request
+   */
+  public HttpRequest disconnect() {
+    getConnection().disconnect();
+    return this;
+  }
+
+  /**
+   * Set chunked streaming mode to the given size
+   *
+   * @param size
+   * @return this request
+   */
+  public HttpRequest chunk(final int size) {
+    getConnection().setChunkedStreamingMode(size);
+    return this;
+  }
+
+  /**
+   * Set the size used when buffering and copying between streams
+   * <p>
+   * This size is also used for send and receive buffers created for both char and
+   * byte arrays
+   * <p>
+   * The default buffer size is 8,192 bytes
+   *
+   * @param size
+   * @return this request
+   */
+  public HttpRequest bufferSize(final int size) {
+    if (size < 1)
+      throw new IllegalArgumentException("Size must be greater than zero");
+    bufferSize = size;
+    return this;
+  }
+
+  /**
+   * Get the configured buffer size
+   * <p>
+   * The default buffer size is 8,192 bytes
+   *
+   * @return buffer size
+   */
+  public int bufferSize() {
+    return bufferSize;
+  }
+
+  /**
+   * Set whether or not the response body should be automatically uncompressed
+   * when read from.
+   * <p>
+   * This will only affect requests that have the 'Content-Encoding' response
+   * header set to 'gzip'.
+   * <p>
+   * This causes all receive methods to use a {@link GZIPInputStream} when
+   * applicable so that higher level streams and readers can read the data
+   * uncompressed.
+   * <p>
+   * Setting this option does not cause any request headers to be set
+   * automatically so {@link #acceptGzipEncoding()} should be used in conjunction
+   * with this setting to tell the server to gzip the response.
+   *
+   * @param uncompress
+   * @return this request
+   */
+  public HttpRequest uncompress(final boolean uncompress) {
+    this.uncompress = uncompress;
+    return this;
+  }
+
+  /**
+   * Create byte array output stream
+   *
+   * @return stream
+   */
+  protected ByteArrayOutputStream byteStream() {
+    final int size = contentLength();
+    if (size > 0)
+      return new ByteArrayOutputStream(size);
+    else
+      return new ByteArrayOutputStream();
+  }
+
+  /**
+   * Get response as {@link String} in given character set
+   * <p>
+   * This will fall back to using the UTF-8 character set if the given charset is
+   * null
+   *
+   * @param charset
+   * @return string
+   * @throws HttpRequestException
+   */
+  public String body(final String charset) throws HttpRequestException {
+    final ByteArrayOutputStream output = byteStream();
+    try {
+      copy(buffer(), output);
+      return output.toString(getValidCharset(charset));
+    } catch (IOException e) {
+      throw new HttpRequestException(e);
+    }
+  }
+
+  /**
+   * Get response as {@link String} using character set returned from
+   * {@link #charset()}
+   *
+   * @return string
+   * @throws HttpRequestException
+   */
+  public String body() throws HttpRequestException {
+    return body(charset());
+  }
+
+  /**
+   * Get the response body as a {@link String} and set it as the value of the
+   * given reference.
+   *
+   * @param output
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest body(final AtomicReference<String> output) throws HttpRequestException {
+    output.set(body());
+    return this;
+  }
+
+  /**
+   * Get the response body as a {@link String} and set it as the value of the
+   * given reference.
+   *
+   * @param output
+   * @param charset
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest body(final AtomicReference<String> output, final String charset) throws HttpRequestException {
+    output.set(body(charset));
+    return this;
+  }
+
+  /**
+   * Is the response body empty?
+   *
+   * @return true if the Content-Length response header is 0, false otherwise
+   * @throws HttpRequestException
+   */
+  public boolean isBodyEmpty() throws HttpRequestException {
+    return contentLength() == 0;
+  }
+
+  /**
+   * Get response as byte array
+   *
+   * @return byte array
+   * @throws HttpRequestException
+   */
+  public byte[] bytes() throws HttpRequestException {
+    final ByteArrayOutputStream output = byteStream();
+    try {
+      copy(buffer(), output);
+    } catch (IOException e) {
+      throw new HttpRequestException(e);
+    }
+    return output.toByteArray();
+  }
+
+  /**
+   * Get response in a buffered stream
+   *
+   * @see #bufferSize(int)
+   * @return stream
+   * @throws HttpRequestException
+   */
+  public BufferedInputStream buffer() throws HttpRequestException {
+    return new BufferedInputStream(stream(), bufferSize);
+  }
+
+  /**
+   * Get stream to response body
+   *
+   * @return stream
+   * @throws HttpRequestException
+   */
+  public InputStream stream() throws HttpRequestException {
+    InputStream stream;
+    if (code() < HTTP_BAD_REQUEST)
+      try {
+        stream = getConnection().getInputStream();
+      } catch (IOException e) {
+        throw new HttpRequestException(e);
+      }
+    else {
+      stream = getConnection().getErrorStream();
+      if (stream == null)
+        try {
+          stream = getConnection().getInputStream();
+        } catch (IOException e) {
+          if (contentLength() > 0)
+            throw new HttpRequestException(e);
+          else
+            stream = new ByteArrayInputStream(new byte[0]);
+        }
+    }
+
+    if (!uncompress || !ENCODING_GZIP.equals(contentEncoding()))
+      return stream;
+    else
+      try {
+        return new GZIPInputStream(stream);
+      } catch (IOException e) {
+        throw new HttpRequestException(e);
+      }
+  }
+
+  /**
+   * Get reader to response body using given character set.
+   * <p>
+   * This will fall back to using the UTF-8 character set if the given charset is
+   * null
+   *
+   * @param charset
+   * @return reader
+   * @throws HttpRequestException
+   */
+  public InputStreamReader reader(final String charset) throws HttpRequestException {
+    try {
+      return new InputStreamReader(stream(), getValidCharset(charset));
+    } catch (UnsupportedEncodingException e) {
+      throw new HttpRequestException(e);
+    }
+  }
+
+  /**
+   * Get reader to response body using the character set returned from
+   * {@link #charset()}
+   *
+   * @return reader
+   * @throws HttpRequestException
+   */
+  public InputStreamReader reader() throws HttpRequestException {
+    return reader(charset());
+  }
+
+  /**
+   * Get buffered reader to response body using the given character set r and the
+   * configured buffer size
+   *
+   *
+   * @see #bufferSize(int)
+   * @param charset
+   * @return reader
+   * @throws HttpRequestException
+   */
+  public BufferedReader bufferedReader(final String charset) throws HttpRequestException {
+    return new BufferedReader(reader(charset), bufferSize);
+  }
+
+  /**
+   * Get buffered reader to response body using the character set returned from
+   * {@link #charset()} and the configured buffer size
+   *
+   * @see #bufferSize(int)
+   * @return reader
+   * @throws HttpRequestException
+   */
+  public BufferedReader bufferedReader() throws HttpRequestException {
+    return bufferedReader(charset());
+  }
+
+  /**
+   * Stream response body to file
+   *
+   * @param file
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest receive(final File file) throws HttpRequestException {
+    final OutputStream output;
+    try {
+      output = new BufferedOutputStream(new FileOutputStream(file), bufferSize);
+    } catch (FileNotFoundException e) {
+      throw new HttpRequestException(e);
+    }
+    return new CloseOperation<HttpRequest>(output, ignoreCloseExceptions) {
+
+      @Override
+      protected HttpRequest run() throws HttpRequestException, IOException {
+        return receive(output);
+      }
+    }.call();
+  }
+
+  /**
+   * Stream response to given output stream
+   *
+   * @param output
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest receive(final OutputStream output) throws HttpRequestException {
+    try {
+      return copy(buffer(), output);
+    } catch (IOException e) {
+      throw new HttpRequestException(e);
+    }
+  }
+
+  /**
+   * Stream response to given print stream
+   *
+   * @param output
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest receive(final PrintStream output) throws HttpRequestException {
+    return receive((OutputStream) output);
+  }
+
+  /**
+   * Receive response into the given appendable
+   *
+   * @param appendable
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest receive(final Appendable appendable) throws HttpRequestException {
+    final BufferedReader reader = bufferedReader();
+    return new CloseOperation<HttpRequest>(reader, ignoreCloseExceptions) {
+
+      @Override
+      public HttpRequest run() throws IOException {
+        final CharBuffer buffer = CharBuffer.allocate(bufferSize);
+        int read;
+        while ((read = reader.read(buffer)) != -1) {
+          buffer.rewind();
+          appendable.append(buffer, 0, read);
+          buffer.rewind();
+        }
+        return HttpRequest.this;
+      }
+    }.call();
+  }
+
+  /**
+   * Receive response into the given writer
+   *
+   * @param writer
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest receive(final Writer writer) throws HttpRequestException {
+    final BufferedReader reader = bufferedReader();
+    return new CloseOperation<HttpRequest>(reader, ignoreCloseExceptions) {
+
+      @Override
+      public HttpRequest run() throws IOException {
+        return copy(reader, writer);
+      }
+    }.call();
+  }
+
+  /**
+   * Set read timeout on connection to given value
+   *
+   * @param timeout
+   * @return this request
+   */
+  public HttpRequest readTimeout(final int timeout) {
+    getConnection().setReadTimeout(timeout);
+    return this;
+  }
+
+  /**
+   * Set connect timeout on connection to given value
+   *
+   * @param timeout
+   * @return this request
+   */
+  public HttpRequest connectTimeout(final int timeout) {
+    getConnection().setConnectTimeout(timeout);
+    return this;
+  }
+
+  /**
+   * Set header name to given value
+   *
+   * @param name
+   * @param value
+   * @return this request
+   */
+  public HttpRequest header(final String name, final String value) {
+    getConnection().setRequestProperty(name, value);
+    return this;
+  }
+
+  /**
+   * Set header name to given value
+   *
+   * @param name
+   * @param value
+   * @return this request
+   */
+  public HttpRequest header(final String name, final Number value) {
+    return header(name, value != null ? value.toString() : null);
+  }
+
+  /**
+   * Set all headers found in given map where the keys are the header names and
+   * the values are the header values
+   *
+   * @param headers
+   * @return this request
+   */
+  public HttpRequest headers(final Map<String, String> headers) {
+    if (!headers.isEmpty())
+      for (Entry<String, String> header : headers.entrySet())
+        header(header);
+    return this;
+  }
+
+  /**
+   * Set header to have given entry's key as the name and value as the value
+   *
+   * @param header
+   * @return this request
+   */
+  public HttpRequest header(final Entry<String, String> header) {
+    return header(header.getKey(), header.getValue());
+  }
+
+  /**
+   * Get a response header
+   *
+   * @param name
+   * @return response header
+   * @throws HttpRequestException
+   */
+  public String header(final String name) throws HttpRequestException {
+    closeOutputQuietly();
+    return getConnection().getHeaderField(name);
+  }
+
+  /**
+   * Get all the response headers
+   *
+   * @return map of response header names to their value(s)
+   * @throws HttpRequestException
+   */
+  public Map<String, List<String>> headers() throws HttpRequestException {
+    closeOutputQuietly();
+    return getConnection().getHeaderFields();
+  }
+
+  /**
+   * Get a date header from the response falling back to returning -1 if the
+   * header is missing or parsing fails
+   *
+   * @param name
+   * @return date, -1 on failures
+   * @throws HttpRequestException
+   */
+  public long dateHeader(final String name) throws HttpRequestException {
+    return dateHeader(name, -1L);
+  }
+
+  /**
+   * Get a date header from the response falling back to returning the given
+   * default value if the header is missing or parsing fails
+   *
+   * @param name
+   * @param defaultValue
+   * @return date, default value on failures
+   * @throws HttpRequestException
+   */
+  public long dateHeader(final String name, final long defaultValue) throws HttpRequestException {
+    closeOutputQuietly();
+    return getConnection().getHeaderFieldDate(name, defaultValue);
+  }
+
+  /**
+   * Get an integer header from the response falling back to returning -1 if the
+   * header is missing or parsing fails
+   *
+   * @param name
+   * @return header value as an integer, -1 when missing or parsing fails
+   * @throws HttpRequestException
+   */
+  public int intHeader(final String name) throws HttpRequestException {
+    return intHeader(name, -1);
+  }
+
+  /**
+   * Get an integer header value from the response falling back to the given
+   * default value if the header is missing or if parsing fails
+   *
+   * @param name
+   * @param defaultValue
+   * @return header value as an integer, default value when missing or parsing
+   *         fails
+   * @throws HttpRequestException
+   */
+  public int intHeader(final String name, final int defaultValue) throws HttpRequestException {
+    closeOutputQuietly();
+    return getConnection().getHeaderFieldInt(name, defaultValue);
+  }
+
+  /**
+   * Get all values of the given header from the response
+   *
+   * @param name
+   * @return non-null but possibly empty array of {@link String} header values
+   */
+  public String[] headers(final String name) {
+    final Map<String, List<String>> headers = headers();
+    if (headers == null || headers.isEmpty())
+      return EMPTY_STRINGS;
+
+    final List<String> values = headers.get(name);
+    if (values != null && !values.isEmpty())
+      return values.toArray(new String[values.size()]);
+    else
+      return EMPTY_STRINGS;
+  }
+
+  /**
+   * Get parameter with given name from header value in response
+   *
+   * @param headerName
+   * @param paramName
+   * @return parameter value or null if missing
+   */
+  public String parameter(final String headerName, final String paramName) {
+    return getParam(header(headerName), paramName);
+  }
+
+  /**
+   * Get all parameters from header value in response
+   * <p>
+   * This will be all key=value pairs after the first ';' that are separated by a
+   * ';'
+   *
+   * @param headerName
+   * @return non-null but possibly empty map of parameter headers
+   */
+  public Map<String, String> parameters(final String headerName) {
+    return getParams(header(headerName));
+  }
+
+  /**
+   * Get parameter values from header value
+   *
+   * @param header
+   * @return parameter value or null if none
+   */
+  protected Map<String, String> getParams(final String header) {
+    if (header == null || header.length() == 0)
+      return Collections.emptyMap();
+
+    final int headerLength = header.length();
+    int start = header.indexOf(';') + 1;
+    if (start == 0 || start == headerLength)
+      return Collections.emptyMap();
+
+    int end = header.indexOf(';', start);
+    if (end == -1)
+      end = headerLength;
+
+    Map<String, String> params = new LinkedHashMap<String, String>();
+    while (start < end) {
+      int nameEnd = header.indexOf('=', start);
+      if (nameEnd != -1 && nameEnd < end) {
+        String name = header.substring(start, nameEnd).trim();
+        if (name.length() > 0) {
+          String value = header.substring(nameEnd + 1, end).trim();
+          int length = value.length();
+          if (length != 0)
+            if (length > 2 && '"' == value.charAt(0) && '"' == value.charAt(length - 1))
+              params.put(name, value.substring(1, length - 1));
+            else
+              params.put(name, value);
+        }
+      }
+
+      start = end + 1;
+      end = header.indexOf(';', start);
+      if (end == -1)
+        end = headerLength;
+    }
+
+    return params;
+  }
+
+  /**
+   * Get parameter value from header value
+   *
+   * @param value
+   * @param paramName
+   * @return parameter value or null if none
+   */
+  protected String getParam(final String value, final String paramName) {
+    if (value == null || value.length() == 0)
+      return null;
+
+    final int length = value.length();
+    int start = value.indexOf(';') + 1;
+    if (start == 0 || start == length)
+      return null;
+
+    int end = value.indexOf(';', start);
+    if (end == -1)
+      end = length;
+
+    while (start < end) {
+      int nameEnd = value.indexOf('=', start);
+      if (nameEnd != -1 && nameEnd < end && paramName.equals(value.substring(start, nameEnd).trim())) {
+        String paramValue = value.substring(nameEnd + 1, end).trim();
+        int valueLength = paramValue.length();
+        if (valueLength != 0)
+          if (valueLength > 2 && '"' == paramValue.charAt(0) && '"' == paramValue.charAt(valueLength - 1))
+            return paramValue.substring(1, valueLength - 1);
+          else
+            return paramValue;
+      }
+
+      start = end + 1;
+      end = value.indexOf(';', start);
+      if (end == -1)
+        end = length;
+    }
+
+    return null;
+  }
+
+  /**
+   * Get 'charset' parameter from 'Content-Type' response header
+   *
+   * @return charset or null if none
+   */
+  public String charset() {
+    return parameter(HEADER_CONTENT_TYPE, PARAM_CHARSET);
+  }
+
+  /**
+   * Set the 'User-Agent' header to given value
+   *
+   * @param userAgent
+   * @return this request
+   */
+  public HttpRequest userAgent(final String userAgent) {
+    return header(HEADER_USER_AGENT, userAgent);
+  }
+
+  /**
+   * Set the 'Referer' header to given value
+   *
+   * @param referer
+   * @return this request
+   */
+  public HttpRequest referer(final String referer) {
+    return header(HEADER_REFERER, referer);
+  }
+
+  /**
+   * Set value of {@link HttpURLConnection#setUseCaches(boolean)}
+   *
+   * @param useCaches
+   * @return this request
+   */
+  public HttpRequest useCaches(final boolean useCaches) {
+    getConnection().setUseCaches(useCaches);
+    return this;
+  }
+
+  /**
+   * Set the 'Accept-Encoding' header to given value
+   *
+   * @param acceptEncoding
+   * @return this request
+   */
+  public HttpRequest acceptEncoding(final String acceptEncoding) {
+    return header(HEADER_ACCEPT_ENCODING, acceptEncoding);
+  }
+
+  /**
+   * Set the 'Accept-Encoding' header to 'gzip'
+   *
+   * @see #uncompress(boolean)
+   * @return this request
+   */
+  public HttpRequest acceptGzipEncoding() {
+    return acceptEncoding(ENCODING_GZIP);
+  }
+
+  /**
+   * Set the 'Accept-Charset' header to given value
+   *
+   * @param acceptCharset
+   * @return this request
+   */
+  public HttpRequest acceptCharset(final String acceptCharset) {
+    return header(HEADER_ACCEPT_CHARSET, acceptCharset);
+  }
+
+  /**
+   * Get the 'Content-Encoding' header from the response
+   *
+   * @return this request
+   */
+  public String contentEncoding() {
+    return header(HEADER_CONTENT_ENCODING);
+  }
+
+  /**
+   * Get the 'Server' header from the response
+   *
+   * @return server
+   */
+  public String server() {
+    return header(HEADER_SERVER);
+  }
+
+  /**
+   * Get the 'Date' header from the response
+   *
+   * @return date value, -1 on failures
+   */
+  public long date() {
+    return dateHeader(HEADER_DATE);
+  }
+
+  /**
+   * Get the 'Cache-Control' header from the response
+   *
+   * @return cache control
+   */
+  public String cacheControl() {
+    return header(HEADER_CACHE_CONTROL);
+  }
+
+  /**
+   * Get the 'ETag' header from the response
+   *
+   * @return entity tag
+   */
+  public String eTag() {
+    return header(HEADER_ETAG);
+  }
+
+  /**
+   * Get the 'Expires' header from the response
+   *
+   * @return expires value, -1 on failures
+   */
+  public long expires() {
+    return dateHeader(HEADER_EXPIRES);
+  }
+
+  /**
+   * Get the 'Last-Modified' header from the response
+   *
+   * @return last modified value, -1 on failures
+   */
+  public long lastModified() {
+    return dateHeader(HEADER_LAST_MODIFIED);
+  }
+
+  /**
+   * Get the 'Location' header from the response
+   *
+   * @return location
+   */
+  public String location() {
+    return header(HEADER_LOCATION);
+  }
+
+  /**
+   * Set the 'Authorization' header to given value
+   *
+   * @param authorization
+   * @return this request
+   */
+  public HttpRequest authorization(final String authorization) {
+    return header(HEADER_AUTHORIZATION, authorization);
+  }
+
+  /**
+   * Set the 'Proxy-Authorization' header to given value
+   *
+   * @param proxyAuthorization
+   * @return this request
+   */
+  public HttpRequest proxyAuthorization(final String proxyAuthorization) {
+    return header(HEADER_PROXY_AUTHORIZATION, proxyAuthorization);
+  }
+
+  /**
+   * Set the 'Authorization' header to given values in Basic authentication format
+   *
+   * @param name
+   * @param password
+   * @return this request
+   */
+  public HttpRequest basic(final String name, final String password) {
+    return authorization("Basic " + Base64.encode(name + ':' + password));
+  }
+
+  /**
+   * Set the 'Proxy-Authorization' header to given values in Basic authentication
+   * format
+   *
+   * @param name
+   * @param password
+   * @return this request
+   */
+  public HttpRequest proxyBasic(final String name, final String password) {
+    return proxyAuthorization("Basic " + Base64.encode(name + ':' + password));
+  }
+
+  /**
+   * Set the 'If-Modified-Since' request header to the given value
+   *
+   * @param ifModifiedSince
+   * @return this request
+   */
+  public HttpRequest ifModifiedSince(final long ifModifiedSince) {
+    getConnection().setIfModifiedSince(ifModifiedSince);
+    return this;
+  }
+
+  /**
+   * Set the 'If-None-Match' request header to the given value
+   *
+   * @param ifNoneMatch
+   * @return this request
+   */
+  public HttpRequest ifNoneMatch(final String ifNoneMatch) {
+    return header(HEADER_IF_NONE_MATCH, ifNoneMatch);
+  }
+
+  /**
+   * Set the 'Content-Type' request header to the given value
+   *
+   * @param contentType
+   * @return this request
+   */
+  public HttpRequest contentType(final String contentType) {
+    return contentType(contentType, null);
+  }
+
+  /**
+   * Set the 'Content-Type' request header to the given value and charset
+   *
+   * @param contentType
+   * @param charset
+   * @return this request
+   */
+  public HttpRequest contentType(final String contentType, final String charset) {
+    if (charset != null && charset.length() > 0) {
+      final String separator = "; " + PARAM_CHARSET + '=';
+      return header(HEADER_CONTENT_TYPE, contentType + separator + charset);
+    } else
+      return header(HEADER_CONTENT_TYPE, contentType);
+  }
+
+  /**
+   * Get the 'Content-Type' header from the response
+   *
+   * @return response header value
+   */
+  public String contentType() {
+    return header(HEADER_CONTENT_TYPE);
+  }
+
+  /**
+   * Get the 'Content-Length' header from the response
+   *
+   * @return response header value
+   */
+  public int contentLength() {
+    return intHeader(HEADER_CONTENT_LENGTH);
+  }
+
+  /**
+   * Set the 'Content-Length' request header to the given value
+   *
+   * @param contentLength
+   * @return this request
+   */
+  public HttpRequest contentLength(final String contentLength) {
+    return contentLength(Integer.parseInt(contentLength));
+  }
+
+  /**
+   * Set the 'Content-Length' request header to the given value
+   *
+   * @param contentLength
+   * @return this request
+   */
+  public HttpRequest contentLength(final int contentLength) {
+    getConnection().setFixedLengthStreamingMode(contentLength);
+    return this;
+  }
+
+  /**
+   * Set the 'Accept' header to given value
+   *
+   * @param accept
+   * @return this request
+   */
+  public HttpRequest accept(final String accept) {
+    return header(HEADER_ACCEPT, accept);
+  }
+
+  /**
+   * Set the 'Accept' header to 'application/json'
+   *
+   * @return this request
+   */
+  public HttpRequest acceptJson() {
+    return accept(CONTENT_TYPE_JSON);
+  }
+
+  /**
+   * Copy from input stream to output stream
+   *
+   * @param input
+   * @param output
+   * @return this request
+   * @throws IOException
+   */
+  protected HttpRequest copy(final InputStream input, final OutputStream output) throws IOException {
+    return new CloseOperation<HttpRequest>(input, ignoreCloseExceptions) {
+
+      @Override
+      public HttpRequest run() throws IOException {
+        final byte[] buffer = new byte[bufferSize];
+        int read;
+        while ((read = input.read(buffer)) != -1) {
+          output.write(buffer, 0, read);
+          totalWritten += read;
+          progress.onUpload(totalWritten, totalSize);
+        }
+        return HttpRequest.this;
+      }
+    }.call();
+  }
+
+  /**
+   * Copy from reader to writer
+   *
+   * @param input
+   * @param output
+   * @return this request
+   * @throws IOException
+   */
+  protected HttpRequest copy(final Reader input, final Writer output) throws IOException {
+    return new CloseOperation<HttpRequest>(input, ignoreCloseExceptions) {
+
+      @Override
+      public HttpRequest run() throws IOException {
+        final char[] buffer = new char[bufferSize];
+        int read;
+        while ((read = input.read(buffer)) != -1) {
+          output.write(buffer, 0, read);
+          totalWritten += read;
+          progress.onUpload(totalWritten, -1);
+        }
+        return HttpRequest.this;
+      }
+    }.call();
+  }
+
+  /**
+   * Set the UploadProgress callback for this request
+   *
+   * @param callback
+   * @return this request
+   */
+  public HttpRequest progress(final UploadProgress callback) {
+    if (callback == null)
+      progress = UploadProgress.DEFAULT;
+    else
+      progress = callback;
+    return this;
+  }
+
+  private HttpRequest incrementTotalSize(final long size) {
+    if (totalSize == -1)
+      totalSize = 0;
+    totalSize += size;
+    return this;
+  }
+
+  /**
+   * Close output stream
+   *
+   * @return this request
+   * @throws HttpRequestException
+   * @throws IOException
+   */
+  protected HttpRequest closeOutput() throws IOException {
+    progress(null);
+    if (output == null)
+      return this;
+    if (multipart)
+      output.write(CRLF + "--" + BOUNDARY + "--" + CRLF);
+    if (ignoreCloseExceptions)
+      try {
+        output.close();
+      } catch (IOException ignored) {
+        // Ignored
+      }
+    else
+      output.close();
+    output = null;
+    return this;
+  }
+
+  /**
+   * Call {@link #closeOutput()} and re-throw a caught {@link IOException}s as an
+   * {@link HttpRequestException}
+   *
+   * @return this request
+   * @throws HttpRequestException
+   */
+  protected HttpRequest closeOutputQuietly() throws HttpRequestException {
+    try {
+      return closeOutput();
+    } catch (IOException e) {
+      throw new HttpRequestException(e);
+    }
+  }
+
+  /**
+   * Open output stream
+   *
+   * @return this request
+   * @throws IOException
+   */
+  protected HttpRequest openOutput() throws IOException {
+    if (output != null)
+      return this;
+    getConnection().setDoOutput(true);
+    final String charset = getParam(getConnection().getRequestProperty(HEADER_CONTENT_TYPE), PARAM_CHARSET);
+    output = new RequestOutputStream(getConnection().getOutputStream(), charset, bufferSize);
+    return this;
+  }
+
+  /**
+   * Start part of a multipart
+   *
+   * @return this request
+   * @throws IOException
+   */
+  protected HttpRequest startPart() throws IOException {
+    if (!multipart) {
+      multipart = true;
+      contentType(CONTENT_TYPE_MULTIPART).openOutput();
+      output.write("--" + BOUNDARY + CRLF);
+    } else
+      output.write(CRLF + "--" + BOUNDARY + CRLF);
+    return this;
+  }
+
+  /**
+   * Write part header
+   *
+   * @param name
+   * @param filename
+   * @return this request
+   * @throws IOException
+   */
+  protected HttpRequest writePartHeader(final String name, final String filename) throws IOException {
+    return writePartHeader(name, filename, null);
+  }
+
+  /**
+   * Write part header
+   *
+   * @param name
+   * @param filename
+   * @param contentType
+   * @return this request
+   * @throws IOException
+   */
+  protected HttpRequest writePartHeader(final String name, final String filename, final String contentType)
+      throws IOException {
+    final StringBuilder partBuffer = new StringBuilder();
+    partBuffer.append("form-data; name=\"").append(name);
+    if (filename != null)
+      partBuffer.append("\"; filename=\"").append(filename);
+    partBuffer.append('"');
+    partHeader("Content-Disposition", partBuffer.toString());
+    if (contentType != null)
+      partHeader(HEADER_CONTENT_TYPE, contentType);
+    return send(CRLF);
+  }
+
+  /**
+   * Write part of a multipart request to the request body
+   *
+   * @param name
+   * @param part
+   * @return this request
+   */
+  public HttpRequest part(final String name, final String part) {
+    return part(name, null, part);
+  }
+
+  /**
+   * Write part of a multipart request to the request body
+   *
+   * @param name
+   * @param filename
+   * @param part
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest part(final String name, final String filename, final String part) throws HttpRequestException {
+    return part(name, filename, null, part);
+  }
+
+  /**
+   * Write part of a multipart request to the request body
+   *
+   * @param name
+   * @param filename
+   * @param contentType value of the Content-Type part header
+   * @param part
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest part(final String name, final String filename, final String contentType, final String part)
+      throws HttpRequestException {
+    try {
+      startPart();
+      writePartHeader(name, filename, contentType);
+      output.write(part);
+    } catch (IOException e) {
+      throw new HttpRequestException(e);
+    }
+    return this;
+  }
+
+  /**
+   * Write part of a multipart request to the request body
+   *
+   * @param name
+   * @param part
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest part(final String name, final Number part) throws HttpRequestException {
+    return part(name, null, part);
+  }
+
+  /**
+   * Write part of a multipart request to the request body
+   *
+   * @param name
+   * @param filename
+   * @param part
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest part(final String name, final String filename, final Number part) throws HttpRequestException {
+    return part(name, filename, part != null ? part.toString() : null);
+  }
+
+  /**
+   * Write part of a multipart request to the request body
+   *
+   * @param name
+   * @param part
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest part(final String name, final File part) throws HttpRequestException {
+    return part(name, null, part);
+  }
+
+  /**
+   * Write part of a multipart request to the request body
+   *
+   * @param name
+   * @param filename
+   * @param part
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest part(final String name, final String filename, final File part) throws HttpRequestException {
+    return part(name, filename, null, part);
+  }
+
+  /**
+   * Write part of a multipart request to the request body
+   *
+   * @param name
+   * @param filename
+   * @param contentType value of the Content-Type part header
+   * @param part
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest part(final String name, final String filename, final String contentType, final File part)
+      throws HttpRequestException {
+    final InputStream stream;
+    try {
+      stream = new BufferedInputStream(new FileInputStream(part));
+      incrementTotalSize(part.length());
+    } catch (IOException e) {
+      throw new HttpRequestException(e);
+    }
+    return part(name, filename, contentType, stream);
+  }
+
+  /**
+   * Write part of a multipart request to the request body
+   *
+   * @param name
+   * @param part
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest part(final String name, final InputStream part) throws HttpRequestException {
+    return part(name, null, null, part);
+  }
+
+  /**
+   * Write part of a multipart request to the request body
+   *
+   * @param name
+   * @param filename
+   * @param contentType value of the Content-Type part header
+   * @param part
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest part(final String name, final String filename, final String contentType, final InputStream part)
+      throws HttpRequestException {
+    try {
+      startPart();
+      writePartHeader(name, filename, contentType);
+      copy(part, output);
+    } catch (IOException e) {
+      throw new HttpRequestException(e);
+    }
+    return this;
+  }
+
+  /**
+   * Write a multipart header to the response body
+   *
+   * @param name
+   * @param value
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest partHeader(final String name, final String value) throws HttpRequestException {
+    return send(name).send(": ").send(value).send(CRLF);
+  }
+
+  /**
+   * Write contents of file to request body
+   *
+   * @param input
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest send(final File input) throws HttpRequestException {
+    final InputStream stream;
+    try {
+      stream = new BufferedInputStream(new FileInputStream(input));
+      incrementTotalSize(input.length());
+    } catch (FileNotFoundException e) {
+      throw new HttpRequestException(e);
+    }
+    return send(stream);
+  }
+
+  /**
+   * Write byte array to request body
+   *
+   * @param input
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest send(final byte[] input) throws HttpRequestException {
+    if (input != null)
+      incrementTotalSize(input.length);
+    return send(new ByteArrayInputStream(input));
+  }
+
+  /**
+   * Write stream to request body
+   * <p>
+   * The given stream will be closed once sending completes
+   *
+   * @param input
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest send(final InputStream input) throws HttpRequestException {
+    try {
+      openOutput();
+      copy(input, output);
+    } catch (IOException e) {
+      throw new HttpRequestException(e);
+    }
+    return this;
+  }
+
+  /**
+   * Write reader to request body
+   * <p>
+   * The given reader will be closed once sending completes
+   *
+   * @param input
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest send(final Reader input) throws HttpRequestException {
+    try {
+      openOutput();
+    } catch (IOException e) {
+      throw new HttpRequestException(e);
+    }
+    final Writer writer = new OutputStreamWriter(output, output.encoder.charset());
+    return new FlushOperation<HttpRequest>(writer) {
+
+      @Override
+      protected HttpRequest run() throws IOException {
+        return copy(input, writer);
+      }
+    }.call();
+  }
+
+  /**
+   * Write char sequence to request body
+   * <p>
+   * The charset configured via {@link #contentType(String)} will be used and
+   * UTF-8 will be used if it is unset.
+   *
+   * @param value
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest send(final CharSequence value) throws HttpRequestException {
+    try {
+      openOutput();
+      output.write(value.toString());
+    } catch (IOException e) {
+      throw new HttpRequestException(e);
+    }
+    return this;
+  }
+
+  /**
+   * Create writer to request output stream
+   *
+   * @return writer
+   * @throws HttpRequestException
+   */
+  public OutputStreamWriter writer() throws HttpRequestException {
+    try {
+      openOutput();
+      return new OutputStreamWriter(output, output.encoder.charset());
+    } catch (IOException e) {
+      throw new HttpRequestException(e);
+    }
+  }
+
+  /**
+   * Write the values in the map as form data to the request body
+   * <p>
+   * The pairs specified will be URL-encoded in UTF-8 and sent with the
+   * 'application/x-www-form-urlencoded' content-type
+   *
+   * @param values
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest form(final Map<?, ?> values) throws HttpRequestException {
+    return form(values, CHARSET_UTF8);
+  }
+
+  /**
+   * Write the key and value in the entry as form data to the request body
+   * <p>
+   * The pair specified will be URL-encoded in UTF-8 and sent with the
+   * 'application/x-www-form-urlencoded' content-type
+   *
+   * @param entry
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest form(final Entry<?, ?> entry) throws HttpRequestException {
+    return form(entry, CHARSET_UTF8);
+  }
+
+  /**
+   * Write the key and value in the entry as form data to the request body
+   * <p>
+   * The pair specified will be URL-encoded and sent with the
+   * 'application/x-www-form-urlencoded' content-type
+   *
+   * @param entry
+   * @param charset
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest form(final Entry<?, ?> entry, final String charset) throws HttpRequestException {
+    return form(entry.getKey(), entry.getValue(), charset);
+  }
+
+  /**
+   * Write the name/value pair as form data to the request body
+   * <p>
+   * The pair specified will be URL-encoded in UTF-8 and sent with the
+   * 'application/x-www-form-urlencoded' content-type
+   *
+   * @param name
+   * @param value
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest form(final Object name, final Object value) throws HttpRequestException {
+    return form(name, value, CHARSET_UTF8);
+  }
+
+  /**
+   * Write the name/value pair as form data to the request body
+   * <p>
+   * The values specified will be URL-encoded and sent with the
+   * 'application/x-www-form-urlencoded' content-type
+   *
+   * @param name
+   * @param value
+   * @param charset
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest form(final Object name, final Object value, String charset) throws HttpRequestException {
+    final boolean first = !form;
+    if (first) {
+      contentType(CONTENT_TYPE_FORM, charset);
+      form = true;
+    }
+    charset = getValidCharset(charset);
+    try {
+      openOutput();
+      if (!first)
+        output.write('&');
+      output.write(URLEncoder.encode(name.toString(), charset));
+      output.write('=');
+      if (value != null)
+        output.write(URLEncoder.encode(value.toString(), charset));
+    } catch (IOException e) {
+      throw new HttpRequestException(e);
+    }
+    return this;
+  }
+
+  /**
+   * Write the values in the map as encoded form data to the request body
+   *
+   * @param values
+   * @param charset
+   * @return this request
+   * @throws HttpRequestException
+   */
+  public HttpRequest form(final Map<?, ?> values, final String charset) throws HttpRequestException {
+    if (!values.isEmpty())
+      for (Entry<?, ?> entry : values.entrySet())
+        form(entry, charset);
+    return this;
+  }
+
+  public HttpRequest setSSLSocketFactory(SSLSocketFactory socketFactory) throws HttpRequestException {
+    final HttpURLConnection connection = getConnection();
+    if (connection instanceof HttpsURLConnection)
+      ((HttpsURLConnection) connection).setSSLSocketFactory(socketFactory);
+    return this;
+  }
+
+  public HttpRequest setHostnameVerifier(HostnameVerifier verifier) {
+    final HttpURLConnection connection = getConnection();
+    if (connection instanceof HttpsURLConnection)
+      ((HttpsURLConnection) connection).setHostnameVerifier(verifier);
+    return this;
+  }
+
+  /**
+   * Get the {@link URL} of this request's connection
+   *
+   * @return request URL
+   */
+  public URL url() {
+    return getConnection().getURL();
+  }
+
+  /**
+   * Get the HTTP method of this request
+   *
+   * @return method
+   */
+  public String method() {
+    return getConnection().getRequestMethod();
+  }
+
+  /**
+   * Configure an HTTP proxy on this connection. Use
+   * {{@link #proxyBasic(String, String)} if this proxy requires basic
+   * authentication.
+   *
+   * @param proxyHost
+   * @param proxyPort
+   * @return this request
+   */
+  public HttpRequest useProxy(final String proxyHost, final int proxyPort) {
+    if (connection != null)
+      throw new IllegalStateException(
+          "The connection has already been created. This method must be called before reading or writing to the request.");
+
+    this.httpProxyHost = proxyHost;
+    this.httpProxyPort = proxyPort;
+    return this;
+  }
+
+  /**
+   * Set whether or not the underlying connection should follow redirects in the
+   * response.
+   *
+   * @param followRedirects - true fo follow redirects, false to not.
+   * @return this request
+   */
+  public HttpRequest followRedirects(final boolean followRedirects) {
+    getConnection().setInstanceFollowRedirects(followRedirects);
+    return this;
+  }
+}
diff --git a/platforms/android/app/src/main/java/com/silkimen/http/JsonUtils.java b/platforms/android/app/src/main/java/com/silkimen/http/JsonUtils.java
new file mode 100644
index 0000000..72f1b48
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/silkimen/http/JsonUtils.java
@@ -0,0 +1,58 @@
+package com.silkimen.http;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class JsonUtils {
+  public static HashMap<String, String> getStringMap(JSONObject object) throws JSONException {
+    HashMap<String, String> map = new HashMap<String, String>();
+
+    if (object == null) {
+      return map;
+    }
+
+    Iterator<?> i = object.keys();
+
+    while (i.hasNext()) {
+      String key = (String) i.next();
+      map.put(key, object.getString(key));
+    }
+    return map;
+  }
+
+  public static HashMap<String, Object> getObjectMap(JSONObject object) throws JSONException {
+    HashMap<String, Object> map = new HashMap<String, Object>();
+
+    if (object == null) {
+      return map;
+    }
+
+    Iterator<?> i = object.keys();
+
+    while (i.hasNext()) {
+      String key = (String) i.next();
+      Object value = object.get(key);
+
+      if (value instanceof JSONArray) {
+        map.put(key, getObjectList((JSONArray) value));
+      } else {
+        map.put(key, object.get(key));
+      }
+    }
+    return map;
+  }
+
+  public static ArrayList<Object> getObjectList(JSONArray array) throws JSONException {
+    ArrayList<Object> list = new ArrayList<Object>();
+
+    for (int i = 0; i < array.length(); i++) {
+      list.add(array.get(i));
+    }
+    return list;
+  }
+}
diff --git a/platforms/android/app/src/main/java/com/silkimen/http/KeyChainKeyManager.java b/platforms/android/app/src/main/java/com/silkimen/http/KeyChainKeyManager.java
new file mode 100644
index 0000000..ecdaa38
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/silkimen/http/KeyChainKeyManager.java
@@ -0,0 +1,57 @@
+package com.silkimen.http;
+
+import android.content.Context;
+import android.security.KeyChain;
+
+import java.net.Socket;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.X509ExtendedKeyManager;
+
+public class KeyChainKeyManager extends X509ExtendedKeyManager {
+  private final String alias;
+  private final X509Certificate[] chain;
+  private final PrivateKey key;
+
+  public KeyChainKeyManager(String alias, PrivateKey key, X509Certificate[] chain) {
+    this.alias = alias;
+    this.key = key;
+    this.chain = chain;
+  }
+
+  @Override
+  public String chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket) {
+    return this.alias;
+  }
+
+  @Override
+  public X509Certificate[] getCertificateChain(String alias) {
+    return chain;
+  }
+
+  @Override
+  public PrivateKey getPrivateKey(String alias) {
+    return key;
+  }
+
+  @Override
+  public final String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
+    // not a client SSLSocket callback
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public final String[] getClientAliases(String keyType, Principal[] issuers) {
+    // not a client SSLSocket callback
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public final String[] getServerAliases(String keyType, Principal[] issuers) {
+    // not a client SSLSocket callback
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/platforms/android/app/src/main/java/com/silkimen/http/OkConnectionFactory.java b/platforms/android/app/src/main/java/com/silkimen/http/OkConnectionFactory.java
new file mode 100644
index 0000000..c1a3ef1
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/silkimen/http/OkConnectionFactory.java
@@ -0,0 +1,26 @@
+package com.silkimen.http;
+
+import okhttp3.OkHttpClient;
+import okhttp3.OkUrlFactory;
+
+import java.net.URL;
+import java.net.HttpURLConnection;
+import java.net.URLStreamHandler;
+import java.net.Proxy;
+
+public class OkConnectionFactory implements HttpRequest.ConnectionFactory {
+  private final OkHttpClient client = new OkHttpClient();
+
+  public HttpURLConnection create(URL url) {
+    OkUrlFactory urlFactory = new OkUrlFactory(this.client);
+
+    return (HttpURLConnection) urlFactory.open(url);
+  }
+
+  public HttpURLConnection create(URL url, Proxy proxy) {
+    OkHttpClient clientWithProxy = new OkHttpClient.Builder().proxy(proxy).build();
+    OkUrlFactory urlFactory = new OkUrlFactory(clientWithProxy);
+
+    return (HttpURLConnection) urlFactory.open(url);
+  }
+}
diff --git a/platforms/android/app/src/main/java/com/silkimen/http/TLSConfiguration.java b/platforms/android/app/src/main/java/com/silkimen/http/TLSConfiguration.java
new file mode 100644
index 0000000..c33df6c
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/silkimen/http/TLSConfiguration.java
@@ -0,0 +1,63 @@
+package com.silkimen.http;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.SecureRandom;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+import com.silkimen.http.TLSSocketFactory;
+
+public class TLSConfiguration {
+  private TrustManager[] trustManagers;
+  private KeyManager[] keyManagers;
+  private HostnameVerifier hostnameVerifier;
+
+  private SSLSocketFactory socketFactory;
+
+  public void setHostnameVerifier(HostnameVerifier hostnameVerifier) {
+    this.hostnameVerifier = hostnameVerifier;
+  }
+
+  public void setKeyManagers(KeyManager[] keyManagers) {
+    this.keyManagers = keyManagers;
+    this.socketFactory = null;
+  }
+
+  public void setTrustManagers(TrustManager[] trustManagers) {
+    this.trustManagers = trustManagers;
+    this.socketFactory = null;
+  }
+
+  public HostnameVerifier getHostnameVerifier() {
+    return this.hostnameVerifier;
+  }
+
+  public SSLSocketFactory getTLSSocketFactory() throws IOException {
+    if (this.socketFactory != null) {
+      return this.socketFactory;
+    }
+
+    try {
+      SSLContext context = SSLContext.getInstance("TLS");
+
+      context.init(this.keyManagers, this.trustManagers, new SecureRandom());
+
+      if (android.os.Build.VERSION.SDK_INT < 20) {
+        this.socketFactory = new TLSSocketFactory(context);
+      } else {
+        this.socketFactory = context.getSocketFactory();
+      }
+
+      return this.socketFactory;
+    } catch (GeneralSecurityException e) {
+      IOException ioException = new IOException("Security exception occured while configuring TLS context");
+      ioException.initCause(e);
+      throw ioException;
+    }
+  }
+}
diff --git a/platforms/android/app/src/main/java/com/silkimen/http/TLSSocketFactory.java b/platforms/android/app/src/main/java/com/silkimen/http/TLSSocketFactory.java
new file mode 100644
index 0000000..9bc75b1
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/silkimen/http/TLSSocketFactory.java
@@ -0,0 +1,63 @@
+package com.silkimen.http;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+public class TLSSocketFactory extends SSLSocketFactory {
+
+  private SSLSocketFactory delegate;
+
+  public TLSSocketFactory(SSLContext context) {
+    delegate = context.getSocketFactory();
+  }
+
+  @Override
+  public String[] getDefaultCipherSuites() {
+    return delegate.getDefaultCipherSuites();
+  }
+
+  @Override
+  public String[] getSupportedCipherSuites() {
+    return delegate.getSupportedCipherSuites();
+  }
+
+  @Override
+  public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
+    return enableTLSOnSocket(delegate.createSocket(socket, host, port, autoClose));
+  }
+
+  @Override
+  public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
+    return enableTLSOnSocket(delegate.createSocket(host, port));
+  }
+
+  @Override
+  public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
+      throws IOException, UnknownHostException {
+    return enableTLSOnSocket(delegate.createSocket(host, port, localHost, localPort));
+  }
+
+  @Override
+  public Socket createSocket(InetAddress host, int port) throws IOException {
+    return enableTLSOnSocket(delegate.createSocket(host, port));
+  }
+
+  @Override
+  public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
+      throws IOException {
+    return enableTLSOnSocket(delegate.createSocket(address, port, localAddress, localPort));
+  }
+
+  private Socket enableTLSOnSocket(Socket socket) {
+    if (socket != null && (socket instanceof SSLSocket)) {
+      ((SSLSocket) socket).setEnabledProtocols(new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" });
+    }
+    return socket;
+  }
+}
diff --git a/platforms/android/app/src/main/java/com/supwisdom/dlapp/MainActivity.java b/platforms/android/app/src/main/java/com/supwisdom/dlapp/MainActivity.java
new file mode 100644
index 0000000..c48c351
--- /dev/null
+++ b/platforms/android/app/src/main/java/com/supwisdom/dlapp/MainActivity.java
@@ -0,0 +1,41 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+ */
+
+package com.supwisdom.dlapp;
+
+import android.os.Bundle;
+import org.apache.cordova.*;
+
+public class MainActivity extends CordovaActivity
+{
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+
+        // enable Cordova apps to be started in the background
+        Bundle extras = getIntent().getExtras();
+        if (extras != null && extras.getBoolean("cdvStartInBackground", false)) {
+            moveTaskToBack(true);
+        }
+
+        // Set by <content src="index.html" /> in config.xml
+        loadUrl(launchUrl);
+    }
+}
diff --git a/platforms/android/app/src/main/java/de/niklasmerz/cordova/fingerprint/Fingerprint.java b/platforms/android/app/src/main/java/de/niklasmerz/cordova/fingerprint/Fingerprint.java
new file mode 100644
index 0000000..32fd67c
--- /dev/null
+++ b/platforms/android/app/src/main/java/de/niklasmerz/cordova/fingerprint/Fingerprint.java
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) https://github.com/mjwheatley/cordova-plugin-android-fingerprint-auth
+ * Modifications copyright (C) 2016 Niklas Merz
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package de.niklasmerz.cordova.fingerprint;
+
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.CordovaInterface;
+
+import android.annotation.TargetApi;
+import android.app.FragmentTransaction;
+import android.app.KeyguardManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Bundle;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyPermanentlyInvalidatedException;
+import android.security.keystore.KeyProperties;
+import android.util.Base64;
+import android.util.DisplayMetrics;
+import android.util.Log;
+
+import org.apache.cordova.PluginResult;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.util.Locale;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+
+@TargetApi(23)
+public class Fingerprint extends CordovaPlugin {
+
+    public static final String TAG = "Fingerprint";
+    public static String packageName;
+
+    private static final String DIALOG_FRAGMENT_TAG = "FpAuthDialog";
+    private static final String ANDROID_KEY_STORE = "AndroidKeyStore";
+
+    KeyguardManager mKeyguardManager;
+    FingerprintAuthenticationDialogFragment mFragment;
+    public static KeyStore mKeyStore;
+    public static KeyGenerator mKeyGenerator;
+    public static Cipher mCipher;
+    private FingerprintManager mFingerPrintManager;
+
+    public static CallbackContext mCallbackContext;
+    public static PluginResult mPluginResult;
+
+    /**
+     * Alias for our key in the Android Key Store
+     */
+    private static String mClientId;
+    /**
+     * Used to encrypt token
+     */
+    private static String mClientSecret;
+
+    /**
+     * Options
+     */
+    private static boolean mDisableBackup = false;
+
+    /**
+     * Constructor.
+     */
+    public Fingerprint() {
+    }
+
+    /**
+     * Sets the context of the Command. This can then be used to do things like
+     * get file paths associated with the Activity.
+     *
+     * @param cordova The context of the main Activity.
+     * @param webView The CordovaWebView Cordova is running in.
+     */
+
+    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
+        super.initialize(cordova, webView);
+        Log.v(TAG, "Init Fingerprint");
+        packageName = cordova.getActivity().getApplicationContext().getPackageName();
+        mPluginResult = new PluginResult(PluginResult.Status.NO_RESULT);
+
+        if (android.os.Build.VERSION.SDK_INT < 23) {
+            return;
+        }
+
+        mKeyguardManager = cordova.getActivity().getSystemService(KeyguardManager.class);
+        mFingerPrintManager = cordova.getActivity().getApplicationContext()
+                .getSystemService(FingerprintManager.class);
+
+        try {
+            mKeyGenerator = KeyGenerator.getInstance(
+                    KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
+            mKeyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
+
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("Failed to get an instance of KeyGenerator", e);
+        } catch (NoSuchProviderException e) {
+            throw new RuntimeException("Failed to get an instance of KeyGenerator", e);
+        } catch (KeyStoreException e) {
+            throw new RuntimeException("Failed to get an instance of KeyStore", e);
+        }
+
+        try {
+            mCipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
+                    + KeyProperties.BLOCK_MODE_CBC + "/"
+                    + KeyProperties.ENCRYPTION_PADDING_PKCS7);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("Failed to get an instance of Cipher", e);
+        } catch (NoSuchPaddingException e) {
+            throw new RuntimeException("Failed to get an instance of Cipher", e);
+        }
+    }
+
+    /**
+     * Executes the request and returns PluginResult.
+     *
+     * @param action          The action to execute.
+     * @param args            JSONArry of arguments for the plugin.
+     * @param callbackContext The callback id used when calling back into JavaScript.
+     * @return A PluginResult object with a status and message.
+     */
+    public boolean execute(final String action,
+                           JSONArray args,
+                           CallbackContext callbackContext) throws JSONException {
+        mCallbackContext = callbackContext;
+        Log.v(TAG, "Fingerprint action: " + action);
+        if (android.os.Build.VERSION.SDK_INT < 23) {
+            Log.e(TAG, "minimum SDK version 23 required");
+            mPluginResult = new PluginResult(PluginResult.Status.ERROR);
+            mCallbackContext.error("minimum SDK version 23 required");
+            mCallbackContext.sendPluginResult(mPluginResult);
+            return true;
+        }
+
+        final JSONObject arg_object = args.getJSONObject(0);
+
+        if (action.equals("authenticate")) {
+            if (!arg_object.has("clientId") || !arg_object.has("clientSecret")) {
+                mPluginResult = new PluginResult(PluginResult.Status.ERROR);
+                mCallbackContext.error("Missing required parameters");
+                mCallbackContext.sendPluginResult(mPluginResult);
+                return true;
+            }
+            mClientId = arg_object.getString("clientId");
+            mClientSecret = arg_object.getString("clientSecret");
+            if (arg_object.has("disableBackup")) {
+                mDisableBackup = arg_object.getBoolean("disableBackup");
+            }
+            // Set language
+            Resources res = cordova.getActivity().getResources();
+            // Change locale settings in the app.
+            DisplayMetrics dm = res.getDisplayMetrics();
+            Configuration conf = res.getConfiguration();
+            //Do not change locale
+            res.updateConfiguration(conf, dm);
+
+            if (isFingerprintAuthAvailable()) {
+                SecretKey key = getSecretKey();
+                boolean isCipherInit = true;
+                if (key == null) {
+                    if (createKey()) {
+                        key = getSecretKey();
+                    }
+                }
+                if (key != null && !initCipher()) {
+                    isCipherInit = false;
+                }
+                if (key != null) {
+                    cordova.getActivity().runOnUiThread(new Runnable() {
+                        public void run() {
+                            // Set up the crypto object for later. The object will be authenticated by use
+                            // of the fingerprint.
+                            mFragment = new FingerprintAuthenticationDialogFragment();
+                            Bundle bundle = new Bundle();
+                            bundle.putBoolean("disableBackup", mDisableBackup);
+                            mFragment.setArguments(bundle);
+
+                            if (initCipher()) {
+                                mFragment.setCancelable(false);
+                                // Show the fingerprint dialog. The user has the option to use the fingerprint with
+                                // crypto, or you can fall back to using a server-side verified password.
+                                mFragment.setCryptoObject(new FingerprintManager.CryptoObject(mCipher));
+                                FragmentTransaction transaction = cordova.getActivity().getFragmentManager().beginTransaction();
+                                transaction.add(mFragment, DIALOG_FRAGMENT_TAG);
+                                transaction.commitAllowingStateLoss();
+                            } else {
+                                if (!mDisableBackup) {
+                                    // This happens if the lock screen has been disabled or or a fingerprint got
+                                    // enrolled. Thus show the dialog to authenticate with their password
+                                    mFragment.setCryptoObject(new FingerprintManager
+                                            .CryptoObject(mCipher));
+                                    mFragment.setStage(FingerprintAuthenticationDialogFragment
+                                            .Stage.NEW_FINGERPRINT_ENROLLED);
+                                    FragmentTransaction transaction = cordova.getActivity().getFragmentManager().beginTransaction();
+                                    transaction.add(mFragment, DIALOG_FRAGMENT_TAG);
+                                    transaction.commitAllowingStateLoss();
+                                } else {
+                                    mCallbackContext.error("Failed to init Cipher and backup disabled.");
+                                    mPluginResult = new PluginResult(PluginResult.Status.ERROR);
+                                    mCallbackContext.sendPluginResult(mPluginResult);
+                                }
+                            }
+                        }
+                    });
+                    mPluginResult.setKeepCallback(true);
+                } else {
+                    mCallbackContext.sendPluginResult(mPluginResult);
+                }
+
+            } else {
+                mPluginResult = new PluginResult(PluginResult.Status.ERROR);
+                mCallbackContext.error("Fingerprint authentication not available");
+                mCallbackContext.sendPluginResult(mPluginResult);
+            }
+            return true;
+        } else if (action.equals("isAvailable")) {
+            if(isFingerprintAuthAvailable() && mFingerPrintManager.isHardwareDetected() && mFingerPrintManager.hasEnrolledFingerprints()){
+              mPluginResult = new PluginResult(PluginResult.Status.OK, "finger");
+              mCallbackContext.success("finger");
+            }else{
+              mPluginResult = new PluginResult(PluginResult.Status.ERROR);
+
+              if (mFingerPrintManager.isHardwareDetected() && !mFingerPrintManager.hasEnrolledFingerprints()) {
+                mCallbackContext.error("Fingerprint authentication not ready");
+              } else {
+                mCallbackContext.error("Fingerprint authentication not available");
+              }
+            }
+            mCallbackContext.sendPluginResult(mPluginResult);
+            return true;
+        }
+        return false;
+    }
+
+    private boolean isFingerprintAuthAvailable() {
+        return mFingerPrintManager.isHardwareDetected()
+                && mFingerPrintManager.hasEnrolledFingerprints();
+    }
+
+    /**
+     * Initialize the {@link Cipher} instance with the created key in the {@link #createKey()}
+     * method.
+     *
+     * @return {@code true} if initialization is successful, {@code false} if the lock screen has
+     * been disabled or reset after the key was generated, or if a fingerprint got enrolled after
+     * the key was generated.
+     */
+    private static boolean initCipher() {
+        boolean initCipher = false;
+        String errorMessage = "";
+        String initCipherExceptionErrorPrefix = "Failed to init Cipher: ";
+        try {
+            SecretKey key = getSecretKey();
+            mCipher.init(Cipher.ENCRYPT_MODE, key);
+            initCipher = true;
+        } catch (InvalidKeyException e) {
+            errorMessage = initCipherExceptionErrorPrefix + "InvalidKeyException: " + e.toString();
+            
+        }
+        if (!initCipher) {
+            Log.e(TAG, errorMessage);
+            createKey();
+        }
+        return initCipher;
+    }
+
+    private static SecretKey getSecretKey() {
+        String errorMessage = "";
+        String getSecretKeyExceptionErrorPrefix = "Failed to get SecretKey from KeyStore: ";
+        SecretKey key = null;
+        try {
+            mKeyStore.load(null);
+            key = (SecretKey) mKeyStore.getKey(mClientId, null);
+        } catch (KeyStoreException e) {
+            errorMessage = getSecretKeyExceptionErrorPrefix
+                    + "KeyStoreException: " + e.toString();;
+        } catch (CertificateException e) {
+            errorMessage = getSecretKeyExceptionErrorPrefix
+                    + "CertificateException: " + e.toString();;
+        } catch (UnrecoverableKeyException e) {
+            errorMessage = getSecretKeyExceptionErrorPrefix
+                    + "UnrecoverableKeyException: " + e.toString();;
+        } catch (IOException e) {
+            errorMessage = getSecretKeyExceptionErrorPrefix
+                    + "IOException: " + e.toString();;
+        } catch (NoSuchAlgorithmException e) {
+            errorMessage = getSecretKeyExceptionErrorPrefix
+                    + "NoSuchAlgorithmException: " + e.toString();;
+        }
+        if (key == null) {
+            Log.e(TAG, errorMessage);
+        }
+        return key;
+    }
+
+    /**
+     * Creates a symmetric key in the Android Key Store which can only be used after the user has
+     * authenticated with fingerprint.
+     */
+    public static boolean createKey() {
+        String errorMessage = "";
+        String createKeyExceptionErrorPrefix = "Failed to create key: ";
+        boolean isKeyCreated = false;
+        // The enrolling flow for fingerprint. This is where you ask the user to set up fingerprint
+        // for your flow. Use of keys is necessary if you need to know if the set of
+        // enrolled fingerprints has changed.
+        try {
+            mKeyStore.load(null);
+            // Set the alias of the entry in Android KeyStore where the key will appear
+            // and the constrains (purposes) in the constructor of the Builder
+            mKeyGenerator.init(new KeyGenParameterSpec.Builder(mClientId,
+                    KeyProperties.PURPOSE_ENCRYPT |
+                            KeyProperties.PURPOSE_DECRYPT)
+                    .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
+                            // Require the user to authenticate with a fingerprint to authorize every use
+                            // of the key
+                    .setUserAuthenticationRequired(true)
+                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
+                    .build());
+            mKeyGenerator.generateKey();
+            isKeyCreated = true;
+        } catch (NoSuchAlgorithmException e) {
+            errorMessage = createKeyExceptionErrorPrefix
+                    + "NoSuchAlgorithmException: " + e.toString();;
+        } catch (InvalidAlgorithmParameterException e) {
+            errorMessage = createKeyExceptionErrorPrefix
+                    + "InvalidAlgorithmParameterException: " + e.toString();;
+        } catch (CertificateException e) {
+            errorMessage = createKeyExceptionErrorPrefix
+                    + "CertificateException: " + e.toString();;
+        } catch (IOException e) {
+            errorMessage = createKeyExceptionErrorPrefix
+                    + "IOException: " + e.toString();;
+        }
+        if (!isKeyCreated) {
+            Log.e(TAG, errorMessage);
+            setPluginResultError(errorMessage);
+        }
+        return isKeyCreated;
+    }
+
+    public static void onAuthenticated(boolean withFingerprint) {
+        JSONObject resultJson = new JSONObject();
+        String errorMessage = "";
+        boolean createdResultJson = false;
+        try {
+
+            if (withFingerprint) {
+                // If the user has authenticated with fingerprint, verify that using cryptography and
+                // then return the encrypted token
+                byte[] encrypted = tryEncrypt();
+                resultJson.put("withFingerprint", Base64.encodeToString(encrypted, 0 /* flags */));
+            } else {
+                // Authentication happened with backup password.
+                resultJson.put("withPassword", true);
+
+                // if failed to init cipher because of InvalidKeyException, create new key
+                if (!initCipher()) {
+                    createKey();
+                }
+            }
+            createdResultJson = true;
+        } catch (BadPaddingException e) {
+            errorMessage = "Failed to encrypt the data with the generated key:" +
+                    " BadPaddingException:  " + e.getMessage();
+            Log.e(TAG, errorMessage);
+        } catch (IllegalBlockSizeException e) {
+            errorMessage = "Failed to encrypt the data with the generated key: " +
+                    "IllegalBlockSizeException: " + e.getMessage();
+            Log.e(TAG, errorMessage);
+        } catch (JSONException e) {
+            errorMessage = "Failed to set resultJson key value pair: " + e.getMessage();
+            Log.e(TAG, errorMessage);
+        }
+
+        if (createdResultJson) {
+            mCallbackContext.success(resultJson);
+            mPluginResult = new PluginResult(PluginResult.Status.OK);
+        } else {
+            mCallbackContext.error(errorMessage);
+            mPluginResult = new PluginResult(PluginResult.Status.ERROR);
+        }
+        mCallbackContext.sendPluginResult(mPluginResult);
+    }
+
+    public static void onCancelled() {
+        mCallbackContext.error("Cancelled");
+    }
+
+    /**
+     * Tries to encrypt some data with the generated key in {@link #createKey} which is
+     * only works if the user has just authenticated via fingerprint.
+     */
+    private static byte[] tryEncrypt() throws BadPaddingException, IllegalBlockSizeException {
+        return mCipher.doFinal(mClientSecret.getBytes());
+    }
+
+    public static boolean setPluginResultError(String errorMessage) {
+        mCallbackContext.error(errorMessage);
+        mPluginResult = new PluginResult(PluginResult.Status.ERROR);
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/java/de/niklasmerz/cordova/fingerprint/FingerprintAuthenticationDialogFragment.java b/platforms/android/app/src/main/java/de/niklasmerz/cordova/fingerprint/FingerprintAuthenticationDialogFragment.java
new file mode 100644
index 0000000..54fb28d
--- /dev/null
+++ b/platforms/android/app/src/main/java/de/niklasmerz/cordova/fingerprint/FingerprintAuthenticationDialogFragment.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * Modifications copyright (C) 2016 Niklas Merz
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package de.niklasmerz.cordova.fingerprint;
+
+import android.app.DialogFragment;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+/**
+ * A dialog which uses fingerprint APIs to authenticate the user, and falls back to password
+ * authentication if fingerprint is not available.
+ */
+public class FingerprintAuthenticationDialogFragment extends DialogFragment
+        implements FingerprintUiHelper.Callback {
+
+    private static final String TAG = "FingerprintAuthDialog";
+    private static final int REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 1;
+
+    private Button mCancelButton;
+    private Button mSecondDialogButton;
+    private View mFingerprintContent;
+
+    private Stage mStage = Stage.FINGERPRINT;
+
+    private KeyguardManager mKeyguardManager;
+    private FingerprintManager.CryptoObject mCryptoObject;
+    private FingerprintUiHelper mFingerprintUiHelper;
+    FingerprintUiHelper.FingerprintUiHelperBuilder mFingerprintUiHelperBuilder;
+
+    boolean disableBackup;
+
+    public FingerprintAuthenticationDialogFragment() {
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Do not create a new Fragment when the Activity is re-created such as orientation changes.
+        setRetainInstance(true);
+        setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Material_Light_Dialog);
+
+        mKeyguardManager = (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
+        mFingerprintUiHelperBuilder = new FingerprintUiHelper.FingerprintUiHelperBuilder(
+                getContext(), getContext().getSystemService(FingerprintManager.class));
+
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        Bundle args = getArguments();
+        disableBackup = args.getBoolean("disableBackup");
+        Log.d(TAG, "disableBackup: " + disableBackup);
+
+        int fingerprint_auth_dialog_title_id = getResources()
+                .getIdentifier("fingerprint_auth_dialog_title", "string",
+                        Fingerprint.packageName);
+        getDialog().setTitle(getString(fingerprint_auth_dialog_title_id));
+        int fingerprint_dialog_container_id = getResources()
+                .getIdentifier("fingerprint_dialog_container", "layout",
+                        Fingerprint.packageName);
+        View v = inflater.inflate(fingerprint_dialog_container_id, container, false);
+        int cancel_button_id = getResources()
+                .getIdentifier("cancel_button", "id", Fingerprint.packageName);
+        mCancelButton = (Button) v.findViewById(cancel_button_id);
+        mCancelButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                Fingerprint.onCancelled();
+                dismissAllowingStateLoss();
+            }
+        });
+
+        int second_dialog_button_id = getResources()
+                .getIdentifier("second_dialog_button", "id", Fingerprint.packageName);
+        mSecondDialogButton = (Button) v.findViewById(second_dialog_button_id);
+        if (disableBackup) {
+            mSecondDialogButton.setVisibility(View.GONE);
+        }
+        mSecondDialogButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                goToBackup();
+            }
+        });
+        int fingerprint_container_id = getResources()
+                .getIdentifier("fingerprint_container", "id", Fingerprint.packageName);
+        mFingerprintContent = v.findViewById(fingerprint_container_id);
+
+        int new_fingerprint_enrolled_description_id = getResources()
+                .getIdentifier("new_fingerprint_enrolled_description", "id",
+                        Fingerprint.packageName);
+
+        int fingerprint_icon_id = getResources()
+                .getIdentifier("fingerprint_icon", "id", Fingerprint.packageName);
+        int fingerprint_status_id = getResources()
+                .getIdentifier("fingerprint_status", "id", Fingerprint.packageName);
+        mFingerprintUiHelper = mFingerprintUiHelperBuilder.build(
+                (ImageView) v.findViewById(fingerprint_icon_id),
+                (TextView) v.findViewById(fingerprint_status_id), this);
+        updateStage();
+
+        // If fingerprint authentication is not available, switch immediately to the backup
+        // (password) screen.
+        if (!mFingerprintUiHelper.isFingerprintAuthAvailable()) {
+            goToBackup();
+        }
+        return v;
+    }
+
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        if (mStage == Stage.FINGERPRINT) {
+            mFingerprintUiHelper.startListening(mCryptoObject);
+        }
+    }
+
+    public void setStage(Stage stage) {
+        mStage = stage;
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mFingerprintUiHelper.stopListening();
+    }
+
+    /**
+     * Sets the crypto object to be passed in when authenticating with fingerprint.
+     */
+    public void setCryptoObject(FingerprintManager.CryptoObject cryptoObject) {
+        mCryptoObject = cryptoObject;
+    }
+
+    /**
+     * Switches to backup (password) screen. This either can happen when fingerprint is not
+     * available or the user chooses to use the password authentication method by pressing the
+     * button. This can also happen when the user had too many fingerprint attempts.
+     */
+    private void goToBackup() {
+        if(disableBackup)
+        {
+            Fingerprint.onCancelled(); 
+            dismissAllowingStateLoss();
+        }
+        else{
+            mStage = Stage.BACKUP;
+            updateStage();
+        }
+    }
+
+    private void updateStage() {
+        int cancel_id = getResources()
+                .getIdentifier("fingerprint_cancel", "string", Fingerprint.packageName);
+        switch (mStage) {
+            case FINGERPRINT:
+                mCancelButton.setText(cancel_id);
+                int use_backup_id = getResources()
+                        .getIdentifier("fingerprint_use_backup", "string", Fingerprint.packageName);
+                mSecondDialogButton.setText(use_backup_id);
+                mFingerprintContent.setVisibility(View.VISIBLE);
+                break;
+            case NEW_FINGERPRINT_ENROLLED:
+                // Intentional fall through
+            case BACKUP:
+                if (mStage == Stage.NEW_FINGERPRINT_ENROLLED) {
+
+                }
+                if (!mKeyguardManager.isKeyguardSecure()) {
+                    // Show a message that the user hasn't set up a lock screen.
+                    int secure_lock_screen_required_id = getResources()
+                            .getIdentifier("secure_lock_screen_required", "string",
+                                    Fingerprint.packageName);
+                    Toast.makeText(getContext(),
+                            getString(secure_lock_screen_required_id),
+                            Toast.LENGTH_LONG).show();
+                    return;
+                }
+                showAuthenticationScreen();
+                break;
+        }
+    }
+
+    private void showAuthenticationScreen() {
+        // Create the Confirm Credentials screen. You can customize the title and description. Or
+        // we will provide a generic one for you if you leave it null
+        Intent intent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, null);
+        if (intent != null) {
+            startActivityForResult(intent, REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS);
+        }
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) {
+            // Challenge completed, proceed with using cipher
+            if (resultCode == getActivity().RESULT_OK) {
+                Fingerprint.onAuthenticated(false /* used backup */);
+            } else {
+                // The user canceled or didn’t complete the lock screen
+                // operation. Go to error/cancellation flow.
+                Fingerprint.onCancelled();
+            }
+            dismissAllowingStateLoss();
+        }
+    }
+
+    @Override
+    public void onAuthenticated() {
+        // Callback from FingerprintUiHelper. Let the activity know that authentication was
+        // successful.
+        Fingerprint.onAuthenticated(true /* withFingerprint */);
+        dismissAllowingStateLoss();
+    }
+
+    @Override
+    public void onError() {
+        if(this.getActivity() != null)
+            goToBackup();
+    }
+
+    @Override
+    public void onCancel(DialogInterface dialog) {
+        super.onCancel(dialog);
+        Fingerprint.onCancelled();
+    }
+
+    /**
+     * Enumeration to indicate which authentication method the user is trying to authenticate with.
+     */
+    public enum Stage {
+        FINGERPRINT,
+        NEW_FINGERPRINT_ENROLLED,
+        BACKUP
+    }
+}
diff --git a/platforms/android/app/src/main/java/de/niklasmerz/cordova/fingerprint/FingerprintUiHelper.java b/platforms/android/app/src/main/java/de/niklasmerz/cordova/fingerprint/FingerprintUiHelper.java
new file mode 100644
index 0000000..e1402c5
--- /dev/null
+++ b/platforms/android/app/src/main/java/de/niklasmerz/cordova/fingerprint/FingerprintUiHelper.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * Modifications copyright (C) 2016 Niklas Merz
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package de.niklasmerz.cordova.fingerprint;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.CancellationSignal;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+
+/**
+ * Small helper class to manage text/icon around fingerprint authentication UI.
+ */
+@TargetApi(23)
+public class FingerprintUiHelper extends FingerprintManager.AuthenticationCallback {
+
+    static final long ERROR_TIMEOUT_MILLIS = 1600;
+    static final long SUCCESS_DELAY_MILLIS = 1300;
+
+    private final Context mContext;
+    private final FingerprintManager mFingerprintManager;
+    private final ImageView mIcon;
+    private final TextView mErrorTextView;
+    private final Callback mCallback;
+    private CancellationSignal mCancellationSignal;
+
+    boolean mSelfCancelled;
+
+    /**
+     * Builder class for {@link FingerprintUiHelper} in which injected fields from Dagger
+     * holds its fields and takes other arguments in the {@link #build} method.
+     */
+    public static class FingerprintUiHelperBuilder {
+        private final FingerprintManager mFingerPrintManager;
+        private final Context mContext;
+
+        public FingerprintUiHelperBuilder(Context context, FingerprintManager fingerprintManager) {
+            mFingerPrintManager = fingerprintManager;
+            mContext = context;
+        }
+
+        public FingerprintUiHelper build(ImageView icon, TextView errorTextView, Callback callback) {
+            return new FingerprintUiHelper(mContext, mFingerPrintManager, icon, errorTextView,
+                    callback);
+        }
+    }
+
+    /**
+     * Constructor for {@link FingerprintUiHelper}. This method is expected to be called from
+     * only the {@link FingerprintUiHelperBuilder} class.
+     */
+    private FingerprintUiHelper(Context context, FingerprintManager fingerprintManager,
+            ImageView icon, TextView errorTextView, Callback callback) {
+        mFingerprintManager = fingerprintManager;
+        mIcon = icon;
+        mErrorTextView = errorTextView;
+        mCallback = callback;
+        mContext = context;
+    }
+
+    public boolean isFingerprintAuthAvailable() {
+        return mFingerprintManager.isHardwareDetected()
+                && mFingerprintManager.hasEnrolledFingerprints();
+    }
+
+    public void startListening(FingerprintManager.CryptoObject cryptoObject) {
+        if (!isFingerprintAuthAvailable()) {
+            return;
+        }
+        mCancellationSignal = new CancellationSignal();
+        mSelfCancelled = false;
+        mFingerprintManager
+                .authenticate(cryptoObject, mCancellationSignal, 0 /* flags */, this, null);
+
+        int ic_fp_40px_id = mContext.getResources()
+                .getIdentifier("ic_fp_40px", "drawable", Fingerprint.packageName);
+        mIcon.setImageResource(ic_fp_40px_id);
+    }
+
+    public void stopListening() {
+        if (mCancellationSignal != null) {
+            mSelfCancelled = true;
+            mCancellationSignal.cancel();
+            mCancellationSignal = null;
+        }
+    }
+
+    @Override
+    public void onAuthenticationError(int errMsgId, CharSequence errString) {
+        if (!mSelfCancelled) {
+            showError(errString);
+            mIcon.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    mCallback.onError();
+                }
+            }, ERROR_TIMEOUT_MILLIS);
+        }
+    }
+
+    @Override
+    public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
+        showError(helpString);
+    }
+
+    @Override
+    public void onAuthenticationFailed() {
+        int fingerprint_not_recognized_id = mContext.getResources()
+                .getIdentifier("fingerprint_not_recognized", "string", Fingerprint.packageName);
+        showError(mIcon.getResources().getString(
+                fingerprint_not_recognized_id));
+    }
+
+    @Override
+    public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
+        mErrorTextView.removeCallbacks(mResetErrorTextRunnable);
+        int ic_fingerprint_success_id = mContext.getResources()
+                .getIdentifier("ic_fingerprint_success", "drawable", Fingerprint.packageName);
+        mIcon.setImageResource(ic_fingerprint_success_id);
+        int success_color_id = mContext.getResources()
+                .getIdentifier("success_color", "color", Fingerprint.packageName);
+        mErrorTextView.setTextColor(
+                mErrorTextView.getResources().getColor(success_color_id, null));
+        int fingerprint_success_id = mContext.getResources()
+                .getIdentifier("fingerprint_success", "string", Fingerprint.packageName);
+        mErrorTextView.setText(
+                mErrorTextView.getResources().getString(fingerprint_success_id));
+        mIcon.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                mCallback.onAuthenticated();
+            }
+        }, SUCCESS_DELAY_MILLIS);
+    }
+
+    private void showError(CharSequence error) {
+        int ic_fingerprint_error_id = mContext.getResources()
+                .getIdentifier("ic_fingerprint_error", "drawable", Fingerprint.packageName);
+        mIcon.setImageResource(ic_fingerprint_error_id);
+        mErrorTextView.setText(error);
+        int warning_color_id = mContext.getResources()
+                .getIdentifier("warning_color", "color", Fingerprint.packageName);
+        mErrorTextView.setTextColor(
+                mErrorTextView.getResources().getColor(warning_color_id, null));
+        mErrorTextView.removeCallbacks(mResetErrorTextRunnable);
+        mErrorTextView.postDelayed(mResetErrorTextRunnable, ERROR_TIMEOUT_MILLIS);
+    }
+
+    Runnable mResetErrorTextRunnable = new Runnable() {
+        @Override
+        public void run() {
+            int hint_color_id = mContext.getResources()
+                    .getIdentifier("hint_color", "color", Fingerprint.packageName);
+            mErrorTextView.setTextColor(
+                    mErrorTextView.getResources().getColor(hint_color_id, null));
+            int fingerprint_hint_id = mContext.getResources()
+                    .getIdentifier("fingerprint_hint", "string", Fingerprint.packageName);
+            mErrorTextView.setText(
+                    mErrorTextView.getResources().getString(fingerprint_hint_id));
+            int ic_fp_40px_id = mContext.getResources()
+                    .getIdentifier("ic_fp_40px", "drawable", Fingerprint.packageName);
+            mIcon.setImageResource(ic_fp_40px_id);
+        }
+    };
+
+    public interface Callback {
+
+        void onAuthenticated();
+
+        void onError();
+    }
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/camera/CameraLauncher.java b/platforms/android/app/src/main/java/org/apache/cordova/camera/CameraLauncher.java
new file mode 100644
index 0000000..fbe8470
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/camera/CameraLauncher.java
@@ -0,0 +1,1407 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.camera;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.apache.cordova.BuildHelper;
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.CordovaResourceApi;
+import org.apache.cordova.LOG;
+import org.apache.cordova.PermissionHelper;
+import org.apache.cordova.PluginResult;
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import android.Manifest;
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
+import android.media.ExifInterface;
+import android.media.MediaScannerConnection;
+import android.media.MediaScannerConnection.MediaScannerConnectionClient;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.provider.DocumentsContract;
+import android.provider.MediaStore;
+import android.provider.OpenableColumns;
+import android.support.v4.content.FileProvider;
+import android.util.Base64;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+
+/**
+ * This class launches the camera view, allows the user to take a picture, closes the camera view,
+ * and returns the captured image.  When the camera view is closed, the screen displayed before
+ * the camera view was shown is redisplayed.
+ */
+public class CameraLauncher extends CordovaPlugin implements MediaScannerConnectionClient {
+
+    private static final int DATA_URL = 0;              // Return base64 encoded string
+    private static final int FILE_URI = 1;              // Return file uri (content://media/external/images/media/2 for Android)
+    private static final int NATIVE_URI = 2;                    // On Android, this is the same as FILE_URI
+
+    private static final int PHOTOLIBRARY = 0;          // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
+    private static final int CAMERA = 1;                // Take picture from camera
+    private static final int SAVEDPHOTOALBUM = 2;       // Choose image from picture library (same as PHOTOLIBRARY for Android)
+
+    private static final int PICTURE = 0;               // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
+    private static final int VIDEO = 1;                 // allow selection of video only, ONLY RETURNS URL
+    private static final int ALLMEDIA = 2;              // allow selection from all media types
+
+    private static final int JPEG = 0;                  // Take a picture of type JPEG
+    private static final int PNG = 1;                   // Take a picture of type PNG
+    private static final String GET_PICTURE = "Get Picture";
+    private static final String GET_VIDEO = "Get Video";
+    private static final String GET_All = "Get All";
+
+    public static final int PERMISSION_DENIED_ERROR = 20;
+    public static final int TAKE_PIC_SEC = 0;
+    public static final int SAVE_TO_ALBUM_SEC = 1;
+
+    private static final String LOG_TAG = "CameraLauncher";
+
+    //Where did this come from?
+    private static final int CROP_CAMERA = 100;
+
+    private int mQuality;                   // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
+    private int targetWidth;                // desired width of the image
+    private int targetHeight;               // desired height of the image
+    private CordovaUri imageUri;            // Uri of captured image
+    private int encodingType;               // Type of encoding to use
+    private int mediaType;                  // What type of media to retrieve
+    private int destType;                   // Source type (needs to be saved for the permission handling)
+    private int srcType;                    // Destination type (needs to be saved for permission handling)
+    private boolean saveToPhotoAlbum;       // Should the picture be saved to the device's photo album
+    private boolean correctOrientation;     // Should the pictures orientation be corrected
+    private boolean orientationCorrected;   // Has the picture's orientation been corrected
+    private boolean allowEdit;              // Should we allow the user to crop the image.
+
+    protected final static String[] permissions = { Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE };
+
+    public CallbackContext callbackContext;
+    private int numPics;
+
+    private MediaScannerConnection conn;    // Used to update gallery app with newly-written files
+    private Uri scanMe;                     // Uri of image to be added to content store
+    private Uri croppedUri;
+    private ExifHelper exifData;            // Exif data from source
+    private String applicationId;
+
+
+    /**
+     * Executes the request and returns PluginResult.
+     *
+     * @param action            The action to execute.
+     * @param args              JSONArry of arguments for the plugin.
+     * @param callbackContext   The callback id used when calling back into JavaScript.
+     * @return                  A PluginResult object with a status and message.
+     */
+    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
+        this.callbackContext = callbackContext;
+        //Adding an API to CoreAndroid to get the BuildConfigValue
+        //This allows us to not make this a breaking change to embedding
+        this.applicationId = (String) BuildHelper.getBuildConfigValue(cordova.getActivity(), "APPLICATION_ID");
+        this.applicationId = preferences.getString("applicationId", this.applicationId);
+
+
+        if (action.equals("takePicture")) {
+            this.srcType = CAMERA;
+            this.destType = FILE_URI;
+            this.saveToPhotoAlbum = false;
+            this.targetHeight = 0;
+            this.targetWidth = 0;
+            this.encodingType = JPEG;
+            this.mediaType = PICTURE;
+            this.mQuality = 50;
+
+            //Take the values from the arguments if they're not already defined (this is tricky)
+            this.destType = args.getInt(1);
+            this.srcType = args.getInt(2);
+            this.mQuality = args.getInt(0);
+            this.targetWidth = args.getInt(3);
+            this.targetHeight = args.getInt(4);
+            this.encodingType = args.getInt(5);
+            this.mediaType = args.getInt(6);
+            this.allowEdit = args.getBoolean(7);
+            this.correctOrientation = args.getBoolean(8);
+            this.saveToPhotoAlbum = args.getBoolean(9);
+
+            // If the user specifies a 0 or smaller width/height
+            // make it -1 so later comparisons succeed
+            if (this.targetWidth < 1) {
+                this.targetWidth = -1;
+            }
+            if (this.targetHeight < 1) {
+                this.targetHeight = -1;
+            }
+
+            // We don't return full-quality PNG files. The camera outputs a JPEG
+            // so requesting it as a PNG provides no actual benefit
+            if (this.targetHeight == -1 && this.targetWidth == -1 && this.mQuality == 100 &&
+                    !this.correctOrientation && this.encodingType == PNG && this.srcType == CAMERA) {
+                this.encodingType = JPEG;
+            }
+
+            try {
+                if (this.srcType == CAMERA) {
+                    this.callTakePicture(destType, encodingType);
+                }
+                else if ((this.srcType == PHOTOLIBRARY) || (this.srcType == SAVEDPHOTOALBUM)) {
+                    // FIXME: Stop always requesting the permission
+                    if(!PermissionHelper.hasPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
+                        PermissionHelper.requestPermission(this, SAVE_TO_ALBUM_SEC, Manifest.permission.READ_EXTERNAL_STORAGE);
+                    } else {
+                        this.getImage(this.srcType, destType, encodingType);
+                    }
+                }
+            }
+            catch (IllegalArgumentException e)
+            {
+                callbackContext.error("Illegal Argument Exception");
+                PluginResult r = new PluginResult(PluginResult.Status.ERROR);
+                callbackContext.sendPluginResult(r);
+                return true;
+            }
+
+            PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
+            r.setKeepCallback(true);
+            callbackContext.sendPluginResult(r);
+
+            return true;
+        }
+        return false;
+    }
+
+    //--------------------------------------------------------------------------
+    // LOCAL METHODS
+    //--------------------------------------------------------------------------
+
+    private String getTempDirectoryPath() {
+        File cache = null;
+
+        // SD Card Mounted
+        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+            cache = cordova.getActivity().getExternalCacheDir();
+        }
+        // Use internal storage
+        else {
+            cache = cordova.getActivity().getCacheDir();
+        }
+
+        // Create the cache directory if it doesn't exist
+        cache.mkdirs();
+        return cache.getAbsolutePath();
+    }
+
+    /**
+     * Take a picture with the camera.
+     * When an image is captured or the camera view is cancelled, the result is returned
+     * in CordovaActivity.onActivityResult, which forwards the result to this.onActivityResult.
+     *
+     * The image can either be returned as a base64 string or a URI that points to the file.
+     * To display base64 string in an img tag, set the source to:
+     *      img.src="data:image/jpeg;base64,"+result;
+     * or to display URI in an img tag
+     *      img.src=result;
+     *
+     * @param returnType        Set the type of image to return.
+     * @param encodingType           Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
+     */
+    public void callTakePicture(int returnType, int encodingType) {
+        boolean saveAlbumPermission = PermissionHelper.hasPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
+                && PermissionHelper.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
+        boolean takePicturePermission = PermissionHelper.hasPermission(this, Manifest.permission.CAMERA);
+
+        // CB-10120: The CAMERA permission does not need to be requested unless it is declared
+        // in AndroidManifest.xml. This plugin does not declare it, but others may and so we must
+        // check the package info to determine if the permission is present.
+
+        if (!takePicturePermission) {
+            takePicturePermission = true;
+            try {
+                PackageManager packageManager = this.cordova.getActivity().getPackageManager();
+                String[] permissionsInPackage = packageManager.getPackageInfo(this.cordova.getActivity().getPackageName(), PackageManager.GET_PERMISSIONS).requestedPermissions;
+                if (permissionsInPackage != null) {
+                    for (String permission : permissionsInPackage) {
+                        if (permission.equals(Manifest.permission.CAMERA)) {
+                            takePicturePermission = false;
+                            break;
+                        }
+                    }
+                }
+            } catch (NameNotFoundException e) {
+                // We are requesting the info for our package, so this should
+                // never be caught
+            }
+        }
+
+        if (takePicturePermission && saveAlbumPermission) {
+            takePicture(returnType, encodingType);
+        } else if (saveAlbumPermission && !takePicturePermission) {
+            PermissionHelper.requestPermission(this, TAKE_PIC_SEC, Manifest.permission.CAMERA);
+        } else if (!saveAlbumPermission && takePicturePermission) {
+            PermissionHelper.requestPermissions(this, TAKE_PIC_SEC,
+                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE});
+        } else {
+            PermissionHelper.requestPermissions(this, TAKE_PIC_SEC, permissions);
+        }
+    }
+
+    public void takePicture(int returnType, int encodingType)
+    {
+        // Save the number of images currently on disk for later
+        this.numPics = queryImgDB(whichContentStore()).getCount();
+
+        // Let's use the intent and see what happens
+        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+
+        // Specify file so that large image is captured and returned
+        File photo = createCaptureFile(encodingType);
+        this.imageUri = new CordovaUri(FileProvider.getUriForFile(cordova.getActivity(),
+                applicationId + ".provider",
+                photo));
+        intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageUri.getCorrectUri());
+        //We can write to this URI, this will hopefully allow us to write files to get to the next step
+        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
+        if (this.cordova != null) {
+            // Let's check to make sure the camera is actually installed. (Legacy Nexus 7 code)
+            PackageManager mPm = this.cordova.getActivity().getPackageManager();
+            if(intent.resolveActivity(mPm) != null)
+            {
+
+                this.cordova.startActivityForResult((CordovaPlugin) this, intent, (CAMERA + 1) * 16 + returnType + 1);
+            }
+            else
+            {
+                LOG.d(LOG_TAG, "Error: You don't have a default camera.  Your device may not be CTS complaint.");
+            }
+        }
+//        else
+//            LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity");
+    }
+
+    /**
+     * Create a file in the applications temporary directory based upon the supplied encoding.
+     *
+     * @param encodingType of the image to be taken
+     * @return a File object pointing to the temporary picture
+     */
+    private File createCaptureFile(int encodingType) {
+        return createCaptureFile(encodingType, "");
+    }
+
+    /**
+     * Create a file in the applications temporary directory based upon the supplied encoding.
+     *
+     * @param encodingType of the image to be taken
+     * @param fileName or resultant File object.
+     * @return a File object pointing to the temporary picture
+     */
+    private File createCaptureFile(int encodingType, String fileName) {
+        if (fileName.isEmpty()) {
+            fileName = ".Pic";
+        }
+
+        if (encodingType == JPEG) {
+            fileName = fileName + ".jpg";
+        } else if (encodingType == PNG) {
+            fileName = fileName + ".png";
+        } else {
+            throw new IllegalArgumentException("Invalid Encoding Type: " + encodingType);
+        }
+
+        return new File(getTempDirectoryPath(), fileName);
+    }
+
+
+
+    /**
+     * Get image from photo library.
+     *
+     * @param srcType           The album to get image from.
+     * @param returnType        Set the type of image to return.
+     * @param encodingType
+     */
+    // TODO: Images selected from SDCARD don't display correctly, but from CAMERA ALBUM do!
+    // TODO: Images from kitkat filechooser not going into crop function
+    public void getImage(int srcType, int returnType, int encodingType) {
+        Intent intent = new Intent();
+        String title = GET_PICTURE;
+        croppedUri = null;
+        if (this.mediaType == PICTURE) {
+            intent.setType("image/*");
+            if (this.allowEdit) {
+                intent.setAction(Intent.ACTION_PICK);
+                intent.putExtra("crop", "true");
+                if (targetWidth > 0) {
+                    intent.putExtra("outputX", targetWidth);
+                }
+                if (targetHeight > 0) {
+                    intent.putExtra("outputY", targetHeight);
+                }
+                if (targetHeight > 0 && targetWidth > 0 && targetWidth == targetHeight) {
+                    intent.putExtra("aspectX", 1);
+                    intent.putExtra("aspectY", 1);
+                }
+                File photo = createCaptureFile(JPEG);
+                croppedUri = Uri.fromFile(photo);
+                intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, croppedUri);
+            } else {
+                intent.setAction(Intent.ACTION_GET_CONTENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
+            }
+        } else if (this.mediaType == VIDEO) {
+            intent.setType("video/*");
+            title = GET_VIDEO;
+            intent.setAction(Intent.ACTION_GET_CONTENT);
+            intent.addCategory(Intent.CATEGORY_OPENABLE);
+        } else if (this.mediaType == ALLMEDIA) {
+            // I wanted to make the type 'image/*, video/*' but this does not work on all versions
+            // of android so I had to go with the wildcard search.
+            intent.setType("*/*");
+            title = GET_All;
+            intent.setAction(Intent.ACTION_GET_CONTENT);
+            intent.addCategory(Intent.CATEGORY_OPENABLE);
+        }
+        if (this.cordova != null) {
+            this.cordova.startActivityForResult((CordovaPlugin) this, Intent.createChooser(intent,
+                    new String(title)), (srcType + 1) * 16 + returnType + 1);
+        }
+    }
+
+
+  /**
+   * Brings up the UI to perform crop on passed image URI
+   *
+   * @param picUri
+   */
+  private void performCrop(Uri picUri, int destType, Intent cameraIntent) {
+    try {
+        Intent cropIntent = new Intent("com.android.camera.action.CROP");
+        // indicate image type and Uri
+        cropIntent.setDataAndType(picUri, "image/*");
+        // set crop properties
+        cropIntent.putExtra("crop", "true");
+
+
+        // indicate output X and Y
+        if (targetWidth > 0) {
+          cropIntent.putExtra("outputX", targetWidth);
+        }
+        if (targetHeight > 0) {
+          cropIntent.putExtra("outputY", targetHeight);
+        }
+        if (targetHeight > 0 && targetWidth > 0 && targetWidth == targetHeight) {
+          cropIntent.putExtra("aspectX", 1);
+          cropIntent.putExtra("aspectY", 1);
+        }
+        // create new file handle to get full resolution crop
+        croppedUri = Uri.fromFile(createCaptureFile(this.encodingType, System.currentTimeMillis() + ""));
+        cropIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        cropIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+        cropIntent.putExtra("output", croppedUri);
+
+
+        // start the activity - we handle returning in onActivityResult
+
+        if (this.cordova != null) {
+            this.cordova.startActivityForResult((CordovaPlugin) this,
+                cropIntent, CROP_CAMERA + destType);
+        }
+    } catch (ActivityNotFoundException anfe) {
+      LOG.e(LOG_TAG, "Crop operation not supported on this device");
+      try {
+          processResultFromCamera(destType, cameraIntent);
+      }
+      catch (IOException e)
+      {
+          e.printStackTrace();
+          LOG.e(LOG_TAG, "Unable to write to file");
+      }
+    }
+  }
+
+    /**
+     * Applies all needed transformation to the image received from the camera.
+     *
+     * @param destType          In which form should we return the image
+     * @param intent            An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
+     */
+    private void processResultFromCamera(int destType, Intent intent) throws IOException {
+        int rotate = 0;
+
+        // Create an ExifHelper to save the exif data that is lost during compression
+        ExifHelper exif = new ExifHelper();
+
+        String sourcePath = (this.allowEdit && this.croppedUri != null) ?
+                FileHelper.stripFileProtocol(this.croppedUri.toString()) :
+                this.imageUri.getFilePath();
+
+
+        if (this.encodingType == JPEG) {
+            try {
+                //We don't support PNG, so let's not pretend we do
+                exif.createInFile(sourcePath);
+                exif.readExifData();
+                rotate = exif.getOrientation();
+
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+
+        Bitmap bitmap = null;
+        Uri galleryUri = null;
+
+        // CB-5479 When this option is given the unchanged image should be saved
+        // in the gallery and the modified image is saved in the temporary
+        // directory
+        if (this.saveToPhotoAlbum) {
+            galleryUri = Uri.fromFile(new File(getPicturesPath()));
+
+            if (this.allowEdit && this.croppedUri != null) {
+                writeUncompressedImage(croppedUri, galleryUri);
+            } else {
+                Uri imageUri = this.imageUri.getFileUri();
+                writeUncompressedImage(imageUri, galleryUri);
+            }
+
+            refreshGallery(galleryUri);
+        }
+
+        // If sending base64 image back
+        if (destType == DATA_URL) {
+            bitmap = getScaledAndRotatedBitmap(sourcePath);
+
+            if (bitmap == null) {
+                // Try to get the bitmap from intent.
+                bitmap = (Bitmap) intent.getExtras().get("data");
+            }
+
+            // Double-check the bitmap.
+            if (bitmap == null) {
+                LOG.d(LOG_TAG, "I either have a null image path or bitmap");
+                this.failPicture("Unable to create bitmap!");
+                return;
+            }
+
+
+            this.processPicture(bitmap, this.encodingType);
+
+            if (!this.saveToPhotoAlbum) {
+                checkForDuplicateImage(DATA_URL);
+            }
+        }
+
+        // If sending filename back
+        else if (destType == FILE_URI || destType == NATIVE_URI) {
+            // If all this is true we shouldn't compress the image.
+            if (this.targetHeight == -1 && this.targetWidth == -1 && this.mQuality == 100 &&
+                    !this.correctOrientation) {
+
+                // If we saved the uncompressed photo to the album, we can just
+                // return the URI we already created
+                if (this.saveToPhotoAlbum) {
+                    this.callbackContext.success(galleryUri.toString());
+                } else {
+                    Uri uri = Uri.fromFile(createCaptureFile(this.encodingType, System.currentTimeMillis() + ""));
+
+                    if (this.allowEdit && this.croppedUri != null) {
+                        Uri croppedUri = Uri.fromFile(new File(getFileNameFromUri(this.croppedUri)));
+                        writeUncompressedImage(croppedUri, uri);
+                    } else {
+                        Uri imageUri = this.imageUri.getFileUri();
+                        writeUncompressedImage(imageUri, uri);
+                    }
+
+                    this.callbackContext.success(uri.toString());
+                }
+            } else {
+                Uri uri = Uri.fromFile(createCaptureFile(this.encodingType, System.currentTimeMillis() + ""));
+                bitmap = getScaledAndRotatedBitmap(sourcePath);
+
+                // Double-check the bitmap.
+                if (bitmap == null) {
+                    LOG.d(LOG_TAG, "I either have a null image path or bitmap");
+                    this.failPicture("Unable to create bitmap!");
+                    return;
+                }
+
+
+                // Add compressed version of captured image to returned media store Uri
+                OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
+                CompressFormat compressFormat = encodingType == JPEG ?
+                        CompressFormat.JPEG :
+                        CompressFormat.PNG;
+
+                bitmap.compress(compressFormat, this.mQuality, os);
+                os.close();
+
+                // Restore exif data to file
+                if (this.encodingType == JPEG) {
+                    String exifPath;
+                    exifPath = uri.getPath();
+                    //We just finished rotating it by an arbitrary orientation, just make sure it's normal
+                    if(rotate != ExifInterface.ORIENTATION_NORMAL)
+                        exif.resetOrientation();
+                    exif.createOutFile(exifPath);
+                    exif.writeExifData();
+                }
+
+                // Send Uri back to JavaScript for viewing image
+                this.callbackContext.success(uri.toString());
+
+            }
+        } else {
+            throw new IllegalStateException();
+        }
+
+        this.cleanup(FILE_URI, this.imageUri.getFileUri(), galleryUri, bitmap);
+        bitmap = null;
+    }
+
+    private String getPicturesPath() {
+        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
+        String imageFileName = "IMG_" + timeStamp + (this.encodingType == JPEG ? ".jpg" : ".png");
+        File storageDir = Environment.getExternalStoragePublicDirectory(
+                Environment.DIRECTORY_PICTURES);
+        storageDir.mkdirs();
+        String galleryPath = storageDir.getAbsolutePath() + "/" + imageFileName;
+        return galleryPath;
+    }
+
+    private void refreshGallery(Uri contentUri) {
+        Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+        mediaScanIntent.setData(contentUri);
+        this.cordova.getActivity().sendBroadcast(mediaScanIntent);
+    }
+
+    /**
+     * Converts output image format int value to string value of mime type.
+     * @param outputFormat int Output format of camera API.
+     *                     Must be value of either JPEG or PNG constant
+     * @return String String value of mime type or empty string if mime type is not supported
+     */
+    private String getMimetypeForFormat(int outputFormat) {
+        if (outputFormat == PNG) return "image/png";
+        if (outputFormat == JPEG) return "image/jpeg";
+        return "";
+    }
+
+
+    private String outputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
+        // Some content: URIs do not map to file paths (e.g. picasa).
+        String realPath = FileHelper.getRealPath(uri, this.cordova);
+
+        // Get filename from uri
+        String fileName = realPath != null ?
+                realPath.substring(realPath.lastIndexOf('/') + 1) :
+                "modified." + (this.encodingType == JPEG ? "jpg" : "png");
+
+        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
+        //String fileName = "IMG_" + timeStamp + (this.encodingType == JPEG ? ".jpg" : ".png");
+        String modifiedPath = getTempDirectoryPath() + "/" + fileName;
+
+        OutputStream os = new FileOutputStream(modifiedPath);
+        CompressFormat compressFormat = this.encodingType == JPEG ?
+                CompressFormat.JPEG :
+                CompressFormat.PNG;
+
+        bitmap.compress(compressFormat, this.mQuality, os);
+        os.close();
+
+        if (exifData != null && this.encodingType == JPEG) {
+            try {
+                if (this.correctOrientation && this.orientationCorrected) {
+                    exifData.resetOrientation();
+                }
+                exifData.createOutFile(modifiedPath);
+                exifData.writeExifData();
+                exifData = null;
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return modifiedPath;
+    }
+
+
+    /**
+     * Applies all needed transformation to the image received from the gallery.
+     *
+     * @param destType In which form should we return the image
+     * @param intent   An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
+     */
+    private void processResultFromGallery(int destType, Intent intent) {
+        Uri uri = intent.getData();
+        if (uri == null) {
+            if (croppedUri != null) {
+                uri = croppedUri;
+            } else {
+                this.failPicture("null data from photo library");
+                return;
+            }
+        }
+        int rotate = 0;
+
+        String fileLocation = FileHelper.getRealPath(uri, this.cordova);
+        LOG.d(LOG_TAG, "File locaton is: " + fileLocation);
+
+        // If you ask for video or all media type you will automatically get back a file URI
+        // and there will be no attempt to resize any returned data
+        if (this.mediaType != PICTURE) {
+            this.callbackContext.success(fileLocation);
+        }
+        else {
+            String uriString = uri.toString();
+            // Get the path to the image. Makes loading so much easier.
+            String mimeType = FileHelper.getMimeType(uriString, this.cordova);
+
+            // This is a special case to just return the path as no scaling,
+            // rotating, nor compressing needs to be done
+            if (this.targetHeight == -1 && this.targetWidth == -1 &&
+                    (destType == FILE_URI || destType == NATIVE_URI) && !this.correctOrientation &&
+                    mimeType.equalsIgnoreCase(getMimetypeForFormat(encodingType)))
+            {
+                this.callbackContext.success(uriString);
+            } else {
+                // If we don't have a valid image so quit.
+                if (!("image/jpeg".equalsIgnoreCase(mimeType) || "image/png".equalsIgnoreCase(mimeType))) {
+                    LOG.d(LOG_TAG, "I either have a null image path or bitmap");
+                    this.failPicture("Unable to retrieve path to picture!");
+                    return;
+                }
+                Bitmap bitmap = null;
+                try {
+                    bitmap = getScaledAndRotatedBitmap(uriString);
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+                if (bitmap == null) {
+                    LOG.d(LOG_TAG, "I either have a null image path or bitmap");
+                    this.failPicture("Unable to create bitmap!");
+                    return;
+                }
+
+                // If sending base64 image back
+                if (destType == DATA_URL) {
+                    this.processPicture(bitmap, this.encodingType);
+                }
+
+                // If sending filename back
+                else if (destType == FILE_URI || destType == NATIVE_URI) {
+                    // Did we modify the image?
+                    if ( (this.targetHeight > 0 && this.targetWidth > 0) ||
+                            (this.correctOrientation && this.orientationCorrected) ||
+                            !mimeType.equalsIgnoreCase(getMimetypeForFormat(encodingType)))
+                    {
+                        try {
+                            String modifiedPath = this.outputModifiedBitmap(bitmap, uri);
+                            // The modified image is cached by the app in order to get around this and not have to delete you
+                            // application cache I'm adding the current system time to the end of the file url.
+                            this.callbackContext.success("file://" + modifiedPath + "?" + System.currentTimeMillis());
+
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                            this.failPicture("Error retrieving image.");
+                        }
+                    } else {
+                        this.callbackContext.success(fileLocation);
+                    }
+                }
+                if (bitmap != null) {
+                    bitmap.recycle();
+                    bitmap = null;
+                }
+                System.gc();
+            }
+        }
+    }
+
+    /**
+     * Called when the camera view exits.
+     *
+     * @param requestCode The request code originally supplied to startActivityForResult(),
+     *                    allowing you to identify who this result came from.
+     * @param resultCode  The integer result code returned by the child activity through its setResult().
+     * @param intent      An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
+     */
+    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+
+        // Get src and dest types from request code for a Camera Activity
+        int srcType = (requestCode / 16) - 1;
+        int destType = (requestCode % 16) - 1;
+
+        // If Camera Crop
+        if (requestCode >= CROP_CAMERA) {
+            if (resultCode == Activity.RESULT_OK) {
+
+                // Because of the inability to pass through multiple intents, this hack will allow us
+                // to pass arcane codes back.
+                destType = requestCode - CROP_CAMERA;
+                try {
+                    processResultFromCamera(destType, intent);
+                } catch (IOException e) {
+                    e.printStackTrace();
+                    LOG.e(LOG_TAG, "Unable to write to file");
+                }
+
+            }// If cancelled
+            else if (resultCode == Activity.RESULT_CANCELED) {
+                this.failPicture("No Image Selected");
+            }
+
+            // If something else
+            else {
+                this.failPicture("Did not complete!");
+            }
+        }
+        // If CAMERA
+        else if (srcType == CAMERA) {
+            // If image available
+            if (resultCode == Activity.RESULT_OK) {
+                try {
+                    if (this.allowEdit) {
+                        Uri tmpFile = FileProvider.getUriForFile(cordova.getActivity(),
+                                applicationId + ".provider",
+                                createCaptureFile(this.encodingType));
+                        performCrop(tmpFile, destType, intent);
+                    } else {
+                        this.processResultFromCamera(destType, intent);
+                    }
+                } catch (IOException e) {
+                    e.printStackTrace();
+                    this.failPicture("Error capturing image.");
+                }
+            }
+
+            // If cancelled
+            else if (resultCode == Activity.RESULT_CANCELED) {
+                this.failPicture("No Image Selected");
+            }
+
+            // If something else
+            else {
+                this.failPicture("Did not complete!");
+            }
+        }
+        // If retrieving photo from library
+        else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
+            if (resultCode == Activity.RESULT_OK && intent != null) {
+                final Intent i = intent;
+                final int finalDestType = destType;
+                cordova.getThreadPool().execute(new Runnable() {
+                    public void run() {
+                        processResultFromGallery(finalDestType, i);
+                    }
+                });
+            } else if (resultCode == Activity.RESULT_CANCELED) {
+                this.failPicture("No Image Selected");
+            } else {
+                this.failPicture("Selection did not complete!");
+            }
+        }
+    }
+
+    private int exifToDegrees(int exifOrientation) {
+        if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) {
+            return 90;
+        } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {
+            return 180;
+        } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {
+            return 270;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Write an inputstream to local disk
+     *
+     * @param fis - The InputStream to write
+     * @param dest - Destination on disk to write to
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    private void writeUncompressedImage(InputStream fis, Uri dest) throws FileNotFoundException,
+            IOException {
+        OutputStream os = null;
+        try {
+            os = this.cordova.getActivity().getContentResolver().openOutputStream(dest);
+            byte[] buffer = new byte[4096];
+            int len;
+            while ((len = fis.read(buffer)) != -1) {
+                os.write(buffer, 0, len);
+            }
+            os.flush();
+        } finally {
+            if (os != null) {
+                try {
+                    os.close();
+                } catch (IOException e) {
+                    LOG.d(LOG_TAG, "Exception while closing output stream.");
+                }
+            }
+            if (fis != null) {
+                try {
+                    fis.close();
+                } catch (IOException e) {
+                    LOG.d(LOG_TAG, "Exception while closing file input stream.");
+                }
+            }
+        }
+    }
+    /**
+     * In the special case where the default width, height and quality are unchanged
+     * we just write the file out to disk saving the expensive Bitmap.compress function.
+     *
+     * @param src
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    private void writeUncompressedImage(Uri src, Uri dest) throws FileNotFoundException,
+            IOException {
+
+        FileInputStream fis = new FileInputStream(FileHelper.stripFileProtocol(src.toString()));
+        writeUncompressedImage(fis, dest);
+
+    }
+
+    /**
+     * Create entry in media store for image
+     *
+     * @return uri
+     */
+    private Uri getUriFromMediaStore() {
+        ContentValues values = new ContentValues();
+        values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
+        Uri uri;
+        try {
+            uri = this.cordova.getActivity().getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
+        } catch (RuntimeException e) {
+            LOG.d(LOG_TAG, "Can't write to external media storage.");
+            try {
+                uri = this.cordova.getActivity().getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
+            } catch (RuntimeException ex) {
+                LOG.d(LOG_TAG, "Can't write to internal media storage.");
+                return null;
+            }
+        }
+        return uri;
+    }
+
+    /**
+     * Return a scaled and rotated bitmap based on the target width and height
+     *
+     * @param imageUrl
+     * @return
+     * @throws IOException
+     */
+    private Bitmap getScaledAndRotatedBitmap(String imageUrl) throws IOException {
+        // If no new width or height were specified, and orientation is not needed return the original bitmap
+        if (this.targetWidth <= 0 && this.targetHeight <= 0 && !(this.correctOrientation)) {
+            InputStream fileStream = null;
+            Bitmap image = null;
+            try {
+                fileStream = FileHelper.getInputStreamFromUriString(imageUrl, cordova);
+                image = BitmapFactory.decodeStream(fileStream);
+            }  catch (OutOfMemoryError e) {
+                callbackContext.error(e.getLocalizedMessage());
+            } catch (Exception e){
+                callbackContext.error(e.getLocalizedMessage());
+            }
+            finally {
+                if (fileStream != null) {
+                    try {
+                        fileStream.close();
+                    } catch (IOException e) {
+                        LOG.d(LOG_TAG, "Exception while closing file input stream.");
+                    }
+                }
+            }
+            return image;
+        }
+
+
+        /*  Copy the inputstream to a temporary file on the device.
+            We then use this temporary file to determine the width/height/orientation.
+            This is the only way to determine the orientation of the photo coming from 3rd party providers (Google Drive, Dropbox,etc)
+            This also ensures we create a scaled bitmap with the correct orientation
+
+             We delete the temporary file once we are done
+         */
+        File localFile = null;
+        Uri galleryUri = null;
+        int rotate = 0;
+        try {
+            InputStream fileStream = FileHelper.getInputStreamFromUriString(imageUrl, cordova);
+            if (fileStream != null) {
+                // Generate a temporary file
+                String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
+                String fileName = "IMG_" + timeStamp + (this.encodingType == JPEG ? ".jpg" : ".png");
+                localFile = new File(getTempDirectoryPath() + fileName);
+                galleryUri = Uri.fromFile(localFile);
+                writeUncompressedImage(fileStream, galleryUri);
+                try {
+                    String mimeType = FileHelper.getMimeType(imageUrl.toString(), cordova);
+                    if ("image/jpeg".equalsIgnoreCase(mimeType)) {
+                        //  ExifInterface doesn't like the file:// prefix
+                        String filePath = galleryUri.toString().replace("file://", "");
+                        // read exifData of source
+                        exifData = new ExifHelper();
+                        exifData.createInFile(filePath);
+                        // Use ExifInterface to pull rotation information
+                        if (this.correctOrientation) {
+                            ExifInterface exif = new ExifInterface(filePath);
+                            rotate = exifToDegrees(exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED));
+                        }
+                    }
+                } catch (Exception oe) {
+                    LOG.w(LOG_TAG,"Unable to read Exif data: "+ oe.toString());
+                    rotate = 0;
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            LOG.e(LOG_TAG,"Exception while getting input stream: "+ e.toString());
+            return null;
+        }
+
+
+
+        try {
+            // figure out the original width and height of the image
+            BitmapFactory.Options options = new BitmapFactory.Options();
+            options.inJustDecodeBounds = true;
+            InputStream fileStream = null;
+            try {
+                fileStream = FileHelper.getInputStreamFromUriString(galleryUri.toString(), cordova);
+                BitmapFactory.decodeStream(fileStream, null, options);
+            } finally {
+                if (fileStream != null) {
+                    try {
+                        fileStream.close();
+                    } catch (IOException e) {
+                        LOG.d(LOG_TAG, "Exception while closing file input stream.");
+                    }
+                }
+            }
+
+
+            //CB-2292: WTF? Why is the width null?
+            if (options.outWidth == 0 || options.outHeight == 0) {
+                return null;
+            }
+
+            // User didn't specify output dimensions, but they need orientation
+            if (this.targetWidth <= 0 && this.targetHeight <= 0) {
+                this.targetWidth = options.outWidth;
+                this.targetHeight = options.outHeight;
+            }
+
+            // Setup target width/height based on orientation
+            int rotatedWidth, rotatedHeight;
+            boolean rotated= false;
+            if (rotate == 90 || rotate == 270) {
+                rotatedWidth = options.outHeight;
+                rotatedHeight = options.outWidth;
+                rotated = true;
+            } else {
+                rotatedWidth = options.outWidth;
+                rotatedHeight = options.outHeight;
+            }
+
+            // determine the correct aspect ratio
+            int[] widthHeight = calculateAspectRatio(rotatedWidth, rotatedHeight);
+
+
+            // Load in the smallest bitmap possible that is closest to the size we want
+            options.inJustDecodeBounds = false;
+            options.inSampleSize = calculateSampleSize(rotatedWidth, rotatedHeight,  widthHeight[0], widthHeight[1]);
+            Bitmap unscaledBitmap = null;
+            try {
+                fileStream = FileHelper.getInputStreamFromUriString(galleryUri.toString(), cordova);
+                unscaledBitmap = BitmapFactory.decodeStream(fileStream, null, options);
+            } finally {
+                if (fileStream != null) {
+                    try {
+                        fileStream.close();
+                    } catch (IOException e) {
+                        LOG.d(LOG_TAG, "Exception while closing file input stream.");
+                    }
+                }
+            }
+            if (unscaledBitmap == null) {
+                return null;
+            }
+
+            int scaledWidth = (!rotated) ? widthHeight[0] : widthHeight[1];
+            int scaledHeight = (!rotated) ? widthHeight[1] : widthHeight[0];
+
+            Bitmap scaledBitmap = Bitmap.createScaledBitmap(unscaledBitmap, scaledWidth, scaledHeight, true);
+            if (scaledBitmap != unscaledBitmap) {
+                unscaledBitmap.recycle();
+                unscaledBitmap = null;
+            }
+            if (this.correctOrientation && (rotate != 0)) {
+                Matrix matrix = new Matrix();
+                matrix.setRotate(rotate);
+                try {
+                    scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
+                    this.orientationCorrected = true;
+                } catch (OutOfMemoryError oom) {
+                    this.orientationCorrected = false;
+                }
+            }
+            return scaledBitmap;
+        }
+        finally {
+            // delete the temporary copy
+            if (localFile != null) {
+                localFile.delete();
+            }
+        }
+
+    }
+
+    /**
+     * Maintain the aspect ratio so the resulting image does not look smooshed
+     *
+     * @param origWidth
+     * @param origHeight
+     * @return
+     */
+    public int[] calculateAspectRatio(int origWidth, int origHeight) {
+        int newWidth = this.targetWidth;
+        int newHeight = this.targetHeight;
+
+        // If no new width or height were specified return the original bitmap
+        if (newWidth <= 0 && newHeight <= 0) {
+            newWidth = origWidth;
+            newHeight = origHeight;
+        }
+        // Only the width was specified
+        else if (newWidth > 0 && newHeight <= 0) {
+            newHeight = (int)((double)(newWidth / (double)origWidth) * origHeight);
+        }
+        // only the height was specified
+        else if (newWidth <= 0 && newHeight > 0) {
+            newWidth = (int)((double)(newHeight / (double)origHeight) * origWidth);
+        }
+        // If the user specified both a positive width and height
+        // (potentially different aspect ratio) then the width or height is
+        // scaled so that the image fits while maintaining aspect ratio.
+        // Alternatively, the specified width and height could have been
+        // kept and Bitmap.SCALE_TO_FIT specified when scaling, but this
+        // would result in whitespace in the new image.
+        else {
+            double newRatio = newWidth / (double) newHeight;
+            double origRatio = origWidth / (double) origHeight;
+
+            if (origRatio > newRatio) {
+                newHeight = (newWidth * origHeight) / origWidth;
+            } else if (origRatio < newRatio) {
+                newWidth = (newHeight * origWidth) / origHeight;
+            }
+        }
+
+        int[] retval = new int[2];
+        retval[0] = newWidth;
+        retval[1] = newHeight;
+        return retval;
+    }
+
+    /**
+     * Figure out what ratio we can load our image into memory at while still being bigger than
+     * our desired width and height
+     *
+     * @param srcWidth
+     * @param srcHeight
+     * @param dstWidth
+     * @param dstHeight
+     * @return
+     */
+    public static int calculateSampleSize(int srcWidth, int srcHeight, int dstWidth, int dstHeight) {
+        final float srcAspect = (float) srcWidth / (float) srcHeight;
+        final float dstAspect = (float) dstWidth / (float) dstHeight;
+
+        if (srcAspect > dstAspect) {
+            return srcWidth / dstWidth;
+        } else {
+            return srcHeight / dstHeight;
+        }
+    }
+
+    /**
+     * Creates a cursor that can be used to determine how many images we have.
+     *
+     * @return a cursor
+     */
+    private Cursor queryImgDB(Uri contentStore) {
+        return this.cordova.getActivity().getContentResolver().query(
+                contentStore,
+                new String[]{MediaStore.Images.Media._ID},
+                null,
+                null,
+                null);
+    }
+
+    /**
+     * Cleans up after picture taking. Checking for duplicates and that kind of stuff.
+     *
+     * @param newImage
+     */
+    private void cleanup(int imageType, Uri oldImage, Uri newImage, Bitmap bitmap) {
+        if (bitmap != null) {
+            bitmap.recycle();
+        }
+
+        // Clean up initial camera-written image file.
+        (new File(FileHelper.stripFileProtocol(oldImage.toString()))).delete();
+
+        checkForDuplicateImage(imageType);
+        // Scan for the gallery to update pic refs in gallery
+        if (this.saveToPhotoAlbum && newImage != null) {
+            this.scanForGallery(newImage);
+        }
+
+        System.gc();
+    }
+
+    /**
+     * Used to find out if we are in a situation where the Camera Intent adds to images
+     * to the content store. If we are using a FILE_URI and the number of images in the DB
+     * increases by 2 we have a duplicate, when using a DATA_URL the number is 1.
+     *
+     * @param type FILE_URI or DATA_URL
+     */
+    private void checkForDuplicateImage(int type) {
+        int diff = 1;
+        Uri contentStore = whichContentStore();
+        Cursor cursor = queryImgDB(contentStore);
+        int currentNumOfImages = cursor.getCount();
+
+        if (type == FILE_URI && this.saveToPhotoAlbum) {
+            diff = 2;
+        }
+
+        // delete the duplicate file if the difference is 2 for file URI or 1 for Data URL
+        if ((currentNumOfImages - numPics) == diff) {
+            cursor.moveToLast();
+            int id = Integer.valueOf(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID)));
+            if (diff == 2) {
+                id--;
+            }
+            Uri uri = Uri.parse(contentStore + "/" + id);
+            this.cordova.getActivity().getContentResolver().delete(uri, null, null);
+            cursor.close();
+        }
+    }
+
+    /**
+     * Determine if we are storing the images in internal or external storage
+     *
+     * @return Uri
+     */
+    private Uri whichContentStore() {
+        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+            return android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+        } else {
+            return android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI;
+        }
+    }
+
+    /**
+     * Compress bitmap using jpeg, convert to Base64 encoded string, and return to JavaScript.
+     *
+     * @param bitmap
+     */
+    public void processPicture(Bitmap bitmap, int encodingType) {
+        ByteArrayOutputStream jpeg_data = new ByteArrayOutputStream();
+        CompressFormat compressFormat = encodingType == JPEG ?
+                CompressFormat.JPEG :
+                CompressFormat.PNG;
+
+        try {
+            if (bitmap.compress(compressFormat, mQuality, jpeg_data)) {
+                byte[] code = jpeg_data.toByteArray();
+                byte[] output = Base64.encode(code, Base64.NO_WRAP);
+                String js_out = new String(output);
+                this.callbackContext.success(js_out);
+                js_out = null;
+                output = null;
+                code = null;
+            }
+        } catch (Exception e) {
+            this.failPicture("Error compressing image.");
+        }
+        jpeg_data = null;
+    }
+
+    /**
+     * Send error message to JavaScript.
+     *
+     * @param err
+     */
+    public void failPicture(String err) {
+        this.callbackContext.error(err);
+    }
+
+    private void scanForGallery(Uri newImage) {
+        this.scanMe = newImage;
+        if (this.conn != null) {
+            this.conn.disconnect();
+        }
+        this.conn = new MediaScannerConnection(this.cordova.getActivity().getApplicationContext(), this);
+        conn.connect();
+    }
+
+    public void onMediaScannerConnected() {
+        try {
+            this.conn.scanFile(this.scanMe.toString(), "image/*");
+        } catch (java.lang.IllegalStateException e) {
+            LOG.e(LOG_TAG, "Can't scan file in MediaScanner after taking picture");
+        }
+
+    }
+
+    public void onScanCompleted(String path, Uri uri) {
+        this.conn.disconnect();
+    }
+
+
+    public void onRequestPermissionResult(int requestCode, String[] permissions,
+                                          int[] grantResults) throws JSONException {
+        for (int r : grantResults) {
+            if (r == PackageManager.PERMISSION_DENIED) {
+                this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, PERMISSION_DENIED_ERROR));
+                return;
+            }
+        }
+        switch (requestCode) {
+            case TAKE_PIC_SEC:
+                takePicture(this.destType, this.encodingType);
+                break;
+            case SAVE_TO_ALBUM_SEC:
+                this.getImage(this.srcType, this.destType, this.encodingType);
+                break;
+        }
+    }
+
+    /**
+     * Taking or choosing a picture launches another Activity, so we need to implement the
+     * save/restore APIs to handle the case where the CordovaActivity is killed by the OS
+     * before we get the launched Activity's result.
+     */
+    public Bundle onSaveInstanceState() {
+        Bundle state = new Bundle();
+        state.putInt("destType", this.destType);
+        state.putInt("srcType", this.srcType);
+        state.putInt("mQuality", this.mQuality);
+        state.putInt("targetWidth", this.targetWidth);
+        state.putInt("targetHeight", this.targetHeight);
+        state.putInt("encodingType", this.encodingType);
+        state.putInt("mediaType", this.mediaType);
+        state.putInt("numPics", this.numPics);
+        state.putBoolean("allowEdit", this.allowEdit);
+        state.putBoolean("correctOrientation", this.correctOrientation);
+        state.putBoolean("saveToPhotoAlbum", this.saveToPhotoAlbum);
+
+        if (this.croppedUri != null) {
+            state.putString("croppedUri", this.croppedUri.toString());
+        }
+
+        if (this.imageUri != null) {
+            state.putString("imageUri", this.imageUri.getFileUri().toString());
+        }
+
+        return state;
+    }
+
+    public void onRestoreStateForActivityResult(Bundle state, CallbackContext callbackContext) {
+        this.destType = state.getInt("destType");
+        this.srcType = state.getInt("srcType");
+        this.mQuality = state.getInt("mQuality");
+        this.targetWidth = state.getInt("targetWidth");
+        this.targetHeight = state.getInt("targetHeight");
+        this.encodingType = state.getInt("encodingType");
+        this.mediaType = state.getInt("mediaType");
+        this.numPics = state.getInt("numPics");
+        this.allowEdit = state.getBoolean("allowEdit");
+        this.correctOrientation = state.getBoolean("correctOrientation");
+        this.saveToPhotoAlbum = state.getBoolean("saveToPhotoAlbum");
+
+        if (state.containsKey("croppedUri")) {
+            this.croppedUri = Uri.parse(state.getString("croppedUri"));
+        }
+
+        if (state.containsKey("imageUri")) {
+            //I have no idea what type of URI is being passed in
+            this.imageUri = new CordovaUri(Uri.parse(state.getString("imageUri")));
+        }
+
+        this.callbackContext = callbackContext;
+    }
+
+ /*
+  * This is dirty, but it does the job.
+  *
+  * Since the FilesProvider doesn't really provide you a way of getting a URL from the file,
+  * and since we actually need the Camera to create the file for us most of the time, we don't
+  * actually write the file, just generate the location based on a timestamp, we need to get it
+  * back from the Intent.
+  *
+  * However, the FilesProvider preserves the path, so we can at least write to it from here, since
+  * we own the context in this case.
+ */
+
+    private String getFileNameFromUri(Uri uri) {
+        String fullUri = uri.toString();
+        String partial_path = fullUri.split("external_files")[1];
+        File external_storage = Environment.getExternalStorageDirectory();
+        String path = external_storage.getAbsolutePath() + partial_path;
+        return path;
+
+    }
+
+
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/camera/CordovaUri.java b/platforms/android/app/src/main/java/org/apache/cordova/camera/CordovaUri.java
new file mode 100644
index 0000000..5c2224d
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/camera/CordovaUri.java
@@ -0,0 +1,104 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova.camera;
+
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.support.v4.content.FileProvider;
+
+import java.io.File;
+
+/*
+ * This class exists because Andorid FilesProvider doesn't work on Android 4.4.4 and below and throws
+ * weird errors.  I'm not sure why writing to shared cache directories is somehow verboten, but it is
+ * and this error is irritating for a Compatibility library to have.
+ *
+ */
+
+public class CordovaUri {
+
+    private Uri androidUri;
+    private String fileName;
+    private Uri fileUri;
+
+    /*
+     * We always expect a FileProvider string to be passed in for the file that we create
+     *
+     */
+    CordovaUri (Uri inputUri)
+    {
+        //Determine whether the file is a content or file URI
+        if(inputUri.getScheme().equals("content"))
+        {
+            androidUri = inputUri;
+            fileName = getFileNameFromUri(androidUri);
+            fileUri = Uri.parse("file://" + fileName);
+        }
+        else
+        {
+            fileUri = inputUri;
+            fileName = FileHelper.stripFileProtocol(inputUri.toString());
+        }
+    }
+
+    public Uri getFileUri()
+    {
+        return fileUri;
+    }
+
+    public String getFilePath()
+    {
+        return fileName;
+    }
+
+    /*
+     * This only gets called by takePicture
+     */
+
+    public Uri getCorrectUri()
+    {
+        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
+            return androidUri;
+        else
+            return fileUri;
+    }
+
+ /*
+  * This is dirty, but it does the job.
+  *
+  * Since the FilesProvider doesn't really provide you a way of getting a URL from the file,
+  * and since we actually need the Camera to create the file for us most of the time, we don't
+  * actually write the file, just generate the location based on a timestamp, we need to get it
+  * back from the Intent.
+  *
+  * However, the FilesProvider preserves the path, so we can at least write to it from here, since
+  * we own the context in this case.
+ */
+
+    private String getFileNameFromUri(Uri uri) {
+        String fullUri = uri.toString();
+        String partial_path = fullUri.split("external_files")[1];
+        File external_storage = Environment.getExternalStorageDirectory();
+        String path = external_storage.getAbsolutePath() + partial_path;
+        return path;
+
+    }
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/camera/ExifHelper.java b/platforms/android/app/src/main/java/org/apache/cordova/camera/ExifHelper.java
new file mode 100644
index 0000000..5160a2f
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/camera/ExifHelper.java
@@ -0,0 +1,185 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.camera;
+
+import java.io.IOException;
+
+import android.media.ExifInterface;
+
+public class ExifHelper {
+    private String aperture = null;
+    private String datetime = null;
+    private String exposureTime = null;
+    private String flash = null;
+    private String focalLength = null;
+    private String gpsAltitude = null;
+    private String gpsAltitudeRef = null;
+    private String gpsDateStamp = null;
+    private String gpsLatitude = null;
+    private String gpsLatitudeRef = null;
+    private String gpsLongitude = null;
+    private String gpsLongitudeRef = null;
+    private String gpsProcessingMethod = null;
+    private String gpsTimestamp = null;
+    private String iso = null;
+    private String make = null;
+    private String model = null;
+    private String orientation = null;
+    private String whiteBalance = null;
+
+    private ExifInterface inFile = null;
+    private ExifInterface outFile = null;
+
+    /**
+     * The file before it is compressed
+     *
+     * @param filePath
+     * @throws IOException
+     */
+    public void createInFile(String filePath) throws IOException {
+        this.inFile = new ExifInterface(filePath);
+    }
+
+    /**
+     * The file after it has been compressed
+     *
+     * @param filePath
+     * @throws IOException
+     */
+    public void createOutFile(String filePath) throws IOException {
+        this.outFile = new ExifInterface(filePath);
+    }
+
+    /**
+     * Reads all the EXIF data from the input file.
+     */
+    public void readExifData() {
+        this.aperture = inFile.getAttribute(ExifInterface.TAG_APERTURE);
+        this.datetime = inFile.getAttribute(ExifInterface.TAG_DATETIME);
+        this.exposureTime = inFile.getAttribute(ExifInterface.TAG_EXPOSURE_TIME);
+        this.flash = inFile.getAttribute(ExifInterface.TAG_FLASH);
+        this.focalLength = inFile.getAttribute(ExifInterface.TAG_FOCAL_LENGTH);
+        this.gpsAltitude = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE);
+        this.gpsAltitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF);
+        this.gpsDateStamp = inFile.getAttribute(ExifInterface.TAG_GPS_DATESTAMP);
+        this.gpsLatitude = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
+        this.gpsLatitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
+        this.gpsLongitude = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
+        this.gpsLongitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
+        this.gpsProcessingMethod = inFile.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD);
+        this.gpsTimestamp = inFile.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP);
+        this.iso = inFile.getAttribute(ExifInterface.TAG_ISO);
+        this.make = inFile.getAttribute(ExifInterface.TAG_MAKE);
+        this.model = inFile.getAttribute(ExifInterface.TAG_MODEL);
+        this.orientation = inFile.getAttribute(ExifInterface.TAG_ORIENTATION);
+        this.whiteBalance = inFile.getAttribute(ExifInterface.TAG_WHITE_BALANCE);
+    }
+
+    /**
+     * Writes the previously stored EXIF data to the output file.
+     *
+     * @throws IOException
+     */
+    public void writeExifData() throws IOException {
+        // Don't try to write to a null file
+        if (this.outFile == null) {
+            return;
+        }
+
+        if (this.aperture != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_APERTURE, this.aperture);
+        }
+        if (this.datetime != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_DATETIME, this.datetime);
+        }
+        if (this.exposureTime != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_EXPOSURE_TIME, this.exposureTime);
+        }
+        if (this.flash != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_FLASH, this.flash);
+        }
+        if (this.focalLength != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_FOCAL_LENGTH, this.focalLength);
+        }
+        if (this.gpsAltitude != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE, this.gpsAltitude);
+        }
+        if (this.gpsAltitudeRef != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF, this.gpsAltitudeRef);
+        }
+        if (this.gpsDateStamp != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_DATESTAMP, this.gpsDateStamp);
+        }
+        if (this.gpsLatitude != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE, this.gpsLatitude);
+        }
+        if (this.gpsLatitudeRef != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, this.gpsLatitudeRef);
+        }
+        if (this.gpsLongitude != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, this.gpsLongitude);
+        }
+        if (this.gpsLongitudeRef != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, this.gpsLongitudeRef);
+        }
+        if (this.gpsProcessingMethod != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD, this.gpsProcessingMethod);
+        }
+        if (this.gpsTimestamp != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_GPS_TIMESTAMP, this.gpsTimestamp);
+        }
+        if (this.iso != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_ISO, this.iso);
+        }
+        if (this.make != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_MAKE, this.make);
+        }
+        if (this.model != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_MODEL, this.model);
+        }
+        if (this.orientation != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_ORIENTATION, this.orientation);
+        }
+        if (this.whiteBalance != null) {
+            this.outFile.setAttribute(ExifInterface.TAG_WHITE_BALANCE, this.whiteBalance);
+        }
+
+        this.outFile.saveAttributes();
+    }
+
+    public int getOrientation() {
+        int o = Integer.parseInt(this.orientation);
+
+        if (o == ExifInterface.ORIENTATION_NORMAL) {
+            return 0;
+        } else if (o == ExifInterface.ORIENTATION_ROTATE_90) {
+            return 90;
+        } else if (o == ExifInterface.ORIENTATION_ROTATE_180) {
+            return 180;
+        } else if (o == ExifInterface.ORIENTATION_ROTATE_270) {
+            return 270;
+        } else {
+            return 0;
+        }
+    }
+
+    public void resetOrientation() {
+        this.orientation = "" + ExifInterface.ORIENTATION_NORMAL;
+    }
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/camera/FileHelper.java b/platforms/android/app/src/main/java/org/apache/cordova/camera/FileHelper.java
new file mode 100644
index 0000000..ccc5e3e
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/camera/FileHelper.java
@@ -0,0 +1,319 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+         http://www.apache.org/licenses/LICENSE-2.0
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+ */
+package org.apache.cordova.camera;
+
+import android.annotation.SuppressLint;
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.provider.DocumentsContract;
+import android.provider.MediaStore;
+import android.webkit.MimeTypeMap;
+
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.LOG;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Locale;
+
+public class FileHelper {
+    private static final String LOG_TAG = "FileUtils";
+    private static final String _DATA = "_data";
+
+    /**
+     * Returns the real path of the given URI string.
+     * If the given URI string represents a content:// URI, the real path is retrieved from the media store.
+     *
+     * @param uriString the URI string of the audio/image/video
+     * @param cordova the current application context
+     * @return the full path to the file
+     */
+    @SuppressWarnings("deprecation")
+    public static String getRealPath(Uri uri, CordovaInterface cordova) {
+        String realPath = null;
+
+        if (Build.VERSION.SDK_INT < 11)
+            realPath = FileHelper.getRealPathFromURI_BelowAPI11(cordova.getActivity(), uri);
+
+        // SDK >= 11
+        else
+            realPath = FileHelper.getRealPathFromURI_API11_And_Above(cordova.getActivity(), uri);
+
+        return realPath;
+    }
+
+    /**
+     * Returns the real path of the given URI.
+     * If the given URI is a content:// URI, the real path is retrieved from the media store.
+     *
+     * @param uri the URI of the audio/image/video
+     * @param cordova the current application context
+     * @return the full path to the file
+     */
+    public static String getRealPath(String uriString, CordovaInterface cordova) {
+        return FileHelper.getRealPath(Uri.parse(uriString), cordova);
+    }
+
+    @SuppressLint("NewApi")
+    public static String getRealPathFromURI_API11_And_Above(final Context context, final Uri uri) {
+
+        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+        // DocumentProvider
+        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
+
+            // ExternalStorageProvider
+            if (isExternalStorageDocument(uri)) {
+                final String docId = DocumentsContract.getDocumentId(uri);
+                final String[] split = docId.split(":");
+                final String type = split[0];
+
+                if ("primary".equalsIgnoreCase(type)) {
+                    return Environment.getExternalStorageDirectory() + "/" + split[1];
+                }
+
+                // TODO handle non-primary volumes
+            }
+            // DownloadsProvider
+            else if (isDownloadsDocument(uri)) {
+
+                final String id = DocumentsContract.getDocumentId(uri);
+                final Uri contentUri = ContentUris.withAppendedId(
+                        Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
+
+                return getDataColumn(context, contentUri, null, null);
+            }
+            // MediaProvider
+            else if (isMediaDocument(uri)) {
+                final String docId = DocumentsContract.getDocumentId(uri);
+                final String[] split = docId.split(":");
+                final String type = split[0];
+
+                Uri contentUri = null;
+                if ("image".equals(type)) {
+                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+                } else if ("video".equals(type)) {
+                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
+                } else if ("audio".equals(type)) {
+                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
+                }
+
+                final String selection = "_id=?";
+                final String[] selectionArgs = new String[] {
+                        split[1]
+                };
+
+                return getDataColumn(context, contentUri, selection, selectionArgs);
+            }
+        }
+        // MediaStore (and general)
+        else if ("content".equalsIgnoreCase(uri.getScheme())) {
+
+            // Return the remote address
+            if (isGooglePhotosUri(uri))
+                return uri.getLastPathSegment();
+
+            return getDataColumn(context, uri, null, null);
+        }
+        // File
+        else if ("file".equalsIgnoreCase(uri.getScheme())) {
+            return uri.getPath();
+        }
+
+        return null;
+    }
+
+    public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri) {
+        String[] proj = { MediaStore.Images.Media.DATA };
+        String result = null;
+
+        try {
+            Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
+            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
+            cursor.moveToFirst();
+            result = cursor.getString(column_index);
+
+        } catch (Exception e) {
+            result = null;
+        }
+        return result;
+    }
+
+    /**
+     * Returns an input stream based on given URI string.
+     *
+     * @param uriString the URI string from which to obtain the input stream
+     * @param cordova the current application context
+     * @return an input stream into the data at the given URI or null if given an invalid URI string
+     * @throws IOException
+     */
+    public static InputStream getInputStreamFromUriString(String uriString, CordovaInterface cordova)
+            throws IOException {
+        InputStream returnValue = null;
+        if (uriString.startsWith("content")) {
+            Uri uri = Uri.parse(uriString);
+            returnValue = cordova.getActivity().getContentResolver().openInputStream(uri);
+        } else if (uriString.startsWith("file://")) {
+            int question = uriString.indexOf("?");
+            if (question > -1) {
+                uriString = uriString.substring(0, question);
+            }
+            if (uriString.startsWith("file:///android_asset/")) {
+                Uri uri = Uri.parse(uriString);
+                String relativePath = uri.getPath().substring(15);
+                returnValue = cordova.getActivity().getAssets().open(relativePath);
+            } else {
+                // might still be content so try that first
+                try {
+                    returnValue = cordova.getActivity().getContentResolver().openInputStream(Uri.parse(uriString));
+                } catch (Exception e) {
+                    returnValue = null;
+                }
+                if (returnValue == null) {
+                    returnValue = new FileInputStream(getRealPath(uriString, cordova));
+                }
+            }
+        } else {
+            returnValue = new FileInputStream(uriString);
+        }
+        return returnValue;
+    }
+
+    /**
+     * Removes the "file://" prefix from the given URI string, if applicable.
+     * If the given URI string doesn't have a "file://" prefix, it is returned unchanged.
+     *
+     * @param uriString the URI string to operate on
+     * @return a path without the "file://" prefix
+     */
+    public static String stripFileProtocol(String uriString) {
+        if (uriString.startsWith("file://")) {
+            uriString = uriString.substring(7);
+        }
+        return uriString;
+    }
+
+    public static String getMimeTypeForExtension(String path) {
+        String extension = path;
+        int lastDot = extension.lastIndexOf('.');
+        if (lastDot != -1) {
+            extension = extension.substring(lastDot + 1);
+        }
+        // Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
+        extension = extension.toLowerCase(Locale.getDefault());
+        if (extension.equals("3ga")) {
+            return "audio/3gpp";
+        }
+        return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+    }
+    
+    /**
+     * Returns the mime type of the data specified by the given URI string.
+     *
+     * @param uriString the URI string of the data
+     * @return the mime type of the specified data
+     */
+    public static String getMimeType(String uriString, CordovaInterface cordova) {
+        String mimeType = null;
+
+        Uri uri = Uri.parse(uriString);
+        if (uriString.startsWith("content://")) {
+            mimeType = cordova.getActivity().getContentResolver().getType(uri);
+        } else {
+            mimeType = getMimeTypeForExtension(uri.getPath());
+        }
+
+        return mimeType;
+    }
+
+    /**
+     * Get the value of the data column for this Uri. This is useful for
+     * MediaStore Uris, and other file-based ContentProviders.
+     *
+     * @param context The context.
+     * @param uri The Uri to query.
+     * @param selection (Optional) Filter used in the query.
+     * @param selectionArgs (Optional) Selection arguments used in the query.
+     * @return The value of the _data column, which is typically a file path.
+     * @author paulburke
+     */
+    public static String getDataColumn(Context context, Uri uri, String selection,
+                                       String[] selectionArgs) {
+
+        Cursor cursor = null;
+        final String column = "_data";
+        final String[] projection = {
+                column
+        };
+
+        try {
+            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
+                    null);
+            if (cursor != null && cursor.moveToFirst()) {
+
+                final int column_index = cursor.getColumnIndexOrThrow(column);
+                return cursor.getString(column_index);
+            }
+        } catch (Exception e) {
+            return null;
+        } finally {
+            if (cursor != null)
+                cursor.close();
+        }
+        return null;
+    }
+
+    /**
+     * @param uri The Uri to check.
+     * @return Whether the Uri authority is ExternalStorageProvider.
+     * @author paulburke
+     */
+    public static boolean isExternalStorageDocument(Uri uri) {
+        return "com.android.externalstorage.documents".equals(uri.getAuthority());
+    }
+
+    /**
+     * @param uri The Uri to check.
+     * @return Whether the Uri authority is DownloadsProvider.
+     * @author paulburke
+     */
+    public static boolean isDownloadsDocument(Uri uri) {
+        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
+    }
+
+    /**
+     * @param uri The Uri to check.
+     * @return Whether the Uri authority is MediaProvider.
+     * @author paulburke
+     */
+    public static boolean isMediaDocument(Uri uri) {
+        return "com.android.providers.media.documents".equals(uri.getAuthority());
+    }
+
+    /**
+     * @param uri The Uri to check.
+     * @return Whether the Uri authority is Google Photos.
+     */
+    public static boolean isGooglePhotosUri(Uri uri) {
+        return "com.google.android.apps.photos.content".equals(uri.getAuthority());
+    }
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/camera/FileProvider.java b/platforms/android/app/src/main/java/org/apache/cordova/camera/FileProvider.java
new file mode 100644
index 0000000..336f93c
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/camera/FileProvider.java
@@ -0,0 +1,21 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.camera;
+
+public class FileProvider extends android.support.v4.content.FileProvider {}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/device/Device.java b/platforms/android/app/src/main/java/org/apache/cordova/device/Device.java
new file mode 100644
index 0000000..e9efcb4
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/device/Device.java
@@ -0,0 +1,174 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.device;
+
+import java.util.TimeZone;
+
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.CordovaInterface;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.provider.Settings;
+
+public class Device extends CordovaPlugin {
+    public static final String TAG = "Device";
+
+    public static String platform;                            // Device OS
+    public static String uuid;                                // Device UUID
+
+    private static final String ANDROID_PLATFORM = "Android";
+    private static final String AMAZON_PLATFORM = "amazon-fireos";
+    private static final String AMAZON_DEVICE = "Amazon";
+
+    /**
+     * Constructor.
+     */
+    public Device() {
+    }
+
+    /**
+     * Sets the context of the Command. This can then be used to do things like
+     * get file paths associated with the Activity.
+     *
+     * @param cordova The context of the main Activity.
+     * @param webView The CordovaWebView Cordova is running in.
+     */
+    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
+        super.initialize(cordova, webView);
+        Device.uuid = getUuid();
+    }
+
+    /**
+     * Executes the request and returns PluginResult.
+     *
+     * @param action            The action to execute.
+     * @param args              JSONArry of arguments for the plugin.
+     * @param callbackContext   The callback id used when calling back into JavaScript.
+     * @return                  True if the action was valid, false if not.
+     */
+    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
+        if ("getDeviceInfo".equals(action)) {
+            JSONObject r = new JSONObject();
+            r.put("uuid", Device.uuid);
+            r.put("version", this.getOSVersion());
+            r.put("platform", this.getPlatform());
+            r.put("model", this.getModel());
+            r.put("manufacturer", this.getManufacturer());
+	        r.put("isVirtual", this.isVirtual());
+            r.put("serial", this.getSerialNumber());
+            callbackContext.success(r);
+        }
+        else {
+            return false;
+        }
+        return true;
+    }
+
+    //--------------------------------------------------------------------------
+    // LOCAL METHODS
+    //--------------------------------------------------------------------------
+
+    /**
+     * Get the OS name.
+     *
+     * @return
+     */
+    public String getPlatform() {
+        String platform;
+        if (isAmazonDevice()) {
+            platform = AMAZON_PLATFORM;
+        } else {
+            platform = ANDROID_PLATFORM;
+        }
+        return platform;
+    }
+
+    /**
+     * Get the device's Universally Unique Identifier (UUID).
+     *
+     * @return
+     */
+    public String getUuid() {
+        String uuid = Settings.Secure.getString(this.cordova.getActivity().getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
+        return uuid;
+    }
+
+    public String getModel() {
+        String model = android.os.Build.MODEL;
+        return model;
+    }
+
+    public String getProductName() {
+        String productname = android.os.Build.PRODUCT;
+        return productname;
+    }
+
+    public String getManufacturer() {
+        String manufacturer = android.os.Build.MANUFACTURER;
+        return manufacturer;
+    }
+
+    public String getSerialNumber() {
+        String serial = android.os.Build.SERIAL;
+        return serial;
+    }
+
+    /**
+     * Get the OS version.
+     *
+     * @return
+     */
+    public String getOSVersion() {
+        String osversion = android.os.Build.VERSION.RELEASE;
+        return osversion;
+    }
+
+    public String getSDKVersion() {
+        @SuppressWarnings("deprecation")
+        String sdkversion = android.os.Build.VERSION.SDK;
+        return sdkversion;
+    }
+
+    public String getTimeZoneID() {
+        TimeZone tz = TimeZone.getDefault();
+        return (tz.getID());
+    }
+
+    /**
+     * Function to check if the device is manufactured by Amazon
+     *
+     * @return
+     */
+    public boolean isAmazonDevice() {
+        if (android.os.Build.MANUFACTURER.equals(AMAZON_DEVICE)) {
+            return true;
+        }
+        return false;
+    }
+
+    public boolean isVirtual() {
+	return android.os.Build.FINGERPRINT.contains("generic") ||
+	    android.os.Build.PRODUCT.contains("sdk");
+    }
+
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/file/AssetFilesystem.java b/platforms/android/app/src/main/java/org/apache/cordova/file/AssetFilesystem.java
new file mode 100644
index 0000000..b035c40
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/file/AssetFilesystem.java
@@ -0,0 +1,294 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+ */
+package org.apache.cordova.file;
+
+import android.content.res.AssetManager;
+import android.net.Uri;
+
+import org.apache.cordova.CordovaResourceApi;
+import org.apache.cordova.LOG;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+public class AssetFilesystem extends Filesystem {
+
+    private final AssetManager assetManager;
+
+    // A custom gradle hook creates the cdvasset.manifest file, which speeds up asset listing a tonne.
+    // See: http://stackoverflow.com/questions/16911558/android-assetmanager-list-incredibly-slow
+    private static Object listCacheLock = new Object();
+    private static boolean listCacheFromFile;
+    private static Map<String, String[]> listCache;
+    private static Map<String, Long> lengthCache;
+
+    private static final String LOG_TAG = "AssetFilesystem";
+
+    private void lazyInitCaches() {
+        synchronized (listCacheLock) {
+            if (listCache == null) {
+                ObjectInputStream ois = null;
+                try {
+                    ois = new ObjectInputStream(assetManager.open("cdvasset.manifest"));
+                    listCache = (Map<String, String[]>) ois.readObject();
+                    lengthCache = (Map<String, Long>) ois.readObject();
+                    listCacheFromFile = true;
+                } catch (ClassNotFoundException e) {
+                    e.printStackTrace();
+                } catch (IOException e) {
+                    // Asset manifest won't exist if the gradle hook isn't set up correctly.
+                } finally {
+                    if (ois != null) {
+                        try {
+                            ois.close();
+                        } catch (IOException e) {
+                            LOG.d(LOG_TAG, e.getLocalizedMessage());
+                        }
+                    }
+                }
+                if (listCache == null) {
+                    LOG.w("AssetFilesystem", "Asset manifest not found. Recursive copies and directory listing will be slow.");
+                    listCache = new HashMap<String, String[]>();
+                }
+            }
+        }
+    }
+
+    private String[] listAssets(String assetPath) throws IOException {
+        if (assetPath.startsWith("/")) {
+            assetPath = assetPath.substring(1);
+        }
+        if (assetPath.endsWith("/")) {
+            assetPath = assetPath.substring(0, assetPath.length() - 1);
+        }
+        lazyInitCaches();
+        String[] ret = listCache.get(assetPath);
+        if (ret == null) {
+            if (listCacheFromFile) {
+                ret = new String[0];
+            } else {
+                ret = assetManager.list(assetPath);
+                listCache.put(assetPath, ret);
+            }
+        }
+        return ret;
+    }
+
+    private long getAssetSize(String assetPath) throws FileNotFoundException {
+        if (assetPath.startsWith("/")) {
+            assetPath = assetPath.substring(1);
+        }
+        lazyInitCaches();
+        if (lengthCache != null) {
+            Long ret = lengthCache.get(assetPath);
+            if (ret == null) {
+                throw new FileNotFoundException("Asset not found: " + assetPath);
+            }
+            return ret;
+        }
+        CordovaResourceApi.OpenForReadResult offr = null;
+        try {
+            offr = resourceApi.openForRead(nativeUriForFullPath(assetPath));
+            long length = offr.length;
+            if (length < 0) {
+                // available() doesn't always yield the file size, but for assets it does.
+                length = offr.inputStream.available();
+            }
+            return length;
+        } catch (IOException e) {
+            FileNotFoundException fnfe = new FileNotFoundException("File not found: " + assetPath);
+            fnfe.initCause(e);
+            throw fnfe;
+        } finally {
+            if (offr != null) {
+                try {
+                    offr.inputStream.close();
+                } catch (IOException e) {
+                    LOG.d(LOG_TAG, e.getLocalizedMessage());
+                }
+            }
+        }
+    }
+
+    public AssetFilesystem(AssetManager assetManager, CordovaResourceApi resourceApi) {
+        super(Uri.parse("file:///android_asset/"), "assets", resourceApi);
+        this.assetManager = assetManager;
+	}
+
+    @Override
+    public Uri toNativeUri(LocalFilesystemURL inputURL) {
+        return nativeUriForFullPath(inputURL.path);
+    }
+
+    @Override
+    public LocalFilesystemURL toLocalUri(Uri inputURL) {
+        if (!"file".equals(inputURL.getScheme())) {
+            return null;
+        }
+        File f = new File(inputURL.getPath());
+        // Removes and duplicate /s (e.g. file:///a//b/c)
+        Uri resolvedUri = Uri.fromFile(f);
+        String rootUriNoTrailingSlash = rootUri.getEncodedPath();
+        rootUriNoTrailingSlash = rootUriNoTrailingSlash.substring(0, rootUriNoTrailingSlash.length() - 1);
+        if (!resolvedUri.getEncodedPath().startsWith(rootUriNoTrailingSlash)) {
+            return null;
+        }
+        String subPath = resolvedUri.getEncodedPath().substring(rootUriNoTrailingSlash.length());
+        // Strip leading slash
+        if (!subPath.isEmpty()) {
+            subPath = subPath.substring(1);
+        }
+        Uri.Builder b = new Uri.Builder()
+            .scheme(LocalFilesystemURL.FILESYSTEM_PROTOCOL)
+            .authority("localhost")
+            .path(name);
+        if (!subPath.isEmpty()) {
+            b.appendEncodedPath(subPath);
+        }
+        if (isDirectory(subPath) || inputURL.getPath().endsWith("/")) {
+            // Add trailing / for directories.
+            b.appendEncodedPath("");
+        }
+        return LocalFilesystemURL.parse(b.build());
+    }
+
+    private boolean isDirectory(String assetPath) {
+        try {
+            return listAssets(assetPath).length != 0;
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
+    @Override
+    public LocalFilesystemURL[] listChildren(LocalFilesystemURL inputURL) throws FileNotFoundException {
+        String pathNoSlashes = inputURL.path.substring(1);
+        if (pathNoSlashes.endsWith("/")) {
+            pathNoSlashes = pathNoSlashes.substring(0, pathNoSlashes.length() - 1);
+        }
+
+        String[] files;
+        try {
+            files = listAssets(pathNoSlashes);
+        } catch (IOException e) {
+            FileNotFoundException fnfe = new FileNotFoundException();
+            fnfe.initCause(e);
+            throw fnfe;
+        }
+
+        LocalFilesystemURL[] entries = new LocalFilesystemURL[files.length];
+        for (int i = 0; i < files.length; ++i) {
+            entries[i] = localUrlforFullPath(new File(inputURL.path, files[i]).getPath());
+        }
+        return entries;
+	}
+
+    @Override
+    public JSONObject getFileForLocalURL(LocalFilesystemURL inputURL,
+                                         String path, JSONObject options, boolean directory)
+            throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException {
+        if (options != null && options.optBoolean("create")) {
+            throw new UnsupportedOperationException("Assets are read-only");
+        }
+
+        // Check whether the supplied path is absolute or relative
+        if (directory && !path.endsWith("/")) {
+            path += "/";
+        }
+
+        LocalFilesystemURL requestedURL;
+        if (path.startsWith("/")) {
+            requestedURL = localUrlforFullPath(normalizePath(path));
+        } else {
+            requestedURL = localUrlforFullPath(normalizePath(inputURL.path + "/" + path));
+        }
+
+        // Throws a FileNotFoundException if it doesn't exist.
+        getFileMetadataForLocalURL(requestedURL);
+
+        boolean isDir = isDirectory(requestedURL.path);
+        if (directory && !isDir) {
+            throw new TypeMismatchException("path doesn't exist or is file");
+        } else if (!directory && isDir) {
+            throw new TypeMismatchException("path doesn't exist or is directory");
+        }
+
+        // Return the directory
+        return makeEntryForURL(requestedURL);
+    }
+
+    @Override
+	public JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException {
+        JSONObject metadata = new JSONObject();
+        long size = inputURL.isDirectory ? 0 : getAssetSize(inputURL.path);
+        try {
+        	metadata.put("size", size);
+        	metadata.put("type", inputURL.isDirectory ? "text/directory" : resourceApi.getMimeType(toNativeUri(inputURL)));
+        	metadata.put("name", new File(inputURL.path).getName());
+        	metadata.put("fullPath", inputURL.path);
+        	metadata.put("lastModifiedDate", 0);
+        } catch (JSONException e) {
+            return null;
+        }
+        return metadata;
+	}
+
+	@Override
+	public boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL) {
+		return false;
+	}
+
+    @Override
+    long writeToFileAtURL(LocalFilesystemURL inputURL, String data, int offset, boolean isBinary) throws NoModificationAllowedException, IOException {
+        throw new NoModificationAllowedException("Assets are read-only");
+    }
+
+    @Override
+    long truncateFileAtURL(LocalFilesystemURL inputURL, long size) throws IOException, NoModificationAllowedException {
+        throw new NoModificationAllowedException("Assets are read-only");
+    }
+
+    @Override
+    String filesystemPathForURL(LocalFilesystemURL url) {
+        return new File(rootUri.getPath(), url.path).toString();
+    }
+
+    @Override
+    LocalFilesystemURL URLforFilesystemPath(String path) {
+        return null;
+    }
+
+    @Override
+    boolean removeFileAtLocalURL(LocalFilesystemURL inputURL) throws InvalidModificationException, NoModificationAllowedException {
+        throw new NoModificationAllowedException("Assets are read-only");
+    }
+
+    @Override
+    boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws NoModificationAllowedException {
+        throw new NoModificationAllowedException("Assets are read-only");
+    }
+
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/file/ContentFilesystem.java b/platforms/android/app/src/main/java/org/apache/cordova/file/ContentFilesystem.java
new file mode 100644
index 0000000..6b983c0
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/file/ContentFilesystem.java
@@ -0,0 +1,223 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+ */
+package org.apache.cordova.file;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.DocumentsContract;
+import android.provider.MediaStore;
+import android.provider.OpenableColumns;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import org.apache.cordova.CordovaResourceApi;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class ContentFilesystem extends Filesystem {
+
+    private final Context context;
+
+	public ContentFilesystem(Context context, CordovaResourceApi resourceApi) {
+		super(Uri.parse("content://"), "content", resourceApi);
+        this.context = context;
+	}
+
+    @Override
+    public Uri toNativeUri(LocalFilesystemURL inputURL) {
+        String authorityAndPath = inputURL.uri.getEncodedPath().substring(this.name.length() + 2);
+        if (authorityAndPath.length() < 2) {
+            return null;
+        }
+        String ret = "content://" + authorityAndPath;
+        String query = inputURL.uri.getEncodedQuery();
+        if (query != null) {
+            ret += '?' + query;
+        }
+        String frag = inputURL.uri.getEncodedFragment();
+        if (frag != null) {
+            ret += '#' + frag;
+        }
+        return Uri.parse(ret);
+    }
+
+    @Override
+    public LocalFilesystemURL toLocalUri(Uri inputURL) {
+        if (!"content".equals(inputURL.getScheme())) {
+            return null;
+        }
+        String subPath = inputURL.getEncodedPath();
+        if (subPath.length() > 0) {
+            subPath = subPath.substring(1);
+        }
+        Uri.Builder b = new Uri.Builder()
+            .scheme(LocalFilesystemURL.FILESYSTEM_PROTOCOL)
+            .authority("localhost")
+            .path(name)
+            .appendPath(inputURL.getAuthority());
+        if (subPath.length() > 0) {
+            b.appendEncodedPath(subPath);
+        }
+        Uri localUri = b.encodedQuery(inputURL.getEncodedQuery())
+            .encodedFragment(inputURL.getEncodedFragment())
+            .build();
+        return LocalFilesystemURL.parse(localUri);
+    }
+
+    @Override
+	public JSONObject getFileForLocalURL(LocalFilesystemURL inputURL,
+			String fileName, JSONObject options, boolean directory) throws IOException, TypeMismatchException, JSONException {
+        throw new UnsupportedOperationException("getFile() not supported for content:. Use resolveLocalFileSystemURL instead.");
+	}
+
+	@Override
+	public boolean removeFileAtLocalURL(LocalFilesystemURL inputURL)
+			throws NoModificationAllowedException {
+        Uri contentUri = toNativeUri(inputURL);
+		try {
+            context.getContentResolver().delete(contentUri, null, null);
+		} catch (UnsupportedOperationException t) {
+			// Was seeing this on the File mobile-spec tests on 4.0.3 x86 emulator.
+			// The ContentResolver applies only when the file was registered in the
+			// first case, which is generally only the case with images.
+            NoModificationAllowedException nmae = new NoModificationAllowedException("Deleting not supported for content uri: " + contentUri);
+            nmae.initCause(t);
+            throw nmae;
+		}
+        return true;
+	}
+
+	@Override
+	public boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL)
+			throws NoModificationAllowedException {
+		throw new NoModificationAllowedException("Cannot remove content url");
+	}
+
+    @Override
+    public LocalFilesystemURL[] listChildren(LocalFilesystemURL inputURL) throws FileNotFoundException {
+        throw new UnsupportedOperationException("readEntriesAtLocalURL() not supported for content:. Use resolveLocalFileSystemURL instead.");
+    }
+
+	@Override
+	public JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException {
+        long size = -1;
+        long lastModified = 0;
+        Uri nativeUri = toNativeUri(inputURL);
+        String mimeType = resourceApi.getMimeType(nativeUri);
+        Cursor cursor = openCursorForURL(nativeUri);
+        try {
+            if (cursor != null && cursor.moveToFirst()) {
+                Long sizeForCursor = resourceSizeForCursor(cursor);
+                if (sizeForCursor != null) {
+                    size = sizeForCursor.longValue();
+                }
+                Long modified = lastModifiedDateForCursor(cursor);
+                if (modified != null)
+                    lastModified = modified.longValue();
+            } else {
+                // Some content providers don't support cursors at all!
+                CordovaResourceApi.OpenForReadResult offr = resourceApi.openForRead(nativeUri);
+                size = offr.length;
+            }
+        } catch (IOException e) {
+            FileNotFoundException fnfe = new FileNotFoundException();
+            fnfe.initCause(e);
+            throw fnfe;
+        } finally {
+        	if (cursor != null)
+        		cursor.close();
+        }
+
+        JSONObject metadata = new JSONObject();
+        try {
+        	metadata.put("size", size);
+        	metadata.put("type", mimeType);
+        	metadata.put("name", name);
+        	metadata.put("fullPath", inputURL.path);
+        	metadata.put("lastModifiedDate", lastModified);
+        } catch (JSONException e) {
+        	return null;
+        }
+        return metadata;
+	}
+
+	@Override
+	public long writeToFileAtURL(LocalFilesystemURL inputURL, String data,
+			int offset, boolean isBinary) throws NoModificationAllowedException {
+        throw new NoModificationAllowedException("Couldn't write to file given its content URI");
+    }
+	@Override
+	public long truncateFileAtURL(LocalFilesystemURL inputURL, long size)
+			throws NoModificationAllowedException {
+        throw new NoModificationAllowedException("Couldn't truncate file given its content URI");
+	}
+
+	protected Cursor openCursorForURL(Uri nativeUri) {
+        ContentResolver contentResolver = context.getContentResolver();
+        try {
+            return contentResolver.query(nativeUri, null, null, null, null);
+        } catch (UnsupportedOperationException e) {
+            return null;
+        }
+	}
+
+	private Long resourceSizeForCursor(Cursor cursor) {
+        int columnIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
+        if (columnIndex != -1) {
+            String sizeStr = cursor.getString(columnIndex);
+            if (sizeStr != null) {
+            	return Long.parseLong(sizeStr);
+            }
+        }
+        return null;
+	}
+	
+	protected Long lastModifiedDateForCursor(Cursor cursor) {
+        int columnIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DATE_MODIFIED);
+        if (columnIndex == -1) {
+            columnIndex = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_LAST_MODIFIED);
+        }
+        if (columnIndex != -1) {
+            String dateStr = cursor.getString(columnIndex);
+            if (dateStr != null) {
+                return Long.parseLong(dateStr);
+            }
+        }
+        return null;
+	}
+
+    @Override
+    public String filesystemPathForURL(LocalFilesystemURL url) {
+        File f = resourceApi.mapUriToFile(toNativeUri(url));
+        return f == null ? null : f.getAbsolutePath();
+    }
+
+	@Override
+	public LocalFilesystemURL URLforFilesystemPath(String path) {
+		// Returns null as we don't support reverse mapping back to content:// URLs
+		return null;
+	}
+
+	@Override
+	public boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL) {
+		return true;
+	}
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/file/DirectoryManager.java b/platforms/android/app/src/main/java/org/apache/cordova/file/DirectoryManager.java
new file mode 100644
index 0000000..07af5ea
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/file/DirectoryManager.java
@@ -0,0 +1,134 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.file;
+
+import android.os.Environment;
+import android.os.StatFs;
+
+import java.io.File;
+
+/**
+ * This class provides file directory utilities.
+ * All file operations are performed on the SD card.
+ *
+ * It is used by the FileUtils class.
+ */
+public class DirectoryManager {
+
+    @SuppressWarnings("unused")
+    private static final String LOG_TAG = "DirectoryManager";
+
+    /**
+     * Determine if a file or directory exists.
+     * @param name				The name of the file to check.
+     * @return					T=exists, F=not found
+     */
+    public static boolean testFileExists(String name) {
+        boolean status;
+
+        // If SD card exists
+        if ((testSaveLocationExists()) && (!name.equals(""))) {
+            File path = Environment.getExternalStorageDirectory();
+            File newPath = constructFilePaths(path.toString(), name);
+            status = newPath.exists();
+        }
+        // If no SD card
+        else {
+            status = false;
+        }
+        return status;
+    }
+
+    /**
+     * Get the free space in external storage
+     *
+     * @return 		Size in KB or -1 if not available
+     */
+    public static long getFreeExternalStorageSpace() {
+        String status = Environment.getExternalStorageState();
+        long freeSpaceInBytes = 0;
+
+        // Check if external storage exists
+        if (status.equals(Environment.MEDIA_MOUNTED)) {
+            freeSpaceInBytes = getFreeSpaceInBytes(Environment.getExternalStorageDirectory().getPath());
+        } else {
+            // If no external storage then return -1
+            return -1;
+        }
+
+        return freeSpaceInBytes / 1024;
+    }
+
+    /**
+     * Given a path return the number of free bytes in the filesystem containing the path.
+     *
+     * @param path to the file system
+     * @return free space in bytes
+     */
+    public static long getFreeSpaceInBytes(String path) {
+        try {
+            StatFs stat = new StatFs(path);
+            long blockSize = stat.getBlockSize();
+            long availableBlocks = stat.getAvailableBlocks();
+            return availableBlocks * blockSize;
+        } catch (IllegalArgumentException e) {
+            // The path was invalid. Just return 0 free bytes.
+            return 0;
+        }
+    }
+
+    /**
+     * Determine if SD card exists.
+     *
+     * @return				T=exists, F=not found
+     */
+    public static boolean testSaveLocationExists() {
+        String sDCardStatus = Environment.getExternalStorageState();
+        boolean status;
+
+        // If SD card is mounted
+        if (sDCardStatus.equals(Environment.MEDIA_MOUNTED)) {
+            status = true;
+        }
+
+        // If no SD card
+        else {
+            status = false;
+        }
+        return status;
+    }
+
+    /**
+     * Create a new file object from two file paths.
+     *
+     * @param file1			Base file path
+     * @param file2			Remaining file path
+     * @return				File object
+     */
+    private static File constructFilePaths (String file1, String file2) {
+        File newPath;
+        if (file2.startsWith(file1)) {
+            newPath = new File(file2);
+        }
+        else {
+            newPath = new File(file1 + "/" + file2);
+        }
+        return newPath;
+    }
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/file/EncodingException.java b/platforms/android/app/src/main/java/org/apache/cordova/file/EncodingException.java
new file mode 100644
index 0000000..e9e1653
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/file/EncodingException.java
@@ -0,0 +1,29 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova.file;
+
+@SuppressWarnings("serial")
+public class EncodingException extends Exception {
+
+    public EncodingException(String message) {
+        super(message);
+    }
+
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/file/FileExistsException.java b/platforms/android/app/src/main/java/org/apache/cordova/file/FileExistsException.java
new file mode 100644
index 0000000..5c4d83d
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/file/FileExistsException.java
@@ -0,0 +1,29 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova.file;
+
+@SuppressWarnings("serial")
+public class FileExistsException extends Exception {
+
+    public FileExistsException(String msg) {
+        super(msg);
+    }
+
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/file/FileUtils.java b/platforms/android/app/src/main/java/org/apache/cordova/file/FileUtils.java
new file mode 100644
index 0000000..1d6e61f
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/file/FileUtils.java
@@ -0,0 +1,1225 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+ */
+package org.apache.cordova.file;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.util.Base64;
+
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.LOG;
+import org.apache.cordova.PermissionHelper;
+import org.apache.cordova.PluginResult;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.security.Permission;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+
+/**
+ * This class provides file and directory services to JavaScript.
+ */
+public class FileUtils extends CordovaPlugin {
+    private static final String LOG_TAG = "FileUtils";
+
+    public static int NOT_FOUND_ERR = 1;
+    public static int SECURITY_ERR = 2;
+    public static int ABORT_ERR = 3;
+
+    public static int NOT_READABLE_ERR = 4;
+    public static int ENCODING_ERR = 5;
+    public static int NO_MODIFICATION_ALLOWED_ERR = 6;
+    public static int INVALID_STATE_ERR = 7;
+    public static int SYNTAX_ERR = 8;
+    public static int INVALID_MODIFICATION_ERR = 9;
+    public static int QUOTA_EXCEEDED_ERR = 10;
+    public static int TYPE_MISMATCH_ERR = 11;
+    public static int PATH_EXISTS_ERR = 12;
+
+    /*
+     * Permission callback codes
+     */
+
+    public static final int ACTION_GET_FILE = 0;
+    public static final int ACTION_WRITE = 1;
+    public static final int ACTION_GET_DIRECTORY = 2;
+
+    public static final int WRITE = 3;
+    public static final int READ = 4;
+
+    public static int UNKNOWN_ERR = 1000;
+
+    private boolean configured = false;
+
+    private PendingRequests pendingRequests;
+
+
+
+    /*
+     * We need both read and write when accessing the storage, I think.
+     */
+
+    private String [] permissions = {
+            Manifest.permission.READ_EXTERNAL_STORAGE,
+            Manifest.permission.WRITE_EXTERNAL_STORAGE };
+
+    // This field exists only to support getEntry, below, which has been deprecated
+    private static FileUtils filePlugin;
+
+    private interface FileOp {
+        void run(JSONArray args) throws Exception;
+    }
+
+    private ArrayList<Filesystem> filesystems;
+
+    public void registerFilesystem(Filesystem fs) {
+    	if (fs != null && filesystemForName(fs.name)== null) {
+    		this.filesystems.add(fs);
+    	}
+    }
+
+    private Filesystem filesystemForName(String name) {
+    	for (Filesystem fs:filesystems) {
+    		if (fs != null && fs.name != null && fs.name.equals(name)) {
+    			return fs;
+    		}
+    	}
+    	return null;
+    }
+
+    protected String[] getExtraFileSystemsPreference(Activity activity) {
+        String fileSystemsStr = preferences.getString("androidextrafilesystems", "files,files-external,documents,sdcard,cache,cache-external,assets,root");
+        return fileSystemsStr.split(",");
+    }
+
+    protected void registerExtraFileSystems(String[] filesystems, HashMap<String, String> availableFileSystems) {
+        HashSet<String> installedFileSystems = new HashSet<String>();
+
+        /* Register filesystems in order */
+        for (String fsName : filesystems) {
+            if (!installedFileSystems.contains(fsName)) {
+                String fsRoot = availableFileSystems.get(fsName);
+                if (fsRoot != null) {
+                    File newRoot = new File(fsRoot);
+                    if (newRoot.mkdirs() || newRoot.isDirectory()) {
+                        registerFilesystem(new LocalFilesystem(fsName, webView.getContext(), webView.getResourceApi(), newRoot));
+                        installedFileSystems.add(fsName);
+                    } else {
+                       LOG.d(LOG_TAG, "Unable to create root dir for filesystem \"" + fsName + "\", skipping");
+                    }
+                } else {
+                    LOG.d(LOG_TAG, "Unrecognized extra filesystem identifier: " + fsName);
+                }
+            }
+        }
+    }
+
+    protected HashMap<String, String> getAvailableFileSystems(Activity activity) {
+        Context context = activity.getApplicationContext();
+        HashMap<String, String> availableFileSystems = new HashMap<String,String>();
+
+        availableFileSystems.put("files", context.getFilesDir().getAbsolutePath());
+        availableFileSystems.put("documents", new File(context.getFilesDir(), "Documents").getAbsolutePath());
+        availableFileSystems.put("cache", context.getCacheDir().getAbsolutePath());
+        availableFileSystems.put("root", "/");
+        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+          try {
+            availableFileSystems.put("files-external", context.getExternalFilesDir(null).getAbsolutePath());
+            availableFileSystems.put("sdcard", Environment.getExternalStorageDirectory().getAbsolutePath());
+            availableFileSystems.put("cache-external", context.getExternalCacheDir().getAbsolutePath());
+          }
+          catch(NullPointerException e) {
+              LOG.d(LOG_TAG, "External storage unavailable, check to see if USB Mass Storage Mode is on");
+          }
+        }
+
+        return availableFileSystems;
+    }
+
+    @Override
+    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
+    	super.initialize(cordova, webView);
+    	this.filesystems = new ArrayList<Filesystem>();
+        this.pendingRequests = new PendingRequests();
+
+    	String tempRoot = null;
+    	String persistentRoot = null;
+
+    	Activity activity = cordova.getActivity();
+    	String packageName = activity.getPackageName();
+
+        String location = preferences.getString("androidpersistentfilelocation", "internal");
+
+    	tempRoot = activity.getCacheDir().getAbsolutePath();
+    	if ("internal".equalsIgnoreCase(location)) {
+    		persistentRoot = activity.getFilesDir().getAbsolutePath() + "/files/";
+    		this.configured = true;
+    	} else if ("compatibility".equalsIgnoreCase(location)) {
+    		/*
+    		 *  Fall-back to compatibility mode -- this is the logic implemented in
+    		 *  earlier versions of this plugin, and should be maintained here so
+    		 *  that apps which were originally deployed with older versions of the
+    		 *  plugin can continue to provide access to files stored under those
+    		 *  versions.
+    		 */
+    		if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+    			persistentRoot = Environment.getExternalStorageDirectory().getAbsolutePath();
+    			tempRoot = Environment.getExternalStorageDirectory().getAbsolutePath() +
+    					"/Android/data/" + packageName + "/cache/";
+    		} else {
+    			persistentRoot = "/data/data/" + packageName;
+    		}
+    		this.configured = true;
+    	}
+
+    	if (this.configured) {
+			// Create the directories if they don't exist.
+			File tmpRootFile = new File(tempRoot);
+            File persistentRootFile = new File(persistentRoot);
+            tmpRootFile.mkdirs();
+            persistentRootFile.mkdirs();
+
+    		// Register initial filesystems
+    		// Note: The temporary and persistent filesystems need to be the first two
+    		// registered, so that they will match window.TEMPORARY and window.PERSISTENT,
+    		// per spec.
+    		this.registerFilesystem(new LocalFilesystem("temporary", webView.getContext(), webView.getResourceApi(), tmpRootFile));
+    		this.registerFilesystem(new LocalFilesystem("persistent", webView.getContext(), webView.getResourceApi(), persistentRootFile));
+    		this.registerFilesystem(new ContentFilesystem(webView.getContext(), webView.getResourceApi()));
+            this.registerFilesystem(new AssetFilesystem(webView.getContext().getAssets(), webView.getResourceApi()));
+
+            registerExtraFileSystems(getExtraFileSystemsPreference(activity), getAvailableFileSystems(activity));
+
+    		// Initialize static plugin reference for deprecated getEntry method
+    		if (filePlugin == null) {
+    			FileUtils.filePlugin = this;
+    		}
+    	} else {
+    		LOG.e(LOG_TAG, "File plugin configuration error: Please set AndroidPersistentFileLocation in config.xml to one of \"internal\" (for new applications) or \"compatibility\" (for compatibility with previous versions)");
+    		activity.finish();
+    	}
+    }
+
+    public static FileUtils getFilePlugin() {
+		return filePlugin;
+	}
+
+	private Filesystem filesystemForURL(LocalFilesystemURL localURL) {
+    	if (localURL == null) return null;
+    	return filesystemForName(localURL.fsName);
+    }
+
+    @Override
+    public Uri remapUri(Uri uri) {
+        // Remap only cdvfile: URLs (not content:).
+        if (!LocalFilesystemURL.FILESYSTEM_PROTOCOL.equals(uri.getScheme())) {
+            return null;
+        }
+        try {
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(uri);
+        	Filesystem fs = this.filesystemForURL(inputURL);
+        	if (fs == null) {
+        		return null;
+        	}
+        	String path = fs.filesystemPathForURL(inputURL);
+        	if (path != null) {
+        		return Uri.parse("file://" + fs.filesystemPathForURL(inputURL));
+        	}
+        	return null;
+        } catch (IllegalArgumentException e) {
+        	return null;
+        }
+    }
+
+    public boolean execute(String action, final String rawArgs, final CallbackContext callbackContext) {
+        if (!configured) {
+            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, "File plugin is not configured. Please see the README.md file for details on how to update config.xml"));
+            return true;
+        }
+        if (action.equals("testSaveLocationExists")) {
+            threadhelper(new FileOp() {
+                public void run(JSONArray args) {
+                    boolean b = DirectoryManager.testSaveLocationExists();
+                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b));
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("getFreeDiskSpace")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) {
+                    // The getFreeDiskSpace plugin API is not documented, but some apps call it anyway via exec().
+                    // For compatibility it always returns free space in the primary external storage, and
+                    // does NOT fallback to internal store if external storage is unavailable.
+                    long l = DirectoryManager.getFreeExternalStorageSpace();
+                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, l));
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("testFileExists")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws JSONException {
+                    String fname=args.getString(0);
+                    boolean b = DirectoryManager.testFileExists(fname);
+                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b));
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("testDirectoryExists")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws JSONException {
+                    String fname=args.getString(0);
+                    boolean b = DirectoryManager.testFileExists(fname);
+                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b));
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("readAsText")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws JSONException, MalformedURLException {
+                    String encoding = args.getString(1);
+                    int start = args.getInt(2);
+                    int end = args.getInt(3);
+                    String fname=args.getString(0);
+                    readFileAs(fname, start, end, callbackContext, encoding, PluginResult.MESSAGE_TYPE_STRING);
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("readAsDataURL")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws JSONException, MalformedURLException  {
+                    int start = args.getInt(1);
+                    int end = args.getInt(2);
+                    String fname=args.getString(0);
+                    readFileAs(fname, start, end, callbackContext, null, -1);
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("readAsArrayBuffer")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws JSONException, MalformedURLException  {
+                    int start = args.getInt(1);
+                    int end = args.getInt(2);
+                    String fname=args.getString(0);
+                    readFileAs(fname, start, end, callbackContext, null, PluginResult.MESSAGE_TYPE_ARRAYBUFFER);
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("readAsBinaryString")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws JSONException, MalformedURLException  {
+                    int start = args.getInt(1);
+                    int end = args.getInt(2);
+                    String fname=args.getString(0);
+                    readFileAs(fname, start, end, callbackContext, null, PluginResult.MESSAGE_TYPE_BINARYSTRING);
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("write")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws JSONException, FileNotFoundException, IOException, NoModificationAllowedException {
+                    String fname=args.getString(0);
+                    String nativeURL = resolveLocalFileSystemURI(fname).getString("nativeURL");
+                    String data=args.getString(1);
+                    int offset=args.getInt(2);
+                    Boolean isBinary=args.getBoolean(3);
+
+                    if(needPermission(nativeURL, WRITE)) {
+                        getWritePermission(rawArgs, ACTION_WRITE, callbackContext);
+                    }
+                    else {
+                        long fileSize = write(fname, data, offset, isBinary);
+                        callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, fileSize));
+                    }
+
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("truncate")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws JSONException, FileNotFoundException, IOException, NoModificationAllowedException {
+                    String fname=args.getString(0);
+                    int offset=args.getInt(1);
+                    long fileSize = truncateFile(fname, offset);
+                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, fileSize));
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("requestAllFileSystems")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws IOException, JSONException {
+                    callbackContext.success(requestAllFileSystems());
+                }
+            }, rawArgs, callbackContext);
+        } else if (action.equals("requestAllPaths")) {
+            cordova.getThreadPool().execute(
+                    new Runnable() {
+                        public void run() {
+                        	try {
+					callbackContext.success(requestAllPaths());
+				} catch (JSONException e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+                        }
+                    }
+            );
+        } else if (action.equals("requestFileSystem")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws JSONException {
+                    int fstype = args.getInt(0);
+                    long requiredSize = args.optLong(1);
+                    requestFileSystem(fstype, requiredSize, callbackContext);
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("resolveLocalFileSystemURI")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws IOException, JSONException {
+                    String fname=args.getString(0);
+                    JSONObject obj = resolveLocalFileSystemURI(fname);
+                    callbackContext.success(obj);
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("getFileMetadata")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws FileNotFoundException, JSONException, MalformedURLException {
+                    String fname=args.getString(0);
+                    JSONObject obj = getFileMetadata(fname);
+                    callbackContext.success(obj);
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("getParent")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws JSONException, IOException {
+                    String fname=args.getString(0);
+                    JSONObject obj = getParent(fname);
+                    callbackContext.success(obj);
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("getDirectory")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException {
+                    String dirname = args.getString(0);
+                    String path = args.getString(1);
+                    String nativeURL = resolveLocalFileSystemURI(dirname).getString("nativeURL");
+                    boolean containsCreate = (args.isNull(2)) ? false : args.getJSONObject(2).optBoolean("create", false);
+
+                    if(containsCreate && needPermission(nativeURL, WRITE)) {
+                        getWritePermission(rawArgs, ACTION_GET_DIRECTORY, callbackContext);
+                    }
+                    else if(!containsCreate && needPermission(nativeURL, READ)) {
+                        getReadPermission(rawArgs, ACTION_GET_DIRECTORY, callbackContext);
+                    }
+                    else {
+                        JSONObject obj = getFile(dirname, path, args.optJSONObject(2), true);
+                        callbackContext.success(obj);
+                    }
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("getFile")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException {
+                    String dirname = args.getString(0);
+                    String path = args.getString(1);
+                    String nativeURL = resolveLocalFileSystemURI(dirname).getString("nativeURL");
+                    boolean containsCreate = (args.isNull(2)) ? false : args.getJSONObject(2).optBoolean("create", false);
+
+                    if(containsCreate && needPermission(nativeURL, WRITE)) {
+                        getWritePermission(rawArgs, ACTION_GET_FILE, callbackContext);
+                    }
+                    else if(!containsCreate && needPermission(nativeURL, READ)) {
+                        getReadPermission(rawArgs, ACTION_GET_FILE, callbackContext);
+                    }
+                    else {
+                        JSONObject obj = getFile(dirname, path, args.optJSONObject(2), false);
+                        callbackContext.success(obj);
+                    }
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("remove")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws JSONException, NoModificationAllowedException, InvalidModificationException, MalformedURLException {
+                    String fname=args.getString(0);
+                    boolean success = remove(fname);
+                    if (success) {
+                        callbackContext.success();
+                    } else {
+                        callbackContext.error(FileUtils.NO_MODIFICATION_ALLOWED_ERR);
+                    }
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("removeRecursively")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws JSONException, FileExistsException, MalformedURLException, NoModificationAllowedException {
+                    String fname=args.getString(0);
+                    boolean success = removeRecursively(fname);
+                    if (success) {
+                        callbackContext.success();
+                    } else {
+                        callbackContext.error(FileUtils.NO_MODIFICATION_ALLOWED_ERR);
+                    }
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("moveTo")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws JSONException, NoModificationAllowedException, IOException, InvalidModificationException, EncodingException, FileExistsException {
+                    String fname=args.getString(0);
+                    String newParent=args.getString(1);
+                    String newName=args.getString(2);
+                    JSONObject entry = transferTo(fname, newParent, newName, true);
+                    callbackContext.success(entry);
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("copyTo")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws JSONException, NoModificationAllowedException, IOException, InvalidModificationException, EncodingException, FileExistsException {
+                    String fname=args.getString(0);
+                    String newParent=args.getString(1);
+                    String newName=args.getString(2);
+                    JSONObject entry = transferTo(fname, newParent, newName, false);
+                    callbackContext.success(entry);
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("readEntries")) {
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws FileNotFoundException, JSONException, MalformedURLException {
+                    String fname=args.getString(0);
+                    JSONArray entries = readEntries(fname);
+                    callbackContext.success(entries);
+                }
+            }, rawArgs, callbackContext);
+        }
+        else if (action.equals("_getLocalFilesystemPath")) {
+            // Internal method for testing: Get the on-disk location of a local filesystem url.
+            // [Currently used for testing file-transfer]
+            threadhelper( new FileOp( ){
+                public void run(JSONArray args) throws FileNotFoundException, JSONException, MalformedURLException {
+                    String localURLstr = args.getString(0);
+                    String fname = filesystemPathForURL(localURLstr);
+                    callbackContext.success(fname);
+                }
+            }, rawArgs, callbackContext);
+        }
+        else {
+            return false;
+        }
+        return true;
+    }
+
+    private void getReadPermission(String rawArgs, int action, CallbackContext callbackContext) {
+        int requestCode = pendingRequests.createRequest(rawArgs, action, callbackContext);
+        PermissionHelper.requestPermission(this, requestCode, Manifest.permission.READ_EXTERNAL_STORAGE);
+    }
+
+    private void getWritePermission(String rawArgs, int action, CallbackContext callbackContext) {
+        int requestCode = pendingRequests.createRequest(rawArgs, action, callbackContext);
+        PermissionHelper.requestPermission(this, requestCode, Manifest.permission.WRITE_EXTERNAL_STORAGE);
+    }
+
+    private boolean hasReadPermission() {
+        return PermissionHelper.hasPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
+    }
+
+    private boolean hasWritePermission() {
+        return PermissionHelper.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
+    }
+
+    private boolean needPermission(String nativeURL, int permissionType) throws JSONException {
+        JSONObject j = requestAllPaths();
+        ArrayList<String> allowedStorageDirectories = new ArrayList<String>();
+        allowedStorageDirectories.add(j.getString("applicationDirectory"));
+        allowedStorageDirectories.add(j.getString("applicationStorageDirectory"));
+        if(j.has("externalApplicationStorageDirectory")) {
+            allowedStorageDirectories.add(j.getString("externalApplicationStorageDirectory"));
+        }
+
+        if(permissionType == READ && hasReadPermission()) {
+            return false;
+        }
+        else if(permissionType == WRITE && hasWritePermission()) {
+            return false;
+        }
+
+        // Permission required if the native url lies outside the allowed storage directories
+        for(String directory : allowedStorageDirectories) {
+            if(nativeURL.startsWith(directory)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+
+    public LocalFilesystemURL resolveNativeUri(Uri nativeUri) {
+        LocalFilesystemURL localURL = null;
+
+        // Try all installed filesystems. Return the best matching URL
+        // (determined by the shortest resulting URL)
+        for (Filesystem fs : filesystems) {
+            LocalFilesystemURL url = fs.toLocalUri(nativeUri);
+            if (url != null) {
+                // A shorter fullPath implies that the filesystem is a better
+                // match for the local path than the previous best.
+                if (localURL == null || (url.uri.toString().length() < localURL.toString().length())) {
+                    localURL = url;
+                }
+            }
+        }
+        return localURL;
+    }
+
+    /*
+     * These two native-only methods can be used by other plugins to translate between
+     * device file system paths and URLs. By design, there is no direct JavaScript
+     * interface to these methods.
+     */
+
+    public String filesystemPathForURL(String localURLstr) throws MalformedURLException {
+        try {
+            LocalFilesystemURL inputURL = LocalFilesystemURL.parse(localURLstr);
+            Filesystem fs = this.filesystemForURL(inputURL);
+            if (fs == null) {
+                throw new MalformedURLException("No installed handlers for this URL");
+            }
+            return fs.filesystemPathForURL(inputURL);
+        } catch (IllegalArgumentException e) {
+            MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL");
+            mue.initCause(e);
+        	throw mue;
+        }
+    }
+
+    public LocalFilesystemURL filesystemURLforLocalPath(String localPath) {
+        LocalFilesystemURL localURL = null;
+        int shortestFullPath = 0;
+
+        // Try all installed filesystems. Return the best matching URL
+        // (determined by the shortest resulting URL)
+        for (Filesystem fs: filesystems) {
+            LocalFilesystemURL url = fs.URLforFilesystemPath(localPath);
+            if (url != null) {
+                // A shorter fullPath implies that the filesystem is a better
+                // match for the local path than the previous best.
+                if (localURL == null || (url.path.length() < shortestFullPath)) {
+                    localURL = url;
+                    shortestFullPath = url.path.length();
+                }
+            }
+        }
+        return localURL;
+    }
+
+
+	/* helper to execute functions async and handle the result codes
+     *
+     */
+    private void threadhelper(final FileOp f, final String rawArgs, final CallbackContext callbackContext){
+        cordova.getThreadPool().execute(new Runnable() {
+            public void run() {
+                try {
+                    JSONArray args = new JSONArray(rawArgs);
+                    f.run(args);
+                } catch ( Exception e) {
+                    if( e instanceof EncodingException){
+                        callbackContext.error(FileUtils.ENCODING_ERR);
+                    } else if(e instanceof FileNotFoundException) {
+                        callbackContext.error(FileUtils.NOT_FOUND_ERR);
+                    } else if(e instanceof FileExistsException) {
+                        callbackContext.error(FileUtils.PATH_EXISTS_ERR);
+                    } else if(e instanceof NoModificationAllowedException ) {
+                        callbackContext.error(FileUtils.NO_MODIFICATION_ALLOWED_ERR);
+                    } else if(e instanceof InvalidModificationException ) {
+                        callbackContext.error(FileUtils.INVALID_MODIFICATION_ERR);
+                    } else if(e instanceof MalformedURLException ) {
+                        callbackContext.error(FileUtils.ENCODING_ERR);
+                    } else if(e instanceof IOException ) {
+                        callbackContext.error(FileUtils.INVALID_MODIFICATION_ERR);
+                    } else if(e instanceof EncodingException ) {
+                        callbackContext.error(FileUtils.ENCODING_ERR);
+                    } else if(e instanceof TypeMismatchException ) {
+                        callbackContext.error(FileUtils.TYPE_MISMATCH_ERR);
+                    } else if(e instanceof JSONException ) {
+                        callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                    } else if (e instanceof SecurityException) {
+                        callbackContext.error(FileUtils.SECURITY_ERR);
+                    } else {
+                        e.printStackTrace();
+                    	callbackContext.error(FileUtils.UNKNOWN_ERR);
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Allows the user to look up the Entry for a file or directory referred to by a local URI.
+     *
+     * @param uriString of the file/directory to look up
+     * @return a JSONObject representing a Entry from the filesystem
+     * @throws MalformedURLException if the url is not valid
+     * @throws FileNotFoundException if the file does not exist
+     * @throws IOException if the user can't read the file
+     * @throws JSONException
+     */
+    private JSONObject resolveLocalFileSystemURI(String uriString) throws IOException, JSONException {
+        if (uriString == null) {
+            throw new MalformedURLException("Unrecognized filesystem URL");
+        }
+        Uri uri = Uri.parse(uriString);
+        boolean isNativeUri = false;
+
+        LocalFilesystemURL inputURL = LocalFilesystemURL.parse(uri);
+        if (inputURL == null) {
+            /* Check for file://, content:// urls */
+            inputURL = resolveNativeUri(uri);
+            isNativeUri = true;
+        }
+
+        try {
+            Filesystem fs = this.filesystemForURL(inputURL);
+            if (fs == null) {
+                throw new MalformedURLException("No installed handlers for this URL");
+            }
+            if (fs.exists(inputURL)) {
+                if (!isNativeUri) {
+                    // If not already resolved as native URI, resolve to a native URI and back to
+                    // fix the terminating slash based on whether the entry is a directory or file.
+                    inputURL = fs.toLocalUri(fs.toNativeUri(inputURL));
+                }
+
+                return fs.getEntryForLocalURL(inputURL);
+            }
+        } catch (IllegalArgumentException e) {
+            MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL");
+            mue.initCause(e);
+        	throw mue;
+        }
+        throw new FileNotFoundException();
+    }
+
+    /**
+     * Read the list of files from this directory.
+     *
+     * @return a JSONArray containing JSONObjects that represent Entry objects.
+     * @throws FileNotFoundException if the directory is not found.
+     * @throws JSONException
+     * @throws MalformedURLException
+     */
+    private JSONArray readEntries(String baseURLstr) throws FileNotFoundException, JSONException, MalformedURLException {
+        try {
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr);
+        	Filesystem fs = this.filesystemForURL(inputURL);
+        	if (fs == null) {
+        		throw new MalformedURLException("No installed handlers for this URL");
+        	}
+        	return fs.readEntriesAtLocalURL(inputURL);
+
+        } catch (IllegalArgumentException e) {
+            MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL");
+            mue.initCause(e);
+        	throw mue;
+        }
+    }
+
+    /**
+     * A setup method that handles the move/copy of files/directories
+     *
+     * @param newName for the file directory to be called, if null use existing file name
+     * @param move if false do a copy, if true do a move
+     * @return a Entry object
+     * @throws NoModificationAllowedException
+     * @throws IOException
+     * @throws InvalidModificationException
+     * @throws EncodingException
+     * @throws JSONException
+     * @throws FileExistsException
+     */
+    private JSONObject transferTo(String srcURLstr, String destURLstr, String newName, boolean move) throws JSONException, NoModificationAllowedException, IOException, InvalidModificationException, EncodingException, FileExistsException {
+        if (srcURLstr == null || destURLstr == null) {
+            // either no source or no destination provided
+        	throw new FileNotFoundException();
+        }
+
+        LocalFilesystemURL srcURL = LocalFilesystemURL.parse(srcURLstr);
+        LocalFilesystemURL destURL = LocalFilesystemURL.parse(destURLstr);
+
+        Filesystem srcFs = this.filesystemForURL(srcURL);
+        Filesystem destFs = this.filesystemForURL(destURL);
+
+        // Check for invalid file name
+        if (newName != null && newName.contains(":")) {
+            throw new EncodingException("Bad file name");
+        }
+
+        return destFs.copyFileToURL(destURL, newName, srcFs, srcURL, move);
+    }
+
+    /**
+     * Deletes a directory and all of its contents, if any. In the event of an error
+     * [e.g. trying to delete a directory that contains a file that cannot be removed],
+     * some of the contents of the directory may be deleted.
+     * It is an error to attempt to delete the root directory of a filesystem.
+     *
+     * @return a boolean representing success of failure
+     * @throws FileExistsException
+     * @throws NoModificationAllowedException
+     * @throws MalformedURLException
+     */
+    private boolean removeRecursively(String baseURLstr) throws FileExistsException, NoModificationAllowedException, MalformedURLException {
+        try {
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr);
+        	// You can't delete the root directory.
+        	if ("".equals(inputURL.path) || "/".equals(inputURL.path)) {
+        		throw new NoModificationAllowedException("You can't delete the root directory");
+        	}
+
+        	Filesystem fs = this.filesystemForURL(inputURL);
+        	if (fs == null) {
+        		throw new MalformedURLException("No installed handlers for this URL");
+        	}
+        	return fs.recursiveRemoveFileAtLocalURL(inputURL);
+
+        } catch (IllegalArgumentException e) {
+            MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL");
+            mue.initCause(e);
+        	throw mue;
+        }
+    }
+
+
+    /**
+     * Deletes a file or directory. It is an error to attempt to delete a directory that is not empty.
+     * It is an error to attempt to delete the root directory of a filesystem.
+     *
+     * @return a boolean representing success of failure
+     * @throws NoModificationAllowedException
+     * @throws InvalidModificationException
+     * @throws MalformedURLException
+     */
+    private boolean remove(String baseURLstr) throws NoModificationAllowedException, InvalidModificationException, MalformedURLException {
+        try {
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr);
+        	// You can't delete the root directory.
+        	if ("".equals(inputURL.path) || "/".equals(inputURL.path)) {
+
+        		throw new NoModificationAllowedException("You can't delete the root directory");
+        	}
+
+        	Filesystem fs = this.filesystemForURL(inputURL);
+        	if (fs == null) {
+        		throw new MalformedURLException("No installed handlers for this URL");
+        	}
+        	return fs.removeFileAtLocalURL(inputURL);
+
+        } catch (IllegalArgumentException e) {
+            MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL");
+            mue.initCause(e);
+        	throw mue;
+        }
+    }
+
+    /**
+     * Creates or looks up a file.
+     *
+     * @param baseURLstr base directory
+     * @param path file/directory to lookup or create
+     * @param options specify whether to create or not
+     * @param directory if true look up directory, if false look up file
+     * @return a Entry object
+     * @throws FileExistsException
+     * @throws IOException
+     * @throws TypeMismatchException
+     * @throws EncodingException
+     * @throws JSONException
+     */
+    private JSONObject getFile(String baseURLstr, String path, JSONObject options, boolean directory) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException {
+        try {
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr);
+        	Filesystem fs = this.filesystemForURL(inputURL);
+        	if (fs == null) {
+        		throw new MalformedURLException("No installed handlers for this URL");
+        	}
+        	return fs.getFileForLocalURL(inputURL, path, options, directory);
+
+        } catch (IllegalArgumentException e) {
+            MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL");
+            mue.initCause(e);
+        	throw mue;
+        }
+
+    }
+
+    /**
+     * Look up the parent DirectoryEntry containing this Entry.
+     * If this Entry is the root of its filesystem, its parent is itself.
+     */
+    private JSONObject getParent(String baseURLstr) throws JSONException, IOException {
+        try {
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr);
+        	Filesystem fs = this.filesystemForURL(inputURL);
+        	if (fs == null) {
+        		throw new MalformedURLException("No installed handlers for this URL");
+        	}
+        	return fs.getParentForLocalURL(inputURL);
+
+        } catch (IllegalArgumentException e) {
+            MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL");
+            mue.initCause(e);
+        	throw mue;
+        }
+    }
+
+    /**
+     * Returns a File that represents the current state of the file that this FileEntry represents.
+     *
+     * @return returns a JSONObject represent a W3C File object
+     */
+    private JSONObject getFileMetadata(String baseURLstr) throws FileNotFoundException, JSONException, MalformedURLException {
+        try {
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr);
+        	Filesystem fs = this.filesystemForURL(inputURL);
+        	if (fs == null) {
+        		throw new MalformedURLException("No installed handlers for this URL");
+        	}
+        	return fs.getFileMetadataForLocalURL(inputURL);
+
+        } catch (IllegalArgumentException e) {
+            MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL");
+            mue.initCause(e);
+        	throw mue;
+        }
+    }
+
+    /**
+     * Requests a filesystem in which to store application data.
+     *
+     * @param type of file system requested
+     * @param requiredSize required free space in the file system in bytes
+     * @param callbackContext context for returning the result or error
+     * @throws JSONException
+     */
+    private void requestFileSystem(int type, long requiredSize, final CallbackContext callbackContext) throws JSONException {
+        Filesystem rootFs = null;
+        try {
+            rootFs = this.filesystems.get(type);
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Pass null through
+        }
+        if (rootFs == null) {
+            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, FileUtils.NOT_FOUND_ERR));
+        } else {
+            // If a nonzero required size was specified, check that the retrieved filesystem has enough free space.
+            long availableSize = 0;
+            if (requiredSize > 0) {
+                availableSize = rootFs.getFreeSpaceInBytes();
+            }
+
+            if (availableSize < requiredSize) {
+                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, FileUtils.QUOTA_EXCEEDED_ERR));
+            } else {
+                JSONObject fs = new JSONObject();
+                fs.put("name", rootFs.name);
+                fs.put("root", rootFs.getRootEntry());
+                callbackContext.success(fs);
+            }
+        }
+    }
+
+    /**
+     * Requests a filesystem in which to store application data.
+     *
+     * @return a JSONObject representing the file system
+     */
+    private JSONArray requestAllFileSystems() throws IOException, JSONException {
+        JSONArray ret = new JSONArray();
+        for (Filesystem fs : filesystems) {
+            ret.put(fs.getRootEntry());
+        }
+        return ret;
+    }
+
+    private static String toDirUrl(File f) {
+        return Uri.fromFile(f).toString() + '/';
+    }
+
+    private JSONObject requestAllPaths() throws JSONException {
+        Context context = cordova.getActivity();
+        JSONObject ret = new JSONObject();
+        ret.put("applicationDirectory", "file:///android_asset/");
+        ret.put("applicationStorageDirectory", toDirUrl(context.getFilesDir().getParentFile()));
+        ret.put("dataDirectory", toDirUrl(context.getFilesDir()));
+        ret.put("cacheDirectory", toDirUrl(context.getCacheDir()));
+        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+          try {
+            ret.put("externalApplicationStorageDirectory", toDirUrl(context.getExternalFilesDir(null).getParentFile()));
+            ret.put("externalDataDirectory", toDirUrl(context.getExternalFilesDir(null)));
+            ret.put("externalCacheDirectory", toDirUrl(context.getExternalCacheDir()));
+            ret.put("externalRootDirectory", toDirUrl(Environment.getExternalStorageDirectory()));
+          }
+          catch(NullPointerException e) {
+            /* If external storage is unavailable, context.getExternal* returns null */
+              LOG.d(LOG_TAG, "Unable to access these paths, most liklely due to USB storage");
+          }
+        }
+        return ret;
+    }
+
+   /**
+     * Returns a JSON object representing the given File. Internal APIs should be modified
+     * to use URLs instead of raw FS paths wherever possible, when interfacing with this plugin.
+     *
+     * @param file the File to convert
+     * @return a JSON representation of the given File
+     * @throws JSONException
+     */
+    public JSONObject getEntryForFile(File file) throws JSONException {
+        JSONObject entry;
+
+        for (Filesystem fs : filesystems) {
+             entry = fs.makeEntryForFile(file);
+             if (entry != null) {
+                 return entry;
+             }
+        }
+        return null;
+    }
+
+    /**
+     * Returns a JSON object representing the given File. Deprecated, as this is only used by
+     * FileTransfer, and because it is a static method that should really be an instance method,
+     * since it depends on the actual filesystem roots in use. Internal APIs should be modified
+     * to use URLs instead of raw FS paths wherever possible, when interfacing with this plugin.
+     *
+     * @param file the File to convert
+     * @return a JSON representation of the given File
+     * @throws JSONException
+     */
+    @Deprecated
+    public static JSONObject getEntry(File file) throws JSONException {
+ 		if (getFilePlugin() != null) {
+             return getFilePlugin().getEntryForFile(file);
+		}
+		return null;
+    }
+
+    /**
+     * Read the contents of a file.
+     * This is done in a background thread; the result is sent to the callback.
+     *
+     * @param start             Start position in the file.
+     * @param end               End position to stop at (exclusive).
+     * @param callbackContext   The context through which to send the result.
+     * @param encoding          The encoding to return contents as.  Typical value is UTF-8. (see http://www.iana.org/assignments/character-sets)
+     * @param resultType        The desired type of data to send to the callback.
+     * @return                  Contents of file.
+     */
+    public void readFileAs(final String srcURLstr, final int start, final int end, final CallbackContext callbackContext, final String encoding, final int resultType) throws MalformedURLException {
+        try {
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(srcURLstr);
+        	Filesystem fs = this.filesystemForURL(inputURL);
+        	if (fs == null) {
+        		throw new MalformedURLException("No installed handlers for this URL");
+        	}
+
+            fs.readFileAtURL(inputURL, start, end, new Filesystem.ReadFileCallback() {
+                public void handleData(InputStream inputStream, String contentType) {
+            		try {
+                        ByteArrayOutputStream os = new ByteArrayOutputStream();
+                        final int BUFFER_SIZE = 8192;
+                        byte[] buffer = new byte[BUFFER_SIZE];
+
+                        for (;;) {
+                            int bytesRead = inputStream.read(buffer, 0, BUFFER_SIZE);
+
+                            if (bytesRead <= 0) {
+                                break;
+                            }
+                            os.write(buffer, 0, bytesRead);
+                        }
+
+            			PluginResult result;
+            			switch (resultType) {
+            			case PluginResult.MESSAGE_TYPE_STRING:
+                            result = new PluginResult(PluginResult.Status.OK, os.toString(encoding));
+            				break;
+            			case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
+                            result = new PluginResult(PluginResult.Status.OK, os.toByteArray());
+            				break;
+            			case PluginResult.MESSAGE_TYPE_BINARYSTRING:
+                            result = new PluginResult(PluginResult.Status.OK, os.toByteArray(), true);
+            				break;
+            			default: // Base64.
+                        byte[] base64 = Base64.encode(os.toByteArray(), Base64.NO_WRAP);
+            			String s = "data:" + contentType + ";base64," + new String(base64, "US-ASCII");
+            			result = new PluginResult(PluginResult.Status.OK, s);
+            			}
+
+            			callbackContext.sendPluginResult(result);
+            		} catch (IOException e) {
+            			LOG.d(LOG_TAG, e.getLocalizedMessage());
+            			callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, NOT_READABLE_ERR));
+                    }
+            	}
+            });
+
+
+        } catch (IllegalArgumentException e) {
+            MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL");
+            mue.initCause(e);
+        	throw mue;
+        } catch (FileNotFoundException e) {
+        	callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, NOT_FOUND_ERR));
+        } catch (IOException e) {
+        	LOG.d(LOG_TAG, e.getLocalizedMessage());
+        	callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, NOT_READABLE_ERR));
+        }
+    }
+
+
+    /**
+     * Write contents of file.
+     *
+     * @param data				The contents of the file.
+     * @param offset			The position to begin writing the file.
+     * @param isBinary          True if the file contents are base64-encoded binary data
+     */
+    /**/
+    public long write(String srcURLstr, String data, int offset, boolean isBinary) throws FileNotFoundException, IOException, NoModificationAllowedException {
+        try {
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(srcURLstr);
+        	Filesystem fs = this.filesystemForURL(inputURL);
+        	if (fs == null) {
+        		throw new MalformedURLException("No installed handlers for this URL");
+        	}
+
+            long x = fs.writeToFileAtURL(inputURL, data, offset, isBinary); LOG.d("TEST",srcURLstr + ": "+x); return x;
+        } catch (IllegalArgumentException e) {
+            MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL");
+            mue.initCause(e);
+        	throw mue;
+        }
+
+    }
+
+    /**
+     * Truncate the file to size
+     */
+    private long truncateFile(String srcURLstr, long size) throws FileNotFoundException, IOException, NoModificationAllowedException {
+        try {
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(srcURLstr);
+        	Filesystem fs = this.filesystemForURL(inputURL);
+        	if (fs == null) {
+        		throw new MalformedURLException("No installed handlers for this URL");
+        	}
+
+            return fs.truncateFileAtURL(inputURL, size);
+        } catch (IllegalArgumentException e) {
+            MalformedURLException mue = new MalformedURLException("Unrecognized filesystem URL");
+            mue.initCause(e);
+        	throw mue;
+        }
+    }
+
+
+    /*
+     * Handle the response
+     */
+
+    public void onRequestPermissionResult(int requestCode, String[] permissions,
+                                          int[] grantResults) throws JSONException {
+
+        final PendingRequests.Request req = pendingRequests.getAndRemove(requestCode);
+        if (req != null) {
+            for(int r:grantResults)
+            {
+                if(r == PackageManager.PERMISSION_DENIED)
+                {
+                    req.getCallbackContext().sendPluginResult(new PluginResult(PluginResult.Status.ERROR, SECURITY_ERR));
+                    return;
+                }
+            }
+            switch(req.getAction())
+            {
+                case ACTION_GET_FILE:
+                    threadhelper( new FileOp( ){
+                        public void run(JSONArray args) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException {
+                            String dirname = args.getString(0);
+
+                            String path = args.getString(1);
+                            JSONObject obj = getFile(dirname, path, args.optJSONObject(2), false);
+                            req.getCallbackContext().success(obj);
+                        }
+                    }, req.getRawArgs(), req.getCallbackContext());
+                    break;
+                case ACTION_GET_DIRECTORY:
+                    threadhelper( new FileOp( ){
+                        public void run(JSONArray args) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException {
+                            String dirname = args.getString(0);
+
+                            String path = args.getString(1);
+                            JSONObject obj = getFile(dirname, path, args.optJSONObject(2), true);
+                            req.getCallbackContext().success(obj);
+                        }
+                    }, req.getRawArgs(), req.getCallbackContext());
+                    break;
+                case ACTION_WRITE:
+                    threadhelper( new FileOp( ){
+                        public void run(JSONArray args) throws JSONException, FileNotFoundException, IOException, NoModificationAllowedException {
+                            String fname=args.getString(0);
+                            String data=args.getString(1);
+                            int offset=args.getInt(2);
+                            Boolean isBinary=args.getBoolean(3);
+                            long fileSize = write(fname, data, offset, isBinary);
+                            req.getCallbackContext().sendPluginResult(new PluginResult(PluginResult.Status.OK, fileSize));
+                        }
+                    }, req.getRawArgs(), req.getCallbackContext());
+                    break;
+            }
+        } else {
+           LOG.d(LOG_TAG, "Received permission callback for unknown request code");
+        }
+    }
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/file/Filesystem.java b/platforms/android/app/src/main/java/org/apache/cordova/file/Filesystem.java
new file mode 100644
index 0000000..c69d3bd
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/file/Filesystem.java
@@ -0,0 +1,331 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+ */
+package org.apache.cordova.file;
+
+import android.net.Uri;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import org.apache.cordova.CordovaResourceApi;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public abstract class Filesystem {
+
+    protected final Uri rootUri;
+    protected final CordovaResourceApi resourceApi;
+    public final String name;
+    private JSONObject rootEntry;
+
+    public Filesystem(Uri rootUri, String name, CordovaResourceApi resourceApi) {
+        this.rootUri = rootUri;
+        this.name = name;
+        this.resourceApi = resourceApi;
+    }
+
+    public interface ReadFileCallback {
+		public void handleData(InputStream inputStream, String contentType) throws IOException;
+	}
+
+    public static JSONObject makeEntryForURL(LocalFilesystemURL inputURL, Uri nativeURL) {
+        try {
+            String path = inputURL.path;
+            int end = path.endsWith("/") ? 1 : 0;
+            String[] parts = path.substring(0, path.length() - end).split("/+");
+            String fileName = parts[parts.length - 1];
+
+            JSONObject entry = new JSONObject();
+            entry.put("isFile", !inputURL.isDirectory);
+            entry.put("isDirectory", inputURL.isDirectory);
+            entry.put("name", fileName);
+            entry.put("fullPath", path);
+            // The file system can't be specified, as it would lead to an infinite loop,
+            // but the filesystem name can be.
+            entry.put("filesystemName", inputURL.fsName);
+            // Backwards compatibility
+            entry.put("filesystem", "temporary".equals(inputURL.fsName) ? 0 : 1);
+
+            String nativeUrlStr = nativeURL.toString();
+            if (inputURL.isDirectory && !nativeUrlStr.endsWith("/")) {
+                nativeUrlStr += "/";
+            }
+            entry.put("nativeURL", nativeUrlStr);
+            return entry;
+        } catch (JSONException e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
+        }
+    }
+
+    public JSONObject makeEntryForURL(LocalFilesystemURL inputURL) {
+        Uri nativeUri = toNativeUri(inputURL);
+        return nativeUri == null ? null : makeEntryForURL(inputURL, nativeUri);
+    }
+
+    public JSONObject makeEntryForNativeUri(Uri nativeUri) {
+        LocalFilesystemURL inputUrl = toLocalUri(nativeUri);
+        return inputUrl == null ? null : makeEntryForURL(inputUrl, nativeUri);
+    }
+
+    public JSONObject getEntryForLocalURL(LocalFilesystemURL inputURL) throws IOException {
+        return makeEntryForURL(inputURL);
+    }
+
+    public JSONObject makeEntryForFile(File file) {
+        return makeEntryForNativeUri(Uri.fromFile(file));
+    }
+
+    abstract JSONObject getFileForLocalURL(LocalFilesystemURL inputURL, String path,
+			JSONObject options, boolean directory) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException;
+
+	abstract boolean removeFileAtLocalURL(LocalFilesystemURL inputURL) throws InvalidModificationException, NoModificationAllowedException;
+
+	abstract boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws FileExistsException, NoModificationAllowedException;
+
+	abstract LocalFilesystemURL[] listChildren(LocalFilesystemURL inputURL) throws FileNotFoundException;
+
+    public final JSONArray readEntriesAtLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException {
+        LocalFilesystemURL[] children = listChildren(inputURL);
+        JSONArray entries = new JSONArray();
+        if (children != null) {
+            for (LocalFilesystemURL url : children) {
+                entries.put(makeEntryForURL(url));
+            }
+        }
+        return entries;
+    }
+
+	abstract JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException;
+
+    public Uri getRootUri() {
+        return rootUri;
+    }
+
+    public boolean exists(LocalFilesystemURL inputURL) {
+        try {
+            getFileMetadataForLocalURL(inputURL);
+        } catch (FileNotFoundException e) {
+            return false;
+        }
+        return true;
+    }
+
+    public Uri nativeUriForFullPath(String fullPath) {
+        Uri ret = null;
+        if (fullPath != null) {
+            String encodedPath = Uri.fromFile(new File(fullPath)).getEncodedPath();
+            if (encodedPath.startsWith("/")) {
+                encodedPath = encodedPath.substring(1);
+            }
+            ret = rootUri.buildUpon().appendEncodedPath(encodedPath).build();
+        }
+        return ret;
+    }
+
+    public LocalFilesystemURL localUrlforFullPath(String fullPath) {
+        Uri nativeUri = nativeUriForFullPath(fullPath);
+        if (nativeUri != null) {
+            return toLocalUri(nativeUri);
+        }
+        return null;
+    }
+
+    /**
+     * Removes multiple repeated //s, and collapses processes ../s.
+     */
+    protected static String normalizePath(String rawPath) {
+        // If this is an absolute path, trim the leading "/" and replace it later
+        boolean isAbsolutePath = rawPath.startsWith("/");
+        if (isAbsolutePath) {
+            rawPath = rawPath.replaceFirst("/+", "");
+        }
+        ArrayList<String> components = new ArrayList<String>(Arrays.asList(rawPath.split("/+")));
+        for (int index = 0; index < components.size(); ++index) {
+            if (components.get(index).equals("..")) {
+                components.remove(index);
+                if (index > 0) {
+                    components.remove(index-1);
+                    --index;
+                }
+            }
+        }
+        StringBuilder normalizedPath = new StringBuilder();
+        for(String component: components) {
+            normalizedPath.append("/");
+            normalizedPath.append(component);
+        }
+        if (isAbsolutePath) {
+            return normalizedPath.toString();
+        } else {
+            return normalizedPath.toString().substring(1);
+        }
+    }
+
+    /**
+     * Gets the free space in bytes available on this filesystem.
+     * Subclasses may override this method to return nonzero free space.
+     */
+    public long getFreeSpaceInBytes() {
+        return 0;
+    }
+
+    public abstract Uri toNativeUri(LocalFilesystemURL inputURL);
+    public abstract LocalFilesystemURL toLocalUri(Uri inputURL);
+
+    public JSONObject getRootEntry() {
+        if (rootEntry == null) {
+            rootEntry = makeEntryForNativeUri(rootUri);
+        }
+        return rootEntry;
+    }
+
+	public JSONObject getParentForLocalURL(LocalFilesystemURL inputURL) throws IOException {
+        Uri parentUri = inputURL.uri;
+        String parentPath = new File(inputURL.uri.getPath()).getParent();
+        if (!"/".equals(parentPath)) {
+            parentUri = inputURL.uri.buildUpon().path(parentPath + '/').build();
+		}
+		return getEntryForLocalURL(LocalFilesystemURL.parse(parentUri));
+	}
+
+    protected LocalFilesystemURL makeDestinationURL(String newName, LocalFilesystemURL srcURL, LocalFilesystemURL destURL, boolean isDirectory) {
+        // I know this looks weird but it is to work around a JSON bug.
+        if ("null".equals(newName) || "".equals(newName)) {
+            newName = srcURL.uri.getLastPathSegment();;
+        }
+
+        String newDest = destURL.uri.toString();
+        if (newDest.endsWith("/")) {
+            newDest = newDest + newName;
+        } else {
+            newDest = newDest + "/" + newName;
+        }
+        if (isDirectory) {
+            newDest += '/';
+        }
+        return LocalFilesystemURL.parse(newDest);
+    }
+
+	/* Read a source URL (possibly from a different filesystem, srcFs,) and copy it to
+	 * the destination URL on this filesystem, optionally with a new filename.
+	 * If move is true, then this method should either perform an atomic move operation
+	 * or remove the source file when finished.
+	 */
+    public JSONObject copyFileToURL(LocalFilesystemURL destURL, String newName,
+            Filesystem srcFs, LocalFilesystemURL srcURL, boolean move) throws IOException, InvalidModificationException, JSONException, NoModificationAllowedException, FileExistsException {
+        // First, check to see that we can do it
+        if (move && !srcFs.canRemoveFileAtLocalURL(srcURL)) {
+            throw new NoModificationAllowedException("Cannot move file at source URL");
+        }
+        final LocalFilesystemURL destination = makeDestinationURL(newName, srcURL, destURL, srcURL.isDirectory);
+
+        Uri srcNativeUri = srcFs.toNativeUri(srcURL);
+
+        CordovaResourceApi.OpenForReadResult ofrr = resourceApi.openForRead(srcNativeUri);
+        OutputStream os = null;
+        try {
+            os = getOutputStreamForURL(destination);
+        } catch (IOException e) {
+            ofrr.inputStream.close();
+            throw e;
+        }
+        // Closes streams.
+        resourceApi.copyResource(ofrr, os);
+
+        if (move) {
+            srcFs.removeFileAtLocalURL(srcURL);
+        }
+        return getEntryForLocalURL(destination);
+    }
+
+    public OutputStream getOutputStreamForURL(LocalFilesystemURL inputURL) throws IOException {
+        return resourceApi.openOutputStream(toNativeUri(inputURL));
+    }
+
+    public void readFileAtURL(LocalFilesystemURL inputURL, long start, long end,
+                              ReadFileCallback readFileCallback) throws IOException {
+        CordovaResourceApi.OpenForReadResult ofrr = resourceApi.openForRead(toNativeUri(inputURL));
+        if (end < 0) {
+            end = ofrr.length;
+        }
+        long numBytesToRead = end - start;
+        try {
+            if (start > 0) {
+                ofrr.inputStream.skip(start);
+            }
+            InputStream inputStream = ofrr.inputStream;
+            if (end < ofrr.length) {
+                inputStream = new LimitedInputStream(inputStream, numBytesToRead);
+            }
+            readFileCallback.handleData(inputStream, ofrr.mimeType);
+        } finally {
+            ofrr.inputStream.close();
+        }
+    }
+
+	abstract long writeToFileAtURL(LocalFilesystemURL inputURL, String data, int offset,
+			boolean isBinary) throws NoModificationAllowedException, IOException;
+
+	abstract long truncateFileAtURL(LocalFilesystemURL inputURL, long size)
+			throws IOException, NoModificationAllowedException;
+
+	// This method should return null if filesystem urls cannot be mapped to paths
+	abstract String filesystemPathForURL(LocalFilesystemURL url);
+
+	abstract LocalFilesystemURL URLforFilesystemPath(String path);
+
+	abstract boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL);
+
+    protected class LimitedInputStream extends FilterInputStream {
+        long numBytesToRead;
+        public LimitedInputStream(InputStream in, long numBytesToRead) {
+            super(in);
+            this.numBytesToRead = numBytesToRead;
+        }
+        @Override
+        public int read() throws IOException {
+            if (numBytesToRead <= 0) {
+                return -1;
+            }
+            numBytesToRead--;
+            return in.read();
+        }
+        @Override
+        public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
+            if (numBytesToRead <= 0) {
+                return -1;
+            }
+            int bytesToRead = byteCount;
+            if (byteCount > numBytesToRead) {
+                bytesToRead = (int)numBytesToRead; // Cast okay; long is less than int here.
+            }
+            int numBytesRead = in.read(buffer, byteOffset, bytesToRead);
+            numBytesToRead -= numBytesRead;
+            return numBytesRead;
+        }
+    }
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/file/InvalidModificationException.java b/platforms/android/app/src/main/java/org/apache/cordova/file/InvalidModificationException.java
new file mode 100644
index 0000000..8f6bec5
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/file/InvalidModificationException.java
@@ -0,0 +1,30 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+
+package org.apache.cordova.file;
+
+@SuppressWarnings("serial")
+public class InvalidModificationException extends Exception {
+
+    public InvalidModificationException(String message) {
+        super(message);
+    }
+
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/file/LocalFilesystem.java b/platforms/android/app/src/main/java/org/apache/cordova/file/LocalFilesystem.java
new file mode 100644
index 0000000..051f994
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/file/LocalFilesystem.java
@@ -0,0 +1,513 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+ */
+package org.apache.cordova.file;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+import org.apache.cordova.CordovaResourceApi;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.os.Build;
+import android.os.Environment;
+import android.util.Base64;
+import android.net.Uri;
+import android.content.Context;
+import android.content.Intent;
+
+import java.nio.charset.Charset;
+
+public class LocalFilesystem extends Filesystem {
+    private final Context context;
+
+    public LocalFilesystem(String name, Context context, CordovaResourceApi resourceApi, File fsRoot) {
+        super(Uri.fromFile(fsRoot).buildUpon().appendEncodedPath("").build(), name, resourceApi);
+        this.context = context;
+    }
+
+    public String filesystemPathForFullPath(String fullPath) {
+	    return new File(rootUri.getPath(), fullPath).toString();
+	}
+
+	@Override
+	public String filesystemPathForURL(LocalFilesystemURL url) {
+		return filesystemPathForFullPath(url.path);
+	}
+
+	private String fullPathForFilesystemPath(String absolutePath) {
+		if (absolutePath != null && absolutePath.startsWith(rootUri.getPath())) {
+			return absolutePath.substring(rootUri.getPath().length() - 1);
+		}
+		return null;
+	}
+
+    @Override
+    public Uri toNativeUri(LocalFilesystemURL inputURL) {
+        return nativeUriForFullPath(inputURL.path);
+    }
+
+    @Override
+    public LocalFilesystemURL toLocalUri(Uri inputURL) {
+        if (!"file".equals(inputURL.getScheme())) {
+            return null;
+        }
+        File f = new File(inputURL.getPath());
+        // Removes and duplicate /s (e.g. file:///a//b/c)
+        Uri resolvedUri = Uri.fromFile(f);
+        String rootUriNoTrailingSlash = rootUri.getEncodedPath();
+        rootUriNoTrailingSlash = rootUriNoTrailingSlash.substring(0, rootUriNoTrailingSlash.length() - 1);
+        if (!resolvedUri.getEncodedPath().startsWith(rootUriNoTrailingSlash)) {
+            return null;
+        }
+        String subPath = resolvedUri.getEncodedPath().substring(rootUriNoTrailingSlash.length());
+        // Strip leading slash
+        if (!subPath.isEmpty()) {
+            subPath = subPath.substring(1);
+        }
+        Uri.Builder b = new Uri.Builder()
+            .scheme(LocalFilesystemURL.FILESYSTEM_PROTOCOL)
+            .authority("localhost")
+            .path(name);
+        if (!subPath.isEmpty()) {
+            b.appendEncodedPath(subPath);
+        }
+        if (f.isDirectory()) {
+            // Add trailing / for directories.
+            b.appendEncodedPath("");
+        }
+        return LocalFilesystemURL.parse(b.build());
+    }
+
+	@Override
+	public LocalFilesystemURL URLforFilesystemPath(String path) {
+	    return localUrlforFullPath(fullPathForFilesystemPath(path));
+	}
+
+	@Override
+	public JSONObject getFileForLocalURL(LocalFilesystemURL inputURL,
+			String path, JSONObject options, boolean directory) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException {
+        boolean create = false;
+        boolean exclusive = false;
+
+        if (options != null) {
+            create = options.optBoolean("create");
+            if (create) {
+                exclusive = options.optBoolean("exclusive");
+            }
+        }
+
+        // Check for a ":" character in the file to line up with BB and iOS
+        if (path.contains(":")) {
+            throw new EncodingException("This path has an invalid \":\" in it.");
+        }
+
+        LocalFilesystemURL requestedURL;
+
+        // Check whether the supplied path is absolute or relative
+        if (directory && !path.endsWith("/")) {
+            path += "/";
+        }
+        if (path.startsWith("/")) {
+        	requestedURL = localUrlforFullPath(normalizePath(path));
+        } else {
+        	requestedURL = localUrlforFullPath(normalizePath(inputURL.path + "/" + path));
+        }
+
+        File fp = new File(this.filesystemPathForURL(requestedURL));
+
+        if (create) {
+            if (exclusive && fp.exists()) {
+                throw new FileExistsException("create/exclusive fails");
+            }
+            if (directory) {
+                fp.mkdir();
+            } else {
+                fp.createNewFile();
+            }
+            if (!fp.exists()) {
+                throw new FileExistsException("create fails");
+            }
+        }
+        else {
+            if (!fp.exists()) {
+                throw new FileNotFoundException("path does not exist");
+            }
+            if (directory) {
+                if (fp.isFile()) {
+                    throw new TypeMismatchException("path doesn't exist or is file");
+                }
+            } else {
+                if (fp.isDirectory()) {
+                    throw new TypeMismatchException("path doesn't exist or is directory");
+                }
+            }
+        }
+
+        // Return the directory
+        return makeEntryForURL(requestedURL);
+	}
+
+	@Override
+	public boolean removeFileAtLocalURL(LocalFilesystemURL inputURL) throws InvalidModificationException {
+
+        File fp = new File(filesystemPathForURL(inputURL));
+
+        // You can't delete a directory that is not empty
+        if (fp.isDirectory() && fp.list().length > 0) {
+            throw new InvalidModificationException("You can't delete a directory that is not empty.");
+        }
+
+        return fp.delete();
+	}
+
+    @Override
+    public boolean exists(LocalFilesystemURL inputURL) {
+        File fp = new File(filesystemPathForURL(inputURL));
+        return fp.exists();
+    }
+
+    @Override
+    public long getFreeSpaceInBytes() {
+        return DirectoryManager.getFreeSpaceInBytes(rootUri.getPath());
+    }
+
+    @Override
+	public boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws FileExistsException {
+        File directory = new File(filesystemPathForURL(inputURL));
+    	return removeDirRecursively(directory);
+	}
+
+	protected boolean removeDirRecursively(File directory) throws FileExistsException {
+        if (directory.isDirectory()) {
+            for (File file : directory.listFiles()) {
+                removeDirRecursively(file);
+            }
+        }
+
+        if (!directory.delete()) {
+            throw new FileExistsException("could not delete: " + directory.getName());
+        } else {
+            return true;
+        }
+	}
+
+    @Override
+    public LocalFilesystemURL[] listChildren(LocalFilesystemURL inputURL) throws FileNotFoundException {
+        File fp = new File(filesystemPathForURL(inputURL));
+
+        if (!fp.exists()) {
+            // The directory we are listing doesn't exist so we should fail.
+            throw new FileNotFoundException();
+        }
+
+        File[] files = fp.listFiles();
+        if (files == null) {
+            // inputURL is a directory
+            return null;
+        }
+        LocalFilesystemURL[] entries = new LocalFilesystemURL[files.length];
+        for (int i = 0; i < files.length; i++) {
+            entries[i] = URLforFilesystemPath(files[i].getPath());
+        }
+
+        return entries;
+	}
+
+	@Override
+	public JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException {
+        File file = new File(filesystemPathForURL(inputURL));
+
+        if (!file.exists()) {
+            throw new FileNotFoundException("File at " + inputURL.uri + " does not exist.");
+        }
+
+        JSONObject metadata = new JSONObject();
+        try {
+            // Ensure that directories report a size of 0
+        	metadata.put("size", file.isDirectory() ? 0 : file.length());
+        	metadata.put("type", resourceApi.getMimeType(Uri.fromFile(file)));
+        	metadata.put("name", file.getName());
+        	metadata.put("fullPath", inputURL.path);
+        	metadata.put("lastModifiedDate", file.lastModified());
+        } catch (JSONException e) {
+        	return null;
+        }
+        return metadata;
+	}
+
+    private void copyFile(Filesystem srcFs, LocalFilesystemURL srcURL, File destFile, boolean move) throws IOException, InvalidModificationException, NoModificationAllowedException {
+        if (move) {
+            String realSrcPath = srcFs.filesystemPathForURL(srcURL);
+            if (realSrcPath != null) {
+                File srcFile = new File(realSrcPath);
+                if (srcFile.renameTo(destFile)) {
+                    return;
+                }
+                // Trying to rename the file failed.  Possibly because we moved across file system on the device.
+            }
+        }
+
+        CordovaResourceApi.OpenForReadResult offr = resourceApi.openForRead(srcFs.toNativeUri(srcURL));
+        copyResource(offr, new FileOutputStream(destFile));
+
+        if (move) {
+            srcFs.removeFileAtLocalURL(srcURL);
+        }
+    }
+
+    private void copyDirectory(Filesystem srcFs, LocalFilesystemURL srcURL, File dstDir, boolean move) throws IOException, NoModificationAllowedException, InvalidModificationException, FileExistsException {
+        if (move) {
+            String realSrcPath = srcFs.filesystemPathForURL(srcURL);
+            if (realSrcPath != null) {
+                File srcDir = new File(realSrcPath);
+                // If the destination directory already exists and is empty then delete it.  This is according to spec.
+                if (dstDir.exists()) {
+                    if (dstDir.list().length > 0) {
+                        throw new InvalidModificationException("directory is not empty");
+                    }
+                    dstDir.delete();
+                }
+                // Try to rename the directory
+                if (srcDir.renameTo(dstDir)) {
+                    return;
+                }
+                // Trying to rename the file failed.  Possibly because we moved across file system on the device.
+            }
+        }
+
+        if (dstDir.exists()) {
+            if (dstDir.list().length > 0) {
+                throw new InvalidModificationException("directory is not empty");
+            }
+        } else {
+            if (!dstDir.mkdir()) {
+                // If we can't create the directory then fail
+                throw new NoModificationAllowedException("Couldn't create the destination directory");
+            }
+        }
+
+        LocalFilesystemURL[] children = srcFs.listChildren(srcURL);
+        for (LocalFilesystemURL childLocalUrl : children) {
+            File target = new File(dstDir, new File(childLocalUrl.path).getName());
+            if (childLocalUrl.isDirectory) {
+                copyDirectory(srcFs, childLocalUrl, target, false);
+            } else {
+                copyFile(srcFs, childLocalUrl, target, false);
+            }
+        }
+
+        if (move) {
+            srcFs.recursiveRemoveFileAtLocalURL(srcURL);
+        }
+    }
+
+	@Override
+	public JSONObject copyFileToURL(LocalFilesystemURL destURL, String newName,
+			Filesystem srcFs, LocalFilesystemURL srcURL, boolean move) throws IOException, InvalidModificationException, JSONException, NoModificationAllowedException, FileExistsException {
+
+		// Check to see if the destination directory exists
+        String newParent = this.filesystemPathForURL(destURL);
+        File destinationDir = new File(newParent);
+        if (!destinationDir.exists()) {
+            // The destination does not exist so we should fail.
+            throw new FileNotFoundException("The source does not exist");
+        }
+
+        // Figure out where we should be copying to
+        final LocalFilesystemURL destinationURL = makeDestinationURL(newName, srcURL, destURL, srcURL.isDirectory);
+
+        Uri dstNativeUri = toNativeUri(destinationURL);
+        Uri srcNativeUri = srcFs.toNativeUri(srcURL);
+        // Check to see if source and destination are the same file
+        if (dstNativeUri.equals(srcNativeUri)) {
+            throw new InvalidModificationException("Can't copy onto itself");
+        }
+
+        if (move && !srcFs.canRemoveFileAtLocalURL(srcURL)) {
+            throw new InvalidModificationException("Source URL is read-only (cannot move)");
+        }
+
+        File destFile = new File(dstNativeUri.getPath());
+        if (destFile.exists()) {
+            if (!srcURL.isDirectory && destFile.isDirectory()) {
+                throw new InvalidModificationException("Can't copy/move a file to an existing directory");
+            } else if (srcURL.isDirectory && destFile.isFile()) {
+                throw new InvalidModificationException("Can't copy/move a directory to an existing file");
+            }
+        }
+
+        if (srcURL.isDirectory) {
+            // E.g. Copy /sdcard/myDir to /sdcard/myDir/backup
+            if (dstNativeUri.toString().startsWith(srcNativeUri.toString() + '/')) {
+                throw new InvalidModificationException("Can't copy directory into itself");
+            }
+            copyDirectory(srcFs, srcURL, destFile, move);
+        } else {
+            copyFile(srcFs, srcURL, destFile, move);
+        }
+        return makeEntryForURL(destinationURL);
+	}
+
+	@Override
+	public long writeToFileAtURL(LocalFilesystemURL inputURL, String data,
+			int offset, boolean isBinary) throws IOException, NoModificationAllowedException {
+
+        boolean append = false;
+        if (offset > 0) {
+            this.truncateFileAtURL(inputURL, offset);
+            append = true;
+        }
+
+        byte[] rawData;
+        if (isBinary) {
+            rawData = Base64.decode(data, Base64.DEFAULT);
+        } else {
+            rawData = data.getBytes(Charset.defaultCharset());
+        }
+        ByteArrayInputStream in = new ByteArrayInputStream(rawData);
+        try
+        {
+        	byte buff[] = new byte[rawData.length];
+            String absolutePath = filesystemPathForURL(inputURL);
+            FileOutputStream out = new FileOutputStream(absolutePath, append);
+            try {
+            	in.read(buff, 0, buff.length);
+            	out.write(buff, 0, rawData.length);
+            	out.flush();
+            } finally {
+            	// Always close the output
+            	out.close();
+            }
+            if (isPublicDirectory(absolutePath)) {
+                broadcastNewFile(Uri.fromFile(new File(absolutePath)));
+            }
+        }
+        catch (NullPointerException e)
+        {
+            // This is a bug in the Android implementation of the Java Stack
+            NoModificationAllowedException realException = new NoModificationAllowedException(inputURL.toString());
+            realException.initCause(e);
+            throw realException;
+        }
+
+        return rawData.length;
+	}
+
+    private boolean isPublicDirectory(String absolutePath) {
+        // TODO: should expose a way to scan app's private files (maybe via a flag).
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            // Lollipop has a bug where SD cards are null.
+            for (File f : context.getExternalMediaDirs()) {
+                if(f != null && absolutePath.startsWith(f.getAbsolutePath())) {
+                    return true;
+                }
+            }
+        }
+
+        String extPath = Environment.getExternalStorageDirectory().getAbsolutePath();
+        return absolutePath.startsWith(extPath);
+    }
+
+     /**
+     * Send broadcast of new file so files appear over MTP
+     */
+    private void broadcastNewFile(Uri nativeUri) {
+        Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, nativeUri);
+        context.sendBroadcast(intent);
+    }
+
+	@Override
+	public long truncateFileAtURL(LocalFilesystemURL inputURL, long size) throws IOException {
+        File file = new File(filesystemPathForURL(inputURL));
+
+        if (!file.exists()) {
+            throw new FileNotFoundException("File at " + inputURL.uri + " does not exist.");
+        }
+
+        RandomAccessFile raf = new RandomAccessFile(filesystemPathForURL(inputURL), "rw");
+        try {
+            if (raf.length() >= size) {
+                FileChannel channel = raf.getChannel();
+                channel.truncate(size);
+                return size;
+            }
+
+            return raf.length();
+        } finally {
+            raf.close();
+        }
+
+
+	}
+
+	@Override
+	public boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL) {
+		String path = filesystemPathForURL(inputURL);
+		File file = new File(path);
+		return file.exists();
+	}
+
+    // This is a copy & paste from CordovaResource API that is required since CordovaResourceApi
+    // has a bug pre-4.0.0.
+    // TODO: Once cordova-android@4.0.0 is released, delete this copy and make the plugin depend on
+    // 4.0.0 with an engine tag.
+    private static void copyResource(CordovaResourceApi.OpenForReadResult input, OutputStream outputStream) throws IOException {
+        try {
+            InputStream inputStream = input.inputStream;
+            if (inputStream instanceof FileInputStream && outputStream instanceof FileOutputStream) {
+                FileChannel inChannel = ((FileInputStream)input.inputStream).getChannel();
+                FileChannel outChannel = ((FileOutputStream)outputStream).getChannel();
+                long offset = 0;
+                long length = input.length;
+                if (input.assetFd != null) {
+                    offset = input.assetFd.getStartOffset();
+                }
+                // transferFrom()'s 2nd arg is a relative position. Need to set the absolute
+                // position first.
+                inChannel.position(offset);
+                outChannel.transferFrom(inChannel, 0, length);
+            } else {
+                final int BUFFER_SIZE = 8192;
+                byte[] buffer = new byte[BUFFER_SIZE];
+
+                for (;;) {
+                    int bytesRead = inputStream.read(buffer, 0, BUFFER_SIZE);
+
+                    if (bytesRead <= 0) {
+                        break;
+                    }
+                    outputStream.write(buffer, 0, bytesRead);
+                }
+            }
+        } finally {
+            input.inputStream.close();
+            if (outputStream != null) {
+                outputStream.close();
+            }
+        }
+    }
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/file/LocalFilesystemURL.java b/platforms/android/app/src/main/java/org/apache/cordova/file/LocalFilesystemURL.java
new file mode 100644
index 0000000..b96b6ee
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/file/LocalFilesystemURL.java
@@ -0,0 +1,64 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+ */
+package org.apache.cordova.file;
+
+import android.net.Uri;
+
+public class LocalFilesystemURL {
+	
+	public static final String FILESYSTEM_PROTOCOL = "cdvfile";
+
+    public final Uri uri;
+    public final String fsName;
+    public final String path;
+    public final boolean isDirectory;
+
+	private LocalFilesystemURL(Uri uri, String fsName, String fsPath, boolean isDirectory) {
+		this.uri = uri;
+        this.fsName = fsName;
+        this.path = fsPath;
+        this.isDirectory = isDirectory;
+	}
+
+    public static LocalFilesystemURL parse(Uri uri) {
+        if (!FILESYSTEM_PROTOCOL.equals(uri.getScheme())) {
+            return null;
+        }
+        String path = uri.getPath();
+        if (path.length() < 1) {
+            return null;
+        }
+        int firstSlashIdx = path.indexOf('/', 1);
+        if (firstSlashIdx < 0) {
+            return null;
+        }
+        String fsName = path.substring(1, firstSlashIdx);
+        path = path.substring(firstSlashIdx);
+        boolean isDirectory = path.charAt(path.length() - 1) == '/';
+        return new LocalFilesystemURL(uri, fsName, path, isDirectory);
+    }
+
+    public static LocalFilesystemURL parse(String uri) {
+        return parse(Uri.parse(uri));
+    }
+
+    public String toString() {
+        return uri.toString();
+    }
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/file/NoModificationAllowedException.java b/platforms/android/app/src/main/java/org/apache/cordova/file/NoModificationAllowedException.java
new file mode 100644
index 0000000..627eafb
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/file/NoModificationAllowedException.java
@@ -0,0 +1,29 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova.file;
+
+@SuppressWarnings("serial")
+public class NoModificationAllowedException extends Exception {
+
+    public NoModificationAllowedException(String message) {
+        super(message);
+    }
+
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/file/PendingRequests.java b/platforms/android/app/src/main/java/org/apache/cordova/file/PendingRequests.java
new file mode 100644
index 0000000..23d6d73
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/file/PendingRequests.java
@@ -0,0 +1,94 @@
+/*

+       Licensed to the Apache Software Foundation (ASF) under one

+       or more contributor license agreements.  See the NOTICE file

+       distributed with this work for additional information

+       regarding copyright ownership.  The ASF licenses this file

+       to you under the Apache License, Version 2.0 (the

+       "License"); you may not use this file except in compliance

+       with the License.  You may obtain a copy of the License at

+

+         http://www.apache.org/licenses/LICENSE-2.0

+

+       Unless required by applicable law or agreed to in writing,

+       software distributed under the License is distributed on an

+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+       KIND, either express or implied.  See the License for the

+       specific language governing permissions and limitations

+       under the License.

+*/

+package org.apache.cordova.file;

+

+import android.util.SparseArray;

+

+import org.apache.cordova.CallbackContext;

+

+/**

+ * Holds pending runtime permission requests

+ */

+class PendingRequests {

+    private int currentReqId = 0;

+    private SparseArray<Request> requests = new SparseArray<Request>();

+

+    /**

+     * Creates a request and adds it to the array of pending requests. Each created request gets a

+     * unique result code for use with requestPermission()

+     * @param rawArgs           The raw arguments passed to the plugin

+     * @param action            The action this request corresponds to (get file, etc.)

+     * @param callbackContext   The CallbackContext for this plugin call

+     * @return                  The request code that can be used to retrieve the Request object

+     */

+    public synchronized int createRequest(String rawArgs, int action, CallbackContext callbackContext)  {

+        Request req = new Request(rawArgs, action, callbackContext);

+        requests.put(req.requestCode, req);

+        return req.requestCode;

+    }

+

+    /**

+     * Gets the request corresponding to this request code and removes it from the pending requests

+     * @param requestCode   The request code for the desired request

+     * @return              The request corresponding to the given request code or null if such a

+     *                      request is not found

+     */

+    public synchronized Request getAndRemove(int requestCode) {

+        Request result = requests.get(requestCode);

+        requests.remove(requestCode);

+        return result;

+    }

+

+    /**

+     * Holds the options and CallbackContext for a call made to the plugin.

+     */

+    public class Request {

+

+        // Unique int used to identify this request in any Android permission callback

+        private int requestCode;

+

+        // Action to be performed after permission request result

+        private int action;

+

+        // Raw arguments passed to plugin

+        private String rawArgs;

+

+        // The callback context for this plugin request

+        private CallbackContext callbackContext;

+

+        private Request(String rawArgs, int action, CallbackContext callbackContext) {

+            this.rawArgs = rawArgs;

+            this.action = action;

+            this.callbackContext = callbackContext;

+            this.requestCode = currentReqId ++;

+        }

+

+        public int getAction() {

+            return this.action;

+        }

+

+        public String getRawArgs() {

+            return rawArgs;

+        }

+

+        public CallbackContext getCallbackContext() {

+            return callbackContext;

+        }

+    }

+}

diff --git a/platforms/android/app/src/main/java/org/apache/cordova/file/TypeMismatchException.java b/platforms/android/app/src/main/java/org/apache/cordova/file/TypeMismatchException.java
new file mode 100644
index 0000000..1315f9a
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/file/TypeMismatchException.java
@@ -0,0 +1,30 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+
+package org.apache.cordova.file;
+
+@SuppressWarnings("serial")
+public class TypeMismatchException extends Exception {
+
+    public TypeMismatchException(String message) {
+        super(message);
+    }
+
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/inappbrowser/InAppBrowser.java b/platforms/android/app/src/main/java/org/apache/cordova/inappbrowser/InAppBrowser.java
new file mode 100644
index 0000000..9b3388c
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/inappbrowser/InAppBrowser.java
@@ -0,0 +1,1259 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.inappbrowser;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Browser;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.text.InputType;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.webkit.CookieManager;
+import android.webkit.CookieSyncManager;
+import android.webkit.HttpAuthHandler;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.Config;
+import org.apache.cordova.CordovaArgs;
+import org.apache.cordova.CordovaHttpAuthHandler;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.LOG;
+import org.apache.cordova.PluginManager;
+import org.apache.cordova.PluginResult;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+
+@SuppressLint("SetJavaScriptEnabled")
+public class InAppBrowser extends CordovaPlugin {
+
+    private static final String NULL = "null";
+    protected static final String LOG_TAG = "InAppBrowser";
+    private static final String SELF = "_self";
+    private static final String SYSTEM = "_system";
+    private static final String EXIT_EVENT = "exit";
+    private static final String LOCATION = "location";
+    private static final String ZOOM = "zoom";
+    private static final String HIDDEN = "hidden";
+    private static final String LOAD_START_EVENT = "loadstart";
+    private static final String LOAD_STOP_EVENT = "loadstop";
+    private static final String LOAD_ERROR_EVENT = "loaderror";
+    private static final String CLEAR_ALL_CACHE = "clearcache";
+    private static final String CLEAR_SESSION_CACHE = "clearsessioncache";
+    private static final String HARDWARE_BACK_BUTTON = "hardwareback";
+    private static final String MEDIA_PLAYBACK_REQUIRES_USER_ACTION = "mediaPlaybackRequiresUserAction";
+    private static final String SHOULD_PAUSE = "shouldPauseOnSuspend";
+    private static final Boolean DEFAULT_HARDWARE_BACK = true;
+    private static final String USER_WIDE_VIEW_PORT = "useWideViewPort";
+    private static final String TOOLBAR_COLOR = "toolbarcolor";
+    private static final String CLOSE_BUTTON_CAPTION = "closebuttoncaption";
+    private static final String CLOSE_BUTTON_COLOR = "closebuttoncolor";
+    private static final String HIDE_NAVIGATION = "hidenavigationbuttons";
+    private static final String NAVIGATION_COLOR = "navigationbuttoncolor";
+    private static final String HIDE_URL = "hideurlbar";
+    private static final String FOOTER = "footer";
+    private static final String FOOTER_COLOR = "footercolor";
+
+    private static final List customizableOptions = Arrays.asList(CLOSE_BUTTON_CAPTION, TOOLBAR_COLOR, NAVIGATION_COLOR, CLOSE_BUTTON_COLOR, FOOTER_COLOR);
+
+    private InAppBrowserDialog dialog;
+    private WebView inAppWebView;
+    private EditText edittext;
+    private CallbackContext callbackContext;
+    private boolean showLocationBar = true;
+    private boolean showZoomControls = true;
+    private boolean openWindowHidden = false;
+    private boolean clearAllCache = false;
+    private boolean clearSessionCache = false;
+    private boolean hadwareBackButton = true;
+    private boolean mediaPlaybackRequiresUserGesture = false;
+    private boolean shouldPauseInAppBrowser = false;
+    private boolean useWideViewPort = true;
+    private ValueCallback<Uri> mUploadCallback;
+    private ValueCallback<Uri[]> mUploadCallbackLollipop;
+    private final static int FILECHOOSER_REQUESTCODE = 1;
+    private final static int FILECHOOSER_REQUESTCODE_LOLLIPOP = 2;
+    private String closeButtonCaption = "";
+    private String closeButtonColor = "";
+    private int toolbarColor = android.graphics.Color.LTGRAY;
+    private boolean hideNavigationButtons = false;
+    private String navigationButtonColor = "";
+    private boolean hideUrlBar = false;
+    private boolean showFooter = false;
+    private String footerColor = "";
+    private String[] allowedSchemes;
+
+    /**
+     * Executes the request and returns PluginResult.
+     *
+     * @param action the action to execute.
+     * @param args JSONArry of arguments for the plugin.
+     * @param callbackContext the callbackContext used when calling back into JavaScript.
+     * @return A PluginResult object with a status and message.
+     */
+    public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
+        if (action.equals("open")) {
+            this.callbackContext = callbackContext;
+            final String url = args.getString(0);
+            String t = args.optString(1);
+            if (t == null || t.equals("") || t.equals(NULL)) {
+                t = SELF;
+            }
+            final String target = t;
+            final HashMap<String, String> features = parseFeature(args.optString(2));
+
+            LOG.d(LOG_TAG, "target = " + target);
+
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    String result = "";
+                    // SELF
+                    if (SELF.equals(target)) {
+                        LOG.d(LOG_TAG, "in self");
+                        /* This code exists for compatibility between 3.x and 4.x versions of Cordova.
+                         * Previously the Config class had a static method, isUrlWhitelisted(). That
+                         * responsibility has been moved to the plugins, with an aggregating method in
+                         * PluginManager.
+                         */
+                        Boolean shouldAllowNavigation = null;
+                        if (url.startsWith("javascript:")) {
+                            shouldAllowNavigation = true;
+                        }
+                        if (shouldAllowNavigation == null) {
+                            try {
+                                Method iuw = Config.class.getMethod("isUrlWhiteListed", String.class);
+                                shouldAllowNavigation = (Boolean)iuw.invoke(null, url);
+                            } catch (NoSuchMethodException e) {
+                                LOG.d(LOG_TAG, e.getLocalizedMessage());
+                            } catch (IllegalAccessException e) {
+                                LOG.d(LOG_TAG, e.getLocalizedMessage());
+                            } catch (InvocationTargetException e) {
+                                LOG.d(LOG_TAG, e.getLocalizedMessage());
+                            }
+                        }
+                        if (shouldAllowNavigation == null) {
+                            try {
+                                Method gpm = webView.getClass().getMethod("getPluginManager");
+                                PluginManager pm = (PluginManager)gpm.invoke(webView);
+                                Method san = pm.getClass().getMethod("shouldAllowNavigation", String.class);
+                                shouldAllowNavigation = (Boolean)san.invoke(pm, url);
+                            } catch (NoSuchMethodException e) {
+                                LOG.d(LOG_TAG, e.getLocalizedMessage());
+                            } catch (IllegalAccessException e) {
+                                LOG.d(LOG_TAG, e.getLocalizedMessage());
+                            } catch (InvocationTargetException e) {
+                                LOG.d(LOG_TAG, e.getLocalizedMessage());
+                            }
+                        }
+                        // load in webview
+                        if (Boolean.TRUE.equals(shouldAllowNavigation)) {
+                            LOG.d(LOG_TAG, "loading in webview");
+                            webView.loadUrl(url);
+                        }
+                        //Load the dialer
+                        else if (url.startsWith(WebView.SCHEME_TEL))
+                        {
+                            try {
+                                LOG.d(LOG_TAG, "loading in dialer");
+                                Intent intent = new Intent(Intent.ACTION_DIAL);
+                                intent.setData(Uri.parse(url));
+                                cordova.getActivity().startActivity(intent);
+                            } catch (android.content.ActivityNotFoundException e) {
+                                LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
+                            }
+                        }
+                        // load in InAppBrowser
+                        else {
+                            LOG.d(LOG_TAG, "loading in InAppBrowser");
+                            result = showWebPage(url, features);
+                        }
+                    }
+                    // SYSTEM
+                    else if (SYSTEM.equals(target)) {
+                        LOG.d(LOG_TAG, "in system");
+                        result = openExternal(url);
+                    }
+                    // BLANK - or anything else
+                    else {
+                        LOG.d(LOG_TAG, "in blank");
+                        result = showWebPage(url, features);
+                    }
+
+                    PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, result);
+                    pluginResult.setKeepCallback(true);
+                    callbackContext.sendPluginResult(pluginResult);
+                }
+            });
+        }
+        else if (action.equals("close")) {
+            closeDialog();
+        }
+        else if (action.equals("injectScriptCode")) {
+            String jsWrapper = null;
+            if (args.getBoolean(1)) {
+                jsWrapper = String.format("(function(){prompt(JSON.stringify([eval(%%s)]), 'gap-iab://%s')})()", callbackContext.getCallbackId());
+            }
+            injectDeferredObject(args.getString(0), jsWrapper);
+        }
+        else if (action.equals("injectScriptFile")) {
+            String jsWrapper;
+            if (args.getBoolean(1)) {
+                jsWrapper = String.format("(function(d) { var c = d.createElement('script'); c.src = %%s; c.onload = function() { prompt('', 'gap-iab://%s'); }; d.body.appendChild(c); })(document)", callbackContext.getCallbackId());
+            } else {
+                jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)";
+            }
+            injectDeferredObject(args.getString(0), jsWrapper);
+        }
+        else if (action.equals("injectStyleCode")) {
+            String jsWrapper;
+            if (args.getBoolean(1)) {
+                jsWrapper = String.format("(function(d) { var c = d.createElement('style'); c.innerHTML = %%s; d.body.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
+            } else {
+                jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)";
+            }
+            injectDeferredObject(args.getString(0), jsWrapper);
+        }
+        else if (action.equals("injectStyleFile")) {
+            String jsWrapper;
+            if (args.getBoolean(1)) {
+                jsWrapper = String.format("(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%s; d.head.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
+            } else {
+                jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document)";
+            }
+            injectDeferredObject(args.getString(0), jsWrapper);
+        }
+        else if (action.equals("show")) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    dialog.show();
+                }
+            });
+            PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
+            pluginResult.setKeepCallback(true);
+            this.callbackContext.sendPluginResult(pluginResult);
+        }
+        else if (action.equals("hide")) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    dialog.hide();
+                }
+            });
+            PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
+            pluginResult.setKeepCallback(true);
+            this.callbackContext.sendPluginResult(pluginResult);
+        }
+        else {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Called when the view navigates.
+     */
+    @Override
+    public void onReset() {
+        closeDialog();
+    }
+
+    /**
+     * Called when the system is about to start resuming a previous activity.
+     */
+    @Override
+    public void onPause(boolean multitasking) {
+        if (shouldPauseInAppBrowser) {
+            inAppWebView.onPause();
+        }
+    }
+
+    /**
+     * Called when the activity will start interacting with the user.
+     */
+    @Override
+    public void onResume(boolean multitasking) {
+        if (shouldPauseInAppBrowser) {
+            inAppWebView.onResume();
+        }
+    }
+
+    /**
+     * Called by AccelBroker when listener is to be shut down.
+     * Stop listener.
+     */
+    public void onDestroy() {
+        closeDialog();
+    }
+
+    /**
+     * Inject an object (script or style) into the InAppBrowser WebView.
+     *
+     * This is a helper method for the inject{Script|Style}{Code|File} API calls, which
+     * provides a consistent method for injecting JavaScript code into the document.
+     *
+     * If a wrapper string is supplied, then the source string will be JSON-encoded (adding
+     * quotes) and wrapped using string formatting. (The wrapper string should have a single
+     * '%s' marker)
+     *
+     * @param source      The source object (filename or script/style text) to inject into
+     *                    the document.
+     * @param jsWrapper   A JavaScript string to wrap the source string in, so that the object
+     *                    is properly injected, or null if the source string is JavaScript text
+     *                    which should be executed directly.
+     */
+    private void injectDeferredObject(String source, String jsWrapper) {
+        if (inAppWebView!=null) {
+            String scriptToInject;
+            if (jsWrapper != null) {
+                org.json.JSONArray jsonEsc = new org.json.JSONArray();
+                jsonEsc.put(source);
+                String jsonRepr = jsonEsc.toString();
+                String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
+                scriptToInject = String.format(jsWrapper, jsonSourceString);
+            } else {
+                scriptToInject = source;
+            }
+            final String finalScriptToInject = scriptToInject;
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @SuppressLint("NewApi")
+                @Override
+                public void run() {
+                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+                        // This action will have the side-effect of blurring the currently focused element
+                        inAppWebView.loadUrl("javascript:" + finalScriptToInject);
+                    } else {
+                        inAppWebView.evaluateJavascript(finalScriptToInject, null);
+                    }
+                }
+            });
+        } else {
+            LOG.d(LOG_TAG, "Can't inject code into the system browser");
+        }
+    }
+
+    /**
+     * Put the list of features into a hash map
+     *
+     * @param optString
+     * @return
+     */
+    private HashMap<String, String> parseFeature(String optString) {
+        if (optString.equals(NULL)) {
+            return null;
+        } else {
+            HashMap<String, String> map = new HashMap<String, String>();
+            StringTokenizer features = new StringTokenizer(optString, ",");
+            StringTokenizer option;
+            while(features.hasMoreElements()) {
+                option = new StringTokenizer(features.nextToken(), "=");
+                if (option.hasMoreElements()) {
+                    String key = option.nextToken();
+                    String value = option.nextToken();
+                    if (!customizableOptions.contains(key)){
+                        value = value.equals("yes") || value.equals("no") ? value : "yes";
+                    }
+                    map.put(key, value);
+                }
+            }
+            return map;
+        }
+    }
+
+    /**
+     * Display a new browser with the specified URL.
+     *
+     * @param url the url to load.
+     * @return "" if ok, or error message.
+     */
+    public String openExternal(String url) {
+        try {
+            Intent intent = null;
+            intent = new Intent(Intent.ACTION_VIEW);
+            // Omitting the MIME type for file: URLs causes "No Activity found to handle Intent".
+            // Adding the MIME type to http: URLs causes them to not be handled by the downloader.
+            Uri uri = Uri.parse(url);
+            if ("file".equals(uri.getScheme())) {
+                intent.setDataAndType(uri, webView.getResourceApi().getMimeType(uri));
+            } else {
+                intent.setData(uri);
+            }
+            intent.putExtra(Browser.EXTRA_APPLICATION_ID, cordova.getActivity().getPackageName());
+            this.cordova.getActivity().startActivity(intent);
+            return "";
+            // not catching FileUriExposedException explicitly because buildtools<24 doesn't know about it
+        } catch (java.lang.RuntimeException e) {
+            LOG.d(LOG_TAG, "InAppBrowser: Error loading url "+url+":"+ e.toString());
+            return e.toString();
+        }
+    }
+
+    /**
+     * Closes the dialog
+     */
+    public void closeDialog() {
+        this.cordova.getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final WebView childView = inAppWebView;
+                // The JS protects against multiple calls, so this should happen only when
+                // closeDialog() is called by other native code.
+                if (childView == null) {
+                    return;
+                }
+
+                childView.setWebViewClient(new WebViewClient() {
+                    // NB: wait for about:blank before dismissing
+                    public void onPageFinished(WebView view, String url) {
+                        if (dialog != null) {
+                            dialog.dismiss();
+                            dialog = null;
+                        }
+                    }
+                });
+                // NB: From SDK 19: "If you call methods on WebView from any thread
+                // other than your app's UI thread, it can cause unexpected results."
+                // http://developer.android.com/guide/webapps/migrating.html#Threads
+                childView.loadUrl("about:blank");
+
+                try {
+                    JSONObject obj = new JSONObject();
+                    obj.put("type", EXIT_EVENT);
+                    sendUpdate(obj, false);
+                } catch (JSONException ex) {
+                    LOG.d(LOG_TAG, "Should never happen");
+                }
+            }
+        });
+    }
+
+    /**
+     * Checks to see if it is possible to go back one page in history, then does so.
+     */
+    public void goBack() {
+        if (this.inAppWebView.canGoBack()) {
+            this.inAppWebView.goBack();
+        }
+    }
+
+    /**
+     * Can the web browser go back?
+     * @return boolean
+     */
+    public boolean canGoBack() {
+        return this.inAppWebView.canGoBack();
+    }
+
+    /**
+     * Has the user set the hardware back button to go back
+     * @return boolean
+     */
+    public boolean hardwareBack() {
+        return hadwareBackButton;
+    }
+
+    /**
+     * Checks to see if it is possible to go forward one page in history, then does so.
+     */
+    private void goForward() {
+        if (this.inAppWebView.canGoForward()) {
+            this.inAppWebView.goForward();
+        }
+    }
+
+    /**
+     * Navigate to the new page
+     *
+     * @param url to load
+     */
+    private void navigate(String url) {
+        InputMethodManager imm = (InputMethodManager)this.cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
+        imm.hideSoftInputFromWindow(edittext.getWindowToken(), 0);
+
+        if (!url.startsWith("http") && !url.startsWith("file:")) {
+            this.inAppWebView.loadUrl("http://" + url);
+        } else {
+            this.inAppWebView.loadUrl(url);
+        }
+        this.inAppWebView.requestFocus();
+    }
+
+
+    /**
+     * Should we show the location bar?
+     *
+     * @return boolean
+     */
+    private boolean getShowLocationBar() {
+        return this.showLocationBar;
+    }
+
+    private InAppBrowser getInAppBrowser(){
+        return this;
+    }
+
+    /**
+     * Display a new browser with the specified URL.
+     *
+     * @param url the url to load.
+     * @param features jsonObject
+     */
+    public String showWebPage(final String url, HashMap<String, String> features) {
+        // Determine if we should hide the location bar.
+        showLocationBar = true;
+        showZoomControls = true;
+        openWindowHidden = false;
+        mediaPlaybackRequiresUserGesture = false;
+
+        if (features != null) {
+            String show = features.get(LOCATION);
+            if (show != null) {
+                showLocationBar = show.equals("yes") ? true : false;
+            }
+            if(showLocationBar) {
+                String hideNavigation = features.get(HIDE_NAVIGATION);
+                String hideUrl = features.get(HIDE_URL);
+                if(hideNavigation != null) hideNavigationButtons = hideNavigation.equals("yes") ? true : false;
+                if(hideUrl != null) hideUrlBar = hideUrl.equals("yes") ? true : false;
+            }
+            String zoom = features.get(ZOOM);
+            if (zoom != null) {
+                showZoomControls = zoom.equals("yes") ? true : false;
+            }
+            String hidden = features.get(HIDDEN);
+            if (hidden != null) {
+                openWindowHidden = hidden.equals("yes") ? true : false;
+            }
+            String hardwareBack = features.get(HARDWARE_BACK_BUTTON);
+            if (hardwareBack != null) {
+                hadwareBackButton = hardwareBack.equals("yes") ? true : false;
+            } else {
+                hadwareBackButton = DEFAULT_HARDWARE_BACK;
+            }
+            String mediaPlayback = features.get(MEDIA_PLAYBACK_REQUIRES_USER_ACTION);
+            if (mediaPlayback != null) {
+                mediaPlaybackRequiresUserGesture = mediaPlayback.equals("yes") ? true : false;
+            }
+            String cache = features.get(CLEAR_ALL_CACHE);
+            if (cache != null) {
+                clearAllCache = cache.equals("yes") ? true : false;
+            } else {
+                cache = features.get(CLEAR_SESSION_CACHE);
+                if (cache != null) {
+                    clearSessionCache = cache.equals("yes") ? true : false;
+                }
+            }
+            String shouldPause = features.get(SHOULD_PAUSE);
+            if (shouldPause != null) {
+                shouldPauseInAppBrowser = shouldPause.equals("yes") ? true : false;
+            }
+            String wideViewPort = features.get(USER_WIDE_VIEW_PORT);
+            if (wideViewPort != null ) {
+                useWideViewPort = wideViewPort.equals("yes") ? true : false;
+            }
+            String closeButtonCaptionSet = features.get(CLOSE_BUTTON_CAPTION);
+            if (closeButtonCaptionSet != null) {
+                closeButtonCaption = closeButtonCaptionSet;
+            }
+            String closeButtonColorSet = features.get(CLOSE_BUTTON_COLOR);
+            if (closeButtonColorSet != null) {
+                closeButtonColor = closeButtonColorSet;
+            }
+            String toolbarColorSet = features.get(TOOLBAR_COLOR);
+            if (toolbarColorSet != null) {
+                toolbarColor = android.graphics.Color.parseColor(toolbarColorSet);
+            }
+            String navigationButtonColorSet = features.get(NAVIGATION_COLOR);
+            if (navigationButtonColorSet != null) {
+                navigationButtonColor = navigationButtonColorSet;
+            }
+            String showFooterSet = features.get(FOOTER);
+            if (showFooterSet != null) {
+                showFooter = showFooterSet.equals("yes") ? true : false;
+            }
+            String footerColorSet = features.get(FOOTER_COLOR);
+            if (footerColorSet != null) {
+                footerColor = footerColorSet;
+            }
+        }
+
+        final CordovaWebView thatWebView = this.webView;
+
+        // Create dialog in new thread
+        Runnable runnable = new Runnable() {
+            /**
+             * Convert our DIP units to Pixels
+             *
+             * @return int
+             */
+            private int dpToPixels(int dipValue) {
+                int value = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP,
+                        (float) dipValue,
+                        cordova.getActivity().getResources().getDisplayMetrics()
+                );
+
+                return value;
+            }
+
+            private View createCloseButton(int id){
+                View _close;
+                Resources activityRes = cordova.getActivity().getResources();
+
+                if (closeButtonCaption != "") {
+                    // Use TextView for text
+                    TextView close = new TextView(cordova.getActivity());
+                    close.setText(closeButtonCaption);
+                    close.setTextSize(20);
+                    if (closeButtonColor != "") close.setTextColor(android.graphics.Color.parseColor(closeButtonColor));
+                    close.setGravity(android.view.Gravity.CENTER_VERTICAL);
+                    close.setPadding(this.dpToPixels(10), 0, this.dpToPixels(10), 0);
+                    _close = close;
+                }
+                else {
+                    ImageButton close = new ImageButton(cordova.getActivity());
+                    int closeResId = activityRes.getIdentifier("ic_action_remove", "drawable", cordova.getActivity().getPackageName());
+                    Drawable closeIcon = activityRes.getDrawable(closeResId);
+                    if (closeButtonColor != "") close.setColorFilter(android.graphics.Color.parseColor(closeButtonColor));
+                    close.setImageDrawable(closeIcon);
+                    close.setScaleType(ImageView.ScaleType.FIT_CENTER);
+                    if (Build.VERSION.SDK_INT >= 16)
+                        close.getAdjustViewBounds();
+
+                    _close = close;
+                }
+
+                RelativeLayout.LayoutParams closeLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
+                closeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+                _close.setLayoutParams(closeLayoutParams);
+
+                if (Build.VERSION.SDK_INT >= 16)
+                    _close.setBackground(null);
+                else
+                    _close.setBackgroundDrawable(null);
+
+                _close.setContentDescription("Close Button");
+                _close.setId(Integer.valueOf(id));
+                _close.setOnClickListener(new View.OnClickListener() {
+                    public void onClick(View v) {
+                        closeDialog();
+                    }
+                });
+
+                return _close;
+            }
+
+            @SuppressLint("NewApi")
+            public void run() {
+
+                // CB-6702 InAppBrowser hangs when opening more than one instance
+                if (dialog != null) {
+                    dialog.dismiss();
+                };
+
+                // Let's create the main dialog
+                dialog = new InAppBrowserDialog(cordova.getActivity(), android.R.style.Theme_NoTitleBar);
+                dialog.getWindow().getAttributes().windowAnimations = android.R.style.Animation_Dialog;
+                dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+                dialog.setCancelable(true);
+                dialog.setInAppBroswer(getInAppBrowser());
+
+                // Main container layout
+                LinearLayout main = new LinearLayout(cordova.getActivity());
+                main.setOrientation(LinearLayout.VERTICAL);
+
+                // Toolbar layout
+                RelativeLayout toolbar = new RelativeLayout(cordova.getActivity());
+                //Please, no more black!
+                toolbar.setBackgroundColor(toolbarColor);
+                toolbar.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, this.dpToPixels(44)));
+                toolbar.setPadding(this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2));
+                toolbar.setHorizontalGravity(Gravity.LEFT);
+                toolbar.setVerticalGravity(Gravity.TOP);
+
+                // Action Button Container layout
+                RelativeLayout actionButtonContainer = new RelativeLayout(cordova.getActivity());
+                actionButtonContainer.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+                actionButtonContainer.setHorizontalGravity(Gravity.LEFT);
+                actionButtonContainer.setVerticalGravity(Gravity.CENTER_VERTICAL);
+                actionButtonContainer.setId(Integer.valueOf(1));
+
+                // Back button
+                ImageButton back = new ImageButton(cordova.getActivity());
+                RelativeLayout.LayoutParams backLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
+                backLayoutParams.addRule(RelativeLayout.ALIGN_LEFT);
+                back.setLayoutParams(backLayoutParams);
+                back.setContentDescription("Back Button");
+                back.setId(Integer.valueOf(2));
+                Resources activityRes = cordova.getActivity().getResources();
+                int backResId = activityRes.getIdentifier("ic_action_previous_item", "drawable", cordova.getActivity().getPackageName());
+                Drawable backIcon = activityRes.getDrawable(backResId);
+                if (navigationButtonColor != "") back.setColorFilter(android.graphics.Color.parseColor(navigationButtonColor));
+                if (Build.VERSION.SDK_INT >= 16)
+                    back.setBackground(null);
+                else
+                    back.setBackgroundDrawable(null);
+                back.setImageDrawable(backIcon);
+                back.setScaleType(ImageView.ScaleType.FIT_CENTER);
+                back.setPadding(0, this.dpToPixels(10), 0, this.dpToPixels(10));
+                if (Build.VERSION.SDK_INT >= 16)
+                    back.getAdjustViewBounds();
+
+                back.setOnClickListener(new View.OnClickListener() {
+                    public void onClick(View v) {
+                        goBack();
+                    }
+                });
+
+                // Forward button
+                ImageButton forward = new ImageButton(cordova.getActivity());
+                RelativeLayout.LayoutParams forwardLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
+                forwardLayoutParams.addRule(RelativeLayout.RIGHT_OF, 2);
+                forward.setLayoutParams(forwardLayoutParams);
+                forward.setContentDescription("Forward Button");
+                forward.setId(Integer.valueOf(3));
+                int fwdResId = activityRes.getIdentifier("ic_action_next_item", "drawable", cordova.getActivity().getPackageName());
+                Drawable fwdIcon = activityRes.getDrawable(fwdResId);
+                if (navigationButtonColor != "") forward.setColorFilter(android.graphics.Color.parseColor(navigationButtonColor));
+                if (Build.VERSION.SDK_INT >= 16)
+                    forward.setBackground(null);
+                else
+                    forward.setBackgroundDrawable(null);
+                forward.setImageDrawable(fwdIcon);
+                forward.setScaleType(ImageView.ScaleType.FIT_CENTER);
+                forward.setPadding(0, this.dpToPixels(10), 0, this.dpToPixels(10));
+                if (Build.VERSION.SDK_INT >= 16)
+                    forward.getAdjustViewBounds();
+
+                forward.setOnClickListener(new View.OnClickListener() {
+                    public void onClick(View v) {
+                        goForward();
+                    }
+                });
+
+                // Edit Text Box
+                edittext = new EditText(cordova.getActivity());
+                RelativeLayout.LayoutParams textLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+                textLayoutParams.addRule(RelativeLayout.RIGHT_OF, 1);
+                textLayoutParams.addRule(RelativeLayout.LEFT_OF, 5);
+                edittext.setLayoutParams(textLayoutParams);
+                edittext.setId(Integer.valueOf(4));
+                edittext.setSingleLine(true);
+                edittext.setText(url);
+                edittext.setInputType(InputType.TYPE_TEXT_VARIATION_URI);
+                edittext.setImeOptions(EditorInfo.IME_ACTION_GO);
+                edittext.setInputType(InputType.TYPE_NULL); // Will not except input... Makes the text NON-EDITABLE
+                edittext.setOnKeyListener(new View.OnKeyListener() {
+                    public boolean onKey(View v, int keyCode, KeyEvent event) {
+                        // If the event is a key-down event on the "enter" button
+                        if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
+                            navigate(edittext.getText().toString());
+                            return true;
+                        }
+                        return false;
+                    }
+                });
+
+
+                // Header Close/Done button
+                View close = createCloseButton(5);
+                toolbar.addView(close);
+
+                // Footer
+                RelativeLayout footer = new RelativeLayout(cordova.getActivity());
+                int _footerColor;
+                if(footerColor != ""){
+                    _footerColor = Color.parseColor(footerColor);
+                }else{
+                    _footerColor = android.graphics.Color.LTGRAY;
+                }
+                footer.setBackgroundColor(_footerColor);
+                RelativeLayout.LayoutParams footerLayout = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, this.dpToPixels(44));
+                footerLayout.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
+                footer.setLayoutParams(footerLayout);
+                if (closeButtonCaption != "") footer.setPadding(this.dpToPixels(8), this.dpToPixels(8), this.dpToPixels(8), this.dpToPixels(8));
+                footer.setHorizontalGravity(Gravity.LEFT);
+                footer.setVerticalGravity(Gravity.BOTTOM);
+
+                View footerClose = createCloseButton(7);
+                footer.addView(footerClose);
+
+
+                // WebView
+                inAppWebView = new WebView(cordova.getActivity());
+                inAppWebView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+                inAppWebView.setId(Integer.valueOf(6));
+                // File Chooser Implemented ChromeClient
+                inAppWebView.setWebChromeClient(new InAppChromeClient(thatWebView) {
+                    // For Android 5.0+
+                    public boolean onShowFileChooser (WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams)
+                    {
+                        LOG.d(LOG_TAG, "File Chooser 5.0+");
+                        // If callback exists, finish it.
+                        if(mUploadCallbackLollipop != null) {
+                            mUploadCallbackLollipop.onReceiveValue(null);
+                        }
+                        mUploadCallbackLollipop = filePathCallback;
+
+                        // Create File Chooser Intent
+                        Intent content = new Intent(Intent.ACTION_GET_CONTENT);
+                        content.addCategory(Intent.CATEGORY_OPENABLE);
+                        content.setType("*/*");
+
+                        // Run cordova startActivityForResult
+                        cordova.startActivityForResult(InAppBrowser.this, Intent.createChooser(content, "Select File"), FILECHOOSER_REQUESTCODE_LOLLIPOP);
+                        return true;
+                    }
+
+                    // For Android 4.1+
+                    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)
+                    {
+                        LOG.d(LOG_TAG, "File Chooser 4.1+");
+                        // Call file chooser for Android 3.0+
+                        openFileChooser(uploadMsg, acceptType);
+                    }
+
+                    // For Android 3.0+
+                    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType)
+                    {
+                        LOG.d(LOG_TAG, "File Chooser 3.0+");
+                        mUploadCallback = uploadMsg;
+                        Intent content = new Intent(Intent.ACTION_GET_CONTENT);
+                        content.addCategory(Intent.CATEGORY_OPENABLE);
+
+                        // run startActivityForResult
+                        cordova.startActivityForResult(InAppBrowser.this, Intent.createChooser(content, "Select File"), FILECHOOSER_REQUESTCODE);
+                    }
+
+                });
+                WebViewClient client = new InAppBrowserClient(thatWebView, edittext);
+                inAppWebView.setWebViewClient(client);
+                WebSettings settings = inAppWebView.getSettings();
+                settings.setJavaScriptEnabled(true);
+                settings.setJavaScriptCanOpenWindowsAutomatically(true);
+                settings.setBuiltInZoomControls(showZoomControls);
+                settings.setPluginState(android.webkit.WebSettings.PluginState.ON);
+
+                if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+                    settings.setMediaPlaybackRequiresUserGesture(mediaPlaybackRequiresUserGesture);
+                }
+
+                String overrideUserAgent = preferences.getString("OverrideUserAgent", null);
+                String appendUserAgent = preferences.getString("AppendUserAgent", null);
+
+                if (overrideUserAgent != null) {
+                    settings.setUserAgentString(overrideUserAgent);
+                }
+                if (appendUserAgent != null) {
+                    settings.setUserAgentString(settings.getUserAgentString() + appendUserAgent);
+                }
+
+                //Toggle whether this is enabled or not!
+                Bundle appSettings = cordova.getActivity().getIntent().getExtras();
+                boolean enableDatabase = appSettings == null ? true : appSettings.getBoolean("InAppBrowserStorageEnabled", true);
+                if (enableDatabase) {
+                    String databasePath = cordova.getActivity().getApplicationContext().getDir("inAppBrowserDB", Context.MODE_PRIVATE).getPath();
+                    settings.setDatabasePath(databasePath);
+                    settings.setDatabaseEnabled(true);
+                }
+                settings.setDomStorageEnabled(true);
+
+                if (clearAllCache) {
+                    CookieManager.getInstance().removeAllCookie();
+                } else if (clearSessionCache) {
+                    CookieManager.getInstance().removeSessionCookie();
+                }
+
+                // Enable Thirdparty Cookies on >=Android 5.0 device
+                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
+                    CookieManager.getInstance().setAcceptThirdPartyCookies(inAppWebView,true);
+                }
+
+                inAppWebView.loadUrl(url);
+                inAppWebView.setId(Integer.valueOf(6));
+                inAppWebView.getSettings().setLoadWithOverviewMode(true);
+                inAppWebView.getSettings().setUseWideViewPort(useWideViewPort);
+                inAppWebView.requestFocus();
+                inAppWebView.requestFocusFromTouch();
+
+                // Add the back and forward buttons to our action button container layout
+                actionButtonContainer.addView(back);
+                actionButtonContainer.addView(forward);
+
+                // Add the views to our toolbar if they haven't been disabled
+                if (!hideNavigationButtons) toolbar.addView(actionButtonContainer);
+                if (!hideUrlBar) toolbar.addView(edittext);
+
+                // Don't add the toolbar if its been disabled
+                if (getShowLocationBar()) {
+                    // Add our toolbar to our main view/layout
+                    main.addView(toolbar);
+                }
+
+                // Add our webview to our main view/layout
+                RelativeLayout webViewLayout = new RelativeLayout(cordova.getActivity());
+                webViewLayout.addView(inAppWebView);
+                main.addView(webViewLayout);
+
+                // Don't add the footer unless it's been enabled
+                if (showFooter) {
+                    webViewLayout.addView(footer);
+                }
+
+                WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
+                lp.copyFrom(dialog.getWindow().getAttributes());
+                lp.width = WindowManager.LayoutParams.MATCH_PARENT;
+                lp.height = WindowManager.LayoutParams.MATCH_PARENT;
+
+                dialog.setContentView(main);
+                dialog.show();
+                dialog.getWindow().setAttributes(lp);
+                // the goal of openhidden is to load the url and not display it
+                // Show() needs to be called to cause the URL to be loaded
+                if(openWindowHidden) {
+                    dialog.hide();
+                }
+            }
+        };
+        this.cordova.getActivity().runOnUiThread(runnable);
+        return "";
+    }
+
+    /**
+     * Create a new plugin success result and send it back to JavaScript
+     *
+     * @param obj a JSONObject contain event payload information
+     */
+    private void sendUpdate(JSONObject obj, boolean keepCallback) {
+        sendUpdate(obj, keepCallback, PluginResult.Status.OK);
+    }
+
+    /**
+     * Create a new plugin result and send it back to JavaScript
+     *
+     * @param obj a JSONObject contain event payload information
+     * @param status the status code to return to the JavaScript environment
+     */
+    private void sendUpdate(JSONObject obj, boolean keepCallback, PluginResult.Status status) {
+        if (callbackContext != null) {
+            PluginResult result = new PluginResult(status, obj);
+            result.setKeepCallback(keepCallback);
+            callbackContext.sendPluginResult(result);
+            if (!keepCallback) {
+                callbackContext = null;
+            }
+        }
+    }
+
+    /**
+     * Receive File Data from File Chooser
+     *
+     * @param requestCode the requested code from chromeclient
+     * @param resultCode the result code returned from android system
+     * @param intent the data from android file chooser
+     */
+    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+        // For Android >= 5.0
+        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            LOG.d(LOG_TAG, "onActivityResult (For Android >= 5.0)");
+            // If RequestCode or Callback is Invalid
+            if(requestCode != FILECHOOSER_REQUESTCODE_LOLLIPOP || mUploadCallbackLollipop == null) {
+                super.onActivityResult(requestCode, resultCode, intent);
+                return;
+            }
+            mUploadCallbackLollipop.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
+            mUploadCallbackLollipop = null;
+        }
+        // For Android < 5.0
+        else {
+            LOG.d(LOG_TAG, "onActivityResult (For Android < 5.0)");
+            // If RequestCode or Callback is Invalid
+            if(requestCode != FILECHOOSER_REQUESTCODE || mUploadCallback == null) {
+                super.onActivityResult(requestCode, resultCode, intent);
+                return;
+            }
+
+            if (null == mUploadCallback) return;
+            Uri result = intent == null || resultCode != cordova.getActivity().RESULT_OK ? null : intent.getData();
+
+            mUploadCallback.onReceiveValue(result);
+            mUploadCallback = null;
+        }
+    }
+
+    /**
+     * The webview client receives notifications about appView
+     */
+    public class InAppBrowserClient extends WebViewClient {
+        EditText edittext;
+        CordovaWebView webView;
+
+        /**
+         * Constructor.
+         *
+         * @param webView
+         * @param mEditText
+         */
+        public InAppBrowserClient(CordovaWebView webView, EditText mEditText) {
+            this.webView = webView;
+            this.edittext = mEditText;
+        }
+
+        /**
+         * Override the URL that should be loaded
+         *
+         * This handles a small subset of all the URIs that would be encountered.
+         *
+         * @param webView
+         * @param url
+         */
+        @Override
+        public boolean shouldOverrideUrlLoading(WebView webView, String url) {
+            if (url.startsWith(WebView.SCHEME_TEL)) {
+                try {
+                    Intent intent = new Intent(Intent.ACTION_DIAL);
+                    intent.setData(Uri.parse(url));
+                    cordova.getActivity().startActivity(intent);
+                    return true;
+                } catch (android.content.ActivityNotFoundException e) {
+                    LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
+                }
+            } else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:") || url.startsWith("intent:")) {
+                try {
+                    Intent intent = new Intent(Intent.ACTION_VIEW);
+                    intent.setData(Uri.parse(url));
+                    cordova.getActivity().startActivity(intent);
+                    return true;
+                } catch (android.content.ActivityNotFoundException e) {
+                    LOG.e(LOG_TAG, "Error with " + url + ": " + e.toString());
+                }
+            }
+            // If sms:5551212?body=This is the message
+            else if (url.startsWith("sms:")) {
+                try {
+                    Intent intent = new Intent(Intent.ACTION_VIEW);
+
+                    // Get address
+                    String address = null;
+                    int parmIndex = url.indexOf('?');
+                    if (parmIndex == -1) {
+                        address = url.substring(4);
+                    } else {
+                        address = url.substring(4, parmIndex);
+
+                        // If body, then set sms body
+                        Uri uri = Uri.parse(url);
+                        String query = uri.getQuery();
+                        if (query != null) {
+                            if (query.startsWith("body=")) {
+                                intent.putExtra("sms_body", query.substring(5));
+                            }
+                        }
+                    }
+                    intent.setData(Uri.parse("sms:" + address));
+                    intent.putExtra("address", address);
+                    intent.setType("vnd.android-dir/mms-sms");
+                    cordova.getActivity().startActivity(intent);
+                    return true;
+                } catch (android.content.ActivityNotFoundException e) {
+                    LOG.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
+                }
+            }
+            // Test for whitelisted custom scheme names like mycoolapp:// or twitteroauthresponse:// (Twitter Oauth Response)
+            else if (!url.startsWith("http:") && !url.startsWith("https:") && url.matches("^[a-z]*://.*?$")) {
+                if (allowedSchemes == null) {
+                    String allowed = preferences.getString("AllowedSchemes", "");
+                    allowedSchemes = allowed.split(",");
+                }
+                if (allowedSchemes != null) {
+                    for (String scheme : allowedSchemes) {
+                        if (url.startsWith(scheme)) {
+                            try {
+                                JSONObject obj = new JSONObject();
+                                obj.put("type", "customscheme");
+                                obj.put("url", url);
+                                sendUpdate(obj, true);
+                                return true;
+                            } catch (JSONException ex) {
+                                LOG.e(LOG_TAG, "Custom Scheme URI passed in has caused a JSON error.");
+                            }
+                        }
+                    }
+                }
+            }
+
+            return false;
+        }
+
+
+        /*
+         * onPageStarted fires the LOAD_START_EVENT
+         *
+         * @param view
+         * @param url
+         * @param favicon
+         */
+        @Override
+        public void onPageStarted(WebView view, String url, Bitmap favicon) {
+            super.onPageStarted(view, url, favicon);
+            String newloc = "";
+            if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:")) {
+                newloc = url;
+            }
+            else
+            {
+                // Assume that everything is HTTP at this point, because if we don't specify,
+                // it really should be.  Complain loudly about this!!!
+                LOG.e(LOG_TAG, "Possible Uncaught/Unknown URI");
+                newloc = "http://" + url;
+            }
+
+            // Update the UI if we haven't already
+            if (!newloc.equals(edittext.getText().toString())) {
+                edittext.setText(newloc);
+            }
+
+            try {
+                JSONObject obj = new JSONObject();
+                obj.put("type", LOAD_START_EVENT);
+                obj.put("url", newloc);
+                sendUpdate(obj, true);
+            } catch (JSONException ex) {
+                LOG.e(LOG_TAG, "URI passed in has caused a JSON error.");
+            }
+        }
+
+
+
+        public void onPageFinished(WebView view, String url) {
+            super.onPageFinished(view, url);
+
+            // CB-10395 InAppBrowser's WebView not storing cookies reliable to local device storage
+            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
+                CookieManager.getInstance().flush();
+            } else {
+                CookieSyncManager.getInstance().sync();
+            }
+
+            // https://issues.apache.org/jira/browse/CB-11248
+            view.clearFocus();
+            view.requestFocus();
+
+            try {
+                JSONObject obj = new JSONObject();
+                obj.put("type", LOAD_STOP_EVENT);
+                obj.put("url", url);
+
+                sendUpdate(obj, true);
+            } catch (JSONException ex) {
+                LOG.d(LOG_TAG, "Should never happen");
+            }
+        }
+
+        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+            super.onReceivedError(view, errorCode, description, failingUrl);
+
+            try {
+                JSONObject obj = new JSONObject();
+                obj.put("type", LOAD_ERROR_EVENT);
+                obj.put("url", failingUrl);
+                obj.put("code", errorCode);
+                obj.put("message", description);
+
+                sendUpdate(obj, true, PluginResult.Status.ERROR);
+            } catch (JSONException ex) {
+                LOG.d(LOG_TAG, "Should never happen");
+            }
+        }
+
+        /**
+         * On received http auth request.
+         */
+        @Override
+        public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
+
+            // Check if there is some plugin which can resolve this auth challenge
+            PluginManager pluginManager = null;
+            try {
+                Method gpm = webView.getClass().getMethod("getPluginManager");
+                pluginManager = (PluginManager)gpm.invoke(webView);
+            } catch (NoSuchMethodException e) {
+                LOG.d(LOG_TAG, e.getLocalizedMessage());
+            } catch (IllegalAccessException e) {
+                LOG.d(LOG_TAG, e.getLocalizedMessage());
+            } catch (InvocationTargetException e) {
+                LOG.d(LOG_TAG, e.getLocalizedMessage());
+            }
+
+            if (pluginManager == null) {
+                try {
+                    Field pmf = webView.getClass().getField("pluginManager");
+                    pluginManager = (PluginManager)pmf.get(webView);
+                } catch (NoSuchFieldException e) {
+                    LOG.d(LOG_TAG, e.getLocalizedMessage());
+                } catch (IllegalAccessException e) {
+                    LOG.d(LOG_TAG, e.getLocalizedMessage());
+                }
+            }
+
+            if (pluginManager != null && pluginManager.onReceivedHttpAuthRequest(webView, new CordovaHttpAuthHandler(handler), host, realm)) {
+                return;
+            }
+
+            // By default handle 401 like we'd normally do!
+            super.onReceivedHttpAuthRequest(view, handler, host, realm);
+        }
+    }
+}
\ No newline at end of file
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/inappbrowser/InAppBrowserDialog.java b/platforms/android/app/src/main/java/org/apache/cordova/inappbrowser/InAppBrowserDialog.java
new file mode 100644
index 0000000..e7b212f
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/inappbrowser/InAppBrowserDialog.java
@@ -0,0 +1,57 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.inappbrowser;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Created by Oliver on 22/11/2013.
+ */
+public class InAppBrowserDialog extends Dialog {
+    Context context;
+    InAppBrowser inAppBrowser = null;
+
+    public InAppBrowserDialog(Context context, int theme) {
+        super(context, theme);
+        this.context = context;
+    }
+
+    public void setInAppBroswer(InAppBrowser browser) {
+        this.inAppBrowser = browser;
+    }
+
+    public void onBackPressed () {
+        if (this.inAppBrowser == null) {
+            this.dismiss();
+        } else {
+            // better to go through the in inAppBrowser
+            // because it does a clean up
+            if (this.inAppBrowser.hardwareBack() && this.inAppBrowser.canGoBack()) {
+                this.inAppBrowser.goBack();
+            }  else {
+                this.inAppBrowser.closeDialog();
+            }
+        }
+    }
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/inappbrowser/InAppChromeClient.java b/platforms/android/app/src/main/java/org/apache/cordova/inappbrowser/InAppChromeClient.java
new file mode 100644
index 0000000..a2145e6
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/inappbrowser/InAppChromeClient.java
@@ -0,0 +1,133 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.inappbrowser;
+
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.LOG;
+import org.apache.cordova.PluginResult;
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import android.webkit.JsPromptResult;
+import android.webkit.WebChromeClient;
+import android.webkit.WebStorage;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.webkit.GeolocationPermissions.Callback;
+
+public class InAppChromeClient extends WebChromeClient {
+
+    private CordovaWebView webView;
+    private String LOG_TAG = "InAppChromeClient";
+    private long MAX_QUOTA = 100 * 1024 * 1024;
+
+    public InAppChromeClient(CordovaWebView webView) {
+        super();
+        this.webView = webView;
+    }
+    /**
+     * Handle database quota exceeded notification.
+     *
+     * @param url
+     * @param databaseIdentifier
+     * @param currentQuota
+     * @param estimatedSize
+     * @param totalUsedQuota
+     * @param quotaUpdater
+     */
+    @Override
+    public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize,
+            long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater)
+    {
+        LOG.d(LOG_TAG, "onExceededDatabaseQuota estimatedSize: %d  currentQuota: %d  totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota);
+        quotaUpdater.updateQuota(MAX_QUOTA);
+    }
+
+    /**
+     * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin.
+     *
+     * @param origin
+     * @param callback
+     */
+    @Override
+    public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
+        super.onGeolocationPermissionsShowPrompt(origin, callback);
+        callback.invoke(origin, true, false);
+    }
+
+    /**
+     * Tell the client to display a prompt dialog to the user.
+     * If the client returns true, WebView will assume that the client will
+     * handle the prompt dialog and call the appropriate JsPromptResult method.
+     *
+     * The prompt bridge provided for the InAppBrowser is capable of executing any
+     * oustanding callback belonging to the InAppBrowser plugin. Care has been
+     * taken that other callbacks cannot be triggered, and that no other code
+     * execution is possible.
+     *
+     * To trigger the bridge, the prompt default value should be of the form:
+     *
+     * gap-iab://<callbackId>
+     *
+     * where <callbackId> is the string id of the callback to trigger (something
+     * like "InAppBrowser0123456789")
+     *
+     * If present, the prompt message is expected to be a JSON-encoded value to
+     * pass to the callback. A JSON_EXCEPTION is returned if the JSON is invalid.
+     *
+     * @param view
+     * @param url
+     * @param message
+     * @param defaultValue
+     * @param result
+     */
+    @Override
+    public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
+        // See if the prompt string uses the 'gap-iab' protocol. If so, the remainder should be the id of a callback to execute.
+        if (defaultValue != null && defaultValue.startsWith("gap")) {
+            if(defaultValue.startsWith("gap-iab://")) {
+                PluginResult scriptResult;
+                String scriptCallbackId = defaultValue.substring(10);
+                if (scriptCallbackId.startsWith("InAppBrowser")) {
+                    if(message == null || message.length() == 0) {
+                        scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray());
+                    } else {
+                        try {
+                            scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray(message));
+                        } catch(JSONException e) {
+                            scriptResult = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
+                        }
+                    }
+                    this.webView.sendPluginResult(scriptResult, scriptCallbackId);
+                    result.confirm("");
+                    return true;
+                }
+            }
+            else
+            {
+                // Anything else with a gap: prefix should get this message
+                LOG.w(LOG_TAG, "InAppBrowser does not support Cordova API calls: " + url + " " + defaultValue); 
+                result.cancel();
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/statusbar/StatusBar.java b/platforms/android/app/src/main/java/org/apache/cordova/statusbar/StatusBar.java
new file mode 100644
index 0000000..714c30e
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/statusbar/StatusBar.java
@@ -0,0 +1,276 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+package org.apache.cordova.statusbar;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.os.Build;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaArgs;
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.LOG;
+import org.apache.cordova.PluginResult;
+import org.json.JSONException;
+import java.util.Arrays;
+
+public class StatusBar extends CordovaPlugin {
+    private static final String TAG = "StatusBar";
+
+    /**
+     * Sets the context of the Command. This can then be used to do things like
+     * get file paths associated with the Activity.
+     *
+     * @param cordova The context of the main Activity.
+     * @param webView The CordovaWebView Cordova is running in.
+     */
+    @Override
+    public void initialize(final CordovaInterface cordova, CordovaWebView webView) {
+        LOG.v(TAG, "StatusBar: initialization");
+        super.initialize(cordova, webView);
+
+        this.cordova.getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Clear flag FLAG_FORCE_NOT_FULLSCREEN which is set initially
+                // by the Cordova.
+                Window window = cordova.getActivity().getWindow();
+                window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+
+                // Read 'StatusBarBackgroundColor' from config.xml, default is #000000.
+                setStatusBarBackgroundColor(preferences.getString("StatusBarBackgroundColor", "#000000"));
+
+                // Read 'StatusBarStyle' from config.xml, default is 'lightcontent'.
+                setStatusBarStyle(preferences.getString("StatusBarStyle", "lightcontent"));
+            }
+        });
+    }
+
+    /**
+     * Executes the request and returns PluginResult.
+     *
+     * @param action            The action to execute.
+     * @param args              JSONArry of arguments for the plugin.
+     * @param callbackContext   The callback id used when calling back into JavaScript.
+     * @return                  True if the action was valid, false otherwise.
+     */
+    @Override
+    public boolean execute(final String action, final CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
+        LOG.v(TAG, "Executing action: " + action);
+        final Activity activity = this.cordova.getActivity();
+        final Window window = activity.getWindow();
+
+        if ("_ready".equals(action)) {
+            boolean statusBarVisible = (window.getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) == 0;
+            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, statusBarVisible));
+            return true;
+        }
+
+        if ("show".equals(action)) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    // SYSTEM_UI_FLAG_FULLSCREEN is available since JellyBean, but we
+                    // use KitKat here to be aligned with "Fullscreen"  preference
+                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+                        int uiOptions = window.getDecorView().getSystemUiVisibility();
+                        uiOptions &= ~View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+                        uiOptions &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
+
+                        window.getDecorView().setSystemUiVisibility(uiOptions);
+                    }
+
+                    // CB-11197 We still need to update LayoutParams to force status bar
+                    // to be hidden when entering e.g. text fields
+                    window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+                }
+            });
+            return true;
+        }
+
+        if ("hide".equals(action)) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    // SYSTEM_UI_FLAG_FULLSCREEN is available since JellyBean, but we
+                    // use KitKat here to be aligned with "Fullscreen"  preference
+                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+                        int uiOptions = window.getDecorView().getSystemUiVisibility()
+                                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                                | View.SYSTEM_UI_FLAG_FULLSCREEN;
+
+                        window.getDecorView().setSystemUiVisibility(uiOptions);
+                    }
+
+                    // CB-11197 We still need to update LayoutParams to force status bar
+                    // to be hidden when entering e.g. text fields
+                    window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+                }
+            });
+            return true;
+        }
+
+        if ("backgroundColorByHexString".equals(action)) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        setStatusBarBackgroundColor(args.getString(0));
+                    } catch (JSONException ignore) {
+                        LOG.e(TAG, "Invalid hexString argument, use f.i. '#777777'");
+                    }
+                }
+            });
+            return true;
+        }
+
+        if ("overlaysWebView".equals(action)) {
+            if (Build.VERSION.SDK_INT >= 21) {
+                this.cordova.getActivity().runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            setStatusBarTransparent(args.getBoolean(0));
+                        } catch (JSONException ignore) {
+                            LOG.e(TAG, "Invalid boolean argument");
+                        }
+                    }
+                });
+                return true;
+            }
+            else return args.getBoolean(0) == false;
+        }
+
+        if ("styleDefault".equals(action)) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    setStatusBarStyle("default");
+                }
+            });
+            return true;
+        }
+
+        if ("styleLightContent".equals(action)) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    setStatusBarStyle("lightcontent");
+                }
+            });
+            return true;
+        }
+
+        if ("styleBlackTranslucent".equals(action)) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    setStatusBarStyle("blacktranslucent");
+                }
+            });
+            return true;
+        }
+
+        if ("styleBlackOpaque".equals(action)) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    setStatusBarStyle("blackopaque");
+                }
+            });
+            return true;
+        }
+
+        return false;
+    }
+
+    private void setStatusBarBackgroundColor(final String colorPref) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            if (colorPref != null && !colorPref.isEmpty()) {
+                final Window window = cordova.getActivity().getWindow();
+                // Method and constants not available on all SDKs but we want to be able to compile this code with any SDK
+                window.clearFlags(0x04000000); // SDK 19: WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+                window.addFlags(0x80000000); // SDK 21: WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+                try {
+                    // Using reflection makes sure any 5.0+ device will work without having to compile with SDK level 21
+                    window.getClass().getMethod("setStatusBarColor", int.class).invoke(window, Color.parseColor(colorPref));
+                } catch (IllegalArgumentException ignore) {
+                    LOG.e(TAG, "Invalid hexString argument, use f.i. '#999999'");
+                } catch (Exception ignore) {
+                    // this should not happen, only in case Android removes this method in a version > 21
+                    LOG.w(TAG, "Method window.setStatusBarColor not found for SDK level " + Build.VERSION.SDK_INT);
+                }
+            }
+        }
+    }
+
+    private void setStatusBarTransparent(final boolean transparent) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            final Window window = cordova.getActivity().getWindow();
+            if (transparent) {
+                window.getDecorView().setSystemUiVisibility(
+                        View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+                window.setStatusBarColor(Color.TRANSPARENT);
+            }
+            else {
+                window.getDecorView().setSystemUiVisibility(
+                        View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                                | View.SYSTEM_UI_FLAG_VISIBLE);
+            }
+        }
+    }
+
+    private void setStatusBarStyle(final String style) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            if (style != null && !style.isEmpty()) {
+                View decorView = cordova.getActivity().getWindow().getDecorView();
+                int uiOptions = decorView.getSystemUiVisibility();
+
+                String[] darkContentStyles = {
+                    "default",
+                };
+
+                String[] lightContentStyles = {
+                    "lightcontent",
+                    "blacktranslucent",
+                    "blackopaque",
+                };
+
+                if (Arrays.asList(darkContentStyles).contains(style.toLowerCase())) {
+                    decorView.setSystemUiVisibility(uiOptions | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+                    return;
+                }
+
+                if (Arrays.asList(lightContentStyles).contains(style.toLowerCase())) {
+                    decorView.setSystemUiVisibility(uiOptions & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+                    return;
+                }
+
+                LOG.e(TAG, "Invalid style, must be either 'default', 'lightcontent' or the deprecated 'blacktranslucent' and 'blackopaque'");
+            }
+        }
+    }
+}
diff --git a/platforms/android/app/src/main/java/org/apache/cordova/whitelist/WhitelistPlugin.java b/platforms/android/app/src/main/java/org/apache/cordova/whitelist/WhitelistPlugin.java
new file mode 100644
index 0000000..3656788
--- /dev/null
+++ b/platforms/android/app/src/main/java/org/apache/cordova/whitelist/WhitelistPlugin.java
@@ -0,0 +1,161 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova.whitelist;
+
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.ConfigXmlParser;
+import org.apache.cordova.LOG;
+import org.apache.cordova.Whitelist;
+import org.xmlpull.v1.XmlPullParser;
+
+import android.content.Context;
+
+public class WhitelistPlugin extends CordovaPlugin {
+    private static final String LOG_TAG = "WhitelistPlugin";
+    private Whitelist allowedNavigations;
+    private Whitelist allowedIntents;
+    private Whitelist allowedRequests;
+
+    // Used when instantiated via reflection by PluginManager
+    public WhitelistPlugin() {
+    }
+    // These can be used by embedders to allow Java-configuration of whitelists.
+    public WhitelistPlugin(Context context) {
+        this(new Whitelist(), new Whitelist(), null);
+        new CustomConfigXmlParser().parse(context);
+    }
+    public WhitelistPlugin(XmlPullParser xmlParser) {
+        this(new Whitelist(), new Whitelist(), null);
+        new CustomConfigXmlParser().parse(xmlParser);
+    }
+    public WhitelistPlugin(Whitelist allowedNavigations, Whitelist allowedIntents, Whitelist allowedRequests) {
+        if (allowedRequests == null) {
+            allowedRequests = new Whitelist();
+            allowedRequests.addWhiteListEntry("file:///*", false);
+            allowedRequests.addWhiteListEntry("data:*", false);
+        }
+        this.allowedNavigations = allowedNavigations;
+        this.allowedIntents = allowedIntents;
+        this.allowedRequests = allowedRequests;
+    }
+    @Override
+    public void pluginInitialize() {
+        if (allowedNavigations == null) {
+            allowedNavigations = new Whitelist();
+            allowedIntents = new Whitelist();
+            allowedRequests = new Whitelist();
+            new CustomConfigXmlParser().parse(webView.getContext());
+        }
+    }
+
+    private class CustomConfigXmlParser extends ConfigXmlParser {
+        @Override
+        public void handleStartTag(XmlPullParser xml) {
+            String strNode = xml.getName();
+            if (strNode.equals("content")) {
+                String startPage = xml.getAttributeValue(null, "src");
+                allowedNavigations.addWhiteListEntry(startPage, false);
+            } else if (strNode.equals("allow-navigation")) {
+                String origin = xml.getAttributeValue(null, "href");
+                if ("*".equals(origin)) {
+                    allowedNavigations.addWhiteListEntry("http://*/*", false);
+                    allowedNavigations.addWhiteListEntry("https://*/*", false);
+                    allowedNavigations.addWhiteListEntry("data:*", false);
+                } else {
+                    allowedNavigations.addWhiteListEntry(origin, false);
+                }
+            } else if (strNode.equals("allow-intent")) {
+                String origin = xml.getAttributeValue(null, "href");
+                allowedIntents.addWhiteListEntry(origin, false);
+            } else if (strNode.equals("access")) {
+                String origin = xml.getAttributeValue(null, "origin");
+                String subdomains = xml.getAttributeValue(null, "subdomains");
+                boolean external = (xml.getAttributeValue(null, "launch-external") != null);
+                if (origin != null) {
+                    if (external) {
+                        LOG.w(LOG_TAG, "Found <access launch-external> within config.xml. Please use <allow-intent> instead.");
+                        allowedIntents.addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase("true") == 0));
+                    } else {
+                        if ("*".equals(origin)) {
+                            allowedRequests.addWhiteListEntry("http://*/*", false);
+                            allowedRequests.addWhiteListEntry("https://*/*", false);
+                        } else {
+                            allowedRequests.addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase("true") == 0));
+                        }
+                    }
+                }
+            }
+        }
+        @Override
+        public void handleEndTag(XmlPullParser xml) {
+        }
+    }
+
+    @Override
+    public Boolean shouldAllowNavigation(String url) {
+        if (allowedNavigations.isUrlWhiteListed(url)) {
+            return true;
+        }
+        return null; // Default policy
+    }
+
+    @Override
+    public Boolean shouldAllowRequest(String url) {
+        if (Boolean.TRUE == shouldAllowNavigation(url)) {
+            return true;
+        }
+        if (allowedRequests.isUrlWhiteListed(url)) {
+            return true;
+        }
+        return null; // Default policy
+    }
+
+    @Override
+    public Boolean shouldOpenExternalUrl(String url) {
+        if (allowedIntents.isUrlWhiteListed(url)) {
+            return true;
+        }
+        return null; // Default policy
+    }
+
+    public Whitelist getAllowedNavigations() {
+        return allowedNavigations;
+    }
+
+    public void setAllowedNavigations(Whitelist allowedNavigations) {
+        this.allowedNavigations = allowedNavigations;
+    }
+
+    public Whitelist getAllowedIntents() {
+        return allowedIntents;
+    }
+
+    public void setAllowedIntents(Whitelist allowedIntents) {
+        this.allowedIntents = allowedIntents;
+    }
+
+    public Whitelist getAllowedRequests() {
+        return allowedRequests;
+    }
+
+    public void setAllowedRequests(Whitelist allowedRequests) {
+        this.allowedRequests = allowedRequests;
+    }
+}
diff --git a/platforms/android/app/src/main/res/drawable-hdpi/back.png b/platforms/android/app/src/main/res/drawable-hdpi/back.png
new file mode 100644
index 0000000..51bac9f
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-hdpi/back.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-hdpi/close.png b/platforms/android/app/src/main/res/drawable-hdpi/close.png
new file mode 100644
index 0000000..3fb7db5
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-hdpi/close.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-hdpi/ic_action_next_item.png b/platforms/android/app/src/main/res/drawable-hdpi/ic_action_next_item.png
new file mode 100644
index 0000000..fa469d8
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-hdpi/ic_action_next_item.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-hdpi/ic_action_previous_item.png b/platforms/android/app/src/main/res/drawable-hdpi/ic_action_previous_item.png
new file mode 100644
index 0000000..e861ecc
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-hdpi/ic_action_previous_item.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-hdpi/ic_action_remove.png b/platforms/android/app/src/main/res/drawable-hdpi/ic_action_remove.png
new file mode 100644
index 0000000..f889617
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-hdpi/ic_action_remove.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-hdpi/ic_fp_40px.png b/platforms/android/app/src/main/res/drawable-hdpi/ic_fp_40px.png
new file mode 100644
index 0000000..48ebd8a
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-hdpi/ic_fp_40px.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-hdpi/icon.png b/platforms/android/app/src/main/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000..4edb4c6
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-land-hdpi/screen.png b/platforms/android/app/src/main/res/drawable-land-hdpi/screen.png
new file mode 100644
index 0000000..2c913c6
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-land-hdpi/screen.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-land-ldpi/screen.png b/platforms/android/app/src/main/res/drawable-land-ldpi/screen.png
new file mode 100644
index 0000000..99733ed
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-land-ldpi/screen.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-land-mdpi/screen.png b/platforms/android/app/src/main/res/drawable-land-mdpi/screen.png
new file mode 100644
index 0000000..08f9099
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-land-mdpi/screen.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-land-xhdpi/screen.png b/platforms/android/app/src/main/res/drawable-land-xhdpi/screen.png
new file mode 100644
index 0000000..67cf009
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-land-xhdpi/screen.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-land-xxhdpi/screen.png b/platforms/android/app/src/main/res/drawable-land-xxhdpi/screen.png
new file mode 100644
index 0000000..40edb57
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-land-xxhdpi/screen.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-land-xxxhdpi/screen.png b/platforms/android/app/src/main/res/drawable-land-xxxhdpi/screen.png
new file mode 100644
index 0000000..4e1b40c
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-land-xxxhdpi/screen.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-ldpi/icon.png b/platforms/android/app/src/main/res/drawable-ldpi/icon.png
new file mode 100644
index 0000000..0508de6
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-ldpi/icon.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-mdpi/back.png b/platforms/android/app/src/main/res/drawable-mdpi/back.png
new file mode 100644
index 0000000..51bac9f
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-mdpi/back.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-mdpi/close.png b/platforms/android/app/src/main/res/drawable-mdpi/close.png
new file mode 100644
index 0000000..3fb7db5
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-mdpi/close.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-mdpi/ic_action_next_item.png b/platforms/android/app/src/main/res/drawable-mdpi/ic_action_next_item.png
new file mode 100644
index 0000000..47365a3
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-mdpi/ic_action_next_item.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-mdpi/ic_action_previous_item.png b/platforms/android/app/src/main/res/drawable-mdpi/ic_action_previous_item.png
new file mode 100644
index 0000000..4ad2df4
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-mdpi/ic_action_previous_item.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-mdpi/ic_action_remove.png b/platforms/android/app/src/main/res/drawable-mdpi/ic_action_remove.png
new file mode 100644
index 0000000..e84853e
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-mdpi/ic_action_remove.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-mdpi/ic_fp_40px.png b/platforms/android/app/src/main/res/drawable-mdpi/ic_fp_40px.png
new file mode 100644
index 0000000..122f442
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-mdpi/ic_fp_40px.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-mdpi/icon.png b/platforms/android/app/src/main/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000..ed81661
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-mdpi/icon.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-nodpi/android_robot.png b/platforms/android/app/src/main/res/drawable-nodpi/android_robot.png
new file mode 100644
index 0000000..40bf934
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-nodpi/android_robot.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-port-hdpi/screen.png b/platforms/android/app/src/main/res/drawable-port-hdpi/screen.png
new file mode 100644
index 0000000..d7c1408
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-port-hdpi/screen.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-port-ldpi/screen.png b/platforms/android/app/src/main/res/drawable-port-ldpi/screen.png
new file mode 100644
index 0000000..d600ced
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-port-ldpi/screen.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-port-mdpi/screen.png b/platforms/android/app/src/main/res/drawable-port-mdpi/screen.png
new file mode 100644
index 0000000..2b19050
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-port-mdpi/screen.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-port-xhdpi/screen.png b/platforms/android/app/src/main/res/drawable-port-xhdpi/screen.png
new file mode 100644
index 0000000..a64fa6d
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-port-xhdpi/screen.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-port-xxhdpi/screen.png b/platforms/android/app/src/main/res/drawable-port-xxhdpi/screen.png
new file mode 100644
index 0000000..81e6fe0
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-port-xxhdpi/screen.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-port-xxxhdpi/screen.png b/platforms/android/app/src/main/res/drawable-port-xxxhdpi/screen.png
new file mode 100644
index 0000000..e26e482
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-port-xxxhdpi/screen.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-xhdpi/back.png b/platforms/android/app/src/main/res/drawable-xhdpi/back.png
new file mode 100644
index 0000000..51bac9f
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-xhdpi/back.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-xhdpi/close.png b/platforms/android/app/src/main/res/drawable-xhdpi/close.png
new file mode 100644
index 0000000..3fb7db5
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-xhdpi/close.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-xhdpi/ic_action_next_item.png b/platforms/android/app/src/main/res/drawable-xhdpi/ic_action_next_item.png
new file mode 100644
index 0000000..5f30474
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-xhdpi/ic_action_next_item.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-xhdpi/ic_action_previous_item.png b/platforms/android/app/src/main/res/drawable-xhdpi/ic_action_previous_item.png
new file mode 100644
index 0000000..ed8ac91
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-xhdpi/ic_action_previous_item.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-xhdpi/ic_action_remove.png b/platforms/android/app/src/main/res/drawable-xhdpi/ic_action_remove.png
new file mode 100644
index 0000000..4cd0458
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-xhdpi/ic_action_remove.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-xhdpi/ic_fp_40px.png b/platforms/android/app/src/main/res/drawable-xhdpi/ic_fp_40px.png
new file mode 100644
index 0000000..e1c9590
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-xhdpi/ic_fp_40px.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-xhdpi/icon.png b/platforms/android/app/src/main/res/drawable-xhdpi/icon.png
new file mode 100644
index 0000000..b764a7e
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-xhdpi/icon.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-xxhdpi/back.png b/platforms/android/app/src/main/res/drawable-xxhdpi/back.png
new file mode 100644
index 0000000..51bac9f
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-xxhdpi/back.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-xxhdpi/close.png b/platforms/android/app/src/main/res/drawable-xxhdpi/close.png
new file mode 100644
index 0000000..3fb7db5
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-xxhdpi/close.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-xxhdpi/ic_action_next_item.png b/platforms/android/app/src/main/res/drawable-xxhdpi/ic_action_next_item.png
new file mode 100644
index 0000000..51479d8
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-xxhdpi/ic_action_next_item.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-xxhdpi/ic_action_previous_item.png b/platforms/android/app/src/main/res/drawable-xxhdpi/ic_action_previous_item.png
new file mode 100644
index 0000000..bc8ff12
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-xxhdpi/ic_action_previous_item.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-xxhdpi/ic_action_remove.png b/platforms/android/app/src/main/res/drawable-xxhdpi/ic_action_remove.png
new file mode 100644
index 0000000..331c545
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-xxhdpi/ic_action_remove.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-xxhdpi/ic_fp_40px.png b/platforms/android/app/src/main/res/drawable-xxhdpi/ic_fp_40px.png
new file mode 100644
index 0000000..f7e8724
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-xxhdpi/ic_fp_40px.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-xxhdpi/icon.png b/platforms/android/app/src/main/res/drawable-xxhdpi/icon.png
new file mode 100644
index 0000000..3c7efa4
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-xxhdpi/icon.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-xxxhdpi/ic_fp_40px.png b/platforms/android/app/src/main/res/drawable-xxxhdpi/ic_fp_40px.png
new file mode 100644
index 0000000..0fb8545
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-xxxhdpi/ic_fp_40px.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable-xxxhdpi/icon.png b/platforms/android/app/src/main/res/drawable-xxxhdpi/icon.png
new file mode 100644
index 0000000..8c027a7
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable-xxxhdpi/icon.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/drawable/ic_fingerprint_error.xml b/platforms/android/app/src/main/res/drawable/ic_fingerprint_error.xml
new file mode 100644
index 0000000..be46116
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable/ic_fingerprint_error.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="40.0dp"
+        android:height="40.0dp"
+        android:viewportWidth="40.0"
+        android:viewportHeight="40.0">
+    <path
+        android:pathData="M20.0,0.0C8.96,0.0 0.0,8.95 0.0,20.0s8.96,20.0 20.0,20.0c11.04,0.0 20.0,-8.95 20.0,-20.0S31.04,0.0 20.0,0.0z"
+        android:fillColor="#F4511E"/>
+    <path
+        android:pathData="M21.33,29.33l-2.67,0.0l0.0,-2.67l2.67,0.0L21.33,29.33zM21.33,22.67l-2.67,0.0l0.0,-12.0l2.67,0.0L21.33,22.67z"
+        android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/platforms/android/app/src/main/res/drawable/ic_fingerprint_success.xml b/platforms/android/app/src/main/res/drawable/ic_fingerprint_success.xml
new file mode 100644
index 0000000..261f3e7
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable/ic_fingerprint_success.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="40.0dp"
+        android:height="40.0dp"
+        android:viewportWidth="40.0"
+        android:viewportHeight="40.0">
+    <path
+        android:pathData="M20.0,20.0m-20.0,0.0a20.0,20.0 0.0,1.0 1.0,40.0 0.0a20.0,20.0 0.0,1.0 1.0,-40.0 0.0"
+        android:fillColor="#009688"/>
+    <path
+        android:pathData="M11.2,21.41l1.63,-1.619999 4.17,4.169998 10.59,-10.589999 1.619999,1.63 -12.209999,12.209999z"
+        android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/platforms/android/app/src/main/res/drawable/icon.png b/platforms/android/app/src/main/res/drawable/icon.png
new file mode 100644
index 0000000..b764a7e
--- /dev/null
+++ b/platforms/android/app/src/main/res/drawable/icon.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/layout/fingerprint_dialog_container.xml b/platforms/android/app/src/main/res/layout/fingerprint_dialog_container.xml
new file mode 100644
index 0000000..0c6face
--- /dev/null
+++ b/platforms/android/app/src/main/res/layout/fingerprint_dialog_container.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <FrameLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <include layout="@layout/fingerprint_dialog_content" />
+
+    </FrameLayout>
+
+    <LinearLayout
+        android:id="@+id/buttonPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:paddingStart="12dp"
+        android:paddingEnd="12dp"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp"
+        android:gravity="bottom"
+        style="?android:attr/buttonBarStyle">
+
+        <Space
+            android:id="@+id/spacer"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:visibility="invisible" />
+        <Button
+            android:id="@+id/cancel_button"
+            style="?android:attr/buttonBarNegativeButtonStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+        <Button
+            android:id="@+id/second_dialog_button"
+            style="?android:attr/buttonBarPositiveButtonStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/res/layout/fingerprint_dialog_content.xml b/platforms/android/app/src/main/res/layout/fingerprint_dialog_content.xml
new file mode 100644
index 0000000..3929eba
--- /dev/null
+++ b/platforms/android/app/src/main/res/layout/fingerprint_dialog_content.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/fingerprint_container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingBottom="8dp"
+    android:paddingStart="24dp"
+    android:paddingEnd="24dp"
+    android:paddingTop="16dp">
+
+    <TextView
+        android:id="@+id/fingerprint_description"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentStart="true"
+        android:layout_alignParentTop="true"
+        android:text="@string/fingerprint_description"
+        android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+        android:textColor="?android:attr/textColorSecondary"/>
+
+
+    <ImageView
+        android:id="@+id/fingerprint_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentStart="true"
+        android:layout_below="@+id/fingerprint_description"
+        android:layout_marginTop="20dp"
+        android:src="@drawable/ic_fp_40px" />
+
+    <TextView
+        android:id="@+id/fingerprint_status"
+        style="@android:style/TextAppearance.Material.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBottom="@+id/fingerprint_icon"
+        android:layout_alignTop="@+id/fingerprint_icon"
+        android:layout_marginStart="16dp"
+        android:layout_toEndOf="@+id/fingerprint_icon"
+        android:gravity="center_vertical"
+        android:text="@string/fingerprint_hint"
+        android:textColor="@color/hint_color" />
+</RelativeLayout>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/res/mipmap-hdpi-v26/back.png b/platforms/android/app/src/main/res/mipmap-hdpi-v26/back.png
new file mode 100644
index 0000000..51bac9f
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-hdpi-v26/back.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-hdpi-v26/close.png b/platforms/android/app/src/main/res/mipmap-hdpi-v26/close.png
new file mode 100644
index 0000000..3fb7db5
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-hdpi-v26/close.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-hdpi-v26/ic_launcher.xml b/platforms/android/app/src/main/res/mipmap-hdpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..be31618
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-hdpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@mipmap/ic_launcher_background" />
+    <foreground android:drawable="@mipmap/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/res/mipmap-hdpi-v26/ic_launcher_background.png b/platforms/android/app/src/main/res/mipmap-hdpi-v26/ic_launcher_background.png
new file mode 100644
index 0000000..021da86
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-hdpi-v26/ic_launcher_background.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-hdpi-v26/ic_launcher_foreground.png b/platforms/android/app/src/main/res/mipmap-hdpi-v26/ic_launcher_foreground.png
new file mode 100644
index 0000000..5384261
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-hdpi-v26/ic_launcher_foreground.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-hdpi/back.png b/platforms/android/app/src/main/res/mipmap-hdpi/back.png
new file mode 100644
index 0000000..51bac9f
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-hdpi/back.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-hdpi/close.png b/platforms/android/app/src/main/res/mipmap-hdpi/close.png
new file mode 100644
index 0000000..3fb7db5
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-hdpi/close.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/platforms/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..5384261
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-hdpi/icon.png b/platforms/android/app/src/main/res/mipmap-hdpi/icon.png
new file mode 100644
index 0000000..4edb4c6
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-hdpi/icon.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-ldpi-v26/ic_launcher.xml b/platforms/android/app/src/main/res/mipmap-ldpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..be31618
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-ldpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@mipmap/ic_launcher_background" />
+    <foreground android:drawable="@mipmap/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/res/mipmap-ldpi-v26/ic_launcher_background.png b/platforms/android/app/src/main/res/mipmap-ldpi-v26/ic_launcher_background.png
new file mode 100644
index 0000000..da47a97
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-ldpi-v26/ic_launcher_background.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-ldpi-v26/ic_launcher_foreground.png b/platforms/android/app/src/main/res/mipmap-ldpi-v26/ic_launcher_foreground.png
new file mode 100644
index 0000000..203223a
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-ldpi-v26/ic_launcher_foreground.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-ldpi/ic_launcher.png b/platforms/android/app/src/main/res/mipmap-ldpi/ic_launcher.png
new file mode 100644
index 0000000..c5fcaeb
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-ldpi/ic_launcher.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-ldpi/icon.png b/platforms/android/app/src/main/res/mipmap-ldpi/icon.png
new file mode 100644
index 0000000..0508de6
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-ldpi/icon.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-mdpi-v26/back.png b/platforms/android/app/src/main/res/mipmap-mdpi-v26/back.png
new file mode 100644
index 0000000..51bac9f
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-mdpi-v26/back.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-mdpi-v26/close.png b/platforms/android/app/src/main/res/mipmap-mdpi-v26/close.png
new file mode 100644
index 0000000..3fb7db5
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-mdpi-v26/close.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-mdpi-v26/ic_launcher.xml b/platforms/android/app/src/main/res/mipmap-mdpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..be31618
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-mdpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@mipmap/ic_launcher_background" />
+    <foreground android:drawable="@mipmap/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/res/mipmap-mdpi-v26/ic_launcher_background.png b/platforms/android/app/src/main/res/mipmap-mdpi-v26/ic_launcher_background.png
new file mode 100644
index 0000000..74e56e5
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-mdpi-v26/ic_launcher_background.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-mdpi-v26/ic_launcher_foreground.png b/platforms/android/app/src/main/res/mipmap-mdpi-v26/ic_launcher_foreground.png
new file mode 100644
index 0000000..8ca658e
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-mdpi-v26/ic_launcher_foreground.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-mdpi/back.png b/platforms/android/app/src/main/res/mipmap-mdpi/back.png
new file mode 100644
index 0000000..51bac9f
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-mdpi/back.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-mdpi/close.png b/platforms/android/app/src/main/res/mipmap-mdpi/close.png
new file mode 100644
index 0000000..3fb7db5
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-mdpi/close.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/platforms/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..a18167b
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-mdpi/icon.png b/platforms/android/app/src/main/res/mipmap-mdpi/icon.png
new file mode 100644
index 0000000..ed81661
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-mdpi/icon.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-xhdpi-v26/ic_launcher.xml b/platforms/android/app/src/main/res/mipmap-xhdpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..be31618
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xhdpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@mipmap/ic_launcher_background" />
+    <foreground android:drawable="@mipmap/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/res/mipmap-xhdpi-v26/ic_launcher_background.png b/platforms/android/app/src/main/res/mipmap-xhdpi-v26/ic_launcher_background.png
new file mode 100644
index 0000000..d0cb62d
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xhdpi-v26/ic_launcher_background.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-xhdpi-v26/ic_launcher_foreground.png b/platforms/android/app/src/main/res/mipmap-xhdpi-v26/ic_launcher_foreground.png
new file mode 100644
index 0000000..ae324f2
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xhdpi-v26/ic_launcher_foreground.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-xhdpi/back.png b/platforms/android/app/src/main/res/mipmap-xhdpi/back.png
new file mode 100644
index 0000000..51bac9f
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xhdpi/back.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-xhdpi/close.png b/platforms/android/app/src/main/res/mipmap-xhdpi/close.png
new file mode 100644
index 0000000..3fb7db5
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xhdpi/close.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/platforms/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..9e3eec3
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-xhdpi/icon.png b/platforms/android/app/src/main/res/mipmap-xhdpi/icon.png
new file mode 100644
index 0000000..b764a7e
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xhdpi/icon.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-xxhdpi-v26/ic_launcher.xml b/platforms/android/app/src/main/res/mipmap-xxhdpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..be31618
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xxhdpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@mipmap/ic_launcher_background" />
+    <foreground android:drawable="@mipmap/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/res/mipmap-xxhdpi-v26/ic_launcher_background.png b/platforms/android/app/src/main/res/mipmap-xxhdpi-v26/ic_launcher_background.png
new file mode 100644
index 0000000..ec38d40
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xxhdpi-v26/ic_launcher_background.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-xxhdpi-v26/ic_launcher_foreground.png b/platforms/android/app/src/main/res/mipmap-xxhdpi-v26/ic_launcher_foreground.png
new file mode 100644
index 0000000..7983ef4
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xxhdpi-v26/ic_launcher_foreground.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-xxhdpi/back.png b/platforms/android/app/src/main/res/mipmap-xxhdpi/back.png
new file mode 100644
index 0000000..51bac9f
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xxhdpi/back.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-xxhdpi/close.png b/platforms/android/app/src/main/res/mipmap-xxhdpi/close.png
new file mode 100644
index 0000000..3fb7db5
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xxhdpi/close.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/platforms/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..a569289
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-xxhdpi/icon.png b/platforms/android/app/src/main/res/mipmap-xxhdpi/icon.png
new file mode 100644
index 0000000..3c7efa4
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xxhdpi/icon.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-xxxhdpi-v26/ic_launcher.xml b/platforms/android/app/src/main/res/mipmap-xxxhdpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..be31618
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xxxhdpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@mipmap/ic_launcher_background" />
+    <foreground android:drawable="@mipmap/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/res/mipmap-xxxhdpi-v26/ic_launcher_background.png b/platforms/android/app/src/main/res/mipmap-xxxhdpi-v26/ic_launcher_background.png
new file mode 100644
index 0000000..d652c08
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xxxhdpi-v26/ic_launcher_background.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-xxxhdpi-v26/ic_launcher_foreground.png b/platforms/android/app/src/main/res/mipmap-xxxhdpi-v26/ic_launcher_foreground.png
new file mode 100644
index 0000000..6857bef
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xxxhdpi-v26/ic_launcher_foreground.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/platforms/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..3c322f2
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/mipmap-xxxhdpi/icon.png b/platforms/android/app/src/main/res/mipmap-xxxhdpi/icon.png
new file mode 100644
index 0000000..8c027a7
--- /dev/null
+++ b/platforms/android/app/src/main/res/mipmap-xxxhdpi/icon.png
Binary files differ
diff --git a/platforms/android/app/src/main/res/values-da/fpauth-strings.xml b/platforms/android/app/src/main/res/values-da/fpauth-strings.xml
new file mode 100644
index 0000000..346666f
--- /dev/null
+++ b/platforms/android/app/src/main/res/values-da/fpauth-strings.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="fingerprint_cancel">Annuller</string>
+    <string name="fingerprint_use_backup">Brug backup</string>
+    <string name="fingerprint_auth_dialog_title">Fingeraftryk Login</string>
+    <string name="fingerprint_ok">Ok</string>
+    <string name="fingerprint_description">Bekræft fingeraftryk for at fortsætte</string>
+    <string name="fingerprint_hint">Rør sensor</string>
+    <string name="fingerprint_not_recognized">Fingeraftryk ikke genkendt. Prøv igen.</string>
+    <string name="fingerprint_success">Fingeraftryk godkendt</string>
+    <string name="new_fingerprint_enrolled_description">Et nyt fingeraftryk blev tilføjet til denne enhed så din adgangskode er krævet.</string>
+    <string name="secure_lock_screen_required">Sikring af skærmlås krævet!</string>
+</resources>
diff --git a/platforms/android/app/src/main/res/values-de/fpauth-strings.xml b/platforms/android/app/src/main/res/values-de/fpauth-strings.xml
new file mode 100644
index 0000000..d5b6bd2
--- /dev/null
+++ b/platforms/android/app/src/main/res/values-de/fpauth-strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+    <string name="fingerprint_cancel">Abbrechen</string>
+    <string name="fingerprint_use_backup">Passwort</string>
+    <string name="fingerprint_auth_dialog_title">Authentifizierung</string>
+    <string name="fingerprint_ok">OK</string>
+    <string name="fingerprint_description">Fingerabdruck bestätigen</string>
+    <string name="fingerprint_hint">Fingerabdrucksensor</string>
+    <string name="fingerprint_not_recognized">Fingerabdruck nicht erkannt. Versuchen Sie es erneut</string>
+    <string name="fingerprint_success">Authentifiziert</string>
+    <string name="new_fingerprint_enrolled_description">Ein neuer Fingerabdruck wurde gespeichert. Bitte geben Sie ihr Passwort ein.</string>
+    <string name="secure_lock_screen_required">Passwortgeschützter Sperrbildschirm benötigt</string>
+</resources>
diff --git a/platforms/android/app/src/main/res/values-el/fpauth-strings.xml b/platforms/android/app/src/main/res/values-el/fpauth-strings.xml
new file mode 100644
index 0000000..1dcfcdb
--- /dev/null
+++ b/platforms/android/app/src/main/res/values-el/fpauth-strings.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="fingerprint_cancel">Ακύρωση</string>
+    <string name="fingerprint_use_backup">Χρήση αρχείου</string>
+    <string name="fingerprint_auth_dialog_title">Ελεγχος αποτυπώματος</string>
+    <string name="fingerprint_ok">Ok</string>
+    <string name="fingerprint_description">Επιβεβαίωση αποτυπώματος</string>
+    <string name="fingerprint_hint">Αιθηστήρας αφής</string>
+    <string name="fingerprint_not_recognized">Σφάλμα. Προσπαθήστε ξανά</string>
+    <string name="fingerprint_success">Σωστό αποτύπωμα</string>
+    <string name="new_fingerprint_enrolled_description">Νεο αποτύπωμα προστέθηκε , απαιτείται ο κωδικός σας.</string>
+    <string name="secure_lock_screen_required">Απαιτείται κλειδωμα οθόνης</string>
+</resources>
diff --git a/platforms/android/app/src/main/res/values-es/fpauth-strings.xml b/platforms/android/app/src/main/res/values-es/fpauth-strings.xml
new file mode 100644
index 0000000..25bdbb2
--- /dev/null
+++ b/platforms/android/app/src/main/res/values-es/fpauth-strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+    <string name="fingerprint_cancel">Cancelar</string>
+    <string name="fingerprint_use_backup">El Respaldo</string>
+    <string name="fingerprint_auth_dialog_title">Autenticación de Huellas Digitales</string>
+    <string name="fingerprint_ok">De Acuerdo</string>
+    <string name="fingerprint_description">Confirmar la huella digital para continuar</string>
+    <string name="fingerprint_hint">Sensor tactil</string>
+    <string name="fingerprint_not_recognized">No se reconoce la huella digital. Inténtalo de nuevo.</string>
+    <string name="fingerprint_success">Reconocido de huella dactilar</string>
+    <string name="new_fingerprint_enrolled_description">Una nueva huella digital fue agregada a este dispositivo, por lo que se requiere la contraseña.</string>
+    <string name="secure_lock_screen_required">¡Requiere pantalla de bloqueo seguro!</string>
+</resources>
diff --git a/platforms/android/app/src/main/res/values-fr/fpauth-strings.xml b/platforms/android/app/src/main/res/values-fr/fpauth-strings.xml
new file mode 100644
index 0000000..4b9d3eb
--- /dev/null
+++ b/platforms/android/app/src/main/res/values-fr/fpauth-strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+    <string name="fingerprint_cancel">Annuler</string>
+    <string name="fingerprint_use_backup">Utiliser la sauvegarde</string>
+    <string name="fingerprint_auth_dialog_title">Authentification par empreinte digitale</string>
+    <string name="fingerprint_ok">Ok</string>
+    <string name="fingerprint_description">Confirmer l\'empreinte pour continuer</string>
+    <string name="fingerprint_hint">Toucher le capteur</string>
+    <string name="fingerprint_not_recognized">Empreinte non reconnue. Essayer à nouveau.</string>
+    <string name="fingerprint_success">Empreinte reconnue</string>
+    <string name="new_fingerprint_enrolled_description">Une nouvelle empreinte digitale a été ajoutée à ce dispositif, de sorte que votre mot de passe est nécessaire.</string>
+    <string name="secure_lock_screen_required">Écran de verrouillage sécurisé nécessaire!</string>
+</resources>
diff --git a/platforms/android/app/src/main/res/values-it/fpauth-strings.xml b/platforms/android/app/src/main/res/values-it/fpauth-strings.xml
new file mode 100644
index 0000000..a226ff8
--- /dev/null
+++ b/platforms/android/app/src/main/res/values-it/fpauth-strings.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="fingerprint_cancel">Cancella</string>
+    <string name="fingerprint_use_backup">Usa backup</string>
+    <string name="fingerprint_auth_dialog_title">Autenticazione impronta digitale</string>
+    <string name="fingerprint_ok">Ok</string>
+    <string name="fingerprint_description">Conferma l\'impronta digitale per continuare</string>
+    <string name="fingerprint_hint">Sensore Touch</string>
+    <string name="fingerprint_not_recognized">Impronta digitale non riconosciuta. Riprova.</string>
+    <string name="fingerprint_success">Impronta digitale riconosciuta</string>
+    <string name="new_fingerprint_enrolled_description">Una nuova impronta è stata aggiunta a questo dispositivo, quindi è necessaria la tua password</string>
+    <string name="secure_lock_screen_required">Blocco schermo richiesto!</string>
+</resources>
diff --git a/platforms/android/app/src/main/res/values-nl/fpauth-strings.xml b/platforms/android/app/src/main/res/values-nl/fpauth-strings.xml
new file mode 100644
index 0000000..e44731c
--- /dev/null
+++ b/platforms/android/app/src/main/res/values-nl/fpauth-strings.xml
@@ -0,0 +1,12 @@
+<resources>
+    <string name="fingerprint_cancel">Annuleer</string>
+    <string name="fingerprint_use_backup">Back-up gebruiken</string>
+    <string name="fingerprint_auth_dialog_title">Authenticatie met vingerafdruk</string>
+    <string name="fingerprint_ok">OK</string>
+    <string name="fingerprint_description">Vingerafdruk bevestigen om verder te gaan</string>
+    <string name="fingerprint_hint">Aanraaksensor</string>
+    <string name="fingerprint_not_recognized">Vingerafdruk niet herkend.Opnieuw proberen.</string>
+    <string name="fingerprint_success">Vingerafdruk herkend</string>
+    <string name="new_fingerprint_enrolled_description">Er werd een nieuwe vingerafdruk aan dit apparaat toegevoegd, waardoor uw wachtwoord is vereist.</string>
+    <string name="secure_lock_screen_required">Beveiligd vergrendelingsscherm vereist!</string>
+</resources>
diff --git a/platforms/android/app/src/main/res/values-pt/fpauth-strings.xml b/platforms/android/app/src/main/res/values-pt/fpauth-strings.xml
new file mode 100644
index 0000000..7c3e581
--- /dev/null
+++ b/platforms/android/app/src/main/res/values-pt/fpauth-strings.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="fingerprint_cancel">Cancelar</string>
+    <string name="fingerprint_use_backup">Use o backup</string>
+    <string name="fingerprint_auth_dialog_title">Autenticação de impressão digital</string>
+    <string name="fingerprint_ok">Ok</string>
+    <string name="fingerprint_description">Confirme a impressão digital para continuar</string>
+    <string name="fingerprint_hint">Sensor de toque</string>
+    <string name="fingerprint_not_recognized">impressão digital não reconhecida. Tente novamente.</string>
+    <string name="fingerprint_success">impressão digital reconhecida</string>
+    <string name="new_fingerprint_enrolled_description">Uma nova impressão digital foi adicionada a este dispositivo, é necessário o seu código</string>
+    <string name="secure_lock_screen_required">É necessário um ecrã de bloqueio seguro!</string>
+</resources>
diff --git a/platforms/android/app/src/main/res/values-zh-rTW/fpauth-strings.xml b/platforms/android/app/src/main/res/values-zh-rTW/fpauth-strings.xml
new file mode 100644
index 0000000..c8345a3
--- /dev/null
+++ b/platforms/android/app/src/main/res/values-zh-rTW/fpauth-strings.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+  <string name="fingerprint_cancel">取消</string>
+  <string name="fingerprint_use_backup">使用手勢密碼</string>
+  <string name="fingerprint_auth_dialog_title">指紋識別</string>
+  <string name="fingerprint_ok">確認</string><string name="fingerprint_description">指紋識別</string>
+  <string name="fingerprint_hint">請觸摸指紋識別傳感器</string>
+  <string name="fingerprint_not_recognized">指紋無法識別,請再試一次</string>
+  <string name="fingerprint_success">指紋識別成功</string>
+  <string name="new_fingerprint_enrolled_description">添加一個新的指紋,需要設置密碼</string>
+  <string name="secure_lock_screen_required">需要安全鎖屏</string>
+</resources>
diff --git a/platforms/android/app/src/main/res/values-zh/fpauth-strings.xml b/platforms/android/app/src/main/res/values-zh/fpauth-strings.xml
new file mode 100644
index 0000000..54d38b7
--- /dev/null
+++ b/platforms/android/app/src/main/res/values-zh/fpauth-strings.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+  <string name="fingerprint_cancel">取消</string>
+  <string name="fingerprint_use_backup">使用手势密码</string>
+  <string name="fingerprint_auth_dialog_title">指纹识别</string>
+  <string name="fingerprint_ok">确认</string><string name="fingerprint_description">指纹识别</string>
+  <string name="fingerprint_hint">请触摸指纹识传感器</string>
+  <string name="fingerprint_not_recognized">指纹无法识别,请再试一次</string>
+  <string name="fingerprint_success">指纹识别成功</string>
+  <string name="new_fingerprint_enrolled_description">添加一个新的指纹,需要设置密码</string>
+  <string name="secure_lock_screen_required">需要安全锁屏</string>
+</resources>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/res/values/fpauth-colors.xml b/platforms/android/app/src/main/res/values/fpauth-colors.xml
new file mode 100644
index 0000000..a24f3c8
--- /dev/null
+++ b/platforms/android/app/src/main/res/values/fpauth-colors.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+    <color name="warning_color">#f4511e</color>
+    <color name="hint_color">#42000000</color>
+    <color name="success_color">#009688</color>
+</resources>
diff --git a/platforms/android/app/src/main/res/values/fpauth-strings.xml b/platforms/android/app/src/main/res/values/fpauth-strings.xml
new file mode 100644
index 0000000..00cc755
--- /dev/null
+++ b/platforms/android/app/src/main/res/values/fpauth-strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+    <string name="fingerprint_cancel">Cancel</string>
+    <string name="fingerprint_use_backup">Use backup</string>
+    <string name="fingerprint_auth_dialog_title">Fingerprint Authentication</string>
+    <string name="fingerprint_ok">Ok</string>
+    <string name="fingerprint_description">Confirm fingerprint to continue</string>
+    <string name="fingerprint_hint">Touch sensor</string>
+    <string name="fingerprint_not_recognized">Fingerprint not recognized. Try again.</string>
+    <string name="fingerprint_success">Fingerprint recognized</string>
+    <string name="new_fingerprint_enrolled_description">A new fingerprint was added to this device, so your password is required.</string>
+    <string name="secure_lock_screen_required">Secure lock screen required!</string>
+</resources>
diff --git a/platforms/android/app/src/main/res/values/strings.xml b/platforms/android/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..d4d339a
--- /dev/null
+++ b/platforms/android/app/src/main/res/values/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+    <string name="app_name">dlapp</string>
+    <string name="launcher_name">@string/app_name</string>
+    <string name="activity_name">@string/launcher_name</string>
+</resources>
diff --git a/platforms/android/app/src/main/res/xml/camera_provider_paths.xml b/platforms/android/app/src/main/res/xml/camera_provider_paths.xml
new file mode 100644
index 0000000..2db87bd
--- /dev/null
+++ b/platforms/android/app/src/main/res/xml/camera_provider_paths.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+    http://www.apache.org/licenses/LICENSE-2.0
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+    <external-path name="external_files" path="."/>
+</paths>
\ No newline at end of file
diff --git a/platforms/android/app/src/main/res/xml/config.xml b/platforms/android/app/src/main/res/xml/config.xml
new file mode 100644
index 0000000..3be6168
--- /dev/null
+++ b/platforms/android/app/src/main/res/xml/config.xml
@@ -0,0 +1,69 @@
+<?xml version='1.0' encoding='utf-8'?>
+<widget id="com.supwisdom.dlapp" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
+    <feature name="Fingerprint">
+        <param name="android-package" value="de.niklasmerz.cordova.fingerprint.Fingerprint" />
+    </feature>
+    <feature name="Whitelist">
+        <param name="android-package" value="org.apache.cordova.whitelist.WhitelistPlugin" />
+        <param name="onload" value="true" />
+    </feature>
+    <feature name="File">
+        <param name="android-package" value="org.apache.cordova.file.FileUtils" />
+        <param name="onload" value="true" />
+    </feature>
+    <allow-navigation href="cdvfile:*" />
+    <feature name="CordovaHttpPlugin">
+        <param name="android-package" value="com.silkimen.cordovahttp.CordovaHttpPlugin" />
+    </feature>
+    <feature name="StatusBar">
+        <param name="android-package" value="org.apache.cordova.statusbar.StatusBar" />
+        <param name="onload" value="true" />
+    </feature>
+    <feature name="QRScanner">
+        <param name="android-package" value="com.bitpay.cordova.qrscanner.QRScanner" />
+    </feature>
+    <feature name="Camera">
+        <param name="android-package" value="org.apache.cordova.camera.CameraLauncher" />
+    </feature>
+    <feature name="InAppBrowser">
+        <param name="android-package" value="org.apache.cordova.inappbrowser.InAppBrowser" />
+    </feature>
+    <feature name="Device">
+        <param name="android-package" value="org.apache.cordova.device.Device" />
+    </feature>
+    <feature name="ThemeableBrowser">
+        <param name="android-package" value="com.initialxy.cordova.themeablebrowser.ThemeableBrowser" />
+    </feature>
+    <name>dlapp</name>
+    <description>
+        A sample Apache Cordova application that responds to the deviceready event.
+    </description>
+    <author email="dev@cordova.apache.org" href="http://cordova.io">
+        Apache Cordova Team
+    </author>
+    <content src="index.html" />
+    <access origin="*" />
+    <allow-intent href="http://*/*" />
+    <allow-intent href="https://*/*" />
+    <allow-intent href="tel:*" />
+    <allow-intent href="sms:*" />
+    <allow-intent href="mailto:*" />
+    <allow-intent href="geo:*" />
+    <allow-navigation href="http://*/*" />
+    <allow-navigation href="https://*/*" />
+    <allow-navigation href="data:*" />
+    <access origin="http://ip*" />
+    <edit-config file="*-Info.plist" mode="merge" target="NSCameraUsageDescription">
+        <string>APP需要使用您的相机权限,没有该权限将无法完成扫一扫功能</string>
+    </edit-config>
+    <allow-intent href="market:*" />
+    <preference name="loglevel" value="DEBUG" />
+    <preference name="AutoHideSplashScreen" value="true" />
+    <preference name="SplashScreenDelay" value="0" />
+    <preference name="ErrorUrl" value="error.html" />
+    <preference name="Orientation" value="portrait" />
+    <preference name="UseSwiftLanguageVersion" value="4.0" />
+    <preference name="DisallowOverscroll" value="true" />
+    <preference name="UIWebViewBounce" value="false" />
+    <preference name="BackupWebStorage" value="local" />
+</widget>
diff --git a/platforms/android/build.gradle b/platforms/android/build.gradle
new file mode 100644
index 0000000..bea8a74
--- /dev/null
+++ b/platforms/android/build.gradle
@@ -0,0 +1,52 @@
+/* Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+*/
+
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+    repositories {
+        google()
+        jcenter()
+    }
+
+    dependencies {
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+
+        classpath 'com.android.tools.build:gradle:3.3.0'
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+
+    //This replaces project.properties w.r.t. build settings
+    project.ext {
+      defaultBuildToolsVersion="28.0.3" //String
+      defaultMinSdkVersion=19 //Integer - Minimum requirement is Android 4.4
+      defaultTargetSdkVersion=28 //Integer - We ALWAYS target the latest by default
+      defaultCompileSdkVersion=28 //Integer - We ALWAYS compile with the latest by default
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
diff --git a/platforms/android/cordova-plugin-qrscanner/dlapp-qrscanner.gradle b/platforms/android/cordova-plugin-qrscanner/dlapp-qrscanner.gradle
new file mode 100644
index 0000000..df682e7
--- /dev/null
+++ b/platforms/android/cordova-plugin-qrscanner/dlapp-qrscanner.gradle
@@ -0,0 +1,12 @@
+repositories {
+    jcenter()
+}
+
+dependencies {
+    compile 'com.journeyapps:zxing-android-embedded:3.3.0'
+    compile 'com.android.support:appcompat-v7:23.1.0'
+}
+
+android {
+    buildToolsVersion '23.0.2' // Older versions may give compile errors
+}
\ No newline at end of file
diff --git a/platforms/android/cordova/Api.js b/platforms/android/cordova/Api.js
new file mode 100644
index 0000000..be6b76b
--- /dev/null
+++ b/platforms/android/cordova/Api.js
@@ -0,0 +1,370 @@
+/**
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+
+var path = require('path');
+var Q = require('q');
+
+var AndroidProject = require('./lib/AndroidProject');
+var PluginManager = require('cordova-common').PluginManager;
+
+var CordovaLogger = require('cordova-common').CordovaLogger;
+var selfEvents = require('cordova-common').events;
+
+var PLATFORM = 'android';
+
+function setupEvents (externalEventEmitter) {
+    if (externalEventEmitter) {
+        // This will make the platform internal events visible outside
+        selfEvents.forwardEventsTo(externalEventEmitter);
+        return externalEventEmitter;
+    }
+
+    // There is no logger if external emitter is not present,
+    // so attach a console logger
+    CordovaLogger.get().subscribe(selfEvents);
+    return selfEvents;
+}
+
+/**
+ * Class, that acts as abstraction over particular platform. Encapsulates the
+ *   platform's properties and methods.
+ *
+ * Platform that implements own PlatformApi instance _should implement all
+ *   prototype methods_ of this class to be fully compatible with cordova-lib.
+ *
+ * The PlatformApi instance also should define the following field:
+ *
+ * * platform: String that defines a platform name.
+ */
+function Api (platform, platformRootDir, events) {
+    this.platform = PLATFORM;
+    this.root = path.resolve(__dirname, '..');
+
+    setupEvents(events);
+
+    const appMain = path.join(this.root, 'app', 'src', 'main');
+    const appRes = path.join(appMain, 'res');
+
+    this.locations = {
+        root: this.root,
+        www: path.join(appMain, 'assets', 'www'),
+        res: appRes,
+        platformWww: path.join(this.root, 'platform_www'),
+        configXml: path.join(appRes, 'xml', 'config.xml'),
+        defaultConfigXml: path.join(this.root, 'cordova', 'defaults.xml'),
+        strings: path.join(appRes, 'values', 'strings.xml'),
+        manifest: path.join(appMain, 'AndroidManifest.xml'),
+        build: path.join(this.root, 'build'),
+        javaSrc: path.join(appMain, 'java'),
+        // NOTE: Due to platformApi spec we need to return relative paths here
+        cordovaJs: 'bin/templates/project/assets/www/cordova.js',
+        cordovaJsSrc: 'cordova-js-src'
+    };
+}
+
+/**
+ * Installs platform to specified directory and creates a platform project.
+ *
+ * @param  {String}  destination Destination directory, where insatll platform to
+ * @param  {ConfigParser}  [config] ConfgiParser instance, used to retrieve
+ *   project creation options, such as package id and project name.
+ * @param  {Object}  [options]  An options object. The most common options are:
+ * @param  {String}  [options.customTemplate]  A path to custom template, that
+ *   should override the default one from platform.
+ * @param  {Boolean}  [options.link]  Flag that indicates that platform's
+ *   sources will be linked to installed platform instead of copying.
+ * @param {EventEmitter} [events] An EventEmitter instance that will be used for
+ *   logging purposes. If no EventEmitter provided, all events will be logged to
+ *   console
+ *
+ * @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
+ *   instance or rejected with CordovaError.
+ */
+Api.createPlatform = function (destination, config, options, events) {
+    events = setupEvents(events);
+    var result;
+    try {
+        result = require('../../lib/create').create(destination, config, options, events).then(function (destination) {
+            var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
+            return new PlatformApi(PLATFORM, destination, events);
+        });
+    } catch (e) {
+        events.emit('error', 'createPlatform is not callable from the android project API.');
+        throw (e);
+    }
+    return result;
+};
+
+/**
+ * Updates already installed platform.
+ *
+ * @param  {String}  destination Destination directory, where platform installed
+ * @param  {Object}  [options]  An options object. The most common options are:
+ * @param  {String}  [options.customTemplate]  A path to custom template, that
+ *   should override the default one from platform.
+ * @param  {Boolean}  [options.link]  Flag that indicates that platform's
+ *   sources will be linked to installed platform instead of copying.
+ * @param {EventEmitter} [events] An EventEmitter instance that will be used for
+ *   logging purposes. If no EventEmitter provided, all events will be logged to
+ *   console
+ *
+ * @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
+ *   instance or rejected with CordovaError.
+ */
+Api.updatePlatform = function (destination, options, events) {
+    events = setupEvents(events);
+    var result;
+    try {
+        result = require('../../lib/create').update(destination, options, events).then(function (destination) {
+            var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
+            return new PlatformApi('android', destination, events);
+        });
+    } catch (e) {
+        events.emit('error', 'updatePlatform is not callable from the android project API, you will need to do this manually.');
+        throw (e);
+    }
+    return result;
+};
+
+/**
+ * Gets a CordovaPlatform object, that represents the platform structure.
+ *
+ * @return  {CordovaPlatform}  A structure that contains the description of
+ *   platform's file structure and other properties of platform.
+ */
+Api.prototype.getPlatformInfo = function () {
+    var result = {};
+    result.locations = this.locations;
+    result.root = this.root;
+    result.name = this.platform;
+    result.version = require('./version');
+    result.projectConfig = this._config;
+
+    return result;
+};
+
+/**
+ * Updates installed platform with provided www assets and new app
+ *   configuration. This method is required for CLI workflow and will be called
+ *   each time before build, so the changes, made to app configuration and www
+ *   code, will be applied to platform.
+ *
+ * @param {CordovaProject} cordovaProject A CordovaProject instance, that defines a
+ *   project structure and configuration, that should be applied to platform
+ *   (contains project's www location and ConfigParser instance for project's
+ *   config).
+ *
+ * @return  {Promise}  Return a promise either fulfilled, or rejected with
+ *   CordovaError instance.
+ */
+Api.prototype.prepare = function (cordovaProject, prepareOptions) {
+    return require('./lib/prepare').prepare.call(this, cordovaProject, prepareOptions);
+};
+
+/**
+ * Installs a new plugin into platform. This method only copies non-www files
+ *   (sources, libs, etc.) to platform. It also doesn't resolves the
+ *   dependencies of plugin. Both of handling of www files, such as assets and
+ *   js-files and resolving dependencies are the responsibility of caller.
+ *
+ * @param  {PluginInfo}  plugin  A PluginInfo instance that represents plugin
+ *   that will be installed.
+ * @param  {Object}  installOptions  An options object. Possible options below:
+ * @param  {Boolean}  installOptions.link: Flag that specifies that plugin
+ *   sources will be symlinked to app's directory instead of copying (if
+ *   possible).
+ * @param  {Object}  installOptions.variables  An object that represents
+ *   variables that will be used to install plugin. See more details on plugin
+ *   variables in documentation:
+ *   https://cordova.apache.org/docs/en/4.0.0/plugin_ref_spec.md.html
+ *
+ * @return  {Promise}  Return a promise either fulfilled, or rejected with
+ *   CordovaError instance.
+ */
+Api.prototype.addPlugin = function (plugin, installOptions) {
+    var project = AndroidProject.getProjectFile(this.root);
+    var self = this;
+
+    installOptions = installOptions || {};
+    installOptions.variables = installOptions.variables || {};
+    // Add PACKAGE_NAME variable into vars
+    if (!installOptions.variables.PACKAGE_NAME) {
+        installOptions.variables.PACKAGE_NAME = project.getPackageName();
+    }
+
+    return Q().then(function () {
+        return PluginManager.get(self.platform, self.locations, project).addPlugin(plugin, installOptions);
+    }).then(function () {
+        if (plugin.getFrameworks(this.platform).length === 0) return;
+        selfEvents.emit('verbose', 'Updating build files since android plugin contained <framework>');
+        // This should pick the correct builder, not just get gradle
+        require('./lib/builders/builders').getBuilder().prepBuildFiles();
+    }.bind(this))
+        // CB-11022 Return truthy value to prevent running prepare after
+        .thenResolve(true);
+};
+
+/**
+ * Removes an installed plugin from platform.
+ *
+ * Since method accepts PluginInfo instance as input parameter instead of plugin
+ *   id, caller shoud take care of managing/storing PluginInfo instances for
+ *   future uninstalls.
+ *
+ * @param  {PluginInfo}  plugin  A PluginInfo instance that represents plugin
+ *   that will be installed.
+ *
+ * @return  {Promise}  Return a promise either fulfilled, or rejected with
+ *   CordovaError instance.
+ */
+Api.prototype.removePlugin = function (plugin, uninstallOptions) {
+    var project = AndroidProject.getProjectFile(this.root);
+
+    if (uninstallOptions && uninstallOptions.usePlatformWww === true) {
+        uninstallOptions.usePlatformWww = false;
+    }
+
+    return PluginManager.get(this.platform, this.locations, project)
+        .removePlugin(plugin, uninstallOptions)
+        .then(function () {
+            if (plugin.getFrameworks(this.platform).length === 0) return;
+
+            selfEvents.emit('verbose', 'Updating build files since android plugin contained <framework>');
+            require('./lib/builders/builders').getBuilder().prepBuildFiles();
+        }.bind(this))
+        // CB-11022 Return truthy value to prevent running prepare after
+        .thenResolve(true);
+};
+
+/**
+ * Builds an application package for current platform.
+ *
+ * @param  {Object}  buildOptions  A build options. This object's structure is
+ *   highly depends on platform's specific. The most common options are:
+ * @param  {Boolean}  buildOptions.debug  Indicates that packages should be
+ *   built with debug configuration. This is set to true by default unless the
+ *   'release' option is not specified.
+ * @param  {Boolean}  buildOptions.release  Indicates that packages should be
+ *   built with release configuration. If not set to true, debug configuration
+ *   will be used.
+ * @param   {Boolean}  buildOptions.device  Specifies that built app is intended
+ *   to run on device
+ * @param   {Boolean}  buildOptions.emulator: Specifies that built app is
+ *   intended to run on emulator
+ * @param   {String}  buildOptions.target  Specifies the device id that will be
+ *   used to run built application.
+ * @param   {Boolean}  buildOptions.nobuild  Indicates that this should be a
+ *   dry-run call, so no build artifacts will be produced.
+ * @param   {String[]}  buildOptions.archs  Specifies chip architectures which
+ *   app packages should be built for. List of valid architectures is depends on
+ *   platform.
+ * @param   {String}  buildOptions.buildConfig  The path to build configuration
+ *   file. The format of this file is depends on platform.
+ * @param   {String[]} buildOptions.argv Raw array of command-line arguments,
+ *   passed to `build` command. The purpose of this property is to pass a
+ *   platform-specific arguments, and eventually let platform define own
+ *   arguments processing logic.
+ *
+ * @return {Promise<Object[]>} A promise either fulfilled with an array of build
+ *   artifacts (application packages) if package was built successfully,
+ *   or rejected with CordovaError. The resultant build artifact objects is not
+ *   strictly typed and may conatin arbitrary set of fields as in sample below.
+ *
+ *     {
+ *         architecture: 'x86',
+ *         buildType: 'debug',
+ *         path: '/path/to/build',
+ *         type: 'app'
+ *     }
+ *
+ * The return value in most cases will contain only one item but in some cases
+ *   there could be multiple items in output array, e.g. when multiple
+ *   arhcitectures is specified.
+ */
+Api.prototype.build = function (buildOptions) {
+    var self = this;
+
+    return require('./lib/check_reqs').run().then(function () {
+        return require('./lib/build').run.call(self, buildOptions);
+    }).then(function (buildResults) {
+        // Cast build result to array of build artifacts
+        return buildResults.apkPaths.map(function (apkPath) {
+            return {
+                buildType: buildResults.buildType,
+                buildMethod: buildResults.buildMethod,
+                path: apkPath,
+                type: 'apk'
+            };
+        });
+    });
+};
+
+/**
+ * Builds an application package for current platform and runs it on
+ *   specified/default device. If no 'device'/'emulator'/'target' options are
+ *   specified, then tries to run app on default device if connected, otherwise
+ *   runs the app on emulator.
+ *
+ * @param   {Object}  runOptions  An options object. The structure is the same
+ *   as for build options.
+ *
+ * @return {Promise} A promise either fulfilled if package was built and ran
+ *   successfully, or rejected with CordovaError.
+ */
+Api.prototype.run = function (runOptions) {
+    var self = this;
+    return require('./lib/check_reqs').run().then(function () {
+        return require('./lib/run').run.call(self, runOptions);
+    });
+};
+
+/**
+ * Cleans out the build artifacts from platform's directory, and also
+ * cleans out the platform www directory if called without options specified.
+ *
+ * @return  {Promise}  Return a promise either fulfilled, or rejected with
+ *   CordovaError.
+ */
+Api.prototype.clean = function (cleanOptions) {
+    var self = this;
+    // This will lint, checking for null won't
+    if (typeof cleanOptions === 'undefined') {
+        cleanOptions = {};
+    }
+
+    return require('./lib/check_reqs').run().then(function () {
+        return require('./lib/build').runClean.call(self, cleanOptions);
+    }).then(function () {
+        return require('./lib/prepare').clean.call(self, cleanOptions);
+    });
+};
+
+/**
+ * Performs a requirements check for current platform. Each platform defines its
+ *   own set of requirements, which should be resolved before platform can be
+ *   built successfully.
+ *
+ * @return  {Promise<Requirement[]>}  Promise, resolved with set of Requirement
+ *   objects for current platform.
+ */
+Api.prototype.requirements = function () {
+    return require('./lib/check_reqs').check_all();
+};
+
+module.exports = Api;
diff --git a/platforms/android/cordova/android_sdk_version b/platforms/android/cordova/android_sdk_version
new file mode 100755
index 0000000..c4082f1
--- /dev/null
+++ b/platforms/android/cordova/android_sdk_version
@@ -0,0 +1,27 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var android_sdk = require('./lib/android_sdk');
+
+android_sdk.print_newest_available_sdk_target().done(null, function (err) {
+    console.error(err);
+    process.exit(2);
+});
diff --git a/platforms/android/cordova/android_sdk_version.bat b/platforms/android/cordova/android_sdk_version.bat
new file mode 100644
index 0000000..a6bc104
--- /dev/null
+++ b/platforms/android/cordova/android_sdk_version.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License.  You may obtain a copy of the License at
+:: 
+:: http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied.  See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0android_sdk_version"
+IF EXIST %script_path% (
+        node %script_path% %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'android_sdk_version' script in 'bin' folder, aborting...>&2
+    EXIT /B 1
+)
diff --git a/platforms/android/cordova/build b/platforms/android/cordova/build
new file mode 100755
index 0000000..d703547
--- /dev/null
+++ b/platforms/android/cordova/build
@@ -0,0 +1,51 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var args = process.argv;
+var Api = require('./Api');
+var nopt = require('nopt');
+var path = require('path');
+
+// Support basic help commands
+if (['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(args[2]) >= 0) {
+    require('./lib/build').help();
+}
+
+// Do some basic argument parsing
+var buildOpts = nopt({
+    'verbose': Boolean,
+    'silent': Boolean,
+    'debug': Boolean,
+    'release': Boolean,
+    'nobuild': Boolean,
+    'buildConfig': path
+}, { 'd': '--verbose' });
+
+// Make buildOptions compatible with PlatformApi build method spec
+buildOpts.argv = buildOpts.argv.original;
+
+require('./loggingHelper').adjustLoggerLevel(buildOpts);
+
+new Api().build(buildOpts)
+    .catch(function (err) {
+        console.error(err.stack);
+        process.exit(2);
+    });
diff --git a/platforms/android/cordova/build.bat b/platforms/android/cordova/build.bat
new file mode 100644
index 0000000..46e966a
--- /dev/null
+++ b/platforms/android/cordova/build.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License.  You may obtain a copy of the License at
+::
+:: http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied.  See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0build"
+IF EXIST %script_path% (
+        node %script_path% %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'build' script in 'cordova' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file
diff --git a/platforms/android/cordova/check_reqs b/platforms/android/cordova/check_reqs
new file mode 100755
index 0000000..e0c1c44
--- /dev/null
+++ b/platforms/android/cordova/check_reqs
@@ -0,0 +1,32 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var check_reqs = require('./lib/check_reqs');
+
+check_reqs.run().done(
+    function success () {
+        console.log('Looks like your environment fully supports cordova-android development!');
+    },
+    function fail (err) {
+        console.log(err);
+        process.exit(2);
+    }
+);
diff --git a/platforms/android/cordova/check_reqs.bat b/platforms/android/cordova/check_reqs.bat
new file mode 100644
index 0000000..846dfa1
--- /dev/null
+++ b/platforms/android/cordova/check_reqs.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License.  You may obtain a copy of the License at
+:: 
+:: http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied.  See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0check_reqs"
+IF EXIST %script_path% (
+        node %script_path% %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'check_reqs' script in 'bin' folder, aborting...>&2
+    EXIT /B 1
+)
diff --git a/platforms/android/cordova/clean b/platforms/android/cordova/clean
new file mode 100755
index 0000000..9db5847
--- /dev/null
+++ b/platforms/android/cordova/clean
@@ -0,0 +1,51 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var Api = require('./Api');
+var path = require('path');
+var nopt = require('nopt');
+
+// Support basic help commands
+if (['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) {
+    console.log('Usage: ' + path.relative(process.cwd(), process.argv[1]));
+    console.log('Cleans the project directory.');
+    process.exit(0);
+}
+
+// Do some basic argument parsing
+var opts = nopt({
+    'verbose': Boolean,
+    'silent': Boolean
+}, { 'd': '--verbose' });
+
+// Make buildOptions compatible with PlatformApi clean method spec
+opts.argv = opts.argv.original;
+
+// Skip cleaning prepared files when not invoking via cordova CLI.
+opts.noPrepare = true;
+
+require('./loggingHelper').adjustLoggerLevel(opts);
+
+new Api().clean(opts)
+    .catch(function (err) {
+        console.error(err.stack);
+        process.exit(2);
+    });
diff --git a/platforms/android/cordova/clean.bat b/platforms/android/cordova/clean.bat
new file mode 100644
index 0000000..445ef6e
--- /dev/null
+++ b/platforms/android/cordova/clean.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License.  You may obtain a copy of the License at
+::
+:: http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied.  See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0clean"
+IF EXIST %script_path% (
+        node %script_path% %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'clean' script in 'cordova' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file
diff --git a/platforms/android/cordova/defaults.xml b/platforms/android/cordova/defaults.xml
new file mode 100644
index 0000000..5286ab9
--- /dev/null
+++ b/platforms/android/cordova/defaults.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<widget xmlns     = "http://www.w3.org/ns/widgets"
+        id        = "io.cordova.helloCordova"
+        version   = "2.0.0">
+
+    <!-- Preferences for Android -->
+    <preference name="loglevel" value="DEBUG" />
+</widget>
diff --git a/platforms/android/cordova/lib/Adb.js b/platforms/android/cordova/lib/Adb.js
new file mode 100644
index 0000000..b6ad8f1
--- /dev/null
+++ b/platforms/android/cordova/lib/Adb.js
@@ -0,0 +1,101 @@
+/**
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+
+var Q = require('q');
+var os = require('os');
+var events = require('cordova-common').events;
+var spawn = require('cordova-common').superspawn.spawn;
+var CordovaError = require('cordova-common').CordovaError;
+
+var Adb = {};
+
+function isDevice (line) {
+    return line.match(/\w+\tdevice/) && !line.match(/emulator/);
+}
+
+function isEmulator (line) {
+    return line.match(/device/) && line.match(/emulator/);
+}
+
+/**
+ * Lists available/connected devices and emulators
+ *
+ * @param   {Object}   opts            Various options
+ * @param   {Boolean}  opts.emulators  Specifies whether this method returns
+ *   emulators only
+ *
+ * @return  {Promise<String[]>}        list of available/connected
+ *   devices/emulators
+ */
+Adb.devices = function (opts) {
+    return spawn('adb', ['devices'], { cwd: os.tmpdir() }).then(function (output) {
+        return output.split('\n').filter(function (line) {
+            // Filter out either real devices or emulators, depending on options
+            return (line && opts && opts.emulators) ? isEmulator(line) : isDevice(line);
+        }).map(function (line) {
+            return line.replace(/\tdevice/, '').replace('\r', '');
+        });
+    });
+};
+
+Adb.install = function (target, packagePath, opts) {
+    events.emit('verbose', 'Installing apk ' + packagePath + ' on target ' + target + '...');
+    var args = ['-s', target, 'install'];
+    if (opts && opts.replace) args.push('-r');
+    return spawn('adb', args.concat(packagePath), { cwd: os.tmpdir() }).then(function (output) {
+        // 'adb install' seems to always returns no error, even if installation fails
+        // so we catching output to detect installation failure
+        if (output.match(/Failure/)) {
+            if (output.match(/INSTALL_PARSE_FAILED_NO_CERTIFICATES/)) {
+                output += '\n\n' + 'Sign the build using \'-- --keystore\' or \'--buildConfig\'' +
+                    ' or sign and deploy the unsigned apk manually using Android tools.';
+            } else if (output.match(/INSTALL_FAILED_VERSION_DOWNGRADE/)) {
+                output += '\n\n' + 'You\'re trying to install apk with a lower versionCode that is already installed.' +
+                    '\nEither uninstall an app or increment the versionCode.';
+            }
+
+            return Q.reject(new CordovaError('Failed to install apk to device: ' + output));
+        }
+    });
+};
+
+Adb.uninstall = function (target, packageId) {
+    events.emit('verbose', 'Uninstalling package ' + packageId + ' from target ' + target + '...');
+    return spawn('adb', ['-s', target, 'uninstall', packageId], { cwd: os.tmpdir() });
+};
+
+Adb.shell = function (target, shellCommand) {
+    events.emit('verbose', 'Running adb shell command "' + shellCommand + '" on target ' + target + '...');
+    var args = ['-s', target, 'shell'];
+    shellCommand = shellCommand.split(/\s+/);
+    return spawn('adb', args.concat(shellCommand), { cwd: os.tmpdir() }).catch(function (output) {
+        return Q.reject(new CordovaError('Failed to execute shell command "' +
+            shellCommand + '"" on device: ' + output));
+    });
+};
+
+Adb.start = function (target, activityName) {
+    events.emit('verbose', 'Starting application "' + activityName + '" on target ' + target + '...');
+    return Adb.shell(target, 'am start -W -a android.intent.action.MAIN -n' + activityName).catch(function (output) {
+        return Q.reject(new CordovaError('Failed to start application "' +
+            activityName + '"" on device: ' + output));
+    });
+};
+
+module.exports = Adb;
diff --git a/platforms/android/cordova/lib/AndroidManifest.js b/platforms/android/cordova/lib/AndroidManifest.js
new file mode 100644
index 0000000..4fe1c2b
--- /dev/null
+++ b/platforms/android/cordova/lib/AndroidManifest.js
@@ -0,0 +1,156 @@
+/**
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+
+var fs = require('fs');
+var et = require('elementtree');
+var xml = require('cordova-common').xmlHelpers;
+
+var DEFAULT_ORIENTATION = 'default';
+
+/** Wraps an AndroidManifest file */
+function AndroidManifest (path) {
+    this.path = path;
+    this.doc = xml.parseElementtreeSync(path);
+    if (this.doc.getroot().tag !== 'manifest') {
+        throw new Error('AndroidManifest at ' + path + ' has incorrect root node name (expected "manifest")');
+    }
+}
+
+AndroidManifest.prototype.getVersionName = function () {
+    return this.doc.getroot().attrib['android:versionName'];
+};
+
+AndroidManifest.prototype.setVersionName = function (versionName) {
+    this.doc.getroot().attrib['android:versionName'] = versionName;
+    return this;
+};
+
+AndroidManifest.prototype.getVersionCode = function () {
+    return this.doc.getroot().attrib['android:versionCode'];
+};
+
+AndroidManifest.prototype.setVersionCode = function (versionCode) {
+    this.doc.getroot().attrib['android:versionCode'] = versionCode;
+    return this;
+};
+
+AndroidManifest.prototype.getPackageId = function () {
+    return this.doc.getroot().attrib['package'];
+};
+
+AndroidManifest.prototype.setPackageId = function (pkgId) {
+    this.doc.getroot().attrib['package'] = pkgId;
+    return this;
+};
+
+AndroidManifest.prototype.getActivity = function () {
+    var activity = this.doc.getroot().find('./application/activity');
+    return {
+        getName: function () {
+            return activity.attrib['android:name'];
+        },
+        setName: function (name) {
+            if (!name) {
+                delete activity.attrib['android:name'];
+            } else {
+                activity.attrib['android:name'] = name;
+            }
+            return this;
+        },
+        getOrientation: function () {
+            return activity.attrib['android:screenOrientation'];
+        },
+        setOrientation: function (orientation) {
+            if (!orientation || orientation.toLowerCase() === DEFAULT_ORIENTATION) {
+                delete activity.attrib['android:screenOrientation'];
+            } else {
+                activity.attrib['android:screenOrientation'] = orientation;
+            }
+            return this;
+        },
+        getLaunchMode: function () {
+            return activity.attrib['android:launchMode'];
+        },
+        setLaunchMode: function (launchMode) {
+            if (!launchMode) {
+                delete activity.attrib['android:launchMode'];
+            } else {
+                activity.attrib['android:launchMode'] = launchMode;
+            }
+            return this;
+        }
+    };
+};
+
+['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion'].forEach(function (sdkPrefName) {
+    // Copy variable reference to avoid closure issues
+    var prefName = sdkPrefName;
+
+    AndroidManifest.prototype['get' + capitalize(prefName)] = function () {
+        var usesSdk = this.doc.getroot().find('./uses-sdk');
+        return usesSdk && usesSdk.attrib['android:' + prefName];
+    };
+
+    AndroidManifest.prototype['set' + capitalize(prefName)] = function (prefValue) {
+        var usesSdk = this.doc.getroot().find('./uses-sdk');
+
+        if (!usesSdk && prefValue) { // if there is no required uses-sdk element, we should create it first
+            usesSdk = new et.Element('uses-sdk');
+            this.doc.getroot().append(usesSdk);
+        }
+
+        if (prefValue) {
+            usesSdk.attrib['android:' + prefName] = prefValue;
+        }
+
+        return this;
+    };
+});
+
+AndroidManifest.prototype.getDebuggable = function () {
+    return this.doc.getroot().find('./application').attrib['android:debuggable'] === 'true';
+};
+
+AndroidManifest.prototype.setDebuggable = function (value) {
+    var application = this.doc.getroot().find('./application');
+    if (value) {
+        application.attrib['android:debuggable'] = 'true';
+    } else {
+        // The default value is "false", so we can remove attribute at all.
+        delete application.attrib['android:debuggable'];
+    }
+    return this;
+};
+
+/**
+ * Writes manifest to disk syncronously. If filename is specified, then manifest
+ *   will be written to that file
+ *
+ * @param   {String}  [destPath]  File to write manifest to. If omitted,
+ *   manifest will be written to file it has been read from.
+ */
+AndroidManifest.prototype.write = function (destPath) {
+    fs.writeFileSync(destPath || this.path, this.doc.write({ indent: 4 }), 'utf-8');
+};
+
+module.exports = AndroidManifest;
+
+function capitalize (str) {
+    return str.charAt(0).toUpperCase() + str.slice(1);
+}
diff --git a/platforms/android/cordova/lib/AndroidProject.js b/platforms/android/cordova/lib/AndroidProject.js
new file mode 100644
index 0000000..3c2586a
--- /dev/null
+++ b/platforms/android/cordova/lib/AndroidProject.js
@@ -0,0 +1,202 @@
+/**
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+
+var fs = require('fs');
+var path = require('path');
+var properties_parser = require('properties-parser');
+var AndroidManifest = require('./AndroidManifest');
+var pluginHandlers = require('./pluginHandlers');
+
+var projectFileCache = {};
+
+function addToPropertyList (projectProperties, key, value) {
+    var i = 1;
+    while (projectProperties.get(key + '.' + i)) { i++; }
+
+    projectProperties.set(key + '.' + i, value);
+    projectProperties.dirty = true;
+}
+
+function removeFromPropertyList (projectProperties, key, value) {
+    var i = 1;
+    var currentValue;
+    while ((currentValue = projectProperties.get(key + '.' + i))) {
+        if (currentValue === value) {
+            while ((currentValue = projectProperties.get(key + '.' + (i + 1)))) {
+                projectProperties.set(key + '.' + i, currentValue);
+                i++;
+            }
+            projectProperties.set(key + '.' + i);
+            break;
+        }
+        i++;
+    }
+    projectProperties.dirty = true;
+}
+
+function getRelativeLibraryPath (parentDir, subDir) {
+    var libraryPath = path.relative(parentDir, subDir);
+    return (path.sep === '\\') ? libraryPath.replace(/\\/g, '/') : libraryPath;
+}
+
+function AndroidProject (projectDir) {
+    this._propertiesEditors = {};
+    this._subProjectDirs = {};
+    this._dirty = false;
+    this.projectDir = projectDir;
+    this.platformWww = path.join(this.projectDir, 'platform_www');
+    this.www = path.join(this.projectDir, 'app/src/main/assets/www');
+}
+
+AndroidProject.getProjectFile = function (projectDir) {
+    if (!projectFileCache[projectDir]) {
+        projectFileCache[projectDir] = new AndroidProject(projectDir);
+    }
+
+    return projectFileCache[projectDir];
+};
+
+AndroidProject.purgeCache = function (projectDir) {
+    if (projectDir) {
+        delete projectFileCache[projectDir];
+    } else {
+        projectFileCache = {};
+    }
+};
+
+/**
+ * Reads the package name out of the Android Manifest file
+ *
+ * @param   {String}  projectDir  The absolute path to the directory containing the project
+ *
+ * @return  {String}              The name of the package
+ */
+AndroidProject.prototype.getPackageName = function () {
+    var manifestPath = path.join(this.projectDir, 'app/src/main/AndroidManifest.xml');
+    return new AndroidManifest(manifestPath).getPackageId();
+};
+
+AndroidProject.prototype.getCustomSubprojectRelativeDir = function (plugin_id, src) {
+    // All custom subprojects are prefixed with the last portion of the package id.
+    // This is to avoid collisions when opening multiple projects in Eclipse that have subprojects with the same name.
+    var packageName = this.getPackageName();
+    var lastDotIndex = packageName.lastIndexOf('.');
+    var prefix = packageName.substring(lastDotIndex + 1);
+    var subRelativeDir = path.join(plugin_id, prefix + '-' + path.basename(src));
+    return subRelativeDir;
+};
+
+AndroidProject.prototype.addSubProject = function (parentDir, subDir) {
+    var parentProjectFile = path.resolve(parentDir, 'project.properties');
+    var subProjectFile = path.resolve(subDir, 'project.properties');
+    var parentProperties = this._getPropertiesFile(parentProjectFile);
+    // TODO: Setting the target needs to happen only for pre-3.7.0 projects
+    if (fs.existsSync(subProjectFile)) {
+        var subProperties = this._getPropertiesFile(subProjectFile);
+        subProperties.set('target', parentProperties.get('target'));
+        subProperties.dirty = true;
+        this._subProjectDirs[subDir] = true;
+    }
+    addToPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));
+
+    this._dirty = true;
+};
+
+AndroidProject.prototype.removeSubProject = function (parentDir, subDir) {
+    var parentProjectFile = path.resolve(parentDir, 'project.properties');
+    var parentProperties = this._getPropertiesFile(parentProjectFile);
+    removeFromPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));
+    delete this._subProjectDirs[subDir];
+    this._dirty = true;
+};
+
+AndroidProject.prototype.addGradleReference = function (parentDir, subDir) {
+    var parentProjectFile = path.resolve(parentDir, 'project.properties');
+    var parentProperties = this._getPropertiesFile(parentProjectFile);
+    addToPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
+    this._dirty = true;
+};
+
+AndroidProject.prototype.removeGradleReference = function (parentDir, subDir) {
+    var parentProjectFile = path.resolve(parentDir, 'project.properties');
+    var parentProperties = this._getPropertiesFile(parentProjectFile);
+    removeFromPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
+    this._dirty = true;
+};
+
+AndroidProject.prototype.addSystemLibrary = function (parentDir, value) {
+    var parentProjectFile = path.resolve(parentDir, 'project.properties');
+    var parentProperties = this._getPropertiesFile(parentProjectFile);
+    addToPropertyList(parentProperties, 'cordova.system.library', value);
+    this._dirty = true;
+};
+
+AndroidProject.prototype.removeSystemLibrary = function (parentDir, value) {
+    var parentProjectFile = path.resolve(parentDir, 'project.properties');
+    var parentProperties = this._getPropertiesFile(parentProjectFile);
+    removeFromPropertyList(parentProperties, 'cordova.system.library', value);
+    this._dirty = true;
+};
+
+AndroidProject.prototype.write = function () {
+    if (!this._dirty) {
+        return;
+    }
+    this._dirty = false;
+
+    for (var filename in this._propertiesEditors) {
+        var editor = this._propertiesEditors[filename];
+        if (editor.dirty) {
+            fs.writeFileSync(filename, editor.toString());
+            editor.dirty = false;
+        }
+    }
+};
+
+AndroidProject.prototype._getPropertiesFile = function (filename) {
+    if (!this._propertiesEditors[filename]) {
+        if (fs.existsSync(filename)) {
+            this._propertiesEditors[filename] = properties_parser.createEditor(filename);
+        } else {
+            this._propertiesEditors[filename] = properties_parser.createEditor();
+        }
+    }
+
+    return this._propertiesEditors[filename];
+};
+
+AndroidProject.prototype.getInstaller = function (type) {
+    return pluginHandlers.getInstaller(type);
+};
+
+AndroidProject.prototype.getUninstaller = function (type) {
+    return pluginHandlers.getUninstaller(type);
+};
+
+/*
+ * This checks if an Android project is clean or has old build artifacts
+ */
+
+AndroidProject.prototype.isClean = function () {
+    var build_path = path.join(this.projectDir, 'build');
+    // If the build directory doesn't exist, it's clean
+    return !(fs.existsSync(build_path));
+};
+
+module.exports = AndroidProject;
diff --git a/platforms/android/cordova/lib/android_sdk.js b/platforms/android/cordova/lib/android_sdk.js
new file mode 100755
index 0000000..1c0ab20
--- /dev/null
+++ b/platforms/android/cordova/lib/android_sdk.js
@@ -0,0 +1,101 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var superspawn = require('cordova-common').superspawn;
+
+var suffix_number_regex = /(\d+)$/;
+// Used for sorting Android targets, example strings to sort:
+//   android-19
+//   android-L
+//   Google Inc.:Google APIs:20
+//   Google Inc.:Glass Development Kit Preview:20
+// The idea is to sort based on largest "suffix" number - meaning the bigger
+// the number at the end, the more recent the target, the closer to the
+// start of the array.
+function sort_by_largest_numerical_suffix (a, b) {
+    var suffix_a = a.match(suffix_number_regex);
+    var suffix_b = b.match(suffix_number_regex);
+    if (suffix_a && suffix_b) {
+        // If the two targets being compared have suffixes, return less than
+        // zero, or greater than zero, based on which suffix is larger.
+        return (parseInt(suffix_a[1]) > parseInt(suffix_b[1]) ? -1 : 1);
+    } else {
+        // If no suffix numbers were detected, leave the order as-is between
+        // elements a and b.
+        return 0;
+    }
+}
+
+module.exports.print_newest_available_sdk_target = function () {
+    return module.exports.list_targets().then(function (targets) {
+        targets.sort(sort_by_largest_numerical_suffix);
+        console.log(targets[0]);
+    });
+};
+
+module.exports.version_string_to_api_level = {
+    '4.0': 14,
+    '4.0.3': 15,
+    '4.1': 16,
+    '4.2': 17,
+    '4.3': 18,
+    '4.4': 19,
+    '4.4W': 20,
+    '5.0': 21,
+    '5.1': 22,
+    '6.0': 23,
+    '7.0': 24,
+    '7.1.1': 25,
+    '8.0': 26
+};
+
+function parse_targets (output) {
+    var target_out = output.split('\n');
+    var targets = [];
+    for (var i = target_out.length - 1; i >= 0; i--) {
+        if (target_out[i].match(/id:/)) { // if "id:" is in the line...
+            targets.push(target_out[i].match(/"(.+)"/)[1]); // .. match whatever is in quotes.
+        }
+    }
+    return targets;
+}
+
+module.exports.list_targets_with_android = function () {
+    return superspawn.spawn('android', ['list', 'target']).then(parse_targets);
+};
+
+module.exports.list_targets_with_avdmanager = function () {
+    return superspawn.spawn('avdmanager', ['list', 'target']).then(parse_targets);
+};
+
+module.exports.list_targets = function () {
+    return module.exports.list_targets_with_avdmanager().catch(function (err) {
+        // If there's an error, like avdmanager could not be found, we can try
+        // as a last resort, to run `android`, in case this is a super old
+        // SDK installation.
+        if (err && (err.code === 'ENOENT' || (err.stderr && err.stderr.match(/not recognized/)))) {
+            return module.exports.list_targets_with_android();
+        } else throw err;
+    }).then(function (targets) {
+        if (targets.length === 0) {
+            return Promise.reject(new Error('No android targets (SDKs) installed!'));
+        }
+        return targets;
+    });
+};
diff --git a/platforms/android/cordova/lib/build.js b/platforms/android/cordova/lib/build.js
new file mode 100644
index 0000000..2f0ba69
--- /dev/null
+++ b/platforms/android/cordova/lib/build.js
@@ -0,0 +1,278 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var Q = require('q');
+var path = require('path');
+var fs = require('fs');
+var nopt = require('nopt');
+
+var Adb = require('./Adb');
+
+var builders = require('./builders/builders');
+var events = require('cordova-common').events;
+var spawn = require('cordova-common').superspawn.spawn;
+var CordovaError = require('cordova-common').CordovaError;
+
+module.exports.parseBuildOptions = parseOpts;
+function parseOpts (options, resolvedTarget, projectRoot) {
+    options = options || {};
+    options.argv = nopt({
+        prepenv: Boolean,
+        versionCode: String,
+        minSdkVersion: String,
+        gradleArg: [String, Array],
+        keystore: path,
+        alias: String,
+        storePassword: String,
+        password: String,
+        keystoreType: String
+    }, {}, options.argv, 0);
+
+    // Android Studio Build method is the default
+    var ret = {
+        buildType: options.release ? 'release' : 'debug',
+        prepEnv: options.argv.prepenv,
+        arch: resolvedTarget && resolvedTarget.arch,
+        extraArgs: []
+    };
+
+    if (options.argv.versionCode) { ret.extraArgs.push('-PcdvVersionCode=' + options.argv.versionCode); }
+    if (options.argv.minSdkVersion) { ret.extraArgs.push('-PcdvMinSdkVersion=' + options.argv.minSdkVersion); }
+    if (options.argv.gradleArg) {
+        ret.extraArgs = ret.extraArgs.concat(options.argv.gradleArg);
+    }
+
+    var packageArgs = {};
+
+    if (options.argv.keystore) { packageArgs.keystore = path.relative(projectRoot, path.resolve(options.argv.keystore)); }
+
+    ['alias', 'storePassword', 'password', 'keystoreType'].forEach(function (flagName) {
+        if (options.argv[flagName]) { packageArgs[flagName] = options.argv[flagName]; }
+    });
+
+    var buildConfig = options.buildConfig;
+
+    // If some values are not specified as command line arguments - use build config to supplement them.
+    // Command line arguemnts have precedence over build config.
+    if (buildConfig) {
+        if (!fs.existsSync(buildConfig)) {
+            throw new Error('Specified build config file does not exist: ' + buildConfig);
+        }
+        events.emit('log', 'Reading build config file: ' + path.resolve(buildConfig));
+        var buildjson = fs.readFileSync(buildConfig, 'utf8');
+        var config = JSON.parse(buildjson.replace(/^\ufeff/, '')); // Remove BOM
+        if (config.android && config.android[ret.buildType]) {
+            var androidInfo = config.android[ret.buildType];
+            if (androidInfo.keystore && !packageArgs.keystore) {
+                if (androidInfo.keystore.substr(0, 1) === '~') {
+                    androidInfo.keystore = process.env.HOME + androidInfo.keystore.substr(1);
+                }
+                packageArgs.keystore = path.resolve(path.dirname(buildConfig), androidInfo.keystore);
+                events.emit('log', 'Reading the keystore from: ' + packageArgs.keystore);
+            }
+
+            ['alias', 'storePassword', 'password', 'keystoreType'].forEach(function (key) {
+                packageArgs[key] = packageArgs[key] || androidInfo[key];
+            });
+        }
+    }
+
+    if (packageArgs.keystore && packageArgs.alias) {
+        ret.packageInfo = new PackageInfo(packageArgs.keystore, packageArgs.alias, packageArgs.storePassword,
+            packageArgs.password, packageArgs.keystoreType);
+    }
+
+    if (!ret.packageInfo) {
+        if (Object.keys(packageArgs).length > 0) {
+            events.emit('warn', '\'keystore\' and \'alias\' need to be specified to generate a signed archive.');
+        }
+    }
+
+    return ret;
+}
+
+/*
+ * Builds the project with the specifed options
+ * Returns a promise.
+ */
+module.exports.runClean = function (options) {
+    var opts = parseOpts(options, null, this.root);
+    var builder = builders.getBuilder();
+
+    return builder.prepEnv(opts).then(function () {
+        return builder.clean(opts);
+    });
+};
+
+/**
+ * Builds the project with the specifed options.
+ *
+ * @param   {BuildOptions}  options      A set of options. See PlatformApi.build
+ *   method documentation for reference.
+ * @param   {Object}  optResolvedTarget  A deployment target. Used to pass
+ *   target architecture from upstream 'run' call. TODO: remove this option in
+ *   favor of setting buildOptions.archs field.
+ *
+ * @return  {Promise<Object>}            Promise, resolved with built packages
+ *   information.
+ */
+module.exports.run = function (options, optResolvedTarget) {
+    var opts = parseOpts(options, optResolvedTarget, this.root);
+    var builder = builders.getBuilder();
+
+    return builder.prepEnv(opts).then(function () {
+        if (opts.prepEnv) {
+            events.emit('verbose', 'Build file successfully prepared.');
+            return;
+        }
+        return builder.build(opts).then(function () {
+            var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
+            events.emit('log', 'Built the following apk(s): \n\t' + apkPaths.join('\n\t'));
+            return {
+                apkPaths: apkPaths,
+                buildType: opts.buildType
+            };
+        });
+    });
+};
+
+/*
+ * Detects the architecture of a device/emulator
+ * Returns "arm" or "x86".
+ */
+module.exports.detectArchitecture = function (target) {
+    function helper () {
+        return Adb.shell(target, 'cat /proc/cpuinfo').then(function (output) {
+            return /intel/i.exec(output) ? 'x86' : 'arm';
+        });
+    }
+    // It sometimes happens (at least on OS X), that this command will hang forever.
+    // To fix it, either unplug & replug device, or restart adb server.
+    return helper().timeout(1000, new CordovaError('Device communication timed out. Try unplugging & replugging the device.')).then(null, function (err) {
+        if (/timed out/.exec('' + err)) {
+            // adb kill-server doesn't seem to do the trick.
+            // Could probably find a x-platform version of killall, but I'm not actually
+            // sure that this scenario even happens on non-OSX machines.
+            events.emit('verbose', 'adb timed out while detecting device/emulator architecture. Killing adb and trying again.');
+            return spawn('killall', ['adb']).then(function () {
+                return helper().then(null, function () {
+                    // The double kill is sadly often necessary, at least on mac.
+                    events.emit('warn', 'adb timed out a second time while detecting device/emulator architecture. Killing adb and trying again.');
+                    return spawn('killall', ['adb']).then(function () {
+                        return helper().then(null, function () {
+                            return Q.reject(new CordovaError('adb timed out a third time while detecting device/emulator architecture. Try unplugging & replugging the device.'));
+                        });
+                    });
+                });
+            }, function () {
+                // For non-killall OS's.
+                return Q.reject(err);
+            });
+        }
+        throw err;
+    });
+};
+
+module.exports.findBestApkForArchitecture = function (buildResults, arch) {
+    var paths = buildResults.apkPaths.filter(function (p) {
+        var apkName = path.basename(p);
+        if (buildResults.buildType === 'debug') {
+            return /-debug/.exec(apkName);
+        }
+        return !/-debug/.exec(apkName);
+    });
+    var archPattern = new RegExp('-' + arch);
+    var hasArchPattern = /-x86|-arm/;
+    for (var i = 0; i < paths.length; ++i) {
+        var apkName = path.basename(paths[i]);
+        if (hasArchPattern.exec(apkName)) {
+            if (archPattern.exec(apkName)) {
+                return paths[i];
+            }
+        } else {
+            return paths[i];
+        }
+    }
+    throw new Error('Could not find apk architecture: ' + arch + ' build-type: ' + buildResults.buildType);
+};
+
+function PackageInfo (keystore, alias, storePassword, password, keystoreType) {
+    this.keystore = {
+        'name': 'key.store',
+        'value': keystore
+    };
+    this.alias = {
+        'name': 'key.alias',
+        'value': alias
+    };
+    if (storePassword) {
+        this.storePassword = {
+            'name': 'key.store.password',
+            'value': storePassword
+        };
+    }
+    if (password) {
+        this.password = {
+            'name': 'key.alias.password',
+            'value': password
+        };
+    }
+    if (keystoreType) {
+        this.keystoreType = {
+            'name': 'key.store.type',
+            'value': keystoreType
+        };
+    }
+}
+
+PackageInfo.prototype = {
+    toProperties: function () {
+        var self = this;
+        var result = '';
+        Object.keys(self).forEach(function (key) {
+            result += self[key].name;
+            result += '=';
+            result += self[key].value.replace(/\\/g, '\\\\');
+            result += '\n';
+        });
+        return result;
+    }
+};
+
+module.exports.help = function () {
+    console.log('Usage: ' + path.relative(process.cwd(), path.join('../build')) + ' [flags] [Signed APK flags]');
+    console.log('Flags:');
+    console.log('    \'--debug\': will build project in debug mode (default)');
+    console.log('    \'--release\': will build project for release');
+    console.log('    \'--nobuild\': will skip build process (useful when using run command)');
+    console.log('    \'--prepenv\': don\'t build, but copy in build scripts where necessary');
+    console.log('    \'--versionCode=#\': Override versionCode for this build. Useful for uploading multiple APKs.');
+    console.log('    \'--minSdkVersion=#\': Override minSdkVersion for this build. Useful for uploading multiple APKs.');
+    console.log('    \'--gradleArg=<gradle command line arg>\': Extra args to pass to the gradle command. Use one flag per arg. Ex. --gradleArg=-PcdvBuildMultipleApks=true');
+    console.log('');
+    console.log('Signed APK flags (overwrites debug/release-signing.proprties) :');
+    console.log('    \'--keystore=<path to keystore>\': Key store used to build a signed archive. (Required)');
+    console.log('    \'--alias=\': Alias for the key store. (Required)');
+    console.log('    \'--storePassword=\': Password for the key store. (Optional - prompted)');
+    console.log('    \'--password=\': Password for the key. (Optional - prompted)');
+    console.log('    \'--keystoreType\': Type of the keystore. (Optional)');
+    process.exit(0);
+};
diff --git a/platforms/android/cordova/lib/builders/ProjectBuilder.js b/platforms/android/cordova/lib/builders/ProjectBuilder.js
new file mode 100644
index 0000000..94e26a0
--- /dev/null
+++ b/platforms/android/cordova/lib/builders/ProjectBuilder.js
@@ -0,0 +1,370 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+/* eslint no-self-assign: 0 */
+/* eslint no-unused-vars: 0 */
+
+var Q = require('q');
+var fs = require('fs');
+var path = require('path');
+var shell = require('shelljs');
+var spawn = require('cordova-common').superspawn.spawn;
+var events = require('cordova-common').events;
+var CordovaError = require('cordova-common').CordovaError;
+var check_reqs = require('../check_reqs');
+
+const MARKER = 'YOUR CHANGES WILL BE ERASED!';
+const SIGNING_PROPERTIES = '-signing.properties';
+const TEMPLATE =
+    '# This file is automatically generated.\n' +
+    '# Do not modify this file -- ' + MARKER + '\n';
+
+class ProjectBuilder {
+    constructor (rootDirectory) {
+        this.root = rootDirectory || path.resolve(__dirname, '../../..');
+        this.binDir = path.join(this.root, 'app', 'build', 'outputs', 'apk');
+    }
+
+    getArgs (cmd, opts) {
+        if (cmd === 'release') {
+            cmd = 'cdvBuildRelease';
+        } else if (cmd === 'debug') {
+            cmd = 'cdvBuildDebug';
+        }
+
+        let args = [cmd, '-b', path.join(this.root, 'build.gradle')];
+
+        if (opts.arch) {
+            args.push('-PcdvBuildArch=' + opts.arch);
+        }
+
+        args.push.apply(args, opts.extraArgs);
+
+        return args;
+    }
+
+    /*
+    * This returns a promise
+    */
+    runGradleWrapper (gradle_cmd) {
+        var gradlePath = path.join(this.root, 'gradlew');
+        var wrapperGradle = path.join(this.root, 'wrapper.gradle');
+        if (fs.existsSync(gradlePath)) {
+            // Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows
+        } else {
+            return spawn(gradle_cmd, ['-p', this.root, 'wrapper', '-b', wrapperGradle], { stdio: 'inherit' });
+        }
+    }
+
+    readProjectProperties () {
+        function findAllUniq (data, r) {
+            var s = {};
+            var m;
+            while ((m = r.exec(data))) {
+                s[m[1]] = 1;
+            }
+            return Object.keys(s);
+        }
+
+        var data = fs.readFileSync(path.join(this.root, 'project.properties'), 'utf8');
+        return {
+            libs: findAllUniq(data, /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg),
+            gradleIncludes: findAllUniq(data, /^\s*cordova\.gradle\.include\.\d+=(.*)(?:\s|$)/mg),
+            systemLibs: findAllUniq(data, /^\s*cordova\.system\.library\.\d+=(.*)(?:\s|$)/mg)
+        };
+    }
+
+    extractRealProjectNameFromManifest () {
+        var manifestPath = path.join(this.root, 'app', 'src', 'main', 'AndroidManifest.xml');
+        var manifestData = fs.readFileSync(manifestPath, 'utf8');
+        var m = /<manifest[\s\S]*?package\s*=\s*"(.*?)"/i.exec(manifestData);
+        if (!m) {
+            throw new CordovaError('Could not find package name in ' + manifestPath);
+        }
+
+        var packageName = m[1];
+        var lastDotIndex = packageName.lastIndexOf('.');
+        return packageName.substring(lastDotIndex + 1);
+    }
+
+    // Makes the project buildable, minus the gradle wrapper.
+    prepBuildFiles () {
+        // Update the version of build.gradle in each dependent library.
+        var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle');
+        var propertiesObj = this.readProjectProperties();
+        var subProjects = propertiesObj.libs;
+
+        // Check and copy the gradle file into the subproject
+        // Called by the loop before this function def
+
+        var checkAndCopy = function (subProject, root) {
+            var subProjectGradle = path.join(root, subProject, 'build.gradle');
+            // This is the future-proof way of checking if a file exists
+            // This must be synchronous to satisfy a Travis test
+            try {
+                fs.accessSync(subProjectGradle, fs.F_OK);
+            } catch (e) {
+                shell.cp('-f', pluginBuildGradle, subProjectGradle);
+            }
+        };
+
+        for (var i = 0; i < subProjects.length; ++i) {
+            if (subProjects[i] !== 'CordovaLib') {
+                checkAndCopy(subProjects[i], this.root);
+            }
+        }
+        var name = this.extractRealProjectNameFromManifest();
+        // Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
+        var settingsGradlePaths = subProjects.map(function (p) {
+            var realDir = p.replace(/[/\\]/g, ':');
+            var libName = realDir.replace(name + '-', '');
+            var str = 'include ":' + libName + '"\n';
+            if (realDir.indexOf(name + '-') !== -1) {
+                str += 'project(":' + libName + '").projectDir = new File("' + p + '")\n';
+            }
+            return str;
+        });
+
+        fs.writeFileSync(path.join(this.root, 'settings.gradle'),
+            '// GENERATED FILE - DO NOT EDIT\n' +
+            'include ":"\n' + settingsGradlePaths.join(''));
+
+        // Update dependencies within build.gradle.
+        var buildGradle = fs.readFileSync(path.join(this.root, 'app', 'build.gradle'), 'utf8');
+        var depsList = '';
+        var root = this.root;
+        var insertExclude = function (p) {
+            var gradlePath = path.join(root, p, 'build.gradle');
+            var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8');
+            if (projectGradleFile.indexOf('CordovaLib') !== -1) {
+                depsList += '{\n        exclude module:("CordovaLib")\n    }\n';
+            } else {
+                depsList += '\n';
+            }
+        };
+        subProjects.forEach(function (p) {
+            events.emit('log', 'Subproject Path: ' + p);
+            var libName = p.replace(/[/\\]/g, ':').replace(name + '-', '');
+            if (libName !== 'app') {
+                depsList += '    implementation(project(path: ":' + libName + '"))';
+                insertExclude(p);
+            }
+        });
+        // For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390
+        var SYSTEM_LIBRARY_MAPPINGS = [
+            [/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'],
+            [/^\/?google\/google_play_services\/libproject\/google-play-services_lib\/?$/, 'com.google.android.gms:play-services:+']
+        ];
+
+        propertiesObj.systemLibs.forEach(function (p) {
+            var mavenRef;
+            // It's already in gradle form if it has two ':'s
+            if (/:.*:/.exec(p)) {
+                mavenRef = p;
+            } else {
+                for (var i = 0; i < SYSTEM_LIBRARY_MAPPINGS.length; ++i) {
+                    var pair = SYSTEM_LIBRARY_MAPPINGS[i];
+                    if (pair[0].exec(p)) {
+                        mavenRef = p.replace(pair[0], pair[1]);
+                        break;
+                    }
+                }
+                if (!mavenRef) {
+                    throw new CordovaError('Unsupported system library (does not work with gradle): ' + p);
+                }
+            }
+            depsList += '    implementation "' + mavenRef + '"\n';
+        });
+
+        buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + '    $2');
+        var includeList = '';
+
+        propertiesObj.gradleIncludes.forEach(function (includePath) {
+            includeList += 'apply from: "../' + includePath + '"\n';
+        });
+        buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2');
+        // This needs to be stored in the app gradle, not the root grade
+        fs.writeFileSync(path.join(this.root, 'app', 'build.gradle'), buildGradle);
+    }
+
+    prepEnv (opts) {
+        var self = this;
+        return check_reqs.check_gradle()
+            .then(function (gradlePath) {
+                return self.runGradleWrapper(gradlePath);
+            }).then(function () {
+                return self.prepBuildFiles();
+            }).then(function () {
+                // If the gradle distribution URL is set, make sure it points to version we want.
+                // If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with.
+                // For some reason, using ^ and $ don't work.  This does the job, though.
+                var distributionUrlRegex = /distributionUrl.*zip/;
+                var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\://services.gradle.org/distributions/gradle-4.10.3-all.zip';
+                var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties');
+                shell.chmod('u+w', gradleWrapperPropertiesPath);
+                shell.sed('-i', distributionUrlRegex, 'distributionUrl=' + distributionUrl, gradleWrapperPropertiesPath);
+
+                var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
+                var propertiesFilePath = path.join(self.root, propertiesFile);
+                if (opts.packageInfo) {
+                    fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
+                } else if (isAutoGenerated(propertiesFilePath)) {
+                    shell.rm('-f', propertiesFilePath);
+                }
+            });
+    }
+
+    /*
+    * Builds the project with gradle.
+    * Returns a promise.
+    */
+    build (opts) {
+        var wrapper = path.join(this.root, 'gradlew');
+        var args = this.getArgs(opts.buildType === 'debug' ? 'debug' : 'release', opts);
+
+        return spawn(wrapper, args, { stdio: 'pipe' })
+            .progress(function (stdio) {
+                if (stdio.stderr) {
+                    /*
+                    * Workaround for the issue with Java printing some unwanted information to
+                    * stderr instead of stdout.
+                    * This function suppresses 'Picked up _JAVA_OPTIONS' message from being
+                    * printed to stderr. See https://issues.apache.org/jira/browse/CB-9971 for
+                    * explanation.
+                    */
+                    var suppressThisLine = /^Picked up _JAVA_OPTIONS: /i.test(stdio.stderr.toString());
+                    if (suppressThisLine) {
+                        return;
+                    }
+                    process.stderr.write(stdio.stderr);
+                } else {
+                    process.stdout.write(stdio.stdout);
+                }
+            }).catch(function (error) {
+                if (error.toString().indexOf('failed to find target with hash string') >= 0) {
+                    return check_reqs.check_android_target(error).then(function () {
+                        // If due to some odd reason - check_android_target succeeds
+                        // we should still fail here.
+                        return Q.reject(error);
+                    });
+                }
+                return Q.reject(error);
+            });
+    }
+
+    clean (opts) {
+        var builder = this;
+        var wrapper = path.join(this.root, 'gradlew');
+        var args = builder.getArgs('clean', opts);
+        return Q().then(function () {
+            return spawn(wrapper, args, { stdio: 'inherit' });
+        })
+            .then(function () {
+                shell.rm('-rf', path.join(builder.root, 'out'));
+
+                ['debug', 'release'].forEach(function (config) {
+                    var propertiesFilePath = path.join(builder.root, config + SIGNING_PROPERTIES);
+                    if (isAutoGenerated(propertiesFilePath)) {
+                        shell.rm('-f', propertiesFilePath);
+                    }
+                });
+            });
+    }
+
+    findOutputApks (build_type, arch) {
+        return findOutputApksHelper(this.binDir, build_type, arch).sort(apkSorter);
+    }
+
+    fetchBuildResults (build_type, arch) {
+        return {
+            apkPaths: this.findOutputApks(build_type, arch),
+            buildType: build_type
+        };
+    }
+}
+
+module.exports = ProjectBuilder;
+
+function apkSorter (fileA, fileB) {
+    // De-prioritize arch specific builds
+    var archSpecificRE = /-x86|-arm/;
+    if (archSpecificRE.exec(fileA)) {
+        return 1;
+    } else if (archSpecificRE.exec(fileB)) {
+        return -1;
+    }
+
+    // De-prioritize unsigned builds
+    var unsignedRE = /-unsigned/;
+    if (unsignedRE.exec(fileA)) {
+        return 1;
+    } else if (unsignedRE.exec(fileB)) {
+        return -1;
+    }
+
+    var timeDiff = fs.statSync(fileB).mtime - fs.statSync(fileA).mtime;
+    return timeDiff === 0 ? fileA.length - fileB.length : timeDiff;
+}
+
+function findOutputApksHelper (dir, build_type, arch) {
+    var shellSilent = shell.config.silent;
+    shell.config.silent = true;
+
+    // list directory recursively
+    var ret = shell.ls('-R', dir).map(function (file) {
+        // ls does not include base directory
+        return path.join(dir, file);
+    }).filter(function (file) {
+        // find all APKs
+        return file.match(/\.apk?$/i);
+    }).filter(function (candidate) {
+        var apkName = path.basename(candidate);
+        // Need to choose between release and debug .apk.
+        if (build_type === 'debug') {
+            return /-debug/.exec(apkName) && !/-unaligned|-unsigned/.exec(apkName);
+        }
+        if (build_type === 'release') {
+            return /-release/.exec(apkName) && !/-unaligned/.exec(apkName);
+        }
+        return true;
+    }).sort(apkSorter);
+
+    shellSilent = shellSilent;
+
+    if (ret.length === 0) {
+        return ret;
+    }
+    // Assume arch-specific build if newest apk has -x86 or -arm.
+    var archSpecific = !!/-x86|-arm/.exec(path.basename(ret[0]));
+    // And show only arch-specific ones (or non-arch-specific)
+    ret = ret.filter(function (p) {
+        return !!/-x86|-arm/.exec(path.basename(p)) === archSpecific;
+    });
+
+    if (archSpecific && ret.length > 1 && arch) {
+        ret = ret.filter(function (p) {
+            return path.basename(p).indexOf('-' + arch) !== -1;
+        });
+    }
+
+    return ret;
+}
+
+function isAutoGenerated (file) {
+    return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
+}
diff --git a/platforms/android/cordova/lib/builders/builders.js b/platforms/android/cordova/lib/builders/builders.js
new file mode 100644
index 0000000..42fc19d
--- /dev/null
+++ b/platforms/android/cordova/lib/builders/builders.js
@@ -0,0 +1,34 @@
+/*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+
+const CordovaError = require('cordova-common').CordovaError;
+
+/**
+ * Helper method that instantiates and returns a builder for specified build type.
+ *
+ * @return {Builder} A builder instance for specified build type.
+ */
+module.exports.getBuilder = function () {
+    try {
+        const Builder = require('./ProjectBuilder');
+        return new Builder();
+    } catch (err) {
+        throw new CordovaError('Failed to instantiate ProjectBuilder builder: ' + err);
+    }
+};
diff --git a/platforms/android/cordova/lib/check_reqs.js b/platforms/android/cordova/lib/check_reqs.js
new file mode 100644
index 0000000..6435e01
--- /dev/null
+++ b/platforms/android/cordova/lib/check_reqs.js
@@ -0,0 +1,436 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var shelljs = require('shelljs');
+var child_process = require('child_process');
+var Q = require('q');
+var path = require('path');
+var fs = require('fs');
+var os = require('os');
+var REPO_ROOT = path.join(__dirname, '..', '..', '..', '..');
+var PROJECT_ROOT = path.join(__dirname, '..', '..');
+var CordovaError = require('cordova-common').CordovaError;
+var superspawn = require('cordova-common').superspawn;
+var android_sdk = require('./android_sdk');
+
+function forgivingWhichSync (cmd) {
+    try {
+        return fs.realpathSync(shelljs.which(cmd));
+    } catch (e) {
+        return '';
+    }
+}
+
+module.exports.isWindows = function () {
+    return (os.platform() === 'win32');
+};
+
+module.exports.isDarwin = function () {
+    return (os.platform() === 'darwin');
+};
+
+// Get valid target from framework/project.properties if run from this repo
+// Otherwise get target from project.properties file within a generated cordova-android project
+module.exports.get_target = function () {
+    function extractFromFile (filePath) {
+        var target = shelljs.grep(/\btarget=/, filePath);
+        if (!target) {
+            throw new Error('Could not find android target within: ' + filePath);
+        }
+        return target.split('=')[1].trim();
+    }
+    var repo_file = path.join(REPO_ROOT, 'framework', 'project.properties');
+    if (fs.existsSync(repo_file)) {
+        return extractFromFile(repo_file);
+    }
+    var project_file = path.join(PROJECT_ROOT, 'project.properties');
+    if (fs.existsSync(project_file)) {
+        // if no target found, we're probably in a project and project.properties is in PROJECT_ROOT.
+        return extractFromFile(project_file);
+    }
+    throw new Error('Could not find android target in either ' + repo_file + ' nor ' + project_file);
+};
+
+// Returns a promise. Called only by build and clean commands.
+module.exports.check_ant = function () {
+    return superspawn.spawn('ant', ['-version']).then(function (output) {
+        // Parse Ant version from command output
+        return /version ((?:\d+\.)+(?:\d+))/i.exec(output)[1];
+    }).catch(function (err) {
+        if (err) {
+            throw new CordovaError('Failed to run `ant -version`. Make sure you have `ant` on your $PATH.');
+        }
+    });
+};
+
+module.exports.get_gradle_wrapper = function () {
+    var androidStudioPath;
+    var i = 0;
+    var foundStudio = false;
+    var program_dir;
+    // OK, This hack only works on Windows, not on Mac OS or Linux.  We will be deleting this eventually!
+    if (module.exports.isWindows()) {
+
+        var result = child_process.spawnSync(path.join(__dirname, 'getASPath.bat'));
+        // console.log('result.stdout =' + result.stdout.toString());
+        // console.log('result.stderr =' + result.stderr.toString());
+
+        if (result.stderr.toString().length > 0) {
+            var androidPath = path.join(process.env['ProgramFiles'], 'Android') + '/';
+            if (fs.existsSync(androidPath)) {
+                program_dir = fs.readdirSync(androidPath);
+                while (i < program_dir.length && !foundStudio) {
+                    if (program_dir[i].startsWith('Android Studio')) {
+                        foundStudio = true;
+                        androidStudioPath = path.join(process.env['ProgramFiles'], 'Android', program_dir[i], 'gradle');
+                    } else { ++i; }
+                }
+            }
+        } else {
+            // console.log('got android studio path from registry');
+            // remove the (os independent) new line char at the end of stdout
+            // add gradle to match the above.
+            androidStudioPath = path.join(result.stdout.toString().split('\r\n')[0], 'gradle');
+        }
+    }
+
+    if (androidStudioPath !== null && fs.existsSync(androidStudioPath)) {
+        var dirs = fs.readdirSync(androidStudioPath);
+        if (dirs[0].split('-')[0] === 'gradle') {
+            return path.join(androidStudioPath, dirs[0], 'bin', 'gradle');
+        }
+    } else {
+        // OK, let's try to check for Gradle!
+        return forgivingWhichSync('gradle');
+    }
+};
+
+// Returns a promise. Called only by build and clean commands.
+module.exports.check_gradle = function () {
+    var sdkDir = process.env['ANDROID_HOME'];
+    var d = Q.defer();
+    if (!sdkDir) {
+        return Q.reject(new CordovaError('Could not find gradle wrapper within Android SDK. Could not find Android SDK directory.\n' +
+            'Might need to install Android SDK or set up \'ANDROID_HOME\' env variable.'));
+    }
+
+    var gradlePath = module.exports.get_gradle_wrapper();
+    if (gradlePath.length !== 0) { d.resolve(gradlePath); } else {
+        d.reject(new CordovaError('Could not find an installed version of Gradle either in Android Studio,\n' +
+                                'or on your system to install the gradle wrapper. Please include gradle \n' +
+                                'in your path, or install Android Studio'));
+    }
+    return d.promise;
+};
+
+// Returns a promise.
+module.exports.check_java = function () {
+    var javacPath = forgivingWhichSync('javac');
+    var hasJavaHome = !!process.env['JAVA_HOME'];
+    return Q().then(function () {
+        if (hasJavaHome) {
+            // Windows java installer doesn't add javac to PATH, nor set JAVA_HOME (ugh).
+            if (!javacPath) {
+                process.env['PATH'] += path.delimiter + path.join(process.env['JAVA_HOME'], 'bin');
+            }
+        } else {
+            if (javacPath) {
+                // OS X has a command for finding JAVA_HOME.
+                var find_java = '/usr/libexec/java_home';
+                var default_java_error_msg = 'Failed to find \'JAVA_HOME\' environment variable. Try setting it manually.';
+                if (fs.existsSync(find_java)) {
+                    return superspawn.spawn(find_java).then(function (stdout) {
+                        process.env['JAVA_HOME'] = stdout.trim();
+                    }).catch(function (err) {
+                        if (err) {
+                            throw new CordovaError(default_java_error_msg);
+                        }
+                    });
+                } else {
+                    // See if we can derive it from javac's location.
+                    // fs.realpathSync is require on Ubuntu, which symplinks from /usr/bin -> JDK
+                    var maybeJavaHome = path.dirname(path.dirname(javacPath));
+                    if (fs.existsSync(path.join(maybeJavaHome, 'lib', 'tools.jar'))) {
+                        process.env['JAVA_HOME'] = maybeJavaHome;
+                    } else {
+                        throw new CordovaError(default_java_error_msg);
+                    }
+                }
+            } else if (module.exports.isWindows()) {
+                // Try to auto-detect java in the default install paths.
+                var oldSilent = shelljs.config.silent;
+                shelljs.config.silent = true;
+                var firstJdkDir =
+                    shelljs.ls(process.env['ProgramFiles'] + '\\java\\jdk*')[0] ||
+                    shelljs.ls('C:\\Program Files\\java\\jdk*')[0] ||
+                    shelljs.ls('C:\\Program Files (x86)\\java\\jdk*')[0];
+                shelljs.config.silent = oldSilent;
+                if (firstJdkDir) {
+                    // shelljs always uses / in paths.
+                    firstJdkDir = firstJdkDir.replace(/\//g, path.sep);
+                    if (!javacPath) {
+                        process.env['PATH'] += path.delimiter + path.join(firstJdkDir, 'bin');
+                    }
+                    process.env['JAVA_HOME'] = firstJdkDir;
+                }
+            }
+        }
+    }).then(function () {
+        return Q.denodeify(child_process.exec)('javac -version')
+            .then(outputs => {
+                // outputs contains two entries: stdout and stderr
+                // Java <= 8 writes version info to stderr, Java >= 9 to stdout
+                const output = outputs.join('').trim();
+                const match = /javac\s+([\d.]+)/i.exec(output);
+                return match && match[1];
+            }, () => {
+                var msg =
+                'Failed to run "javac -version", make sure that you have a JDK version 8 installed.\n' +
+                'You can get it from the following location:\n' +
+                'https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html';
+                if (process.env['JAVA_HOME']) {
+                    msg += '\n\n';
+                    msg += 'Your JAVA_HOME is invalid: ' + process.env['JAVA_HOME'];
+                }
+                throw new CordovaError(msg);
+            });
+    });
+};
+
+// Returns a promise.
+module.exports.check_android = function () {
+    return Q().then(function () {
+        var androidCmdPath = forgivingWhichSync('android');
+        var adbInPath = forgivingWhichSync('adb');
+        var avdmanagerInPath = forgivingWhichSync('avdmanager');
+        var hasAndroidHome = !!process.env['ANDROID_HOME'] && fs.existsSync(process.env['ANDROID_HOME']);
+        function maybeSetAndroidHome (value) {
+            if (!hasAndroidHome && fs.existsSync(value)) {
+                hasAndroidHome = true;
+                process.env['ANDROID_HOME'] = value;
+            }
+        }
+        // First ensure ANDROID_HOME is set
+        // If we have no hints (nothing in PATH), try a few default locations
+        if (!hasAndroidHome && !androidCmdPath && !adbInPath && !avdmanagerInPath) {
+            if (process.env['ANDROID_SDK_ROOT']) {
+                // Quick fix to set ANDROID_HOME according to ANDROID_SDK_ROOT
+                // if ANDROID_HOME is **not** defined and
+                // ANDROID_SDK_ROOT **is** defined
+                // according to environment variables as documented in:
+                // https://developer.android.com/studio/command-line/variables
+                maybeSetAndroidHome(path.join(process.env['ANDROID_SDK_ROOT']));
+            }
+            if (module.exports.isWindows()) {
+                // Android Studio 1.0 installer
+                maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'sdk'));
+                maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'sdk'));
+                // Android Studio pre-1.0 installer
+                maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'android-studio', 'sdk'));
+                maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'android-studio', 'sdk'));
+                // Stand-alone installer
+                maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'android-sdk'));
+                maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'android-sdk'));
+            } else if (module.exports.isDarwin()) {
+                // Android Studio 1.0 installer
+                maybeSetAndroidHome(path.join(process.env['HOME'], 'Library', 'Android', 'sdk'));
+                // Android Studio pre-1.0 installer
+                maybeSetAndroidHome('/Applications/Android Studio.app/sdk');
+                // Stand-alone zip file that user might think to put under /Applications
+                maybeSetAndroidHome('/Applications/android-sdk-macosx');
+                maybeSetAndroidHome('/Applications/android-sdk');
+            }
+            if (process.env['HOME']) {
+                // Stand-alone zip file that user might think to put under their home directory
+                maybeSetAndroidHome(path.join(process.env['HOME'], 'android-sdk-macosx'));
+                maybeSetAndroidHome(path.join(process.env['HOME'], 'android-sdk'));
+            }
+        }
+        if (!hasAndroidHome) {
+            // If we dont have ANDROID_HOME, but we do have some tools on the PATH, try to infer from the tooling PATH.
+            var parentDir, grandParentDir;
+            if (androidCmdPath) {
+                parentDir = path.dirname(androidCmdPath);
+                grandParentDir = path.dirname(parentDir);
+                if (path.basename(parentDir) === 'tools' || fs.existsSync(path.join(grandParentDir, 'tools', 'android'))) {
+                    maybeSetAndroidHome(grandParentDir);
+                } else {
+                    throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting it manually.\n' +
+                        'Detected \'android\' command at ' + parentDir + ' but no \'tools\' directory found near.\n' +
+                        'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'tools directory.');
+                }
+            }
+            if (adbInPath) {
+                parentDir = path.dirname(adbInPath);
+                grandParentDir = path.dirname(parentDir);
+                if (path.basename(parentDir) === 'platform-tools') {
+                    maybeSetAndroidHome(grandParentDir);
+                } else {
+                    throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting it manually.\n' +
+                        'Detected \'adb\' command at ' + parentDir + ' but no \'platform-tools\' directory found near.\n' +
+                        'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'platform-tools directory.');
+                }
+            }
+            if (avdmanagerInPath) {
+                parentDir = path.dirname(avdmanagerInPath);
+                grandParentDir = path.dirname(parentDir);
+                if (path.basename(parentDir) === 'bin' && path.basename(grandParentDir) === 'tools') {
+                    maybeSetAndroidHome(path.dirname(grandParentDir));
+                } else {
+                    throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting it manually.\n' +
+                        'Detected \'avdmanager\' command at ' + parentDir + ' but no \'tools' + path.sep + 'bin\' directory found near.\n' +
+                        'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'tools' + path.sep + 'bin directory.');
+                }
+            }
+        }
+        if (!process.env['ANDROID_HOME']) {
+            throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting it manually.\n' +
+                'Failed to find \'android\' command in your \'PATH\'. Try update your \'PATH\' to include path to valid SDK directory.');
+        }
+        if (!fs.existsSync(process.env['ANDROID_HOME'])) {
+            throw new CordovaError('\'ANDROID_HOME\' environment variable is set to non-existent path: ' + process.env['ANDROID_HOME'] +
+                '\nTry update it manually to point to valid SDK directory.');
+        }
+        // Next let's make sure relevant parts of the SDK tooling is in our PATH
+        if (hasAndroidHome && !androidCmdPath) {
+            process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'tools');
+        }
+        if (hasAndroidHome && !adbInPath) {
+            process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'platform-tools');
+        }
+        if (hasAndroidHome && !avdmanagerInPath) {
+            process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'tools', 'bin');
+        }
+        return hasAndroidHome;
+    });
+};
+
+// TODO: is this actually needed?
+module.exports.getAbsoluteAndroidCmd = function () {
+    var cmd = forgivingWhichSync('android');
+    if (cmd.length === 0) {
+        cmd = forgivingWhichSync('sdkmanager');
+    }
+    if (module.exports.isWindows()) {
+        return '"' + cmd + '"';
+    }
+    return cmd.replace(/(\s)/g, '\\$1');
+};
+
+module.exports.check_android_target = function (originalError) {
+    // valid_target can look like:
+    //   android-19
+    //   android-L
+    //   Google Inc.:Google APIs:20
+    //   Google Inc.:Glass Development Kit Preview:20
+    var desired_api_level = module.exports.get_target();
+    return android_sdk.list_targets().then(function (targets) {
+        if (targets.indexOf(desired_api_level) >= 0) {
+            return targets;
+        }
+        var androidCmd = module.exports.getAbsoluteAndroidCmd();
+        var msg = 'Please install Android target / API level: "' + desired_api_level + '".\n\n' +
+            'Hint: Open the SDK manager by running: ' + androidCmd + '\n' +
+            'You will require:\n' +
+            '1. "SDK Platform" for API level ' + desired_api_level + '\n' +
+            '2. "Android SDK Platform-tools (latest)\n' +
+            '3. "Android SDK Build-tools" (latest)';
+        if (originalError) {
+            msg = originalError + '\n' + msg;
+        }
+        throw new CordovaError(msg);
+    });
+};
+
+// Returns a promise.
+module.exports.run = function () {
+    return Q.all([this.check_java(), this.check_android()]).then(function (values) {
+        console.log('Checking Java JDK and Android SDK versions');
+        console.log('ANDROID_SDK_ROOT=' + process.env['ANDROID_SDK_ROOT'] + ' (recommended setting)');
+        console.log('ANDROID_HOME=' + process.env['ANDROID_HOME'] + ' (DEPRECATED)');
+
+        if (!String(values[0]).startsWith('1.8.')) {
+            throw new CordovaError(
+                'Requirements check failed for JDK 8 (\'1.8.*\')! Detected version: ' + values[0] + '\n' +
+                'Check your ANDROID_SDK_ROOT / JAVA_HOME / PATH environment variables.'
+            );
+        }
+
+        if (!values[1]) {
+            throw new CordovaError('Requirements check failed for Android SDK! Android SDK was not detected.');
+        }
+    });
+};
+
+/**
+ * Object thar represents one of requirements for current platform.
+ * @param {String} id         The unique identifier for this requirements.
+ * @param {String} name       The name of requirements. Human-readable field.
+ * @param {String} version    The version of requirement installed. In some cases could be an array of strings
+ *                            (for example, check_android_target returns an array of android targets installed)
+ * @param {Boolean} installed Indicates whether the requirement is installed or not
+ */
+var Requirement = function (id, name, version, installed) {
+    this.id = id;
+    this.name = name;
+    this.installed = installed || false;
+    this.metadata = {
+        version: version
+    };
+};
+
+/**
+ * Methods that runs all checks one by one and returns a result of checks
+ * as an array of Requirement objects. This method intended to be used by cordova-lib check_reqs method
+ *
+ * @return Promise<Requirement[]> Array of requirements. Due to implementation, promise is always fulfilled.
+ */
+module.exports.check_all = function () {
+
+    var requirements = [
+        new Requirement('java', 'Java JDK'),
+        new Requirement('androidSdk', 'Android SDK'),
+        new Requirement('androidTarget', 'Android target'),
+        new Requirement('gradle', 'Gradle')
+    ];
+
+    var checkFns = [
+        this.check_java,
+        this.check_android,
+        this.check_android_target,
+        this.check_gradle
+    ];
+
+    // Then execute requirement checks one-by-one
+    return checkFns.reduce(function (promise, checkFn, idx) {
+        // Update each requirement with results
+        var requirement = requirements[idx];
+        return promise.then(checkFn).then(function (version) {
+            requirement.installed = true;
+            requirement.metadata.version = version;
+        }, function (err) {
+            requirement.metadata.reason = err instanceof Error ? err.message : err;
+        });
+    }, Q()).then(function () {
+        // When chain is completed, return requirements array to upstream API
+        return requirements;
+    });
+};
diff --git a/platforms/android/cordova/lib/config/GradlePropertiesParser.js b/platforms/android/cordova/lib/config/GradlePropertiesParser.js
new file mode 100644
index 0000000..b45c0a6
--- /dev/null
+++ b/platforms/android/cordova/lib/config/GradlePropertiesParser.js
@@ -0,0 +1,104 @@
+/**
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+
+let fs = require('fs');
+let path = require('path');
+let propertiesParser = require('properties-parser');
+let events = require('cordova-common').events;
+
+class GradlePropertiesParser {
+    /**
+    * Loads and Edits Gradle Properties File.
+    *
+    * @param {String} platformDir is the path of the Android platform directory
+    */
+    constructor (platformDir) {
+        this._defaults = {
+            // 10 seconds -> 6 seconds
+            'org.gradle.daemon': 'true',
+
+            // to allow dex in process
+            'org.gradle.jvmargs': '-Xmx2048m',
+
+            // allow NDK to be used - required by Gradle 1.5 plugin
+            'android.useDeprecatedNdk': 'true'
+
+            // Shaves another 100ms, but produces a "try at own risk" warning. Not worth it (yet):
+            // 'org.gradle.parallel': 'true'
+        };
+
+        this.gradleFilePath = path.join(platformDir, 'gradle.properties');
+    }
+
+    configure (userConfigs) {
+        events.emit('verbose', '[Gradle Properties] Preparing Configuration');
+
+        this._initializeEditor();
+
+        events.emit('verbose', '[Gradle Properties] Appending default configuration properties');
+        this._configureProperties(this._defaults);
+
+        events.emit('verbose', '[Gradle Properties] Appending custom configuration properties');
+        this._configureProperties(userConfigs);
+
+        this._save();
+    }
+
+    /**
+     * Initialize the properties editor for parsing, setting, etc.
+     */
+    _initializeEditor () {
+        // Touch empty gradle.properties file if missing.
+        if (!fs.existsSync(this.gradleFilePath)) {
+            events.emit('verbose', '[Gradle Properties] File missing, creating file with Cordova defaults.');
+            fs.writeFileSync(this.gradleFilePath, '', 'utf-8');
+        }
+
+        // Create an editor for parsing, getting, and setting configurations.
+        this.gradleFile = propertiesParser.createEditor(this.gradleFilePath);
+    }
+
+    /**
+     * Validate that defaults or user configuration properties are set and
+     * set the missing items.
+     */
+    _configureProperties (properties) {
+        // Iterate though the properties and set only if missing.
+        Object.keys(properties).forEach(key => {
+            let value = this.gradleFile.get(key);
+
+            if (!value) {
+                events.emit('verbose', `[Gradle Properties] Appending configuration item: ${key}=${properties[key]}`);
+                this.gradleFile.set(key, properties[key]);
+            } else if (value !== properties[key]) {
+                events.emit('info', `[Gradle Properties] Detected Gradle property "${key}" with the value of "${value}", Cordova's recommended value is "${properties[key]}"`);
+            }
+        });
+    }
+
+    /**
+     * Saves any changes that has been made to the properties file.
+     */
+    _save () {
+        events.emit('verbose', '[Gradle Properties] Updating and Saving File');
+        this.gradleFile.save();
+    }
+}
+
+module.exports = GradlePropertiesParser;
diff --git a/platforms/android/cordova/lib/device.js b/platforms/android/cordova/lib/device.js
new file mode 100644
index 0000000..1559e9b
--- /dev/null
+++ b/platforms/android/cordova/lib/device.js
@@ -0,0 +1,111 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var build = require('./build');
+var path = require('path');
+var Adb = require('./Adb');
+var AndroidManifest = require('./AndroidManifest');
+var spawn = require('cordova-common').superspawn.spawn;
+var CordovaError = require('cordova-common').CordovaError;
+var events = require('cordova-common').events;
+
+/**
+ * Returns a promise for the list of the device ID's found
+ * @param lookHarder When true, try restarting adb if no devices are found.
+ */
+module.exports.list = function (lookHarder) {
+    return Adb.devices().then(function (list) {
+        if (list.length === 0 && lookHarder) {
+            // adb kill-server doesn't seem to do the trick.
+            // Could probably find a x-platform version of killall, but I'm not actually
+            // sure that this scenario even happens on non-OSX machines.
+            return spawn('killall', ['adb']).then(function () {
+                events.emit('verbose', 'Restarting adb to see if more devices are detected.');
+                return Adb.devices();
+            }, function () {
+                // For non-killall OS's.
+                return list;
+            });
+        }
+        return list;
+    });
+};
+
+module.exports.resolveTarget = function (target) {
+    return this.list(true).then(function (device_list) {
+        if (!device_list || !device_list.length) {
+            return Promise.reject(new CordovaError('Failed to deploy to device, no devices found.'));
+        }
+        // default device
+        target = target || device_list[0];
+
+        if (device_list.indexOf(target) < 0) {
+            return Promise.reject(new CordovaError('ERROR: Unable to find target \'' + target + '\'.'));
+        }
+
+        return build.detectArchitecture(target).then(function (arch) {
+            return { target: target, arch: arch, isEmulator: false };
+        });
+    });
+};
+
+/*
+ * Installs a previously built application on the device
+ * and launches it.
+ * Returns a promise.
+ */
+module.exports.install = function (target, buildResults) {
+    return Promise.resolve().then(function () {
+        if (target && typeof target === 'object') {
+            return target;
+        }
+        return module.exports.resolveTarget(target);
+    }).then(function (resolvedTarget) {
+        var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
+        var manifest = new AndroidManifest(path.join(__dirname, '../../app/src/main/AndroidManifest.xml'));
+        var pkgName = manifest.getPackageId();
+        var launchName = pkgName + '/.' + manifest.getActivity().getName();
+        events.emit('log', 'Using apk: ' + apk_path);
+        events.emit('log', 'Package name: ' + pkgName);
+
+        return Adb.install(resolvedTarget.target, apk_path, { replace: true }).catch(function (error) {
+            // CB-9557 CB-10157 only uninstall and reinstall app if the one that
+            // is already installed on device was signed w/different certificate
+            if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString())) { throw error; }
+
+            events.emit('warn', 'Uninstalling app from device and reinstalling it again because the ' +
+                'installed app already signed with different key');
+
+            // This promise is always resolved, even if 'adb uninstall' fails to uninstall app
+            // or the app doesn't installed at all, so no error catching needed.
+            return Adb.uninstall(resolvedTarget.target, pkgName).then(function () {
+                return Adb.install(resolvedTarget.target, apk_path, { replace: true });
+            });
+        }).then(function () {
+            // unlock screen
+            return Adb.shell(resolvedTarget.target, 'input keyevent 82');
+        }).then(function () {
+            return Adb.start(resolvedTarget.target, launchName);
+        }).then(function () {
+            events.emit('log', 'LAUNCH SUCCESS');
+        });
+    });
+};
diff --git a/platforms/android/cordova/lib/emulator.js b/platforms/android/cordova/lib/emulator.js
new file mode 100644
index 0000000..fcdc170
--- /dev/null
+++ b/platforms/android/cordova/lib/emulator.js
@@ -0,0 +1,530 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var android_versions = require('android-versions');
+var retry = require('./retry');
+var build = require('./build');
+var path = require('path');
+var Adb = require('./Adb');
+var AndroidManifest = require('./AndroidManifest');
+var events = require('cordova-common').events;
+var superspawn = require('cordova-common').superspawn;
+var CordovaError = require('cordova-common').CordovaError;
+var shelljs = require('shelljs');
+var android_sdk = require('./android_sdk');
+var check_reqs = require('./check_reqs');
+
+var os = require('os');
+var fs = require('fs');
+var child_process = require('child_process');
+
+// constants
+var ONE_SECOND = 1000; // in milliseconds
+var ONE_MINUTE = 60 * ONE_SECOND; // in milliseconds
+var INSTALL_COMMAND_TIMEOUT = 5 * ONE_MINUTE; // in milliseconds
+var NUM_INSTALL_RETRIES = 3;
+var CHECK_BOOTED_INTERVAL = 3 * ONE_SECOND; // in milliseconds
+var EXEC_KILL_SIGNAL = 'SIGKILL';
+
+function forgivingWhichSync (cmd) {
+    try {
+        return fs.realpathSync(shelljs.which(cmd));
+    } catch (e) {
+        return '';
+    }
+}
+
+module.exports.list_images_using_avdmanager = function () {
+    return superspawn.spawn('avdmanager', ['list', 'avd']).then(function (output) {
+        var response = output.split('\n');
+        var emulator_list = [];
+        for (var i = 1; i < response.length; i++) {
+            // To return more detailed information use img_obj
+            var img_obj = {};
+            if (response[i].match(/Name:\s/)) {
+                img_obj['name'] = response[i].split('Name: ')[1].replace('\r', '');
+                if (response[i + 1].match(/Device:\s/)) {
+                    i++;
+                    img_obj['device'] = response[i].split('Device: ')[1].replace('\r', '');
+                }
+                if (response[i + 1].match(/Path:\s/)) {
+                    i++;
+                    img_obj['path'] = response[i].split('Path: ')[1].replace('\r', '');
+                }
+                if (response[i + 1].match(/Target:\s/)) {
+                    i++;
+                    if (response[i + 1].match(/ABI:\s/)) {
+                        img_obj['abi'] = response[i + 1].split('ABI: ')[1].replace('\r', '');
+                    }
+                    // This next conditional just aims to match the old output of `android list avd`
+                    // We do so so that we don't have to change the logic when parsing for the
+                    // best emulator target to spawn (see below in `best_image`)
+                    // This allows us to transitionally support both `android` and `avdmanager` binaries,
+                    // depending on what SDK version the user has
+                    if (response[i + 1].match(/Based\son:\s/)) {
+                        img_obj['target'] = response[i + 1].split('Based on:')[1];
+                        if (img_obj['target'].match(/Tag\/ABI:\s/)) {
+                            img_obj['target'] = img_obj['target'].split('Tag/ABI:')[0].replace('\r', '').trim();
+                            if (img_obj['target'].indexOf('(') > -1) {
+                                img_obj['target'] = img_obj['target'].substr(0, img_obj['target'].indexOf('(') - 1).trim();
+                            }
+                        }
+                        var version_string = img_obj['target'].replace(/Android\s+/, '');
+
+                        var api_level = android_sdk.version_string_to_api_level[version_string];
+                        if (api_level) {
+                            img_obj['target'] += ' (API level ' + api_level + ')';
+                        }
+                    }
+                }
+                if (response[i + 1].match(/Skin:\s/)) {
+                    i++;
+                    img_obj['skin'] = response[i].split('Skin: ')[1].replace('\r', '');
+                }
+
+                emulator_list.push(img_obj);
+            }
+            /* To just return a list of names use this
+            if (response[i].match(/Name:\s/)) {
+                emulator_list.push(response[i].split('Name: ')[1].replace('\r', '');
+            } */
+
+        }
+        return emulator_list;
+    });
+};
+
+module.exports.list_images_using_android = function () {
+    return superspawn.spawn('android', ['list', 'avd']).then(function (output) {
+        var response = output.split('\n');
+        var emulator_list = [];
+        for (var i = 1; i < response.length; i++) {
+            // To return more detailed information use img_obj
+            var img_obj = {};
+            if (response[i].match(/Name:\s/)) {
+                img_obj['name'] = response[i].split('Name: ')[1].replace('\r', '');
+                if (response[i + 1].match(/Device:\s/)) {
+                    i++;
+                    img_obj['device'] = response[i].split('Device: ')[1].replace('\r', '');
+                }
+                if (response[i + 1].match(/Path:\s/)) {
+                    i++;
+                    img_obj['path'] = response[i].split('Path: ')[1].replace('\r', '');
+                }
+                if (response[i + 1].match(/\(API\slevel\s/) || (response[i + 2] && response[i + 2].match(/\(API\slevel\s/))) {
+                    i++;
+                    var secondLine = response[i + 1].match(/\(API\slevel\s/) ? response[i + 1] : '';
+                    img_obj['target'] = (response[i] + secondLine).split('Target: ')[1].replace('\r', '');
+                }
+                if (response[i + 1].match(/ABI:\s/)) {
+                    i++;
+                    img_obj['abi'] = response[i].split('ABI: ')[1].replace('\r', '');
+                }
+                if (response[i + 1].match(/Skin:\s/)) {
+                    i++;
+                    img_obj['skin'] = response[i].split('Skin: ')[1].replace('\r', '');
+                }
+
+                emulator_list.push(img_obj);
+            }
+            /* To just return a list of names use this
+            if (response[i].match(/Name:\s/)) {
+                emulator_list.push(response[i].split('Name: ')[1].replace('\r', '');
+            } */
+
+        }
+        return emulator_list;
+    });
+};
+
+/**
+ * Returns a Promise for a list of emulator images in the form of objects
+ * {
+       name   : <emulator_name>,
+       device : <device>,
+       path   : <path_to_emulator_image>,
+       target : <api_target>,
+       abi    : <cpu>,
+       skin   : <skin>
+   }
+ */
+module.exports.list_images = function () {
+    return Promise.resolve().then(function () {
+        if (forgivingWhichSync('avdmanager')) {
+            return module.exports.list_images_using_avdmanager();
+        } else if (forgivingWhichSync('android')) {
+            return module.exports.list_images_using_android();
+        } else {
+            return Promise.reject(new CordovaError('Could not find either `android` or `avdmanager` on your $PATH! Are you sure the Android SDK is installed and available?'));
+        }
+    }).then(function (avds) {
+        // In case we're missing the Android OS version string from the target description, add it.
+        return avds.map(function (avd) {
+            if (avd.target && avd.target.indexOf('Android API') > -1 && avd.target.indexOf('API level') < 0) {
+                var api_level = avd.target.match(/\d+/);
+                if (api_level) {
+                    var level = android_versions.get(api_level);
+                    if (level) {
+                        avd.target = 'Android ' + level.semver + ' (API level ' + api_level + ')';
+                    }
+                }
+            }
+            return avd;
+        });
+    });
+};
+
+/**
+ * Will return the closest avd to the projects target
+ * or undefined if no avds exist.
+ * Returns a promise.
+ */
+module.exports.best_image = function () {
+    return this.list_images().then(function (images) {
+        // Just return undefined if there is no images
+        if (images.length === 0) return;
+
+        var closest = 9999;
+        var best = images[0];
+        var project_target = parseInt(check_reqs.get_target().replace('android-', ''));
+        for (var i in images) {
+            var target = images[i].target;
+            if (target && target.indexOf('API level') > -1) {
+                var num = parseInt(target.split('(API level ')[1].replace(')', ''));
+                if (num === project_target) {
+                    return images[i];
+                } else if (project_target - num < closest && project_target > num) {
+                    closest = project_target - num;
+                    best = images[i];
+                }
+            }
+        }
+        return best;
+    });
+};
+
+// Returns a promise.
+module.exports.list_started = function () {
+    return Adb.devices({ emulators: true });
+};
+
+// Returns a promise.
+// TODO: we should remove this, there's a more robust method under android_sdk.js
+module.exports.list_targets = function () {
+    return superspawn.spawn('android', ['list', 'targets'], { cwd: os.tmpdir() }).then(function (output) {
+        var target_out = output.split('\n');
+        var targets = [];
+        for (var i = target_out.length; i >= 0; i--) {
+            if (target_out[i].match(/id:/)) {
+                targets.push(targets[i].split(' ')[1]);
+            }
+        }
+        return targets;
+    });
+};
+
+/*
+ * Gets unused port for android emulator, between 5554 and 5584
+ * Returns a promise.
+ */
+module.exports.get_available_port = function () {
+    var self = this;
+
+    return self.list_started().then(function (emulators) {
+        for (var p = 5584; p >= 5554; p -= 2) {
+            if (emulators.indexOf('emulator-' + p) === -1) {
+                events.emit('verbose', 'Found available port: ' + p);
+                return p;
+            }
+        }
+        throw new CordovaError('Could not find an available avd port');
+    });
+};
+
+/*
+ * Starts an emulator with the given ID,
+ * and returns the started ID of that emulator.
+ * If no ID is given it will use the first image available,
+ * if no image is available it will error out (maybe create one?).
+ * If no boot timeout is given or the value is negative it will wait forever for
+ * the emulator to boot
+ *
+ * Returns a promise.
+ */
+module.exports.start = function (emulator_ID, boot_timeout) {
+    var self = this;
+
+    return Promise.resolve().then(function () {
+        if (emulator_ID) return Promise.resolve(emulator_ID);
+
+        return self.best_image().then(function (best) {
+            if (best && best.name) {
+                events.emit('warn', 'No emulator specified, defaulting to ' + best.name);
+                return best.name;
+            }
+
+            var androidCmd = check_reqs.getAbsoluteAndroidCmd();
+            return Promise.reject(new CordovaError('No emulator images (avds) found.\n' +
+                '1. Download desired System Image by running: ' + androidCmd + ' sdk\n' +
+                '2. Create an AVD by running: ' + androidCmd + ' avd\n' +
+                'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\n'));
+        });
+    }).then(function (emulatorId) {
+        return self.get_available_port().then(function (port) {
+            // Figure out the directory the emulator binary runs in, and set the cwd to that directory.
+            // Workaround for https://code.google.com/p/android/issues/detail?id=235461
+            var emulator_dir = path.dirname(shelljs.which('emulator'));
+            var args = ['-avd', emulatorId, '-port', port];
+            // Don't wait for it to finish, since the emulator will probably keep running for a long time.
+            child_process
+                .spawn('emulator', args, { stdio: 'inherit', detached: true, cwd: emulator_dir })
+                .unref();
+
+            // wait for emulator to start
+            events.emit('log', 'Waiting for emulator to start...');
+            return self.wait_for_emulator(port);
+        });
+    }).then(function (emulatorId) {
+        if (!emulatorId) { return Promise.reject(new CordovaError('Failed to start emulator')); }
+
+        // wait for emulator to boot up
+        process.stdout.write('Waiting for emulator to boot (this may take a while)...');
+        return self.wait_for_boot(emulatorId, boot_timeout).then(function (success) {
+            if (success) {
+                events.emit('log', 'BOOT COMPLETE');
+                // unlock screen
+                return Adb.shell(emulatorId, 'input keyevent 82').then(function () {
+                    // return the new emulator id for the started emulators
+                    return emulatorId;
+                });
+            } else {
+                // We timed out waiting for the boot to happen
+                return null;
+            }
+        });
+    });
+};
+
+/*
+ * Waits for an emulator to boot on a given port.
+ * Returns this emulator's ID in a promise.
+ */
+module.exports.wait_for_emulator = function (port) {
+    var self = this;
+    return Promise.resolve().then(function () {
+        var emulator_id = 'emulator-' + port;
+        return Adb.shell(emulator_id, 'getprop dev.bootcomplete').then(function (output) {
+            if (output.indexOf('1') >= 0) {
+                return emulator_id;
+            }
+            return self.wait_for_emulator(port);
+        }, function (error) {
+            if ((error && error.message &&
+            (error.message.indexOf('not found') > -1)) ||
+            (error.message.indexOf('device offline') > -1) ||
+            (error.message.indexOf('device still connecting') > -1) ||
+            (error.message.indexOf('device still authorizing') > -1)) {
+                // emulator not yet started, continue waiting
+                return self.wait_for_emulator(port);
+            } else {
+                // something unexpected has happened
+                throw error;
+            }
+        });
+    });
+};
+
+/*
+ * Waits for the core android process of the emulator to start. Returns a
+ * promise that resolves to a boolean indicating success. Not specifying a
+ * time_remaining or passing a negative value will cause it to wait forever
+ */
+module.exports.wait_for_boot = function (emulator_id, time_remaining) {
+    var self = this;
+    return Adb.shell(emulator_id, 'ps').then(function (output) {
+        if (output.match(/android\.process\.acore/)) {
+            return true;
+        } else if (time_remaining === 0) {
+            return false;
+        } else {
+            process.stdout.write('.');
+
+            return new Promise(resolve => {
+                const delay = time_remaining < CHECK_BOOTED_INTERVAL ? time_remaining : CHECK_BOOTED_INTERVAL;
+
+                setTimeout(() => {
+                    const updated_time = time_remaining >= 0 ? Math.max(time_remaining - CHECK_BOOTED_INTERVAL, 0) : time_remaining;
+                    resolve(self.wait_for_boot(emulator_id, updated_time));
+                }, delay);
+            });
+        }
+    });
+};
+
+/*
+ * Create avd
+ * TODO : Enter the stdin input required to complete the creation of an avd.
+ * Returns a promise.
+ */
+module.exports.create_image = function (name, target) {
+    console.log('Creating new avd named ' + name);
+    if (target) {
+        return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', target]).then(null, function (error) {
+            console.error('ERROR : Failed to create emulator image : ');
+            console.error(' Do you have the latest android targets including ' + target + '?');
+            console.error(error);
+        });
+    } else {
+        console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.');
+        // TODO: there's a more robust method for finding targets in android_sdk.js
+        return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]]).then(function () {
+            // TODO: This seems like another error case, even though it always happens.
+            console.error('ERROR : Unable to create an avd emulator, no targets found.');
+            console.error('Ensure you have targets available by running the "android" command');
+            return Promise.reject(new CordovaError());
+        }, function (error) {
+            console.error('ERROR : Failed to create emulator image : ');
+            console.error(error);
+        });
+    }
+};
+
+module.exports.resolveTarget = function (target) {
+    return this.list_started().then(function (emulator_list) {
+        if (emulator_list.length < 1) {
+            return Promise.reject(new CordovaError('No running Android emulators found, please start an emulator before deploying your project.'));
+        }
+
+        // default emulator
+        target = target || emulator_list[0];
+        if (emulator_list.indexOf(target) < 0) {
+            return Promise.reject(new CordovaError('Unable to find target \'' + target + '\'. Failed to deploy to emulator.'));
+        }
+
+        return build.detectArchitecture(target).then(function (arch) {
+            return { target: target, arch: arch, isEmulator: true };
+        });
+    });
+};
+
+/*
+ * Installs a previously built application on the emulator and launches it.
+ * If no target is specified, then it picks one.
+ * If no started emulators are found, error out.
+ * Returns a promise.
+ */
+module.exports.install = function (givenTarget, buildResults) {
+
+    var target;
+    // We need to find the proper path to the Android Manifest
+    const manifestPath = path.join(__dirname, '..', '..', 'app', 'src', 'main', 'AndroidManifest.xml');
+    const manifest = new AndroidManifest(manifestPath);
+    const pkgName = manifest.getPackageId();
+
+    // resolve the target emulator
+    return Promise.resolve().then(function () {
+        if (givenTarget && typeof givenTarget === 'object') {
+            return givenTarget;
+        } else {
+            return module.exports.resolveTarget(givenTarget);
+        }
+
+    // set the resolved target
+    }).then(function (resolvedTarget) {
+        target = resolvedTarget;
+
+    // install the app
+    }).then(function () {
+        // This promise is always resolved, even if 'adb uninstall' fails to uninstall app
+        // or the app doesn't installed at all, so no error catching needed.
+        return Promise.resolve().then(function () {
+
+            var apk_path = build.findBestApkForArchitecture(buildResults, target.arch);
+            var execOptions = {
+                cwd: os.tmpdir(),
+                timeout: INSTALL_COMMAND_TIMEOUT, // in milliseconds
+                killSignal: EXEC_KILL_SIGNAL
+            };
+
+            events.emit('log', 'Using apk: ' + apk_path);
+            events.emit('log', 'Package name: ' + pkgName);
+            events.emit('verbose', 'Installing app on emulator...');
+
+            // A special function to call adb install in specific environment w/ specific options.
+            // Introduced as a part of fix for http://issues.apache.org/jira/browse/CB-9119
+            // to workaround sporadic emulator hangs
+            function adbInstallWithOptions (target, apk, opts) {
+                events.emit('verbose', 'Installing apk ' + apk + ' on ' + target + '...');
+
+                var command = 'adb -s ' + target + ' install -r "' + apk + '"';
+                return new Promise(function (resolve, reject) {
+                    child_process.exec(command, opts, function (err, stdout, stderr) {
+                        if (err) reject(new CordovaError('Error executing "' + command + '": ' + stderr));
+                        // adb does not return an error code even if installation fails. Instead it puts a specific
+                        // message to stdout, so we have to use RegExp matching to detect installation failure.
+                        else if (/Failure/.test(stdout)) {
+                            if (stdout.match(/INSTALL_PARSE_FAILED_NO_CERTIFICATES/)) {
+                                stdout += 'Sign the build using \'-- --keystore\' or \'--buildConfig\'' +
+                                    ' or sign and deploy the unsigned apk manually using Android tools.';
+                            } else if (stdout.match(/INSTALL_FAILED_VERSION_DOWNGRADE/)) {
+                                stdout += 'You\'re trying to install apk with a lower versionCode that is already installed.' +
+                                    '\nEither uninstall an app or increment the versionCode.';
+                            }
+
+                            reject(new CordovaError('Failed to install apk to emulator: ' + stdout));
+                        } else resolve(stdout);
+                    });
+                });
+            }
+
+            function installPromise () {
+                return adbInstallWithOptions(target.target, apk_path, execOptions).catch(function (error) {
+                    // CB-9557 CB-10157 only uninstall and reinstall app if the one that
+                    // is already installed on device was signed w/different certificate
+                    if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString())) { throw error; }
+
+                    events.emit('warn', 'Uninstalling app from device and reinstalling it because the ' +
+                        'currently installed app was signed with different key');
+
+                    // This promise is always resolved, even if 'adb uninstall' fails to uninstall app
+                    // or the app doesn't installed at all, so no error catching needed.
+                    return Adb.uninstall(target.target, pkgName).then(function () {
+                        return adbInstallWithOptions(target.target, apk_path, execOptions);
+                    });
+                });
+            }
+
+            return retry.retryPromise(NUM_INSTALL_RETRIES, installPromise).then(function (output) {
+                events.emit('log', 'INSTALL SUCCESS');
+            });
+        });
+    // unlock screen
+    }).then(function () {
+
+        events.emit('verbose', 'Unlocking screen...');
+        return Adb.shell(target.target, 'input keyevent 82');
+    }).then(function () {
+        Adb.start(target.target, pkgName + '/.' + manifest.getActivity().getName());
+    // report success or failure
+    }).then(function (output) {
+        events.emit('log', 'LAUNCH SUCCESS');
+    });
+};
diff --git a/platforms/android/cordova/lib/getASPath.bat b/platforms/android/cordova/lib/getASPath.bat
new file mode 100644
index 0000000..14dad43
--- /dev/null
+++ b/platforms/android/cordova/lib/getASPath.bat
@@ -0,0 +1,3 @@
+@ECHO OFF
+for /f "tokens=2*" %%a in ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Android Studio" /v Path') do set "ASPath=%%~b"
+ECHO %ASPath%
\ No newline at end of file
diff --git a/platforms/android/cordova/lib/install-device b/platforms/android/cordova/lib/install-device
new file mode 100755
index 0000000..0387388
--- /dev/null
+++ b/platforms/android/cordova/lib/install-device
@@ -0,0 +1,42 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var device = require('./device');
+var args = process.argv;
+
+if (args.length > 2) {
+    var install_target;
+    if (args[2].substring(0, 9) === '--target=') {
+        install_target = args[2].substring(9, args[2].length);
+        device.install(install_target).catch(function (err) {
+            console.error('ERROR: ' + err);
+            process.exit(2);
+        });
+    } else {
+        console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
+        process.exit(2);
+    }
+} else {
+    device.install().catch(function (err) {
+        console.error('ERROR: ' + err);
+        process.exit(2);
+    });
+}
diff --git a/platforms/android/cordova/lib/install-device.bat b/platforms/android/cordova/lib/install-device.bat
new file mode 100644
index 0000000..109b470
--- /dev/null
+++ b/platforms/android/cordova/lib/install-device.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License.  You may obtain a copy of the License at
+:: 
+:: http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied.  See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0install-device"
+IF EXIST %script_path% (
+        node %script_path% %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'install-device' script in 'cordova\lib' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file
diff --git a/platforms/android/cordova/lib/install-emulator b/platforms/android/cordova/lib/install-emulator
new file mode 100755
index 0000000..2d46dbe
--- /dev/null
+++ b/platforms/android/cordova/lib/install-emulator
@@ -0,0 +1,38 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var emulator = require('./emulator');
+var args = process.argv;
+
+var install_target;
+if (args.length > 2) {
+    if (args[2].substring(0, 9) === '--target=') {
+        install_target = args[2].substring(9, args[2].length);
+    } else {
+        console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
+        process.exit(2);
+    }
+}
+
+emulator.install(install_target).catch(function (err) {
+    console.error('ERROR: ' + err);
+    process.exit(2);
+});
diff --git a/platforms/android/cordova/lib/install-emulator.bat b/platforms/android/cordova/lib/install-emulator.bat
new file mode 100644
index 0000000..a28c23a
--- /dev/null
+++ b/platforms/android/cordova/lib/install-emulator.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License.  You may obtain a copy of the License at
+:: 
+:: http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied.  See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0install-emulator"
+IF EXIST %script_path% (
+        node %script_path% %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'install-emulator' script in 'cordova\lib' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file
diff --git a/platforms/android/cordova/lib/list-devices b/platforms/android/cordova/lib/list-devices
new file mode 100755
index 0000000..339c665
--- /dev/null
+++ b/platforms/android/cordova/lib/list-devices
@@ -0,0 +1,34 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var devices = require('./device');
+
+// Usage support for when args are given
+require('./check_reqs').check_android().then(function () {
+    devices.list().then(function (device_list) {
+        device_list && device_list.forEach(function (dev) {
+            console.log(dev);
+        });
+    }, function (err) {
+        console.error('ERROR: ' + err);
+        process.exit(2);
+    });
+});
diff --git a/platforms/android/cordova/lib/list-devices.bat b/platforms/android/cordova/lib/list-devices.bat
new file mode 100644
index 0000000..ad5f03e
--- /dev/null
+++ b/platforms/android/cordova/lib/list-devices.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License.  You may obtain a copy of the License at
+:: 
+:: http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied.  See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0list-devices"
+IF EXIST %script_path% (
+        node %script_path% %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'list-devices' script in 'cordova\lib' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file
diff --git a/platforms/android/cordova/lib/list-emulator-images b/platforms/android/cordova/lib/list-emulator-images
new file mode 100755
index 0000000..03cfb19
--- /dev/null
+++ b/platforms/android/cordova/lib/list-emulator-images
@@ -0,0 +1,34 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var emulators = require('./emulator');
+
+// Usage support for when args are given
+require('./check_reqs').check_android().then(function () {
+    emulators.list_images().then(function (emulator_list) {
+        emulator_list && emulator_list.forEach(function (emu) {
+            console.log(emu.name);
+        });
+    }, function (err) {
+        console.error('ERROR: ' + err);
+        process.exit(2);
+    });
+});
diff --git a/platforms/android/cordova/lib/list-emulator-images.bat b/platforms/android/cordova/lib/list-emulator-images.bat
new file mode 100644
index 0000000..616ffb7
--- /dev/null
+++ b/platforms/android/cordova/lib/list-emulator-images.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License.  You may obtain a copy of the License at
+:: 
+:: http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied.  See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0list-emulator-images"
+IF EXIST %script_path% (
+        node %script_path% %*
+) ELSE (
+    ECHO. 
+    ECHO ERROR: Could not find 'list-emulator-images' script in 'cordova\lib' folder, aborting...>&2
+    EXIT /B 1
+)
diff --git a/platforms/android/cordova/lib/list-started-emulators b/platforms/android/cordova/lib/list-started-emulators
new file mode 100755
index 0000000..2a83e03
--- /dev/null
+++ b/platforms/android/cordova/lib/list-started-emulators
@@ -0,0 +1,34 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var emulators = require('./emulator');
+
+// Usage support for when args are given
+require('./check_reqs').check_android().then(function () {
+    emulators.list_started().then(function (emulator_list) {
+        emulator_list && emulator_list.forEach(function (emu) {
+            console.log(emu);
+        });
+    }, function (err) {
+        console.error('ERROR: ' + err);
+        process.exit(2);
+    });
+});
diff --git a/platforms/android/cordova/lib/list-started-emulators.bat b/platforms/android/cordova/lib/list-started-emulators.bat
new file mode 100644
index 0000000..eed02a5
--- /dev/null
+++ b/platforms/android/cordova/lib/list-started-emulators.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License.  You may obtain a copy of the License at
+:: 
+:: http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied.  See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0list-started-emulators"
+IF EXIST %script_path% (
+        node %script_path% %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'list-started-emulators' script in 'cordova\lib' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file
diff --git a/platforms/android/cordova/lib/log.js b/platforms/android/cordova/lib/log.js
new file mode 100644
index 0000000..ec69f8c
--- /dev/null
+++ b/platforms/android/cordova/lib/log.js
@@ -0,0 +1,56 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var path = require('path');
+var os = require('os');
+var Q = require('q');
+var child_process = require('child_process');
+var ROOT = path.join(__dirname, '..', '..');
+
+/*
+ * Starts running logcat in the shell.
+ * Returns a promise.
+ */
+module.exports.run = function () {
+    var d = Q.defer();
+    var adb = child_process.spawn('adb', ['logcat'], { cwd: os.tmpdir() });
+
+    adb.stdout.on('data', function (data) {
+        var lines = data ? data.toString().split('\n') : [];
+        var out = lines.filter(function (x) { return x.indexOf('nativeGetEnabledTags') < 0; });
+        console.log(out.join('\n'));
+    });
+
+    adb.stderr.on('data', console.error);
+    adb.on('close', function (code) {
+        if (code > 0) {
+            d.reject('Failed to run logcat command.');
+        } else d.resolve();
+    });
+
+    return d.promise;
+};
+
+module.exports.help = function () {
+    console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'log')));
+    console.log('Gives the logcat output on the command line.');
+    process.exit(0);
+};
diff --git a/platforms/android/cordova/lib/plugin-build.gradle b/platforms/android/cordova/lib/plugin-build.gradle
new file mode 100644
index 0000000..032b870
--- /dev/null
+++ b/platforms/android/cordova/lib/plugin-build.gradle
@@ -0,0 +1,69 @@
+/* Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+*/
+
+// GENERATED FILE! DO NOT EDIT!
+
+buildscript {
+    repositories {
+        google()
+        jcenter()
+    }
+
+    // Switch the Android Gradle plugin version requirement depending on the
+    // installed version of Gradle. This dependency is documented at
+    // http://tools.android.com/tech-docs/new-build-system/version-compatibility
+    // and https://issues.apache.org/jira/browse/CB-8143
+    dependencies {
+        classpath 'com.android.tools.build:gradle:1.0.0+'
+    }
+}
+
+apply plugin: 'com.android.library'
+
+dependencies {
+    implementation fileTree(dir: 'libs', include: '*.jar')
+    debugCompile project(path: ":CordovaLib", configuration: "debug")
+    releaseCompile project(path: ":CordovaLib", configuration: "release")
+}
+
+android {
+    compileSdkVersion cdvCompileSdkVersion
+    buildToolsVersion cdvBuildToolsVersion
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_6
+        targetCompatibility JavaVersion.VERSION_1_6
+    }
+
+    sourceSets {
+        main {
+            manifest.srcFile 'AndroidManifest.xml'
+            java.srcDirs = ['src']
+            resources.srcDirs = ['src']
+            aidl.srcDirs = ['src']
+            renderscript.srcDirs = ['src']
+            res.srcDirs = ['res']
+            assets.srcDirs = ['assets']
+            jniLibs.srcDirs = ['libs']
+        }
+    }
+}
+
+if (file('build-extras.gradle').exists()) {
+    apply from: 'build-extras.gradle'
+}
diff --git a/platforms/android/cordova/lib/pluginHandlers.js b/platforms/android/cordova/lib/pluginHandlers.js
new file mode 100644
index 0000000..6d1a733
--- /dev/null
+++ b/platforms/android/cordova/lib/pluginHandlers.js
@@ -0,0 +1,334 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var fs = require('fs');
+var path = require('path');
+var shell = require('shelljs');
+var events = require('cordova-common').events;
+var CordovaError = require('cordova-common').CordovaError;
+
+var handlers = {
+    'source-file': {
+        install: function (obj, plugin, project, options) {
+            if (!obj.src) throw new CordovaError(generateAttributeError('src', 'source-file', plugin.id));
+            if (!obj.targetDir) throw new CordovaError(generateAttributeError('target-dir', 'source-file', plugin.id));
+
+            var dest = getInstallDestination(obj);
+
+            if (options && options.force) {
+                copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
+            } else {
+                copyNewFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
+            }
+        },
+        uninstall: function (obj, plugin, project, options) {
+            var dest = getInstallDestination(obj);
+
+            // TODO: Add Koltin extension to uninstall, since they are handled like Java files
+            if (obj.src.endsWith('java')) {
+                deleteJava(project.projectDir, dest);
+            } else {
+                // Just remove the file, not the whole parent directory
+                removeFile(project.projectDir, dest);
+            }
+        }
+    },
+    'lib-file': {
+        install: function (obj, plugin, project, options) {
+            var dest = path.join('app/libs', path.basename(obj.src));
+            copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
+        },
+        uninstall: function (obj, plugin, project, options) {
+            var dest = path.join('app/libs', path.basename(obj.src));
+            removeFile(project.projectDir, dest);
+        }
+    },
+    'resource-file': {
+        install: function (obj, plugin, project, options) {
+            var dest = path.join('app', 'src', 'main', obj.target);
+            copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
+        },
+        uninstall: function (obj, plugin, project, options) {
+            var dest = path.join('app', 'src', 'main', obj.target);
+            removeFile(project.projectDir, dest);
+        }
+    },
+    'framework': {
+        install: function (obj, plugin, project, options) {
+            var src = obj.src;
+            if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));
+
+            events.emit('verbose', 'Installing Android library: ' + src);
+            var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
+            var subDir;
+
+            if (obj.custom) {
+                var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
+                copyNewFile(plugin.dir, src, project.projectDir, subRelativeDir, !!(options && options.link));
+                subDir = path.resolve(project.projectDir, subRelativeDir);
+            } else {
+                obj.type = 'sys';
+                subDir = src;
+            }
+
+            if (obj.type === 'gradleReference') {
+                project.addGradleReference(parentDir, subDir);
+            } else if (obj.type === 'sys') {
+                project.addSystemLibrary(parentDir, subDir);
+            } else {
+                project.addSubProject(parentDir, subDir);
+            }
+        },
+        uninstall: function (obj, plugin, project, options) {
+            var src = obj.src;
+            if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));
+
+            events.emit('verbose', 'Uninstalling Android library: ' + src);
+            var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
+            var subDir;
+
+            if (obj.custom) {
+                var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
+                removeFile(project.projectDir, subRelativeDir);
+                subDir = path.resolve(project.projectDir, subRelativeDir);
+                // If it's the last framework in the plugin, remove the parent directory.
+                var parDir = path.dirname(subDir);
+                if (fs.existsSync(parDir) && fs.readdirSync(parDir).length === 0) {
+                    fs.rmdirSync(parDir);
+                }
+            } else {
+                obj.type = 'sys';
+                subDir = src;
+            }
+
+            if (obj.type === 'gradleReference') {
+                project.removeGradleReference(parentDir, subDir);
+            } else if (obj.type === 'sys') {
+                project.removeSystemLibrary(parentDir, subDir);
+            } else {
+                project.removeSubProject(parentDir, subDir);
+            }
+        }
+    },
+    asset: {
+        install: function (obj, plugin, project, options) {
+            if (!obj.src) {
+                throw new CordovaError(generateAttributeError('src', 'asset', plugin.id));
+            }
+            if (!obj.target) {
+                throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));
+            }
+
+            copyFile(plugin.dir, obj.src, project.www, obj.target);
+            if (options && options.usePlatformWww) {
+                // CB-11022 copy file to both directories if usePlatformWww is specified
+                copyFile(plugin.dir, obj.src, project.platformWww, obj.target);
+            }
+        },
+        uninstall: function (obj, plugin, project, options) {
+            var target = obj.target || obj.src;
+
+            if (!target) throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));
+
+            removeFileF(path.resolve(project.www, target));
+            removeFileF(path.resolve(project.www, 'plugins', plugin.id));
+            if (options && options.usePlatformWww) {
+                // CB-11022 remove file from both directories if usePlatformWww is specified
+                removeFileF(path.resolve(project.platformWww, target));
+                removeFileF(path.resolve(project.platformWww, 'plugins', plugin.id));
+            }
+        }
+    },
+    'js-module': {
+        install: function (obj, plugin, project, options) {
+            // Copy the plugin's files into the www directory.
+            var moduleSource = path.resolve(plugin.dir, obj.src);
+            var moduleName = plugin.id + '.' + (obj.name || path.basename(obj.src, path.extname(obj.src)));
+
+            // Read in the file, prepend the cordova.define, and write it back out.
+            var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM
+            if (moduleSource.match(/.*\.json$/)) {
+                scriptContent = 'module.exports = ' + scriptContent;
+            }
+            scriptContent = 'cordova.define("' + moduleName + '", function(require, exports, module) {\n' + scriptContent + '\n});\n';
+
+            var wwwDest = path.resolve(project.www, 'plugins', plugin.id, obj.src);
+            shell.mkdir('-p', path.dirname(wwwDest));
+            fs.writeFileSync(wwwDest, scriptContent, 'utf-8');
+
+            if (options && options.usePlatformWww) {
+                // CB-11022 copy file to both directories if usePlatformWww is specified
+                var platformWwwDest = path.resolve(project.platformWww, 'plugins', plugin.id, obj.src);
+                shell.mkdir('-p', path.dirname(platformWwwDest));
+                fs.writeFileSync(platformWwwDest, scriptContent, 'utf-8');
+            }
+        },
+        uninstall: function (obj, plugin, project, options) {
+            var pluginRelativePath = path.join('plugins', plugin.id, obj.src);
+            removeFileAndParents(project.www, pluginRelativePath);
+            if (options && options.usePlatformWww) {
+                // CB-11022 remove file from both directories if usePlatformWww is specified
+                removeFileAndParents(project.platformWww, pluginRelativePath);
+            }
+        }
+    }
+};
+
+module.exports.getInstaller = function (type) {
+    if (handlers[type] && handlers[type].install) {
+        return handlers[type].install;
+    }
+
+    events.emit('verbose', '<' + type + '> is not supported for android plugins');
+};
+
+module.exports.getUninstaller = function (type) {
+    if (handlers[type] && handlers[type].uninstall) {
+        return handlers[type].uninstall;
+    }
+
+    events.emit('verbose', '<' + type + '> is not supported for android plugins');
+};
+
+function copyFile (plugin_dir, src, project_dir, dest, link) {
+    src = path.resolve(plugin_dir, src);
+    if (!fs.existsSync(src)) throw new CordovaError('"' + src + '" not found!');
+
+    // check that src path is inside plugin directory
+    var real_path = fs.realpathSync(src);
+    var real_plugin_path = fs.realpathSync(plugin_dir);
+    if (real_path.indexOf(real_plugin_path) !== 0) { throw new CordovaError('File "' + src + '" is located outside the plugin directory "' + plugin_dir + '"'); }
+
+    dest = path.resolve(project_dir, dest);
+
+    // check that dest path is located in project directory
+    if (dest.indexOf(project_dir) !== 0) { throw new CordovaError('Destination "' + dest + '" for source file "' + src + '" is located outside the project'); }
+
+    shell.mkdir('-p', path.dirname(dest));
+    if (link) {
+        symlinkFileOrDirTree(src, dest);
+    } else if (fs.statSync(src).isDirectory()) {
+        // XXX shelljs decides to create a directory when -R|-r is used which sucks. http://goo.gl/nbsjq
+        shell.cp('-Rf', src + '/*', dest);
+    } else {
+        shell.cp('-f', src, dest);
+    }
+}
+
+// Same as copy file but throws error if target exists
+function copyNewFile (plugin_dir, src, project_dir, dest, link) {
+    var target_path = path.resolve(project_dir, dest);
+    if (fs.existsSync(target_path)) { throw new CordovaError('"' + target_path + '" already exists!'); }
+
+    copyFile(plugin_dir, src, project_dir, dest, !!link);
+}
+
+function symlinkFileOrDirTree (src, dest) {
+    if (fs.existsSync(dest)) {
+        shell.rm('-Rf', dest);
+    }
+
+    if (fs.statSync(src).isDirectory()) {
+        shell.mkdir('-p', dest);
+        fs.readdirSync(src).forEach(function (entry) {
+            symlinkFileOrDirTree(path.join(src, entry), path.join(dest, entry));
+        });
+    } else {
+        fs.symlinkSync(path.relative(fs.realpathSync(path.dirname(dest)), src), dest);
+    }
+}
+
+// checks if file exists and then deletes. Error if doesn't exist
+function removeFile (project_dir, src) {
+    var file = path.resolve(project_dir, src);
+    shell.rm('-Rf', file);
+}
+
+// deletes file/directory without checking
+function removeFileF (file) {
+    shell.rm('-Rf', file);
+}
+
+// Sometimes we want to remove some java, and prune any unnecessary empty directories
+function deleteJava (project_dir, destFile) {
+    removeFileAndParents(project_dir, destFile, 'src');
+}
+
+function removeFileAndParents (baseDir, destFile, stopper) {
+    stopper = stopper || '.';
+    var file = path.resolve(baseDir, destFile);
+    if (!fs.existsSync(file)) return;
+
+    removeFileF(file);
+
+    // check if directory is empty
+    var curDir = path.dirname(file);
+
+    while (curDir !== path.resolve(baseDir, stopper)) {
+        if (fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {
+            fs.rmdirSync(curDir);
+            curDir = path.resolve(curDir, '..');
+        } else {
+            // directory not empty...do nothing
+            break;
+        }
+    }
+}
+
+function generateAttributeError (attribute, element, id) {
+    return 'Required attribute "' + attribute + '" not specified in <' + element + '> element from plugin: ' + id;
+}
+
+function getInstallDestination (obj) {
+    var APP_MAIN_PREFIX = 'app/src/main';
+    var PATH_SEPARATOR = '/';
+
+    var PATH_SEP_MATCH = '\\' + PATH_SEPARATOR;
+    var PATH_SEP_OR_EOL_MATCH = '(\\' + PATH_SEPARATOR + '|$)';
+
+    var appReg = new RegExp('^app' + PATH_SEP_OR_EOL_MATCH);
+    var libsReg = new RegExp('^libs' + PATH_SEP_OR_EOL_MATCH);
+    var srcReg = new RegExp('^src' + PATH_SEP_OR_EOL_MATCH);
+    var srcMainReg = new RegExp('^src' + PATH_SEP_MATCH + 'main' + PATH_SEP_OR_EOL_MATCH);
+
+    if (appReg.test(obj.targetDir)) {
+        // If any source file is using the new app directory structure,
+        // don't penalize it
+        return path.join(obj.targetDir, path.basename(obj.src));
+    } else {
+        // Plugin using deprecated target directory structure (GH-580)
+        if (obj.src.endsWith('.java')) {
+            return path.join(APP_MAIN_PREFIX, 'java', obj.targetDir.replace(srcReg, ''),
+                path.basename(obj.src));
+        } else if (obj.src.endsWith('.aidl')) {
+            return path.join(APP_MAIN_PREFIX, 'aidl', obj.targetDir.replace(srcReg, ''),
+                path.basename(obj.src));
+        } else if (libsReg.test(obj.targetDir)) {
+            if (obj.src.endsWith('.so')) {
+                return path.join(APP_MAIN_PREFIX, 'jniLibs', obj.targetDir.replace(libsReg, ''),
+                    path.basename(obj.src));
+            } else {
+                return path.join('app', obj.targetDir, path.basename(obj.src));
+            }
+        } else if (srcMainReg.test(obj.targetDir)) {
+            return path.join('app', obj.targetDir, path.basename(obj.src));
+        }
+
+        // For all other source files not using the new app directory structure,
+        // add 'app/src/main' to the targetDir
+        return path.join(APP_MAIN_PREFIX, obj.targetDir, path.basename(obj.src));
+    }
+}
diff --git a/platforms/android/cordova/lib/prepare.js b/platforms/android/cordova/lib/prepare.js
new file mode 100644
index 0000000..49e0a7d
--- /dev/null
+++ b/platforms/android/cordova/lib/prepare.js
@@ -0,0 +1,701 @@
+/**
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+/* eslint no-useless-escape: 0 */
+
+var Q = require('q');
+var fs = require('fs');
+var path = require('path');
+var shell = require('shelljs');
+var events = require('cordova-common').events;
+var AndroidManifest = require('./AndroidManifest');
+var checkReqs = require('./check_reqs');
+var xmlHelpers = require('cordova-common').xmlHelpers;
+var CordovaError = require('cordova-common').CordovaError;
+var ConfigParser = require('cordova-common').ConfigParser;
+var FileUpdater = require('cordova-common').FileUpdater;
+var PlatformJson = require('cordova-common').PlatformJson;
+var PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger;
+var PluginInfoProvider = require('cordova-common').PluginInfoProvider;
+
+const GradlePropertiesParser = require('./config/GradlePropertiesParser');
+
+module.exports.prepare = function (cordovaProject, options) {
+    var self = this;
+
+    var platformJson = PlatformJson.load(this.locations.root, this.platform);
+    var munger = new PlatformMunger(this.platform, this.locations.root, platformJson, new PluginInfoProvider());
+
+    this._config = updateConfigFilesFrom(cordovaProject.projectConfig, munger, this.locations);
+
+    // Get the min SDK version from config.xml
+    const minSdkVersion = this._config.getPreference('android-minSdkVersion', 'android');
+
+    let gradlePropertiesUserConfig = {};
+    if (minSdkVersion) gradlePropertiesUserConfig.cdvMinSdkVersion = minSdkVersion;
+
+    let gradlePropertiesParser = new GradlePropertiesParser(this.locations.root);
+    gradlePropertiesParser.configure(gradlePropertiesUserConfig);
+
+    // Update own www dir with project's www assets and plugins' assets and js-files
+    return Q.when(updateWww(cordovaProject, this.locations)).then(function () {
+        // update project according to config.xml changes.
+        return updateProjectAccordingTo(self._config, self.locations);
+    }).then(function () {
+        updateIcons(cordovaProject, path.relative(cordovaProject.root, self.locations.res));
+        updateSplashes(cordovaProject, path.relative(cordovaProject.root, self.locations.res));
+        updateFileResources(cordovaProject, path.relative(cordovaProject.root, self.locations.root));
+    }).then(function () {
+        events.emit('verbose', 'Prepared android project successfully');
+    });
+};
+
+module.exports.clean = function (options) {
+    // A cordovaProject isn't passed into the clean() function, because it might have
+    // been called from the platform shell script rather than the CLI. Check for the
+    // noPrepare option passed in by the non-CLI clean script. If that's present, or if
+    // there's no config.xml found at the project root, then don't clean prepared files.
+    var projectRoot = path.resolve(this.root, '../..');
+    if ((options && options.noPrepare) || !fs.existsSync(this.locations.configXml) ||
+            !fs.existsSync(this.locations.configXml)) {
+        return Q();
+    }
+
+    var projectConfig = new ConfigParser(this.locations.configXml);
+
+    var self = this;
+    return Q().then(function () {
+        cleanWww(projectRoot, self.locations);
+        cleanIcons(projectRoot, projectConfig, path.relative(projectRoot, self.locations.res));
+        cleanSplashes(projectRoot, projectConfig, path.relative(projectRoot, self.locations.res));
+        cleanFileResources(projectRoot, projectConfig, path.relative(projectRoot, self.locations.root));
+    });
+};
+
+/**
+ * Updates config files in project based on app's config.xml and config munge,
+ *   generated by plugins.
+ *
+ * @param   {ConfigParser}   sourceConfig  A project's configuration that will
+ *   be merged into platform's config.xml
+ * @param   {ConfigChanges}  configMunger  An initialized ConfigChanges instance
+ *   for this platform.
+ * @param   {Object}         locations     A map of locations for this platform
+ *
+ * @return  {ConfigParser}                 An instance of ConfigParser, that
+ *   represents current project's configuration. When returned, the
+ *   configuration is already dumped to appropriate config.xml file.
+ */
+function updateConfigFilesFrom (sourceConfig, configMunger, locations) {
+    events.emit('verbose', 'Generating platform-specific config.xml from defaults for android at ' + locations.configXml);
+
+    // First cleanup current config and merge project's one into own
+    // Overwrite platform config.xml with defaults.xml.
+    shell.cp('-f', locations.defaultConfigXml, locations.configXml);
+
+    // Then apply config changes from global munge to all config files
+    // in project (including project's config)
+    configMunger.reapply_global_munge().save_all();
+
+    events.emit('verbose', 'Merging project\'s config.xml into platform-specific android config.xml');
+    // Merge changes from app's config.xml into platform's one
+    var config = new ConfigParser(locations.configXml);
+    xmlHelpers.mergeXml(sourceConfig.doc.getroot(),
+        config.doc.getroot(), 'android', /* clobber= */true);
+
+    config.write();
+    return config;
+}
+
+/**
+ * Logs all file operations via the verbose event stream, indented.
+ */
+function logFileOp (message) {
+    events.emit('verbose', '  ' + message);
+}
+
+/**
+ * Updates platform 'www' directory by replacing it with contents of
+ *   'platform_www' and app www. Also copies project's overrides' folder into
+ *   the platform 'www' folder
+ *
+ * @param   {Object}  cordovaProject    An object which describes cordova project.
+ * @param   {Object}  destinations      An object that contains destination
+ *   paths for www files.
+ */
+function updateWww (cordovaProject, destinations) {
+    var sourceDirs = [
+        path.relative(cordovaProject.root, cordovaProject.locations.www),
+        path.relative(cordovaProject.root, destinations.platformWww)
+    ];
+
+    // If project contains 'merges' for our platform, use them as another overrides
+    var merges_path = path.join(cordovaProject.root, 'merges', 'android');
+    if (fs.existsSync(merges_path)) {
+        events.emit('verbose', 'Found "merges/android" folder. Copying its contents into the android project.');
+        sourceDirs.push(path.join('merges', 'android'));
+    }
+
+    var targetDir = path.relative(cordovaProject.root, destinations.www);
+    events.emit(
+        'verbose', 'Merging and updating files from [' + sourceDirs.join(', ') + '] to ' + targetDir);
+    FileUpdater.mergeAndUpdateDir(
+        sourceDirs, targetDir, { rootDir: cordovaProject.root }, logFileOp);
+}
+
+/**
+ * Cleans all files from the platform 'www' directory.
+ */
+function cleanWww (projectRoot, locations) {
+    var targetDir = path.relative(projectRoot, locations.www);
+    events.emit('verbose', 'Cleaning ' + targetDir);
+
+    // No source paths are specified, so mergeAndUpdateDir() will clear the target directory.
+    FileUpdater.mergeAndUpdateDir(
+        [], targetDir, { rootDir: projectRoot, all: true }, logFileOp);
+}
+
+/**
+ * Updates project structure and AndroidManifest according to project's configuration.
+ *
+ * @param   {ConfigParser}  platformConfig  A project's configuration that will
+ *   be used to update project
+ * @param   {Object}  locations       A map of locations for this platform
+ */
+function updateProjectAccordingTo (platformConfig, locations) {
+    // Update app name by editing res/values/strings.xml
+    var strings = xmlHelpers.parseElementtreeSync(locations.strings);
+
+    var name = platformConfig.name();
+    strings.find('string[@name="app_name"]').text = name.replace(/\'/g, '\\\'');
+
+    var shortName = platformConfig.shortName && platformConfig.shortName();
+    if (shortName && shortName !== name) {
+        strings.find('string[@name="launcher_name"]').text = shortName.replace(/\'/g, '\\\'');
+    }
+
+    fs.writeFileSync(locations.strings, strings.write({ indent: 4 }), 'utf-8');
+    events.emit('verbose', 'Wrote out android application name "' + name + '" to ' + locations.strings);
+
+    // Java packages cannot support dashes
+    var androidPkgName = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');
+
+    var manifest = new AndroidManifest(locations.manifest);
+    var manifestId = manifest.getPackageId();
+
+    manifest.getActivity()
+        .setOrientation(platformConfig.getPreference('orientation'))
+        .setLaunchMode(findAndroidLaunchModePreference(platformConfig));
+
+    manifest.setVersionName(platformConfig.version())
+        .setVersionCode(platformConfig.android_versionCode() || default_versionCode(platformConfig.version()))
+        .setPackageId(androidPkgName)
+        .setMinSdkVersion(platformConfig.getPreference('android-minSdkVersion', 'android'))
+        .setMaxSdkVersion(platformConfig.getPreference('android-maxSdkVersion', 'android'))
+        .setTargetSdkVersion(platformConfig.getPreference('android-targetSdkVersion', 'android'))
+        .write();
+
+    // Java file paths shouldn't be hard coded
+    var javaPattern = path.join(locations.javaSrc, manifestId.replace(/\./g, '/'), '*.java');
+    var java_files = shell.ls(javaPattern).filter(function (f) {
+        return shell.grep(/extends\s+CordovaActivity/g, f);
+    });
+
+    if (java_files.length === 0) {
+        throw new CordovaError('No Java files found that extend CordovaActivity.');
+    } else if (java_files.length > 1) {
+        events.emit('log', 'Multiple candidate Java files that extend CordovaActivity found. Guessing at the first one, ' + java_files[0]);
+    }
+
+    var destFile = path.join(locations.root, 'app', 'src', 'main', 'java', androidPkgName.replace(/\./g, '/'), path.basename(java_files[0]));
+    shell.mkdir('-p', path.dirname(destFile));
+    shell.sed(/package [\w\.]*;/, 'package ' + androidPkgName + ';', java_files[0]).to(destFile);
+    events.emit('verbose', 'Wrote out Android package name "' + androidPkgName + '" to ' + destFile);
+
+    var removeOrigPkg = checkReqs.isWindows() || checkReqs.isDarwin() ?
+        manifestId.toUpperCase() !== androidPkgName.toUpperCase() :
+        manifestId !== androidPkgName;
+
+    if (removeOrigPkg) {
+        // If package was name changed we need to remove old java with main activity
+        shell.rm('-Rf', java_files[0]);
+        // remove any empty directories
+        var currentDir = path.dirname(java_files[0]);
+        var sourcesRoot = path.resolve(locations.root, 'src');
+        while (currentDir !== sourcesRoot) {
+            if (fs.existsSync(currentDir) && fs.readdirSync(currentDir).length === 0) {
+                fs.rmdirSync(currentDir);
+                currentDir = path.resolve(currentDir, '..');
+            } else {
+                break;
+            }
+        }
+    }
+}
+
+// Consturct the default value for versionCode as
+// PATCH + MINOR * 100 + MAJOR * 10000
+// see http://developer.android.com/tools/publishing/versioning.html
+function default_versionCode (version) {
+    var nums = version.split('-')[0].split('.');
+    var versionCode = 0;
+    if (+nums[0]) {
+        versionCode += +nums[0] * 10000;
+    }
+    if (+nums[1]) {
+        versionCode += +nums[1] * 100;
+    }
+    if (+nums[2]) {
+        versionCode += +nums[2];
+    }
+
+    events.emit('verbose', 'android-versionCode not found in config.xml. Generating a code based on version in config.xml (' + version + '): ' + versionCode);
+    return versionCode;
+}
+
+function getImageResourcePath (resourcesDir, type, density, name, sourceName) {
+    if (/\.9\.png$/.test(sourceName)) {
+        name = name.replace(/\.png$/, '.9.png');
+    }
+    var resourcePath = path.join(resourcesDir, (density ? type + '-' + density : type), name);
+    return resourcePath;
+}
+
+function getAdaptiveImageResourcePath (resourcesDir, type, density, name, sourceName) {
+    if (/\.9\.png$/.test(sourceName)) {
+        name = name.replace(/\.png$/, '.9.png');
+    }
+    var resourcePath = path.join(resourcesDir, (density ? type + '-' + density + '-v26' : type), name);
+    return resourcePath;
+}
+
+function updateSplashes (cordovaProject, platformResourcesDir) {
+    var resources = cordovaProject.projectConfig.getSplashScreens('android');
+
+    // if there are "splash" elements in config.xml
+    if (resources.length === 0) {
+        events.emit('verbose', 'This app does not have splash screens defined');
+        return;
+    }
+
+    var resourceMap = mapImageResources(cordovaProject.root, platformResourcesDir, 'drawable', 'screen.png');
+
+    var hadMdpi = false;
+    resources.forEach(function (resource) {
+        if (!resource.density) {
+            return;
+        }
+        if (resource.density === 'mdpi') {
+            hadMdpi = true;
+        }
+        var targetPath = getImageResourcePath(
+            platformResourcesDir, 'drawable', resource.density, 'screen.png', path.basename(resource.src));
+        resourceMap[targetPath] = resource.src;
+    });
+
+    // There's no "default" drawable, so assume default == mdpi.
+    if (!hadMdpi && resources.defaultResource) {
+        var targetPath = getImageResourcePath(
+            platformResourcesDir, 'drawable', 'mdpi', 'screen.png', path.basename(resources.defaultResource.src));
+        resourceMap[targetPath] = resources.defaultResource.src;
+    }
+
+    events.emit('verbose', 'Updating splash screens at ' + platformResourcesDir);
+    FileUpdater.updatePaths(
+        resourceMap, { rootDir: cordovaProject.root }, logFileOp);
+}
+
+function cleanSplashes (projectRoot, projectConfig, platformResourcesDir) {
+    var resources = projectConfig.getSplashScreens('android');
+    if (resources.length > 0) {
+        var resourceMap = mapImageResources(projectRoot, platformResourcesDir, 'drawable', 'screen.png');
+        events.emit('verbose', 'Cleaning splash screens at ' + platformResourcesDir);
+
+        // No source paths are specified in the map, so updatePaths() will delete the target files.
+        FileUpdater.updatePaths(
+            resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
+    }
+}
+
+function updateIcons (cordovaProject, platformResourcesDir) {
+    let icons = cordovaProject.projectConfig.getIcons('android');
+
+    // Skip if there are no app defined icons in config.xml
+    if (icons.length === 0) {
+        events.emit('verbose', 'This app does not have launcher icons defined');
+        return;
+    }
+
+    // 1. loop icons determin if there is an error in the setup.
+    // 2. during initial loop, also setup for legacy support.
+    let errorMissingAttributes = [];
+    let errorLegacyIconNeeded = [];
+    let hasAdaptive = false;
+    icons.forEach((icon, key) => {
+        if (
+            (icon.background && !icon.foreground)
+            || (!icon.background && icon.foreground)
+            || (!icon.background && !icon.foreground && !icon.src)
+        ) {
+            errorMissingAttributes.push(icon.density ? icon.density : 'size=' + (icon.height || icon.width));
+        }
+
+        if (icon.foreground) {
+            hasAdaptive = true;
+
+            if (
+                !icon.src
+                && (
+                    icon.foreground.startsWith('@color')
+                    || path.extname(path.basename(icon.foreground)) === '.xml'
+                )
+            ) {
+                errorLegacyIconNeeded.push(icon.density ? icon.density : 'size=' + (icon.height || icon.width));
+            } else if (!icon.src) {
+                icons[key].src = icon.foreground;
+            }
+        }
+    });
+
+    let errorMessage = [];
+    if (errorMissingAttributes.length > 0) {
+        errorMessage.push('One of the following attributes are set but missing the other for the density type: ' + errorMissingAttributes.join(', ') + '. Please ensure that all require attributes are defined.');
+    }
+
+    if (errorLegacyIconNeeded.length > 0) {
+        errorMessage.push('For the following icons with the density of: ' + errorLegacyIconNeeded.join(', ') + ', adaptive foreground with a defined color or vector can not be used as a standard fallback icon for older Android devices. To support older Android environments, please provide a value for the src attribute.');
+    }
+
+    if (errorMessage.length > 0) {
+        throw new CordovaError(errorMessage.join(' '));
+    }
+
+    let resourceMap = Object.assign(
+        {},
+        mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher.png'),
+        mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_foreground.png'),
+        mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_background.png'),
+        mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_foreground.xml'),
+        mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_background.xml'),
+        mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher.xml')
+    );
+
+    let preparedIcons = prepareIcons(icons);
+
+    if (hasAdaptive) {
+        resourceMap = updateIconResourceForAdaptive(preparedIcons, resourceMap, platformResourcesDir);
+    }
+
+    resourceMap = updateIconResourceForLegacy(preparedIcons, resourceMap, platformResourcesDir);
+
+    events.emit('verbose', 'Updating icons at ' + platformResourcesDir);
+    FileUpdater.updatePaths(resourceMap, { rootDir: cordovaProject.root }, logFileOp);
+}
+
+function updateIconResourceForAdaptive (preparedIcons, resourceMap, platformResourcesDir) {
+    let android_icons = preparedIcons.android_icons;
+    let default_icon = preparedIcons.default_icon;
+
+    // The source paths for icons and splashes are relative to
+    // project's config.xml location, so we use it as base path.
+    let background;
+    let foreground;
+    let targetPathBackground;
+    let targetPathForeground;
+
+    for (let density in android_icons) {
+        let backgroundVal = '@mipmap/ic_launcher_background';
+        let foregroundVal = '@mipmap/ic_launcher_foreground';
+
+        background = android_icons[density].background;
+        foreground = android_icons[density].foreground;
+
+        if (background.startsWith('@color')) {
+            // Colors Use Case
+            backgroundVal = background; // Example: @color/background_foobar_1
+        } else if (path.extname(path.basename(background)) === '.xml') {
+            // Vector Use Case
+            targetPathBackground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher_background.xml', path.basename(android_icons[density].background));
+            resourceMap[targetPathBackground] = android_icons[density].background;
+        } else if (path.extname(path.basename(background)) === '.png') {
+            // Images Use Case
+            targetPathBackground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher_background.png', path.basename(android_icons[density].background));
+            resourceMap[targetPathBackground] = android_icons[density].background;
+        }
+
+        if (foreground.startsWith('@color')) {
+            // Colors Use Case
+            foregroundVal = foreground;
+        } else if (path.extname(path.basename(foreground)) === '.xml') {
+            // Vector Use Case
+            targetPathForeground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher_foreground.xml', path.basename(android_icons[density].foreground));
+            resourceMap[targetPathForeground] = android_icons[density].foreground;
+        } else if (path.extname(path.basename(foreground)) === '.png') {
+            // Images Use Case
+            targetPathForeground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher_foreground.png', path.basename(android_icons[density].foreground));
+            resourceMap[targetPathForeground] = android_icons[density].foreground;
+        }
+
+        // create an XML for DPI and set color
+        const icLauncherTemplate = `<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="` + backgroundVal + `" />
+    <foreground android:drawable="` + foregroundVal + `" />
+</adaptive-icon>`;
+
+        let launcherXmlPath = path.join(platformResourcesDir, 'mipmap-' + density + '-v26', 'ic_launcher.xml');
+
+        // Remove the XML from the resourceMap so the file does not get removed.
+        delete resourceMap[launcherXmlPath];
+
+        fs.writeFileSync(path.resolve(launcherXmlPath), icLauncherTemplate);
+    }
+
+    // There's no "default" drawable, so assume default == mdpi.
+    if (default_icon && !android_icons.mdpi) {
+        let defaultTargetPathBackground;
+        let defaultTargetPathForeground;
+
+        if (background.startsWith('@color')) {
+            // Colors Use Case
+            targetPathBackground = default_icon.background;
+        } else if (path.extname(path.basename(background)) === '.xml') {
+            // Vector Use Case
+            defaultTargetPathBackground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher_background.xml', path.basename(default_icon.background));
+            resourceMap[defaultTargetPathBackground] = default_icon.background;
+        } else if (path.extname(path.basename(background)) === '.png') {
+            // Images Use Case
+            defaultTargetPathBackground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher_background.png', path.basename(default_icon.background));
+            resourceMap[defaultTargetPathBackground] = default_icon.background;
+        }
+
+        if (foreground.startsWith('@color')) {
+            // Colors Use Case
+            targetPathForeground = default_icon.foreground;
+        } else if (path.extname(path.basename(foreground)) === '.xml') {
+            // Vector Use Case
+            defaultTargetPathForeground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher_foreground.xml', path.basename(default_icon.foreground));
+            resourceMap[defaultTargetPathForeground] = default_icon.foreground;
+        } else if (path.extname(path.basename(foreground)) === '.png') {
+            // Images Use Case
+            defaultTargetPathForeground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher_foreground.png', path.basename(default_icon.foreground));
+            resourceMap[defaultTargetPathForeground] = default_icon.foreground;
+        }
+    }
+
+    return resourceMap;
+}
+
+function updateIconResourceForLegacy (preparedIcons, resourceMap, platformResourcesDir) {
+    let android_icons = preparedIcons.android_icons;
+    let default_icon = preparedIcons.default_icon;
+
+    // The source paths for icons and splashes are relative to
+    // project's config.xml location, so we use it as base path.
+    for (var density in android_icons) {
+        var targetPath = getImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher.png', path.basename(android_icons[density].src));
+        resourceMap[targetPath] = android_icons[density].src;
+    }
+
+    // There's no "default" drawable, so assume default == mdpi.
+    if (default_icon && !android_icons.mdpi) {
+        var defaultTargetPath = getImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher.png', path.basename(default_icon.src));
+        resourceMap[defaultTargetPath] = default_icon.src;
+    }
+
+    return resourceMap;
+}
+
+function prepareIcons (icons) {
+    // http://developer.android.com/design/style/iconography.html
+    const SIZE_TO_DENSITY_MAP = {
+        36: 'ldpi',
+        48: 'mdpi',
+        72: 'hdpi',
+        96: 'xhdpi',
+        144: 'xxhdpi',
+        192: 'xxxhdpi'
+    };
+
+    let android_icons = {};
+    let default_icon;
+
+    // find the best matching icon for a given density or size
+    // @output android_icons
+    var parseIcon = function (icon, icon_size) {
+        // do I have a platform icon for that density already
+        var density = icon.density || SIZE_TO_DENSITY_MAP[icon_size];
+        if (!density) {
+            // invalid icon defition ( or unsupported size)
+            return;
+        }
+        var previous = android_icons[density];
+        if (previous && previous.platform) {
+            return;
+        }
+        android_icons[density] = icon;
+    };
+
+    // iterate over all icon elements to find the default icon and call parseIcon
+    for (var i = 0; i < icons.length; i++) {
+        var icon = icons[i];
+        var size = icon.width;
+
+        if (!size) {
+            size = icon.height;
+        }
+
+        if (!size && !icon.density) {
+            if (default_icon) {
+                let found = {};
+                let favor = {};
+
+                // populating found icon.
+                if (icon.background && icon.foreground) {
+                    found.background = icon.background;
+                    found.foreground = icon.foreground;
+                }
+                if (icon.src) {
+                    found.src = icon.src;
+                }
+
+                if (default_icon.background && default_icon.foreground) {
+                    favor.background = default_icon.background;
+                    favor.foreground = default_icon.foreground;
+                }
+                if (default_icon.src) {
+                    favor.src = default_icon.src;
+                }
+
+                events.emit('verbose', 'Found extra default icon: ' + JSON.stringify(found) + ' and ignoring in favor of ' + JSON.stringify(favor) + '.');
+            } else {
+                default_icon = icon;
+            }
+        } else {
+            parseIcon(icon, size);
+        }
+    }
+
+    return {
+        android_icons: android_icons,
+        default_icon: default_icon
+    };
+}
+
+function cleanIcons (projectRoot, projectConfig, platformResourcesDir) {
+    var icons = projectConfig.getIcons('android');
+
+    // Skip if there are no app defined icons in config.xml
+    if (icons.length === 0) {
+        events.emit('verbose', 'This app does not have launcher icons defined');
+        return;
+    }
+
+    let resourceMap = Object.assign(
+        {},
+        mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher.png'),
+        mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_foreground.png'),
+        mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_background.png'),
+        mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_foreground.xml'),
+        mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_background.xml'),
+        mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher.xml')
+    );
+
+    events.emit('verbose', 'Cleaning icons at ' + platformResourcesDir);
+
+    // No source paths are specified in the map, so updatePaths() will delete the target files.
+    FileUpdater.updatePaths(resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
+}
+
+/**
+ * Gets a map containing resources of a specified name from all drawable folders in a directory.
+ */
+function mapImageResources (rootDir, subDir, type, resourceName) {
+    var pathMap = {};
+    shell.ls(path.join(rootDir, subDir, type + '-*')).forEach(function (drawableFolder) {
+        var imagePath = path.join(subDir, path.basename(drawableFolder), resourceName);
+        pathMap[imagePath] = null;
+    });
+    return pathMap;
+}
+
+function updateFileResources (cordovaProject, platformDir) {
+    var files = cordovaProject.projectConfig.getFileResources('android');
+
+    // if there are resource-file elements in config.xml
+    if (files.length === 0) {
+        events.emit('verbose', 'This app does not have additional resource files defined');
+        return;
+    }
+
+    var resourceMap = {};
+    files.forEach(function (res) {
+        var targetPath = path.join(platformDir, res.target);
+        resourceMap[targetPath] = res.src;
+    });
+
+    events.emit('verbose', 'Updating resource files at ' + platformDir);
+    FileUpdater.updatePaths(
+        resourceMap, { rootDir: cordovaProject.root }, logFileOp);
+}
+
+function cleanFileResources (projectRoot, projectConfig, platformDir) {
+    var files = projectConfig.getFileResources('android', true);
+    if (files.length > 0) {
+        events.emit('verbose', 'Cleaning resource files at ' + platformDir);
+
+        var resourceMap = {};
+        files.forEach(function (res) {
+            var filePath = path.join(platformDir, res.target);
+            resourceMap[filePath] = null;
+        });
+
+        FileUpdater.updatePaths(
+            resourceMap, {
+                rootDir: projectRoot, all: true }, logFileOp);
+    }
+}
+
+/**
+ * Gets and validates 'AndroidLaunchMode' prepference from config.xml. Returns
+ *   preference value and warns if it doesn't seems to be valid
+ *
+ * @param   {ConfigParser}  platformConfig  A configParser instance for
+ *   platform.
+ *
+ * @return  {String}                  Preference's value from config.xml or
+ *   default value, if there is no such preference. The default value is
+ *   'singleTop'
+ */
+function findAndroidLaunchModePreference (platformConfig) {
+    var launchMode = platformConfig.getPreference('AndroidLaunchMode');
+    if (!launchMode) {
+        // Return a default value
+        return 'singleTop';
+    }
+
+    var expectedValues = ['standard', 'singleTop', 'singleTask', 'singleInstance'];
+    var valid = expectedValues.indexOf(launchMode) >= 0;
+    if (!valid) {
+        // Note: warn, but leave the launch mode as developer wanted, in case the list of options changes in the future
+        events.emit('warn', 'Unrecognized value for AndroidLaunchMode preference: ' +
+            launchMode + '. Expected values are: ' + expectedValues.join(', '));
+    }
+
+    return launchMode;
+}
diff --git a/platforms/android/cordova/lib/retry.js b/platforms/android/cordova/lib/retry.js
new file mode 100644
index 0000000..b2b9a44
--- /dev/null
+++ b/platforms/android/cordova/lib/retry.js
@@ -0,0 +1,64 @@
+#!/usr/bin/env node
+
+/*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+
+'use strict';
+
+var events = require('cordova-common').events;
+
+/*
+ * Retry a promise-returning function a number of times, propagating its
+ * results on success or throwing its error on a failed final attempt.
+ *
+ * @arg {Number}   attemptsLeft    - The number of times to retry the passed call.
+ * @arg {Function} promiseFunction - A function that returns a promise.
+ * @arg {...}                      - Arguments to pass to promiseFunction.
+ *
+ * @returns {Promise}
+ */
+module.exports.retryPromise = function (attemptsLeft, promiseFunction) {
+
+    // NOTE:
+    //      get all trailing arguments, by skipping the first two (attemptsLeft and
+    //      promiseFunction) because they shouldn't get passed to promiseFunction
+    var promiseFunctionArguments = Array.prototype.slice.call(arguments, 2);
+
+    return promiseFunction.apply(undefined, promiseFunctionArguments).then(
+        // on success pass results through
+        function onFulfilled (value) {
+            return value;
+        },
+
+        // on rejection either retry, or throw the error
+        function onRejected (error) {
+            attemptsLeft -= 1;
+
+            if (attemptsLeft < 1) {
+                throw error;
+            }
+
+            events.emit('verbose', 'A retried call failed. Retrying ' + attemptsLeft + ' more time(s).');
+
+            // retry call self again with the same arguments, except attemptsLeft is now lower
+            var fullArguments = [attemptsLeft, promiseFunction].concat(promiseFunctionArguments);
+            return module.exports.retryPromise.apply(undefined, fullArguments);
+        }
+    );
+};
diff --git a/platforms/android/cordova/lib/run.js b/platforms/android/cordova/lib/run.js
new file mode 100644
index 0000000..221467b
--- /dev/null
+++ b/platforms/android/cordova/lib/run.js
@@ -0,0 +1,131 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var path = require('path');
+var emulator = require('./emulator');
+var device = require('./device');
+var Q = require('q');
+var events = require('cordova-common').events;
+
+function getInstallTarget (runOptions) {
+    var install_target;
+    if (runOptions.target) {
+        install_target = runOptions.target;
+    } else if (runOptions.device) {
+        install_target = '--device';
+    } else if (runOptions.emulator) {
+        install_target = '--emulator';
+    }
+
+    return install_target;
+}
+
+/**
+ * Runs the application on a device if available. If no device is found, it will
+ *   use a started emulator. If no started emulators are found it will attempt
+ *   to start an avd. If no avds are found it will error out.
+ *
+ * @param   {Object}  runOptions  various run/build options. See Api.js build/run
+ *   methods for reference.
+ *
+ * @return  {Promise}
+ */
+module.exports.run = function (runOptions) {
+    runOptions = runOptions || {};
+
+    var self = this;
+    var install_target = getInstallTarget(runOptions);
+
+    return Q().then(function () {
+        if (!install_target) {
+            // no target given, deploy to device if available, otherwise use the emulator.
+            return device.list().then(function (device_list) {
+                if (device_list.length > 0) {
+                    events.emit('warn', 'No target specified, deploying to device \'' + device_list[0] + '\'.');
+                    install_target = device_list[0];
+                } else {
+                    events.emit('warn', 'No target specified and no devices found, deploying to emulator');
+                    install_target = '--emulator';
+                }
+            });
+        }
+    }).then(function () {
+        if (install_target === '--device') {
+            return device.resolveTarget(null);
+        } else if (install_target === '--emulator') {
+            // Give preference to any already started emulators. Else, start one.
+            return emulator.list_started().then(function (started) {
+                return started && started.length > 0 ? started[0] : emulator.start();
+            }).then(function (emulatorId) {
+                return emulator.resolveTarget(emulatorId);
+            });
+        }
+        // They specified a specific device/emulator ID.
+        return device.list().then(function (devices) {
+            if (devices.indexOf(install_target) > -1) {
+                return device.resolveTarget(install_target);
+            }
+            return emulator.list_started().then(function (started_emulators) {
+                if (started_emulators.indexOf(install_target) > -1) {
+                    return emulator.resolveTarget(install_target);
+                }
+                return emulator.list_images().then(function (avds) {
+                    // if target emulator isn't started, then start it.
+                    for (var avd in avds) {
+                        if (avds[avd].name === install_target) {
+                            return emulator.start(install_target).then(function (emulatorId) {
+                                return emulator.resolveTarget(emulatorId);
+                            });
+                        }
+                    }
+                    return Q.reject('Target \'' + install_target + '\' not found, unable to run project');
+                });
+            });
+        });
+    }).then(function (resolvedTarget) {
+        return new Promise((resolve) => {
+            const builder = require('./builders/builders').getBuilder();
+            const buildOptions = require('./build').parseBuildOptions(runOptions, null, self.root);
+            resolve(builder.fetchBuildResults(buildOptions.buildType, buildOptions.arch));
+        }).then(function (buildResults) {
+            if (resolvedTarget && resolvedTarget.isEmulator) {
+                return emulator.wait_for_boot(resolvedTarget.target).then(function () {
+                    return emulator.install(resolvedTarget, buildResults);
+                });
+            }
+
+            return device.install(resolvedTarget, buildResults);
+        });
+    });
+};
+
+module.exports.help = function () {
+    console.log('Usage: ' + path.relative(process.cwd(), process.argv[1]) + ' [options]');
+    console.log('Build options :');
+    console.log('    --debug : Builds project in debug mode');
+    console.log('    --release : Builds project in release mode');
+    console.log('    --nobuild : Runs the currently built project without recompiling');
+    console.log('Deploy options :');
+    console.log('    --device : Will deploy the built project to a device');
+    console.log('    --emulator : Will deploy the built project to an emulator if one exists');
+    console.log('    --target=<target_id> : Installs to the target with the specified id.');
+    process.exit(0);
+};
diff --git a/platforms/android/cordova/lib/start-emulator b/platforms/android/cordova/lib/start-emulator
new file mode 100755
index 0000000..20c92b7
--- /dev/null
+++ b/platforms/android/cordova/lib/start-emulator
@@ -0,0 +1,38 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var emulator = require('./emulator');
+var args = process.argv;
+
+var install_target;
+if (args.length > 2) {
+    if (args[2].substring(0, 9) === '--target=') {
+        install_target = args[2].substring(9, args[2].length);
+    } else {
+        console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
+        process.exit(2);
+    }
+}
+
+emulator.start(install_target).catch(function (err) {
+    console.error('ERROR: ' + err);
+    process.exit(2);
+});
diff --git a/platforms/android/cordova/lib/start-emulator.bat b/platforms/android/cordova/lib/start-emulator.bat
new file mode 100644
index 0000000..6c237ea
--- /dev/null
+++ b/platforms/android/cordova/lib/start-emulator.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License.  You may obtain a copy of the License at
+:: 
+:: http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied.  See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0start-emulator"
+IF EXIST %script_path% (
+        node %script_path% %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'start-emulator' script in 'cordova\lib' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file
diff --git a/platforms/android/cordova/log b/platforms/android/cordova/log
new file mode 100755
index 0000000..6829f28
--- /dev/null
+++ b/platforms/android/cordova/log
@@ -0,0 +1,36 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var log = require('./lib/log');
+var reqs = require('./lib/check_reqs');
+var args = process.argv;
+
+// Usage support for when args are given
+if (args.length > 2) {
+    log.help();
+} else {
+    reqs.run().done(function () {
+        return log.run();
+    }, function (err) {
+        console.error('ERROR: ' + err);
+        process.exit(2);
+    });
+}
diff --git a/platforms/android/cordova/log.bat b/platforms/android/cordova/log.bat
new file mode 100644
index 0000000..4b2b434
--- /dev/null
+++ b/platforms/android/cordova/log.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License.  You may obtain a copy of the License at
+::
+:: http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied.  See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0log"
+IF EXIST %script_path% (
+        node %script_path% %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'log' script in 'cordova' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file
diff --git a/platforms/android/cordova/loggingHelper.js b/platforms/android/cordova/loggingHelper.js
new file mode 100644
index 0000000..32b2ee0
--- /dev/null
+++ b/platforms/android/cordova/loggingHelper.js
@@ -0,0 +1,18 @@
+var CordovaLogger = require('cordova-common').CordovaLogger;
+
+module.exports = {
+    adjustLoggerLevel: function (opts) {
+        if (opts instanceof Array) {
+            opts.silent = opts.indexOf('--silent') !== -1;
+            opts.verbose = opts.indexOf('--verbose') !== -1;
+        }
+
+        if (opts.silent) {
+            CordovaLogger.get().setLevel('error');
+        }
+
+        if (opts.verbose) {
+            CordovaLogger.get().setLevel('verbose');
+        }
+    }
+};
diff --git a/platforms/android/cordova/run b/platforms/android/cordova/run
new file mode 100755
index 0000000..a3d6f53
--- /dev/null
+++ b/platforms/android/cordova/run
@@ -0,0 +1,54 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var Api = require('./Api');
+var nopt = require('nopt');
+var path = require('path');
+
+// Support basic help commands
+if (['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) {
+    require('./lib/run').help();
+}
+
+// Do some basic argument parsing
+var runOpts = nopt({
+    'verbose': Boolean,
+    'silent': Boolean,
+    'debug': Boolean,
+    'release': Boolean,
+    'nobuild': Boolean,
+    'buildConfig': path,
+    'archs': String,
+    'device': Boolean,
+    'emulator': Boolean,
+    'target': String
+}, { 'd': '--verbose' });
+
+// Make runOptions compatible with PlatformApi run method spec
+runOpts.argv = runOpts.argv.remain;
+
+require('./loggingHelper').adjustLoggerLevel(runOpts);
+
+new Api().run(runOpts)
+    .catch(function (err) {
+        console.error(err, err.stack);
+        process.exit(2);
+    });
diff --git a/platforms/android/cordova/run.bat b/platforms/android/cordova/run.bat
new file mode 100644
index 0000000..b0bc28b
--- /dev/null
+++ b/platforms/android/cordova/run.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License.  You may obtain a copy of the License at
+::
+:: http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied.  See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0run"
+IF EXIST %script_path% (
+        node %script_path% %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'run' script in 'cordova' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file
diff --git a/platforms/android/cordova/version b/platforms/android/cordova/version
new file mode 100755
index 0000000..299fce6
--- /dev/null
+++ b/platforms/android/cordova/version
@@ -0,0 +1,29 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+// Coho updates this line:
+var VERSION = "8.0.0";
+
+module.exports.version = VERSION;
+
+if (!module.parent) {
+    console.log(VERSION);
+}
diff --git a/platforms/android/cordova/version.bat b/platforms/android/cordova/version.bat
new file mode 100644
index 0000000..3610c17
--- /dev/null
+++ b/platforms/android/cordova/version.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License.  You may obtain a copy of the License at
+::
+:: http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied.  See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0version"
+IF EXIST %script_path% (
+        node %script_path% %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'version' script in 'cordova' folder, aborting...>&2
+    EXIT /B 1
+)
diff --git a/platforms/android/gradle.properties b/platforms/android/gradle.properties
new file mode 100644
index 0000000..11bc459
--- /dev/null
+++ b/platforms/android/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.daemon=true
+org.gradle.jvmargs=-Xmx2048m
+android.useDeprecatedNdk=true
\ No newline at end of file
diff --git a/platforms/android/platform_www/cordova-js-src/android/nativeapiprovider.js b/platforms/android/platform_www/cordova-js-src/android/nativeapiprovider.js
new file mode 100644
index 0000000..2e9aa67
--- /dev/null
+++ b/platforms/android/platform_www/cordova-js-src/android/nativeapiprovider.js
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+*/
+
+/**
+ * Exports the ExposedJsApi.java object if available, otherwise exports the PromptBasedNativeApi.
+ */
+
+var nativeApi = this._cordovaNative || require('cordova/android/promptbasednativeapi');
+var currentApi = nativeApi;
+
+module.exports = {
+    get: function() { return currentApi; },
+    setPreferPrompt: function(value) {
+        currentApi = value ? require('cordova/android/promptbasednativeapi') : nativeApi;
+    },
+    // Used only by tests.
+    set: function(value) {
+        currentApi = value;
+    }
+};
diff --git a/platforms/android/platform_www/cordova-js-src/android/promptbasednativeapi.js b/platforms/android/platform_www/cordova-js-src/android/promptbasednativeapi.js
new file mode 100644
index 0000000..f7fb6bc
--- /dev/null
+++ b/platforms/android/platform_www/cordova-js-src/android/promptbasednativeapi.js
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+*/
+
+/**
+ * Implements the API of ExposedJsApi.java, but uses prompt() to communicate.
+ * This is used pre-JellyBean, where addJavascriptInterface() is disabled.
+ */
+
+module.exports = {
+    exec: function(bridgeSecret, service, action, callbackId, argsJson) {
+        return prompt(argsJson, 'gap:'+JSON.stringify([bridgeSecret, service, action, callbackId]));
+    },
+    setNativeToJsBridgeMode: function(bridgeSecret, value) {
+        prompt(value, 'gap_bridge_mode:' + bridgeSecret);
+    },
+    retrieveJsMessages: function(bridgeSecret, fromOnlineEvent) {
+        return prompt(+fromOnlineEvent, 'gap_poll:' + bridgeSecret);
+    }
+};
diff --git a/platforms/android/platform_www/cordova-js-src/exec.js b/platforms/android/platform_www/cordova-js-src/exec.js
new file mode 100644
index 0000000..39e8c97
--- /dev/null
+++ b/platforms/android/platform_www/cordova-js-src/exec.js
@@ -0,0 +1,286 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * Execute a cordova command.  It is up to the native side whether this action
+ * is synchronous or asynchronous.  The native side can return:
+ *      Synchronous: PluginResult object as a JSON string
+ *      Asynchronous: Empty string ""
+ * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
+ * depending upon the result of the action.
+ *
+ * @param {Function} success    The success callback
+ * @param {Function} fail       The fail callback
+ * @param {String} service      The name of the service to use
+ * @param {String} action       Action to be run in cordova
+ * @param {String[]} [args]     Zero or more arguments to pass to the method
+ */
+var cordova = require('cordova'),
+    nativeApiProvider = require('cordova/android/nativeapiprovider'),
+    utils = require('cordova/utils'),
+    base64 = require('cordova/base64'),
+    channel = require('cordova/channel'),
+    jsToNativeModes = {
+        PROMPT: 0,
+        JS_OBJECT: 1
+    },
+    nativeToJsModes = {
+        // Polls for messages using the JS->Native bridge.
+        POLLING: 0,
+        // For LOAD_URL to be viable, it would need to have a work-around for
+        // the bug where the soft-keyboard gets dismissed when a message is sent.
+        LOAD_URL: 1,
+        // For the ONLINE_EVENT to be viable, it would need to intercept all event
+        // listeners (both through addEventListener and window.ononline) as well
+        // as set the navigator property itself.
+        ONLINE_EVENT: 2,
+        EVAL_BRIDGE: 3
+    },
+    jsToNativeBridgeMode,  // Set lazily.
+    nativeToJsBridgeMode = nativeToJsModes.EVAL_BRIDGE,
+    pollEnabled = false,
+    bridgeSecret = -1;
+
+var messagesFromNative = [];
+var isProcessing = false;
+var resolvedPromise = typeof Promise == 'undefined' ? null : Promise.resolve();
+var nextTick = resolvedPromise ? function(fn) { resolvedPromise.then(fn); } : function(fn) { setTimeout(fn); };
+
+function androidExec(success, fail, service, action, args) {
+    if (bridgeSecret < 0) {
+        // If we ever catch this firing, we'll need to queue up exec()s
+        // and fire them once we get a secret. For now, I don't think
+        // it's possible for exec() to be called since plugins are parsed but
+        // not run until until after onNativeReady.
+        throw new Error('exec() called without bridgeSecret');
+    }
+    // Set default bridge modes if they have not already been set.
+    // By default, we use the failsafe, since addJavascriptInterface breaks too often
+    if (jsToNativeBridgeMode === undefined) {
+        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
+    }
+
+    // If args is not provided, default to an empty array
+    args = args || [];
+
+    // Process any ArrayBuffers in the args into a string.
+    for (var i = 0; i < args.length; i++) {
+        if (utils.typeName(args[i]) == 'ArrayBuffer') {
+            args[i] = base64.fromArrayBuffer(args[i]);
+        }
+    }
+
+    var callbackId = service + cordova.callbackId++,
+        argsJson = JSON.stringify(args);
+    if (success || fail) {
+        cordova.callbacks[callbackId] = {success:success, fail:fail};
+    }
+
+    var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);
+    // If argsJson was received by Java as null, try again with the PROMPT bridge mode.
+    // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2.  See CB-2666.
+    if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && msgs === "@Null arguments.") {
+        androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
+        androidExec(success, fail, service, action, args);
+        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
+    } else if (msgs) {
+        messagesFromNative.push(msgs);
+        // Always process async to avoid exceptions messing up stack.
+        nextTick(processMessages);
+    }
+}
+
+androidExec.init = function() {
+    bridgeSecret = +prompt('', 'gap_init:' + nativeToJsBridgeMode);
+    channel.onNativeReady.fire();
+};
+
+function pollOnceFromOnlineEvent() {
+    pollOnce(true);
+}
+
+function pollOnce(opt_fromOnlineEvent) {
+    if (bridgeSecret < 0) {
+        // This can happen when the NativeToJsMessageQueue resets the online state on page transitions.
+        // We know there's nothing to retrieve, so no need to poll.
+        return;
+    }
+    var msgs = nativeApiProvider.get().retrieveJsMessages(bridgeSecret, !!opt_fromOnlineEvent);
+    if (msgs) {
+        messagesFromNative.push(msgs);
+        // Process sync since we know we're already top-of-stack.
+        processMessages();
+    }
+}
+
+function pollingTimerFunc() {
+    if (pollEnabled) {
+        pollOnce();
+        setTimeout(pollingTimerFunc, 50);
+    }
+}
+
+function hookOnlineApis() {
+    function proxyEvent(e) {
+        cordova.fireWindowEvent(e.type);
+    }
+    // The network module takes care of firing online and offline events.
+    // It currently fires them only on document though, so we bridge them
+    // to window here (while first listening for exec()-releated online/offline
+    // events).
+    window.addEventListener('online', pollOnceFromOnlineEvent, false);
+    window.addEventListener('offline', pollOnceFromOnlineEvent, false);
+    cordova.addWindowEventHandler('online');
+    cordova.addWindowEventHandler('offline');
+    document.addEventListener('online', proxyEvent, false);
+    document.addEventListener('offline', proxyEvent, false);
+}
+
+hookOnlineApis();
+
+androidExec.jsToNativeModes = jsToNativeModes;
+androidExec.nativeToJsModes = nativeToJsModes;
+
+androidExec.setJsToNativeBridgeMode = function(mode) {
+    if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {
+        mode = jsToNativeModes.PROMPT;
+    }
+    nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);
+    jsToNativeBridgeMode = mode;
+};
+
+androidExec.setNativeToJsBridgeMode = function(mode) {
+    if (mode == nativeToJsBridgeMode) {
+        return;
+    }
+    if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {
+        pollEnabled = false;
+    }
+
+    nativeToJsBridgeMode = mode;
+    // Tell the native side to switch modes.
+    // Otherwise, it will be set by androidExec.init()
+    if (bridgeSecret >= 0) {
+        nativeApiProvider.get().setNativeToJsBridgeMode(bridgeSecret, mode);
+    }
+
+    if (mode == nativeToJsModes.POLLING) {
+        pollEnabled = true;
+        setTimeout(pollingTimerFunc, 1);
+    }
+};
+
+function buildPayload(payload, message) {
+    var payloadKind = message.charAt(0);
+    if (payloadKind == 's') {
+        payload.push(message.slice(1));
+    } else if (payloadKind == 't') {
+        payload.push(true);
+    } else if (payloadKind == 'f') {
+        payload.push(false);
+    } else if (payloadKind == 'N') {
+        payload.push(null);
+    } else if (payloadKind == 'n') {
+        payload.push(+message.slice(1));
+    } else if (payloadKind == 'A') {
+        var data = message.slice(1);
+        payload.push(base64.toArrayBuffer(data));
+    } else if (payloadKind == 'S') {
+        payload.push(window.atob(message.slice(1)));
+    } else if (payloadKind == 'M') {
+        var multipartMessages = message.slice(1);
+        while (multipartMessages !== "") {
+            var spaceIdx = multipartMessages.indexOf(' ');
+            var msgLen = +multipartMessages.slice(0, spaceIdx);
+            var multipartMessage = multipartMessages.substr(spaceIdx + 1, msgLen);
+            multipartMessages = multipartMessages.slice(spaceIdx + msgLen + 1);
+            buildPayload(payload, multipartMessage);
+        }
+    } else {
+        payload.push(JSON.parse(message));
+    }
+}
+
+// Processes a single message, as encoded by NativeToJsMessageQueue.java.
+function processMessage(message) {
+    var firstChar = message.charAt(0);
+    if (firstChar == 'J') {
+        // This is deprecated on the .java side. It doesn't work with CSP enabled.
+        eval(message.slice(1));
+    } else if (firstChar == 'S' || firstChar == 'F') {
+        var success = firstChar == 'S';
+        var keepCallback = message.charAt(1) == '1';
+        var spaceIdx = message.indexOf(' ', 2);
+        var status = +message.slice(2, spaceIdx);
+        var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);
+        var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);
+        var payloadMessage = message.slice(nextSpaceIdx + 1);
+        var payload = [];
+        buildPayload(payload, payloadMessage);
+        cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);
+    } else {
+        console.log("processMessage failed: invalid message: " + JSON.stringify(message));
+    }
+}
+
+function processMessages() {
+    // Check for the reentrant case.
+    if (isProcessing) {
+        return;
+    }
+    if (messagesFromNative.length === 0) {
+        return;
+    }
+    isProcessing = true;
+    try {
+        var msg = popMessageFromQueue();
+        // The Java side can send a * message to indicate that it
+        // still has messages waiting to be retrieved.
+        if (msg == '*' && messagesFromNative.length === 0) {
+            nextTick(pollOnce);
+            return;
+        }
+        processMessage(msg);
+    } finally {
+        isProcessing = false;
+        if (messagesFromNative.length > 0) {
+            nextTick(processMessages);
+        }
+    }
+}
+
+function popMessageFromQueue() {
+    var messageBatch = messagesFromNative.shift();
+    if (messageBatch == '*') {
+        return '*';
+    }
+
+    var spaceIdx = messageBatch.indexOf(' ');
+    var msgLen = +messageBatch.slice(0, spaceIdx);
+    var message = messageBatch.substr(spaceIdx + 1, msgLen);
+    messageBatch = messageBatch.slice(spaceIdx + msgLen + 1);
+    if (messageBatch) {
+        messagesFromNative.unshift(messageBatch);
+    }
+    return message;
+}
+
+module.exports = androidExec;
diff --git a/platforms/android/platform_www/cordova-js-src/platform.js b/platforms/android/platform_www/cordova-js-src/platform.js
new file mode 100644
index 0000000..2bfd024
--- /dev/null
+++ b/platforms/android/platform_www/cordova-js-src/platform.js
@@ -0,0 +1,125 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+// The last resume event that was received that had the result of a plugin call.
+var lastResumeEvent = null;
+
+module.exports = {
+    id: 'android',
+    bootstrap: function() {
+        var channel = require('cordova/channel'),
+            cordova = require('cordova'),
+            exec = require('cordova/exec'),
+            modulemapper = require('cordova/modulemapper');
+
+        // Get the shared secret needed to use the bridge.
+        exec.init();
+
+        // TODO: Extract this as a proper plugin.
+        modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');
+
+        var APP_PLUGIN_NAME = Number(cordova.platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';
+
+        // Inject a listener for the backbutton on the document.
+        var backButtonChannel = cordova.addDocumentEventHandler('backbutton');
+        backButtonChannel.onHasSubscribersChange = function() {
+            // If we just attached the first handler or detached the last handler,
+            // let native know we need to override the back button.
+            exec(null, null, APP_PLUGIN_NAME, "overrideBackbutton", [this.numHandlers == 1]);
+        };
+
+        // Add hardware MENU and SEARCH button handlers
+        cordova.addDocumentEventHandler('menubutton');
+        cordova.addDocumentEventHandler('searchbutton');
+
+        function bindButtonChannel(buttonName) {
+            // generic button bind used for volumeup/volumedown buttons
+            var volumeButtonChannel = cordova.addDocumentEventHandler(buttonName + 'button');
+            volumeButtonChannel.onHasSubscribersChange = function() {
+                exec(null, null, APP_PLUGIN_NAME, "overrideButton", [buttonName, this.numHandlers == 1]);
+            };
+        }
+        // Inject a listener for the volume buttons on the document.
+        bindButtonChannel('volumeup');
+        bindButtonChannel('volumedown');
+
+        // The resume event is not "sticky", but it is possible that the event
+        // will contain the result of a plugin call. We need to ensure that the
+        // plugin result is delivered even after the event is fired (CB-10498)
+        var cordovaAddEventListener = document.addEventListener;
+
+        document.addEventListener = function(evt, handler, capture) {
+            cordovaAddEventListener(evt, handler, capture);
+
+            if (evt === 'resume' && lastResumeEvent) {
+                handler(lastResumeEvent);
+            }
+        };
+
+        // Let native code know we are all done on the JS side.
+        // Native code will then un-hide the WebView.
+        channel.onCordovaReady.subscribe(function() {
+            exec(onMessageFromNative, null, APP_PLUGIN_NAME, 'messageChannel', []);
+            exec(null, null, APP_PLUGIN_NAME, "show", []);
+        });
+    }
+};
+
+function onMessageFromNative(msg) {
+    var cordova = require('cordova');
+    var action = msg.action;
+
+    switch (action)
+    {
+        // Button events
+        case 'backbutton':
+        case 'menubutton':
+        case 'searchbutton':
+        // App life cycle events
+        case 'pause':
+        // Volume events
+        case 'volumedownbutton':
+        case 'volumeupbutton':
+            cordova.fireDocumentEvent(action);
+            break;
+        case 'resume':
+            if(arguments.length > 1 && msg.pendingResult) {
+                if(arguments.length === 2) {
+                    msg.pendingResult.result = arguments[1];
+                } else {
+                    // The plugin returned a multipart message
+                    var res = [];
+                    for(var i = 1; i < arguments.length; i++) {
+                        res.push(arguments[i]);
+                    }
+                    msg.pendingResult.result = res;
+                }
+
+                // Save the plugin result so that it can be delivered to the js
+                // even if they miss the initial firing of the event
+                lastResumeEvent = msg;
+            }
+            cordova.fireDocumentEvent(action, msg);
+            break;
+        default:
+            throw new Error('Unknown event action ' + action);
+    }
+}
diff --git a/platforms/android/platform_www/cordova-js-src/plugin/android/app.js b/platforms/android/platform_www/cordova-js-src/plugin/android/app.js
new file mode 100644
index 0000000..22cf96e
--- /dev/null
+++ b/platforms/android/platform_www/cordova-js-src/plugin/android/app.js
@@ -0,0 +1,108 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var exec = require('cordova/exec');
+var APP_PLUGIN_NAME = Number(require('cordova').platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';
+
+module.exports = {
+    /**
+    * Clear the resource cache.
+    */
+    clearCache:function() {
+        exec(null, null, APP_PLUGIN_NAME, "clearCache", []);
+    },
+
+    /**
+    * Load the url into the webview or into new browser instance.
+    *
+    * @param url           The URL to load
+    * @param props         Properties that can be passed in to the activity:
+    *      wait: int                           => wait msec before loading URL
+    *      loadingDialog: "Title,Message"      => display a native loading dialog
+    *      loadUrlTimeoutValue: int            => time in msec to wait before triggering a timeout error
+    *      clearHistory: boolean              => clear webview history (default=false)
+    *      openExternal: boolean              => open in a new browser (default=false)
+    *
+    * Example:
+    *      navigator.app.loadUrl("http://server/myapp/index.html", {wait:2000, loadingDialog:"Wait,Loading App", loadUrlTimeoutValue: 60000});
+    */
+    loadUrl:function(url, props) {
+        exec(null, null, APP_PLUGIN_NAME, "loadUrl", [url, props]);
+    },
+
+    /**
+    * Cancel loadUrl that is waiting to be loaded.
+    */
+    cancelLoadUrl:function() {
+        exec(null, null, APP_PLUGIN_NAME, "cancelLoadUrl", []);
+    },
+
+    /**
+    * Clear web history in this web view.
+    * Instead of BACK button loading the previous web page, it will exit the app.
+    */
+    clearHistory:function() {
+        exec(null, null, APP_PLUGIN_NAME, "clearHistory", []);
+    },
+
+    /**
+    * Go to previous page displayed.
+    * This is the same as pressing the backbutton on Android device.
+    */
+    backHistory:function() {
+        exec(null, null, APP_PLUGIN_NAME, "backHistory", []);
+    },
+
+    /**
+    * Override the default behavior of the Android back button.
+    * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
+    *
+    * Note: The user should not have to call this method.  Instead, when the user
+    *       registers for the "backbutton" event, this is automatically done.
+    *
+    * @param override        T=override, F=cancel override
+    */
+    overrideBackbutton:function(override) {
+        exec(null, null, APP_PLUGIN_NAME, "overrideBackbutton", [override]);
+    },
+
+    /**
+    * Override the default behavior of the Android volume button.
+    * If overridden, when the volume button is pressed, the "volume[up|down]button"
+    * JavaScript event will be fired.
+    *
+    * Note: The user should not have to call this method.  Instead, when the user
+    *       registers for the "volume[up|down]button" event, this is automatically done.
+    *
+    * @param button          volumeup, volumedown
+    * @param override        T=override, F=cancel override
+    */
+    overrideButton:function(button, override) {
+        exec(null, null, APP_PLUGIN_NAME, "overrideButton", [button, override]);
+    },
+
+    /**
+    * Exit and terminate the application.
+    */
+    exitApp:function() {
+        return exec(null, null, APP_PLUGIN_NAME, "exitApp", []);
+    }
+};
diff --git a/platforms/android/platform_www/cordova.js b/platforms/android/platform_www/cordova.js
new file mode 100644
index 0000000..0f2d2e6
--- /dev/null
+++ b/platforms/android/platform_www/cordova.js
@@ -0,0 +1,1908 @@
+// Platform: android
+// 882658ab17740dbdece764e68c1f1f1f44fe3f9d
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+ 
+     http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+;(function() {
+var PLATFORM_VERSION_BUILD_LABEL = '8.0.0';
+// file: src/scripts/require.js
+
+var require;
+var define;
+
+(function () {
+    var modules = {};
+    // Stack of moduleIds currently being built.
+    var requireStack = [];
+    // Map of module ID -> index into requireStack of modules currently being built.
+    var inProgressModules = {};
+    var SEPARATOR = '.';
+
+    function build (module) {
+        var factory = module.factory;
+        var localRequire = function (id) {
+            var resultantId = id;
+            // Its a relative path, so lop off the last portion and add the id (minus "./")
+            if (id.charAt(0) === '.') {
+                resultantId = module.id.slice(0, module.id.lastIndexOf(SEPARATOR)) + SEPARATOR + id.slice(2);
+            }
+            return require(resultantId);
+        };
+        module.exports = {};
+        delete module.factory;
+        factory(localRequire, module.exports, module);
+        return module.exports;
+    }
+
+    require = function (id) {
+        if (!modules[id]) {
+            throw 'module ' + id + ' not found';
+        } else if (id in inProgressModules) {
+            var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
+            throw 'Cycle in require graph: ' + cycle;
+        }
+        if (modules[id].factory) {
+            try {
+                inProgressModules[id] = requireStack.length;
+                requireStack.push(id);
+                return build(modules[id]);
+            } finally {
+                delete inProgressModules[id];
+                requireStack.pop();
+            }
+        }
+        return modules[id].exports;
+    };
+
+    define = function (id, factory) {
+        if (modules[id]) {
+            throw 'module ' + id + ' already defined';
+        }
+
+        modules[id] = {
+            id: id,
+            factory: factory
+        };
+    };
+
+    define.remove = function (id) {
+        delete modules[id];
+    };
+
+    define.moduleMap = modules;
+})();
+
+// Export for use in node
+if (typeof module === 'object' && typeof require === 'function') {
+    module.exports.require = require;
+    module.exports.define = define;
+}
+
+// file: src/cordova.js
+define("cordova", function(require, exports, module) {
+
+// Workaround for Windows 10 in hosted environment case
+// http://www.w3.org/html/wg/drafts/html/master/browsers.html#named-access-on-the-window-object
+if (window.cordova && !(window.cordova instanceof HTMLElement)) { // eslint-disable-line no-undef
+    throw new Error('cordova already defined');
+}
+
+var channel = require('cordova/channel');
+var platform = require('cordova/platform');
+
+/**
+ * Intercept calls to addEventListener + removeEventListener and handle deviceready,
+ * resume, and pause events.
+ */
+var m_document_addEventListener = document.addEventListener;
+var m_document_removeEventListener = document.removeEventListener;
+var m_window_addEventListener = window.addEventListener;
+var m_window_removeEventListener = window.removeEventListener;
+
+/**
+ * Houses custom event handlers to intercept on document + window event listeners.
+ */
+var documentEventHandlers = {};
+var windowEventHandlers = {};
+
+document.addEventListener = function (evt, handler, capture) {
+    var e = evt.toLowerCase();
+    if (typeof documentEventHandlers[e] !== 'undefined') {
+        documentEventHandlers[e].subscribe(handler);
+    } else {
+        m_document_addEventListener.call(document, evt, handler, capture);
+    }
+};
+
+window.addEventListener = function (evt, handler, capture) {
+    var e = evt.toLowerCase();
+    if (typeof windowEventHandlers[e] !== 'undefined') {
+        windowEventHandlers[e].subscribe(handler);
+    } else {
+        m_window_addEventListener.call(window, evt, handler, capture);
+    }
+};
+
+document.removeEventListener = function (evt, handler, capture) {
+    var e = evt.toLowerCase();
+    // If unsubscribing from an event that is handled by a plugin
+    if (typeof documentEventHandlers[e] !== 'undefined') {
+        documentEventHandlers[e].unsubscribe(handler);
+    } else {
+        m_document_removeEventListener.call(document, evt, handler, capture);
+    }
+};
+
+window.removeEventListener = function (evt, handler, capture) {
+    var e = evt.toLowerCase();
+    // If unsubscribing from an event that is handled by a plugin
+    if (typeof windowEventHandlers[e] !== 'undefined') {
+        windowEventHandlers[e].unsubscribe(handler);
+    } else {
+        m_window_removeEventListener.call(window, evt, handler, capture);
+    }
+};
+
+function createEvent (type, data) {
+    var event = document.createEvent('Events');
+    event.initEvent(type, false, false);
+    if (data) {
+        for (var i in data) {
+            if (data.hasOwnProperty(i)) {
+                event[i] = data[i];
+            }
+        }
+    }
+    return event;
+}
+
+/* eslint-disable no-undef */
+var cordova = {
+    define: define,
+    require: require,
+    version: PLATFORM_VERSION_BUILD_LABEL,
+    platformVersion: PLATFORM_VERSION_BUILD_LABEL,
+    platformId: platform.id,
+
+    /* eslint-enable no-undef */
+
+    /**
+     * Methods to add/remove your own addEventListener hijacking on document + window.
+     */
+    addWindowEventHandler: function (event) {
+        return (windowEventHandlers[event] = channel.create(event));
+    },
+    addStickyDocumentEventHandler: function (event) {
+        return (documentEventHandlers[event] = channel.createSticky(event));
+    },
+    addDocumentEventHandler: function (event) {
+        return (documentEventHandlers[event] = channel.create(event));
+    },
+    removeWindowEventHandler: function (event) {
+        delete windowEventHandlers[event];
+    },
+    removeDocumentEventHandler: function (event) {
+        delete documentEventHandlers[event];
+    },
+    /**
+     * Retrieve original event handlers that were replaced by Cordova
+     *
+     * @return object
+     */
+    getOriginalHandlers: function () {
+        return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},
+            'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};
+    },
+    /**
+     * Method to fire event from native code
+     * bNoDetach is required for events which cause an exception which needs to be caught in native code
+     */
+    fireDocumentEvent: function (type, data, bNoDetach) {
+        var evt = createEvent(type, data);
+        if (typeof documentEventHandlers[type] !== 'undefined') {
+            if (bNoDetach) {
+                documentEventHandlers[type].fire(evt);
+            } else {
+                setTimeout(function () {
+                    // Fire deviceready on listeners that were registered before cordova.js was loaded.
+                    if (type === 'deviceready') {
+                        document.dispatchEvent(evt);
+                    }
+                    documentEventHandlers[type].fire(evt);
+                }, 0);
+            }
+        } else {
+            document.dispatchEvent(evt);
+        }
+    },
+    fireWindowEvent: function (type, data) {
+        var evt = createEvent(type, data);
+        if (typeof windowEventHandlers[type] !== 'undefined') {
+            setTimeout(function () {
+                windowEventHandlers[type].fire(evt);
+            }, 0);
+        } else {
+            window.dispatchEvent(evt);
+        }
+    },
+
+    /**
+     * Plugin callback mechanism.
+     */
+    // Randomize the starting callbackId to avoid collisions after refreshing or navigating.
+    // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.
+    callbackId: Math.floor(Math.random() * 2000000000),
+    callbacks: {},
+    callbackStatus: {
+        NO_RESULT: 0,
+        OK: 1,
+        CLASS_NOT_FOUND_EXCEPTION: 2,
+        ILLEGAL_ACCESS_EXCEPTION: 3,
+        INSTANTIATION_EXCEPTION: 4,
+        MALFORMED_URL_EXCEPTION: 5,
+        IO_EXCEPTION: 6,
+        INVALID_ACTION: 7,
+        JSON_EXCEPTION: 8,
+        ERROR: 9
+    },
+
+    /**
+     * Called by native code when returning successful result from an action.
+     */
+    callbackSuccess: function (callbackId, args) {
+        cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
+    },
+
+    /**
+     * Called by native code when returning error result from an action.
+     */
+    callbackError: function (callbackId, args) {
+        // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
+        // Derive success from status.
+        cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
+    },
+
+    /**
+     * Called by native code when returning the result from an action.
+     */
+    callbackFromNative: function (callbackId, isSuccess, status, args, keepCallback) {
+        try {
+            var callback = cordova.callbacks[callbackId];
+            if (callback) {
+                if (isSuccess && status === cordova.callbackStatus.OK) {
+                    callback.success && callback.success.apply(null, args);
+                } else if (!isSuccess) {
+                    callback.fail && callback.fail.apply(null, args);
+                }
+                /*
+                else
+                    Note, this case is intentionally not caught.
+                    this can happen if isSuccess is true, but callbackStatus is NO_RESULT
+                    which is used to remove a callback from the list without calling the callbacks
+                    typically keepCallback is false in this case
+                */
+                // Clear callback if not expecting any more results
+                if (!keepCallback) {
+                    delete cordova.callbacks[callbackId];
+                }
+            }
+        } catch (err) {
+            var msg = 'Error in ' + (isSuccess ? 'Success' : 'Error') + ' callbackId: ' + callbackId + ' : ' + err;
+            console && console.log && console.log(msg);
+            console && console.log && err.stack && console.log(err.stack);
+            cordova.fireWindowEvent('cordovacallbackerror', { 'message': msg });
+            throw err;
+        }
+    },
+    addConstructor: function (func) {
+        channel.onCordovaReady.subscribe(function () {
+            try {
+                func();
+            } catch (e) {
+                console.log('Failed to run constructor: ' + e);
+            }
+        });
+    }
+};
+
+module.exports = cordova;
+
+});
+
+// file: /Users/erisu/git/apache/cordova/cordova-android/cordova-js-src/android/nativeapiprovider.js
+define("cordova/android/nativeapiprovider", function(require, exports, module) {
+
+/**
+ * Exports the ExposedJsApi.java object if available, otherwise exports the PromptBasedNativeApi.
+ */
+
+var nativeApi = this._cordovaNative || require('cordova/android/promptbasednativeapi');
+var currentApi = nativeApi;
+
+module.exports = {
+    get: function() { return currentApi; },
+    setPreferPrompt: function(value) {
+        currentApi = value ? require('cordova/android/promptbasednativeapi') : nativeApi;
+    },
+    // Used only by tests.
+    set: function(value) {
+        currentApi = value;
+    }
+};
+
+});
+
+// file: /Users/erisu/git/apache/cordova/cordova-android/cordova-js-src/android/promptbasednativeapi.js
+define("cordova/android/promptbasednativeapi", function(require, exports, module) {
+
+/**
+ * Implements the API of ExposedJsApi.java, but uses prompt() to communicate.
+ * This is used pre-JellyBean, where addJavascriptInterface() is disabled.
+ */
+
+module.exports = {
+    exec: function(bridgeSecret, service, action, callbackId, argsJson) {
+        return prompt(argsJson, 'gap:'+JSON.stringify([bridgeSecret, service, action, callbackId]));
+    },
+    setNativeToJsBridgeMode: function(bridgeSecret, value) {
+        prompt(value, 'gap_bridge_mode:' + bridgeSecret);
+    },
+    retrieveJsMessages: function(bridgeSecret, fromOnlineEvent) {
+        return prompt(+fromOnlineEvent, 'gap_poll:' + bridgeSecret);
+    }
+};
+
+});
+
+// file: src/common/argscheck.js
+define("cordova/argscheck", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+
+var moduleExports = module.exports;
+
+var typeMap = {
+    'A': 'Array',
+    'D': 'Date',
+    'N': 'Number',
+    'S': 'String',
+    'F': 'Function',
+    'O': 'Object'
+};
+
+function extractParamName (callee, argIndex) {
+    return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex];
+}
+
+function checkArgs (spec, functionName, args, opt_callee) {
+    if (!moduleExports.enableChecks) {
+        return;
+    }
+    var errMsg = null;
+    var typeName;
+    for (var i = 0; i < spec.length; ++i) {
+        var c = spec.charAt(i);
+        var cUpper = c.toUpperCase();
+        var arg = args[i];
+        // Asterix means allow anything.
+        if (c === '*') {
+            continue;
+        }
+        typeName = utils.typeName(arg);
+        if ((arg === null || arg === undefined) && c === cUpper) {
+            continue;
+        }
+        if (typeName !== typeMap[cUpper]) {
+            errMsg = 'Expected ' + typeMap[cUpper];
+            break;
+        }
+    }
+    if (errMsg) {
+        errMsg += ', but got ' + typeName + '.';
+        errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
+        // Don't log when running unit tests.
+        if (typeof jasmine === 'undefined') {
+            console.error(errMsg);
+        }
+        throw TypeError(errMsg);
+    }
+}
+
+function getValue (value, defaultValue) {
+    return value === undefined ? defaultValue : value;
+}
+
+moduleExports.checkArgs = checkArgs;
+moduleExports.getValue = getValue;
+moduleExports.enableChecks = true;
+
+});
+
+// file: src/common/base64.js
+define("cordova/base64", function(require, exports, module) {
+
+var base64 = exports;
+
+base64.fromArrayBuffer = function (arrayBuffer) {
+    var array = new Uint8Array(arrayBuffer);
+    return uint8ToBase64(array);
+};
+
+base64.toArrayBuffer = function (str) {
+    var decodedStr = typeof atob !== 'undefined' ? atob(str) : Buffer.from(str, 'base64').toString('binary'); // eslint-disable-line no-undef
+    var arrayBuffer = new ArrayBuffer(decodedStr.length);
+    var array = new Uint8Array(arrayBuffer);
+    for (var i = 0, len = decodedStr.length; i < len; i++) {
+        array[i] = decodedStr.charCodeAt(i);
+    }
+    return arrayBuffer;
+};
+
+// ------------------------------------------------------------------------------
+
+/* This code is based on the performance tests at http://jsperf.com/b64tests
+ * This 12-bit-at-a-time algorithm was the best performing version on all
+ * platforms tested.
+ */
+
+var b64_6bit = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+var b64_12bit;
+
+var b64_12bitTable = function () {
+    b64_12bit = [];
+    for (var i = 0; i < 64; i++) {
+        for (var j = 0; j < 64; j++) {
+            b64_12bit[i * 64 + j] = b64_6bit[i] + b64_6bit[j];
+        }
+    }
+    b64_12bitTable = function () { return b64_12bit; };
+    return b64_12bit;
+};
+
+function uint8ToBase64 (rawData) {
+    var numBytes = rawData.byteLength;
+    var output = '';
+    var segment;
+    var table = b64_12bitTable();
+    for (var i = 0; i < numBytes - 2; i += 3) {
+        segment = (rawData[i] << 16) + (rawData[i + 1] << 8) + rawData[i + 2];
+        output += table[segment >> 12];
+        output += table[segment & 0xfff];
+    }
+    if (numBytes - i === 2) {
+        segment = (rawData[i] << 16) + (rawData[i + 1] << 8);
+        output += table[segment >> 12];
+        output += b64_6bit[(segment & 0xfff) >> 6];
+        output += '=';
+    } else if (numBytes - i === 1) {
+        segment = (rawData[i] << 16);
+        output += table[segment >> 12];
+        output += '==';
+    }
+    return output;
+}
+
+});
+
+// file: src/common/builder.js
+define("cordova/builder", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+
+function each (objects, func, context) {
+    for (var prop in objects) {
+        if (objects.hasOwnProperty(prop)) {
+            func.apply(context, [objects[prop], prop]);
+        }
+    }
+}
+
+function clobber (obj, key, value) {
+    exports.replaceHookForTesting(obj, key);
+    var needsProperty = false;
+    try {
+        obj[key] = value;
+    } catch (e) {
+        needsProperty = true;
+    }
+    // Getters can only be overridden by getters.
+    if (needsProperty || obj[key] !== value) {
+        utils.defineGetter(obj, key, function () {
+            return value;
+        });
+    }
+}
+
+function assignOrWrapInDeprecateGetter (obj, key, value, message) {
+    if (message) {
+        utils.defineGetter(obj, key, function () {
+            console.log(message);
+            delete obj[key];
+            clobber(obj, key, value);
+            return value;
+        });
+    } else {
+        clobber(obj, key, value);
+    }
+}
+
+function include (parent, objects, clobber, merge) {
+    each(objects, function (obj, key) {
+        try {
+            var result = obj.path ? require(obj.path) : {};
+
+            if (clobber) {
+                // Clobber if it doesn't exist.
+                if (typeof parent[key] === 'undefined') {
+                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+                } else if (typeof obj.path !== 'undefined') {
+                    // If merging, merge properties onto parent, otherwise, clobber.
+                    if (merge) {
+                        recursiveMerge(parent[key], result);
+                    } else {
+                        assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+                    }
+                }
+                result = parent[key];
+            } else {
+                // Overwrite if not currently defined.
+                if (typeof parent[key] === 'undefined') {
+                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+                } else {
+                    // Set result to what already exists, so we can build children into it if they exist.
+                    result = parent[key];
+                }
+            }
+
+            if (obj.children) {
+                include(result, obj.children, clobber, merge);
+            }
+        } catch (e) {
+            utils.alert('Exception building Cordova JS globals: ' + e + ' for key "' + key + '"');
+        }
+    });
+}
+
+/**
+ * Merge properties from one object onto another recursively.  Properties from
+ * the src object will overwrite existing target property.
+ *
+ * @param target Object to merge properties into.
+ * @param src Object to merge properties from.
+ */
+function recursiveMerge (target, src) {
+    for (var prop in src) {
+        if (src.hasOwnProperty(prop)) {
+            if (target.prototype && target.prototype.constructor === target) {
+                // If the target object is a constructor override off prototype.
+                clobber(target.prototype, prop, src[prop]);
+            } else {
+                if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {
+                    recursiveMerge(target[prop], src[prop]);
+                } else {
+                    clobber(target, prop, src[prop]);
+                }
+            }
+        }
+    }
+}
+
+exports.buildIntoButDoNotClobber = function (objects, target) {
+    include(target, objects, false, false);
+};
+exports.buildIntoAndClobber = function (objects, target) {
+    include(target, objects, true, false);
+};
+exports.buildIntoAndMerge = function (objects, target) {
+    include(target, objects, true, true);
+};
+exports.recursiveMerge = recursiveMerge;
+exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
+exports.replaceHookForTesting = function () {};
+
+});
+
+// file: src/common/channel.js
+define("cordova/channel", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+var nextGuid = 1;
+
+/**
+ * Custom pub-sub "channel" that can have functions subscribed to it
+ * This object is used to define and control firing of events for
+ * cordova initialization, as well as for custom events thereafter.
+ *
+ * The order of events during page load and Cordova startup is as follows:
+ *
+ * onDOMContentLoaded*         Internal event that is received when the web page is loaded and parsed.
+ * onNativeReady*              Internal event that indicates the Cordova native side is ready.
+ * onCordovaReady*             Internal event fired when all Cordova JavaScript objects have been created.
+ * onDeviceReady*              User event fired to indicate that Cordova is ready
+ * onResume                    User event fired to indicate a start/resume lifecycle event
+ * onPause                     User event fired to indicate a pause lifecycle event
+ *
+ * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
+ * All listeners that subscribe after the event is fired will be executed right away.
+ *
+ * The only Cordova events that user code should register for are:
+ *      deviceready           Cordova native code is initialized and Cordova APIs can be called from JavaScript
+ *      pause                 App has moved to background
+ *      resume                App has returned to foreground
+ *
+ * Listeners can be registered as:
+ *      document.addEventListener("deviceready", myDeviceReadyListener, false);
+ *      document.addEventListener("resume", myResumeListener, false);
+ *      document.addEventListener("pause", myPauseListener, false);
+ *
+ * The DOM lifecycle events should be used for saving and restoring state
+ *      window.onload
+ *      window.onunload
+ *
+ */
+
+/**
+ * Channel
+ * @constructor
+ * @param type  String the channel name
+ */
+var Channel = function (type, sticky) {
+    this.type = type;
+    // Map of guid -> function.
+    this.handlers = {};
+    // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
+    this.state = sticky ? 1 : 0;
+    // Used in sticky mode to remember args passed to fire().
+    this.fireArgs = null;
+    // Used by onHasSubscribersChange to know if there are any listeners.
+    this.numHandlers = 0;
+    // Function that is called when the first listener is subscribed, or when
+    // the last listener is unsubscribed.
+    this.onHasSubscribersChange = null;
+};
+var channel = {
+    /**
+     * Calls the provided function only after all of the channels specified
+     * have been fired. All channels must be sticky channels.
+     */
+    join: function (h, c) {
+        var len = c.length;
+        var i = len;
+        var f = function () {
+            if (!(--i)) h();
+        };
+        for (var j = 0; j < len; j++) {
+            if (c[j].state === 0) {
+                throw Error('Can only use join with sticky channels.');
+            }
+            c[j].subscribe(f);
+        }
+        if (!len) h();
+    },
+    /* eslint-disable no-return-assign */
+    create: function (type) {
+        return channel[type] = new Channel(type, false);
+    },
+    createSticky: function (type) {
+        return channel[type] = new Channel(type, true);
+    },
+    /* eslint-enable no-return-assign */
+    /**
+     * cordova Channels that must fire before "deviceready" is fired.
+     */
+    deviceReadyChannelsArray: [],
+    deviceReadyChannelsMap: {},
+
+    /**
+     * Indicate that a feature needs to be initialized before it is ready to be used.
+     * This holds up Cordova's "deviceready" event until the feature has been initialized
+     * and Cordova.initComplete(feature) is called.
+     *
+     * @param feature {String}     The unique feature name
+     */
+    waitForInitialization: function (feature) {
+        if (feature) {
+            var c = channel[feature] || this.createSticky(feature);
+            this.deviceReadyChannelsMap[feature] = c;
+            this.deviceReadyChannelsArray.push(c);
+        }
+    },
+
+    /**
+     * Indicate that initialization code has completed and the feature is ready to be used.
+     *
+     * @param feature {String}     The unique feature name
+     */
+    initializationComplete: function (feature) {
+        var c = this.deviceReadyChannelsMap[feature];
+        if (c) {
+            c.fire();
+        }
+    }
+};
+
+function checkSubscriptionArgument (argument) {
+    if (typeof argument !== 'function' && typeof argument.handleEvent !== 'function') {
+        throw new Error(
+            'Must provide a function or an EventListener object ' +
+                'implementing the handleEvent interface.'
+        );
+    }
+}
+
+/**
+ * Subscribes the given function to the channel. Any time that
+ * Channel.fire is called so too will the function.
+ * Optionally specify an execution context for the function
+ * and a guid that can be used to stop subscribing to the channel.
+ * Returns the guid.
+ */
+Channel.prototype.subscribe = function (eventListenerOrFunction, eventListener) {
+    checkSubscriptionArgument(eventListenerOrFunction);
+    var handleEvent, guid;
+
+    if (eventListenerOrFunction && typeof eventListenerOrFunction === 'object') {
+        // Received an EventListener object implementing the handleEvent interface
+        handleEvent = eventListenerOrFunction.handleEvent;
+        eventListener = eventListenerOrFunction;
+    } else {
+        // Received a function to handle event
+        handleEvent = eventListenerOrFunction;
+    }
+
+    if (this.state === 2) {
+        handleEvent.apply(eventListener || this, this.fireArgs);
+        return;
+    }
+
+    guid = eventListenerOrFunction.observer_guid;
+    if (typeof eventListener === 'object') {
+        handleEvent = utils.close(eventListener, handleEvent);
+    }
+
+    if (!guid) {
+        // First time any channel has seen this subscriber
+        guid = '' + nextGuid++;
+    }
+    handleEvent.observer_guid = guid;
+    eventListenerOrFunction.observer_guid = guid;
+
+    // Don't add the same handler more than once.
+    if (!this.handlers[guid]) {
+        this.handlers[guid] = handleEvent;
+        this.numHandlers++;
+        if (this.numHandlers === 1) {
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+/**
+ * Unsubscribes the function with the given guid from the channel.
+ */
+Channel.prototype.unsubscribe = function (eventListenerOrFunction) {
+    checkSubscriptionArgument(eventListenerOrFunction);
+    var handleEvent, guid, handler;
+
+    if (eventListenerOrFunction && typeof eventListenerOrFunction === 'object') {
+        // Received an EventListener object implementing the handleEvent interface
+        handleEvent = eventListenerOrFunction.handleEvent;
+    } else {
+        // Received a function to handle event
+        handleEvent = eventListenerOrFunction;
+    }
+
+    guid = handleEvent.observer_guid;
+    handler = this.handlers[guid];
+    if (handler) {
+        delete this.handlers[guid];
+        this.numHandlers--;
+        if (this.numHandlers === 0) {
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+/**
+ * Calls all functions subscribed to this channel.
+ */
+Channel.prototype.fire = function (e) {
+    var fail = false; // eslint-disable-line no-unused-vars
+    var fireArgs = Array.prototype.slice.call(arguments);
+    // Apply stickiness.
+    if (this.state === 1) {
+        this.state = 2;
+        this.fireArgs = fireArgs;
+    }
+    if (this.numHandlers) {
+        // Copy the values first so that it is safe to modify it from within
+        // callbacks.
+        var toCall = [];
+        for (var item in this.handlers) {
+            toCall.push(this.handlers[item]);
+        }
+        for (var i = 0; i < toCall.length; ++i) {
+            toCall[i].apply(this, fireArgs);
+        }
+        if (this.state === 2 && this.numHandlers) {
+            this.numHandlers = 0;
+            this.handlers = {};
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+// defining them here so they are ready super fast!
+// DOM event that is received when the web page is loaded and parsed.
+channel.createSticky('onDOMContentLoaded');
+
+// Event to indicate the Cordova native side is ready.
+channel.createSticky('onNativeReady');
+
+// Event to indicate that all Cordova JavaScript objects have been created
+// and it's time to run plugin constructors.
+channel.createSticky('onCordovaReady');
+
+// Event to indicate that all automatically loaded JS plugins are loaded and ready.
+// FIXME remove this
+channel.createSticky('onPluginsReady');
+
+// Event to indicate that Cordova is ready
+channel.createSticky('onDeviceReady');
+
+// Event to indicate a resume lifecycle event
+channel.create('onResume');
+
+// Event to indicate a pause lifecycle event
+channel.create('onPause');
+
+// Channels that must fire before "deviceready" is fired.
+channel.waitForInitialization('onCordovaReady');
+channel.waitForInitialization('onDOMContentLoaded');
+
+module.exports = channel;
+
+});
+
+// file: /Users/erisu/git/apache/cordova/cordova-android/cordova-js-src/exec.js
+define("cordova/exec", function(require, exports, module) {
+
+/**
+ * Execute a cordova command.  It is up to the native side whether this action
+ * is synchronous or asynchronous.  The native side can return:
+ *      Synchronous: PluginResult object as a JSON string
+ *      Asynchronous: Empty string ""
+ * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
+ * depending upon the result of the action.
+ *
+ * @param {Function} success    The success callback
+ * @param {Function} fail       The fail callback
+ * @param {String} service      The name of the service to use
+ * @param {String} action       Action to be run in cordova
+ * @param {String[]} [args]     Zero or more arguments to pass to the method
+ */
+var cordova = require('cordova'),
+    nativeApiProvider = require('cordova/android/nativeapiprovider'),
+    utils = require('cordova/utils'),
+    base64 = require('cordova/base64'),
+    channel = require('cordova/channel'),
+    jsToNativeModes = {
+        PROMPT: 0,
+        JS_OBJECT: 1
+    },
+    nativeToJsModes = {
+        // Polls for messages using the JS->Native bridge.
+        POLLING: 0,
+        // For LOAD_URL to be viable, it would need to have a work-around for
+        // the bug where the soft-keyboard gets dismissed when a message is sent.
+        LOAD_URL: 1,
+        // For the ONLINE_EVENT to be viable, it would need to intercept all event
+        // listeners (both through addEventListener and window.ononline) as well
+        // as set the navigator property itself.
+        ONLINE_EVENT: 2,
+        EVAL_BRIDGE: 3
+    },
+    jsToNativeBridgeMode,  // Set lazily.
+    nativeToJsBridgeMode = nativeToJsModes.EVAL_BRIDGE,
+    pollEnabled = false,
+    bridgeSecret = -1;
+
+var messagesFromNative = [];
+var isProcessing = false;
+var resolvedPromise = typeof Promise == 'undefined' ? null : Promise.resolve();
+var nextTick = resolvedPromise ? function(fn) { resolvedPromise.then(fn); } : function(fn) { setTimeout(fn); };
+
+function androidExec(success, fail, service, action, args) {
+    if (bridgeSecret < 0) {
+        // If we ever catch this firing, we'll need to queue up exec()s
+        // and fire them once we get a secret. For now, I don't think
+        // it's possible for exec() to be called since plugins are parsed but
+        // not run until until after onNativeReady.
+        throw new Error('exec() called without bridgeSecret');
+    }
+    // Set default bridge modes if they have not already been set.
+    // By default, we use the failsafe, since addJavascriptInterface breaks too often
+    if (jsToNativeBridgeMode === undefined) {
+        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
+    }
+
+    // If args is not provided, default to an empty array
+    args = args || [];
+
+    // Process any ArrayBuffers in the args into a string.
+    for (var i = 0; i < args.length; i++) {
+        if (utils.typeName(args[i]) == 'ArrayBuffer') {
+            args[i] = base64.fromArrayBuffer(args[i]);
+        }
+    }
+
+    var callbackId = service + cordova.callbackId++,
+        argsJson = JSON.stringify(args);
+    if (success || fail) {
+        cordova.callbacks[callbackId] = {success:success, fail:fail};
+    }
+
+    var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);
+    // If argsJson was received by Java as null, try again with the PROMPT bridge mode.
+    // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2.  See CB-2666.
+    if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && msgs === "@Null arguments.") {
+        androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
+        androidExec(success, fail, service, action, args);
+        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
+    } else if (msgs) {
+        messagesFromNative.push(msgs);
+        // Always process async to avoid exceptions messing up stack.
+        nextTick(processMessages);
+    }
+}
+
+androidExec.init = function() {
+    bridgeSecret = +prompt('', 'gap_init:' + nativeToJsBridgeMode);
+    channel.onNativeReady.fire();
+};
+
+function pollOnceFromOnlineEvent() {
+    pollOnce(true);
+}
+
+function pollOnce(opt_fromOnlineEvent) {
+    if (bridgeSecret < 0) {
+        // This can happen when the NativeToJsMessageQueue resets the online state on page transitions.
+        // We know there's nothing to retrieve, so no need to poll.
+        return;
+    }
+    var msgs = nativeApiProvider.get().retrieveJsMessages(bridgeSecret, !!opt_fromOnlineEvent);
+    if (msgs) {
+        messagesFromNative.push(msgs);
+        // Process sync since we know we're already top-of-stack.
+        processMessages();
+    }
+}
+
+function pollingTimerFunc() {
+    if (pollEnabled) {
+        pollOnce();
+        setTimeout(pollingTimerFunc, 50);
+    }
+}
+
+function hookOnlineApis() {
+    function proxyEvent(e) {
+        cordova.fireWindowEvent(e.type);
+    }
+    // The network module takes care of firing online and offline events.
+    // It currently fires them only on document though, so we bridge them
+    // to window here (while first listening for exec()-releated online/offline
+    // events).
+    window.addEventListener('online', pollOnceFromOnlineEvent, false);
+    window.addEventListener('offline', pollOnceFromOnlineEvent, false);
+    cordova.addWindowEventHandler('online');
+    cordova.addWindowEventHandler('offline');
+    document.addEventListener('online', proxyEvent, false);
+    document.addEventListener('offline', proxyEvent, false);
+}
+
+hookOnlineApis();
+
+androidExec.jsToNativeModes = jsToNativeModes;
+androidExec.nativeToJsModes = nativeToJsModes;
+
+androidExec.setJsToNativeBridgeMode = function(mode) {
+    if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {
+        mode = jsToNativeModes.PROMPT;
+    }
+    nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);
+    jsToNativeBridgeMode = mode;
+};
+
+androidExec.setNativeToJsBridgeMode = function(mode) {
+    if (mode == nativeToJsBridgeMode) {
+        return;
+    }
+    if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {
+        pollEnabled = false;
+    }
+
+    nativeToJsBridgeMode = mode;
+    // Tell the native side to switch modes.
+    // Otherwise, it will be set by androidExec.init()
+    if (bridgeSecret >= 0) {
+        nativeApiProvider.get().setNativeToJsBridgeMode(bridgeSecret, mode);
+    }
+
+    if (mode == nativeToJsModes.POLLING) {
+        pollEnabled = true;
+        setTimeout(pollingTimerFunc, 1);
+    }
+};
+
+function buildPayload(payload, message) {
+    var payloadKind = message.charAt(0);
+    if (payloadKind == 's') {
+        payload.push(message.slice(1));
+    } else if (payloadKind == 't') {
+        payload.push(true);
+    } else if (payloadKind == 'f') {
+        payload.push(false);
+    } else if (payloadKind == 'N') {
+        payload.push(null);
+    } else if (payloadKind == 'n') {
+        payload.push(+message.slice(1));
+    } else if (payloadKind == 'A') {
+        var data = message.slice(1);
+        payload.push(base64.toArrayBuffer(data));
+    } else if (payloadKind == 'S') {
+        payload.push(window.atob(message.slice(1)));
+    } else if (payloadKind == 'M') {
+        var multipartMessages = message.slice(1);
+        while (multipartMessages !== "") {
+            var spaceIdx = multipartMessages.indexOf(' ');
+            var msgLen = +multipartMessages.slice(0, spaceIdx);
+            var multipartMessage = multipartMessages.substr(spaceIdx + 1, msgLen);
+            multipartMessages = multipartMessages.slice(spaceIdx + msgLen + 1);
+            buildPayload(payload, multipartMessage);
+        }
+    } else {
+        payload.push(JSON.parse(message));
+    }
+}
+
+// Processes a single message, as encoded by NativeToJsMessageQueue.java.
+function processMessage(message) {
+    var firstChar = message.charAt(0);
+    if (firstChar == 'J') {
+        // This is deprecated on the .java side. It doesn't work with CSP enabled.
+        eval(message.slice(1));
+    } else if (firstChar == 'S' || firstChar == 'F') {
+        var success = firstChar == 'S';
+        var keepCallback = message.charAt(1) == '1';
+        var spaceIdx = message.indexOf(' ', 2);
+        var status = +message.slice(2, spaceIdx);
+        var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);
+        var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);
+        var payloadMessage = message.slice(nextSpaceIdx + 1);
+        var payload = [];
+        buildPayload(payload, payloadMessage);
+        cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);
+    } else {
+        console.log("processMessage failed: invalid message: " + JSON.stringify(message));
+    }
+}
+
+function processMessages() {
+    // Check for the reentrant case.
+    if (isProcessing) {
+        return;
+    }
+    if (messagesFromNative.length === 0) {
+        return;
+    }
+    isProcessing = true;
+    try {
+        var msg = popMessageFromQueue();
+        // The Java side can send a * message to indicate that it
+        // still has messages waiting to be retrieved.
+        if (msg == '*' && messagesFromNative.length === 0) {
+            nextTick(pollOnce);
+            return;
+        }
+        processMessage(msg);
+    } finally {
+        isProcessing = false;
+        if (messagesFromNative.length > 0) {
+            nextTick(processMessages);
+        }
+    }
+}
+
+function popMessageFromQueue() {
+    var messageBatch = messagesFromNative.shift();
+    if (messageBatch == '*') {
+        return '*';
+    }
+
+    var spaceIdx = messageBatch.indexOf(' ');
+    var msgLen = +messageBatch.slice(0, spaceIdx);
+    var message = messageBatch.substr(spaceIdx + 1, msgLen);
+    messageBatch = messageBatch.slice(spaceIdx + msgLen + 1);
+    if (messageBatch) {
+        messagesFromNative.unshift(messageBatch);
+    }
+    return message;
+}
+
+module.exports = androidExec;
+
+});
+
+// file: src/common/exec/proxy.js
+define("cordova/exec/proxy", function(require, exports, module) {
+
+// internal map of proxy function
+var CommandProxyMap = {};
+
+module.exports = {
+
+    // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);
+    add: function (id, proxyObj) {
+        console.log('adding proxy for ' + id);
+        CommandProxyMap[id] = proxyObj;
+        return proxyObj;
+    },
+
+    // cordova.commandProxy.remove("Accelerometer");
+    remove: function (id) {
+        var proxy = CommandProxyMap[id];
+        delete CommandProxyMap[id];
+        CommandProxyMap[id] = null;
+        return proxy;
+    },
+
+    get: function (service, action) {
+        return (CommandProxyMap[service] ? CommandProxyMap[service][action] : null);
+    }
+};
+
+});
+
+// file: src/common/init.js
+define("cordova/init", function(require, exports, module) {
+
+var channel = require('cordova/channel');
+var cordova = require('cordova');
+var modulemapper = require('cordova/modulemapper');
+var platform = require('cordova/platform');
+var pluginloader = require('cordova/pluginloader');
+var utils = require('cordova/utils');
+
+var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady];
+
+function logUnfiredChannels (arr) {
+    for (var i = 0; i < arr.length; ++i) {
+        if (arr[i].state !== 2) {
+            console.log('Channel not fired: ' + arr[i].type);
+        }
+    }
+}
+
+window.setTimeout(function () {
+    if (channel.onDeviceReady.state !== 2) {
+        console.log('deviceready has not fired after 5 seconds.');
+        logUnfiredChannels(platformInitChannelsArray);
+        logUnfiredChannels(channel.deviceReadyChannelsArray);
+    }
+}, 5000);
+
+// Replace navigator before any modules are required(), to ensure it happens as soon as possible.
+// We replace it so that properties that can't be clobbered can instead be overridden.
+function replaceNavigator (origNavigator) {
+    var CordovaNavigator = function () {};
+    CordovaNavigator.prototype = origNavigator;
+    var newNavigator = new CordovaNavigator();
+    // This work-around really only applies to new APIs that are newer than Function.bind.
+    // Without it, APIs such as getGamepads() break.
+    if (CordovaNavigator.bind) {
+        for (var key in origNavigator) {
+            if (typeof origNavigator[key] === 'function') {
+                newNavigator[key] = origNavigator[key].bind(origNavigator);
+            } else {
+                (function (k) {
+                    utils.defineGetterSetter(newNavigator, key, function () {
+                        return origNavigator[k];
+                    });
+                })(key);
+            }
+        }
+    }
+    return newNavigator;
+}
+
+if (window.navigator) {
+    window.navigator = replaceNavigator(window.navigator);
+}
+
+if (!window.console) {
+    window.console = {
+        log: function () {}
+    };
+}
+if (!window.console.warn) {
+    window.console.warn = function (msg) {
+        this.log('warn: ' + msg);
+    };
+}
+
+// Register pause, resume and deviceready channels as events on document.
+channel.onPause = cordova.addDocumentEventHandler('pause');
+channel.onResume = cordova.addDocumentEventHandler('resume');
+channel.onActivated = cordova.addDocumentEventHandler('activated');
+channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
+
+// Listen for DOMContentLoaded and notify our channel subscribers.
+if (document.readyState === 'complete' || document.readyState === 'interactive') {
+    channel.onDOMContentLoaded.fire();
+} else {
+    document.addEventListener('DOMContentLoaded', function () {
+        channel.onDOMContentLoaded.fire();
+    }, false);
+}
+
+// _nativeReady is global variable that the native side can set
+// to signify that the native code is ready. It is a global since
+// it may be called before any cordova JS is ready.
+if (window._nativeReady) {
+    channel.onNativeReady.fire();
+}
+
+modulemapper.clobbers('cordova', 'cordova');
+modulemapper.clobbers('cordova/exec', 'cordova.exec');
+modulemapper.clobbers('cordova/exec', 'Cordova.exec');
+
+// Call the platform-specific initialization.
+platform.bootstrap && platform.bootstrap();
+
+// Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js.
+// The delay allows the attached modules to be defined before the plugin loader looks for them.
+setTimeout(function () {
+    pluginloader.load(function () {
+        channel.onPluginsReady.fire();
+    });
+}, 0);
+
+/**
+ * Create all cordova objects once native side is ready.
+ */
+channel.join(function () {
+    modulemapper.mapModules(window);
+
+    platform.initialize && platform.initialize();
+
+    // Fire event to notify that all objects are created
+    channel.onCordovaReady.fire();
+
+    // Fire onDeviceReady event once page has fully loaded, all
+    // constructors have run and cordova info has been received from native
+    // side.
+    channel.join(function () {
+        require('cordova').fireDocumentEvent('deviceready');
+    }, channel.deviceReadyChannelsArray);
+
+}, platformInitChannelsArray);
+
+});
+
+// file: src/common/modulemapper.js
+define("cordova/modulemapper", function(require, exports, module) {
+
+var builder = require('cordova/builder');
+var moduleMap = define.moduleMap; // eslint-disable-line no-undef
+var symbolList;
+var deprecationMap;
+
+exports.reset = function () {
+    symbolList = [];
+    deprecationMap = {};
+};
+
+function addEntry (strategy, moduleName, symbolPath, opt_deprecationMessage) {
+    if (!(moduleName in moduleMap)) {
+        throw new Error('Module ' + moduleName + ' does not exist.');
+    }
+    symbolList.push(strategy, moduleName, symbolPath);
+    if (opt_deprecationMessage) {
+        deprecationMap[symbolPath] = opt_deprecationMessage;
+    }
+}
+
+// Note: Android 2.3 does have Function.bind().
+exports.clobbers = function (moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('c', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.merges = function (moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('m', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.defaults = function (moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('d', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.runs = function (moduleName) {
+    addEntry('r', moduleName, null);
+};
+
+function prepareNamespace (symbolPath, context) {
+    if (!symbolPath) {
+        return context;
+    }
+    var parts = symbolPath.split('.');
+    var cur = context;
+    for (var i = 0, part; part = parts[i]; ++i) { // eslint-disable-line no-cond-assign
+        cur = cur[part] = cur[part] || {};
+    }
+    return cur;
+}
+
+exports.mapModules = function (context) {
+    var origSymbols = {};
+    context.CDV_origSymbols = origSymbols;
+    for (var i = 0, len = symbolList.length; i < len; i += 3) {
+        var strategy = symbolList[i];
+        var moduleName = symbolList[i + 1];
+        var module = require(moduleName);
+        // <runs/>
+        if (strategy === 'r') {
+            continue;
+        }
+        var symbolPath = symbolList[i + 2];
+        var lastDot = symbolPath.lastIndexOf('.');
+        var namespace = symbolPath.substr(0, lastDot);
+        var lastName = symbolPath.substr(lastDot + 1);
+
+        var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;
+        var parentObj = prepareNamespace(namespace, context);
+        var target = parentObj[lastName];
+
+        if (strategy === 'm' && target) {
+            builder.recursiveMerge(target, module);
+        } else if ((strategy === 'd' && !target) || (strategy !== 'd')) {
+            if (!(symbolPath in origSymbols)) {
+                origSymbols[symbolPath] = target;
+            }
+            builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
+        }
+    }
+};
+
+exports.getOriginalSymbol = function (context, symbolPath) {
+    var origSymbols = context.CDV_origSymbols;
+    if (origSymbols && (symbolPath in origSymbols)) {
+        return origSymbols[symbolPath];
+    }
+    var parts = symbolPath.split('.');
+    var obj = context;
+    for (var i = 0; i < parts.length; ++i) {
+        obj = obj && obj[parts[i]];
+    }
+    return obj;
+};
+
+exports.reset();
+
+});
+
+// file: /Users/erisu/git/apache/cordova/cordova-android/cordova-js-src/platform.js
+define("cordova/platform", function(require, exports, module) {
+
+// The last resume event that was received that had the result of a plugin call.
+var lastResumeEvent = null;
+
+module.exports = {
+    id: 'android',
+    bootstrap: function() {
+        var channel = require('cordova/channel'),
+            cordova = require('cordova'),
+            exec = require('cordova/exec'),
+            modulemapper = require('cordova/modulemapper');
+
+        // Get the shared secret needed to use the bridge.
+        exec.init();
+
+        // TODO: Extract this as a proper plugin.
+        modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');
+
+        var APP_PLUGIN_NAME = Number(cordova.platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';
+
+        // Inject a listener for the backbutton on the document.
+        var backButtonChannel = cordova.addDocumentEventHandler('backbutton');
+        backButtonChannel.onHasSubscribersChange = function() {
+            // If we just attached the first handler or detached the last handler,
+            // let native know we need to override the back button.
+            exec(null, null, APP_PLUGIN_NAME, "overrideBackbutton", [this.numHandlers == 1]);
+        };
+
+        // Add hardware MENU and SEARCH button handlers
+        cordova.addDocumentEventHandler('menubutton');
+        cordova.addDocumentEventHandler('searchbutton');
+
+        function bindButtonChannel(buttonName) {
+            // generic button bind used for volumeup/volumedown buttons
+            var volumeButtonChannel = cordova.addDocumentEventHandler(buttonName + 'button');
+            volumeButtonChannel.onHasSubscribersChange = function() {
+                exec(null, null, APP_PLUGIN_NAME, "overrideButton", [buttonName, this.numHandlers == 1]);
+            };
+        }
+        // Inject a listener for the volume buttons on the document.
+        bindButtonChannel('volumeup');
+        bindButtonChannel('volumedown');
+
+        // The resume event is not "sticky", but it is possible that the event
+        // will contain the result of a plugin call. We need to ensure that the
+        // plugin result is delivered even after the event is fired (CB-10498)
+        var cordovaAddEventListener = document.addEventListener;
+
+        document.addEventListener = function(evt, handler, capture) {
+            cordovaAddEventListener(evt, handler, capture);
+
+            if (evt === 'resume' && lastResumeEvent) {
+                handler(lastResumeEvent);
+            }
+        };
+
+        // Let native code know we are all done on the JS side.
+        // Native code will then un-hide the WebView.
+        channel.onCordovaReady.subscribe(function() {
+            exec(onMessageFromNative, null, APP_PLUGIN_NAME, 'messageChannel', []);
+            exec(null, null, APP_PLUGIN_NAME, "show", []);
+        });
+    }
+};
+
+function onMessageFromNative(msg) {
+    var cordova = require('cordova');
+    var action = msg.action;
+
+    switch (action)
+    {
+        // Button events
+        case 'backbutton':
+        case 'menubutton':
+        case 'searchbutton':
+        // App life cycle events
+        case 'pause':
+        // Volume events
+        case 'volumedownbutton':
+        case 'volumeupbutton':
+            cordova.fireDocumentEvent(action);
+            break;
+        case 'resume':
+            if(arguments.length > 1 && msg.pendingResult) {
+                if(arguments.length === 2) {
+                    msg.pendingResult.result = arguments[1];
+                } else {
+                    // The plugin returned a multipart message
+                    var res = [];
+                    for(var i = 1; i < arguments.length; i++) {
+                        res.push(arguments[i]);
+                    }
+                    msg.pendingResult.result = res;
+                }
+
+                // Save the plugin result so that it can be delivered to the js
+                // even if they miss the initial firing of the event
+                lastResumeEvent = msg;
+            }
+            cordova.fireDocumentEvent(action, msg);
+            break;
+        default:
+            throw new Error('Unknown event action ' + action);
+    }
+}
+
+});
+
+// file: /Users/erisu/git/apache/cordova/cordova-android/cordova-js-src/plugin/android/app.js
+define("cordova/plugin/android/app", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+var APP_PLUGIN_NAME = Number(require('cordova').platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';
+
+module.exports = {
+    /**
+    * Clear the resource cache.
+    */
+    clearCache:function() {
+        exec(null, null, APP_PLUGIN_NAME, "clearCache", []);
+    },
+
+    /**
+    * Load the url into the webview or into new browser instance.
+    *
+    * @param url           The URL to load
+    * @param props         Properties that can be passed in to the activity:
+    *      wait: int                           => wait msec before loading URL
+    *      loadingDialog: "Title,Message"      => display a native loading dialog
+    *      loadUrlTimeoutValue: int            => time in msec to wait before triggering a timeout error
+    *      clearHistory: boolean              => clear webview history (default=false)
+    *      openExternal: boolean              => open in a new browser (default=false)
+    *
+    * Example:
+    *      navigator.app.loadUrl("http://server/myapp/index.html", {wait:2000, loadingDialog:"Wait,Loading App", loadUrlTimeoutValue: 60000});
+    */
+    loadUrl:function(url, props) {
+        exec(null, null, APP_PLUGIN_NAME, "loadUrl", [url, props]);
+    },
+
+    /**
+    * Cancel loadUrl that is waiting to be loaded.
+    */
+    cancelLoadUrl:function() {
+        exec(null, null, APP_PLUGIN_NAME, "cancelLoadUrl", []);
+    },
+
+    /**
+    * Clear web history in this web view.
+    * Instead of BACK button loading the previous web page, it will exit the app.
+    */
+    clearHistory:function() {
+        exec(null, null, APP_PLUGIN_NAME, "clearHistory", []);
+    },
+
+    /**
+    * Go to previous page displayed.
+    * This is the same as pressing the backbutton on Android device.
+    */
+    backHistory:function() {
+        exec(null, null, APP_PLUGIN_NAME, "backHistory", []);
+    },
+
+    /**
+    * Override the default behavior of the Android back button.
+    * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
+    *
+    * Note: The user should not have to call this method.  Instead, when the user
+    *       registers for the "backbutton" event, this is automatically done.
+    *
+    * @param override        T=override, F=cancel override
+    */
+    overrideBackbutton:function(override) {
+        exec(null, null, APP_PLUGIN_NAME, "overrideBackbutton", [override]);
+    },
+
+    /**
+    * Override the default behavior of the Android volume button.
+    * If overridden, when the volume button is pressed, the "volume[up|down]button"
+    * JavaScript event will be fired.
+    *
+    * Note: The user should not have to call this method.  Instead, when the user
+    *       registers for the "volume[up|down]button" event, this is automatically done.
+    *
+    * @param button          volumeup, volumedown
+    * @param override        T=override, F=cancel override
+    */
+    overrideButton:function(button, override) {
+        exec(null, null, APP_PLUGIN_NAME, "overrideButton", [button, override]);
+    },
+
+    /**
+    * Exit and terminate the application.
+    */
+    exitApp:function() {
+        return exec(null, null, APP_PLUGIN_NAME, "exitApp", []);
+    }
+};
+
+});
+
+// file: src/common/pluginloader.js
+define("cordova/pluginloader", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+// Helper function to inject a <script> tag.
+// Exported for testing.
+exports.injectScript = function (url, onload, onerror) {
+    var script = document.createElement('script');
+    // onload fires even when script fails loads with an error.
+    script.onload = onload;
+    // onerror fires for malformed URLs.
+    script.onerror = onerror;
+    script.src = url;
+    document.head.appendChild(script);
+};
+
+function injectIfNecessary (id, url, onload, onerror) {
+    onerror = onerror || onload;
+    if (id in define.moduleMap) { // eslint-disable-line no-undef
+        onload();
+    } else {
+        exports.injectScript(url, function () {
+            if (id in define.moduleMap) { // eslint-disable-line no-undef
+                onload();
+            } else {
+                onerror();
+            }
+        }, onerror);
+    }
+}
+
+function onScriptLoadingComplete (moduleList, finishPluginLoading) {
+    // Loop through all the plugins and then through their clobbers and merges.
+    for (var i = 0, module; module = moduleList[i]; i++) { // eslint-disable-line no-cond-assign
+        if (module.clobbers && module.clobbers.length) {
+            for (var j = 0; j < module.clobbers.length; j++) {
+                modulemapper.clobbers(module.id, module.clobbers[j]);
+            }
+        }
+
+        if (module.merges && module.merges.length) {
+            for (var k = 0; k < module.merges.length; k++) {
+                modulemapper.merges(module.id, module.merges[k]);
+            }
+        }
+
+        // Finally, if runs is truthy we want to simply require() the module.
+        if (module.runs) {
+            modulemapper.runs(module.id);
+        }
+    }
+
+    finishPluginLoading();
+}
+
+// Handler for the cordova_plugins.js content.
+// See plugman's plugin_loader.js for the details of this object.
+// This function is only called if the really is a plugins array that isn't empty.
+// Otherwise the onerror response handler will just call finishPluginLoading().
+function handlePluginsObject (path, moduleList, finishPluginLoading) {
+    // Now inject the scripts.
+    var scriptCounter = moduleList.length;
+
+    if (!scriptCounter) {
+        finishPluginLoading();
+        return;
+    }
+    function scriptLoadedCallback () {
+        if (!--scriptCounter) {
+            onScriptLoadingComplete(moduleList, finishPluginLoading);
+        }
+    }
+
+    for (var i = 0; i < moduleList.length; i++) {
+        injectIfNecessary(moduleList[i].id, path + moduleList[i].file, scriptLoadedCallback);
+    }
+}
+
+function findCordovaPath () {
+    var path = null;
+    var scripts = document.getElementsByTagName('script');
+    var term = '/cordova.js';
+    for (var n = scripts.length - 1; n > -1; n--) {
+        var src = scripts[n].src.replace(/\?.*$/, ''); // Strip any query param (CB-6007).
+        if (src.indexOf(term) === (src.length - term.length)) {
+            path = src.substring(0, src.length - term.length) + '/';
+            break;
+        }
+    }
+    return path;
+}
+
+// Tries to load all plugins' js-modules.
+// This is an async process, but onDeviceReady is blocked on onPluginsReady.
+// onPluginsReady is fired when there are no plugins to load, or they are all done.
+exports.load = function (callback) {
+    var pathPrefix = findCordovaPath();
+    if (pathPrefix === null) {
+        console.log('Could not find cordova.js script tag. Plugin loading may fail.');
+        pathPrefix = '';
+    }
+    injectIfNecessary('cordova/plugin_list', pathPrefix + 'cordova_plugins.js', function () {
+        var moduleList = require('cordova/plugin_list');
+        handlePluginsObject(pathPrefix, moduleList, callback);
+    }, callback);
+};
+
+});
+
+// file: src/common/urlutil.js
+define("cordova/urlutil", function(require, exports, module) {
+
+/**
+ * For already absolute URLs, returns what is passed in.
+ * For relative URLs, converts them to absolute ones.
+ */
+exports.makeAbsolute = function makeAbsolute (url) {
+    var anchorEl = document.createElement('a');
+    anchorEl.href = url;
+    return anchorEl.href;
+};
+
+});
+
+// file: src/common/utils.js
+define("cordova/utils", function(require, exports, module) {
+
+var utils = exports;
+
+/**
+ * Defines a property getter / setter for obj[key].
+ */
+utils.defineGetterSetter = function (obj, key, getFunc, opt_setFunc) {
+    if (Object.defineProperty) {
+        var desc = {
+            get: getFunc,
+            configurable: true
+        };
+        if (opt_setFunc) {
+            desc.set = opt_setFunc;
+        }
+        Object.defineProperty(obj, key, desc);
+    } else {
+        obj.__defineGetter__(key, getFunc);
+        if (opt_setFunc) {
+            obj.__defineSetter__(key, opt_setFunc);
+        }
+    }
+};
+
+/**
+ * Defines a property getter for obj[key].
+ */
+utils.defineGetter = utils.defineGetterSetter;
+
+utils.arrayIndexOf = function (a, item) {
+    if (a.indexOf) {
+        return a.indexOf(item);
+    }
+    var len = a.length;
+    for (var i = 0; i < len; ++i) {
+        if (a[i] === item) {
+            return i;
+        }
+    }
+    return -1;
+};
+
+/**
+ * Returns whether the item was found in the array.
+ */
+utils.arrayRemove = function (a, item) {
+    var index = utils.arrayIndexOf(a, item);
+    if (index !== -1) {
+        a.splice(index, 1);
+    }
+    return index !== -1;
+};
+
+utils.typeName = function (val) {
+    return Object.prototype.toString.call(val).slice(8, -1);
+};
+
+/**
+ * Returns an indication of whether the argument is an array or not
+ */
+utils.isArray = Array.isArray ||
+                function (a) { return utils.typeName(a) === 'Array'; };
+
+/**
+ * Returns an indication of whether the argument is a Date or not
+ */
+utils.isDate = function (d) {
+    return (d instanceof Date);
+};
+
+/**
+ * Does a deep clone of the object.
+ */
+utils.clone = function (obj) {
+    if (!obj || typeof obj === 'function' || utils.isDate(obj) || typeof obj !== 'object') {
+        return obj;
+    }
+
+    var retVal, i;
+
+    if (utils.isArray(obj)) {
+        retVal = [];
+        for (i = 0; i < obj.length; ++i) {
+            retVal.push(utils.clone(obj[i]));
+        }
+        return retVal;
+    }
+
+    retVal = {};
+    for (i in obj) {
+        // https://issues.apache.org/jira/browse/CB-11522 'unknown' type may be returned in
+        // custom protocol activation case on Windows Phone 8.1 causing "No such interface supported" exception
+        // on cloning.
+        if ((!(i in retVal) || retVal[i] !== obj[i]) && typeof obj[i] !== 'undefined' && typeof obj[i] !== 'unknown') { // eslint-disable-line valid-typeof
+            retVal[i] = utils.clone(obj[i]);
+        }
+    }
+    return retVal;
+};
+
+/**
+ * Returns a wrapped version of the function
+ */
+utils.close = function (context, func, params) {
+    return function () {
+        var args = params || arguments;
+        return func.apply(context, args);
+    };
+};
+
+// ------------------------------------------------------------------------------
+function UUIDcreatePart (length) {
+    var uuidpart = '';
+    for (var i = 0; i < length; i++) {
+        var uuidchar = parseInt((Math.random() * 256), 10).toString(16);
+        if (uuidchar.length === 1) {
+            uuidchar = '0' + uuidchar;
+        }
+        uuidpart += uuidchar;
+    }
+    return uuidpart;
+}
+
+/**
+ * Create a UUID
+ */
+utils.createUUID = function () {
+    return UUIDcreatePart(4) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(6);
+};
+
+/**
+ * Extends a child object from a parent object using classical inheritance
+ * pattern.
+ */
+utils.extend = (function () {
+    // proxy used to establish prototype chain
+    var F = function () {};
+    // extend Child from Parent
+    return function (Child, Parent) {
+
+        F.prototype = Parent.prototype;
+        Child.prototype = new F();
+        Child.__super__ = Parent.prototype;
+        Child.prototype.constructor = Child;
+    };
+}());
+
+/**
+ * Alerts a message in any available way: alert or console.log.
+ */
+utils.alert = function (msg) {
+    if (window.alert) {
+        window.alert(msg);
+    } else if (console && console.log) {
+        console.log(msg);
+    }
+};
+
+});
+
+window.cordova = require('cordova');
+// file: src/scripts/bootstrap.js
+
+require('cordova/init');
+
+})();
\ No newline at end of file
diff --git a/platforms/android/platform_www/cordova_plugins.js b/platforms/android/platform_www/cordova_plugins.js
new file mode 100644
index 0000000..049ccd6
--- /dev/null
+++ b/platforms/android/platform_www/cordova_plugins.js
@@ -0,0 +1,339 @@
+cordova.define('cordova/plugin_list', function(require, exports, module) {
+  module.exports = [
+    {
+      "id": "cordova-plugin-fingerprint-aio.Fingerprint",
+      "file": "plugins/cordova-plugin-fingerprint-aio/www/Fingerprint.js",
+      "pluginId": "cordova-plugin-fingerprint-aio",
+      "clobbers": [
+        "Fingerprint"
+      ]
+    },
+    {
+      "id": "cordova-plugin-touch-id.TouchID",
+      "file": "plugins/cordova-plugin-touch-id/www/TouchID.js",
+      "pluginId": "cordova-plugin-touch-id",
+      "clobbers": [
+        "window.plugins.touchid"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.DirectoryEntry",
+      "file": "plugins/cordova-plugin-file/www/DirectoryEntry.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.DirectoryEntry"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.DirectoryReader",
+      "file": "plugins/cordova-plugin-file/www/DirectoryReader.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.DirectoryReader"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.Entry",
+      "file": "plugins/cordova-plugin-file/www/Entry.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.Entry"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.File",
+      "file": "plugins/cordova-plugin-file/www/File.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.File"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileEntry",
+      "file": "plugins/cordova-plugin-file/www/FileEntry.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileEntry"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileError",
+      "file": "plugins/cordova-plugin-file/www/FileError.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileError"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileReader",
+      "file": "plugins/cordova-plugin-file/www/FileReader.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileReader"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileSystem",
+      "file": "plugins/cordova-plugin-file/www/FileSystem.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileSystem"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileUploadOptions",
+      "file": "plugins/cordova-plugin-file/www/FileUploadOptions.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileUploadOptions"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileUploadResult",
+      "file": "plugins/cordova-plugin-file/www/FileUploadResult.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileUploadResult"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileWriter",
+      "file": "plugins/cordova-plugin-file/www/FileWriter.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileWriter"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.Flags",
+      "file": "plugins/cordova-plugin-file/www/Flags.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.Flags"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.LocalFileSystem",
+      "file": "plugins/cordova-plugin-file/www/LocalFileSystem.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.LocalFileSystem"
+      ],
+      "merges": [
+        "window"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.Metadata",
+      "file": "plugins/cordova-plugin-file/www/Metadata.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.Metadata"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.ProgressEvent",
+      "file": "plugins/cordova-plugin-file/www/ProgressEvent.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.ProgressEvent"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.fileSystems",
+      "file": "plugins/cordova-plugin-file/www/fileSystems.js",
+      "pluginId": "cordova-plugin-file"
+    },
+    {
+      "id": "cordova-plugin-file.requestFileSystem",
+      "file": "plugins/cordova-plugin-file/www/requestFileSystem.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.requestFileSystem"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.resolveLocalFileSystemURI",
+      "file": "plugins/cordova-plugin-file/www/resolveLocalFileSystemURI.js",
+      "pluginId": "cordova-plugin-file",
+      "merges": [
+        "window"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.isChrome",
+      "file": "plugins/cordova-plugin-file/www/browser/isChrome.js",
+      "pluginId": "cordova-plugin-file",
+      "runs": true
+    },
+    {
+      "id": "cordova-plugin-file.androidFileSystem",
+      "file": "plugins/cordova-plugin-file/www/android/FileSystem.js",
+      "pluginId": "cordova-plugin-file",
+      "merges": [
+        "FileSystem"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.fileSystems-roots",
+      "file": "plugins/cordova-plugin-file/www/fileSystems-roots.js",
+      "pluginId": "cordova-plugin-file",
+      "runs": true
+    },
+    {
+      "id": "cordova-plugin-file.fileSystemPaths",
+      "file": "plugins/cordova-plugin-file/www/fileSystemPaths.js",
+      "pluginId": "cordova-plugin-file",
+      "merges": [
+        "cordova"
+      ],
+      "runs": true
+    },
+    {
+      "id": "cordova-plugin-advanced-http.cookie-handler",
+      "file": "plugins/cordova-plugin-advanced-http/www/cookie-handler.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.global-configs",
+      "file": "plugins/cordova-plugin-advanced-http/www/global-configs.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.helpers",
+      "file": "plugins/cordova-plugin-advanced-http/www/helpers.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.js-util",
+      "file": "plugins/cordova-plugin-advanced-http/www/js-util.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.local-storage-store",
+      "file": "plugins/cordova-plugin-advanced-http/www/local-storage-store.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.lodash",
+      "file": "plugins/cordova-plugin-advanced-http/www/lodash.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.messages",
+      "file": "plugins/cordova-plugin-advanced-http/www/messages.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.public-interface",
+      "file": "plugins/cordova-plugin-advanced-http/www/public-interface.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.tough-cookie",
+      "file": "plugins/cordova-plugin-advanced-http/www/umd-tough-cookie.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.url-util",
+      "file": "plugins/cordova-plugin-advanced-http/www/url-util.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.http",
+      "file": "plugins/cordova-plugin-advanced-http/www/advanced-http.js",
+      "pluginId": "cordova-plugin-advanced-http",
+      "clobbers": [
+        "cordova.plugin.http"
+      ]
+    },
+    {
+      "id": "cordova-plugin-statusbar.statusbar",
+      "file": "plugins/cordova-plugin-statusbar/www/statusbar.js",
+      "pluginId": "cordova-plugin-statusbar",
+      "clobbers": [
+        "window.StatusBar"
+      ]
+    },
+    {
+      "id": "cordova-plugin-qrscanner.QRScanner",
+      "file": "plugins/cordova-plugin-qrscanner/www/www.min.js",
+      "pluginId": "cordova-plugin-qrscanner",
+      "clobbers": [
+        "QRScanner"
+      ]
+    },
+    {
+      "id": "cordova-plugin-camera.Camera",
+      "file": "plugins/cordova-plugin-camera/www/CameraConstants.js",
+      "pluginId": "cordova-plugin-camera",
+      "clobbers": [
+        "Camera"
+      ]
+    },
+    {
+      "id": "cordova-plugin-camera.CameraPopoverOptions",
+      "file": "plugins/cordova-plugin-camera/www/CameraPopoverOptions.js",
+      "pluginId": "cordova-plugin-camera",
+      "clobbers": [
+        "CameraPopoverOptions"
+      ]
+    },
+    {
+      "id": "cordova-plugin-camera.camera",
+      "file": "plugins/cordova-plugin-camera/www/Camera.js",
+      "pluginId": "cordova-plugin-camera",
+      "clobbers": [
+        "navigator.camera"
+      ]
+    },
+    {
+      "id": "cordova-plugin-camera.CameraPopoverHandle",
+      "file": "plugins/cordova-plugin-camera/www/CameraPopoverHandle.js",
+      "pluginId": "cordova-plugin-camera",
+      "clobbers": [
+        "CameraPopoverHandle"
+      ]
+    },
+    {
+      "id": "cordova-plugin-inappbrowser.inappbrowser",
+      "file": "plugins/cordova-plugin-inappbrowser/www/inappbrowser.js",
+      "pluginId": "cordova-plugin-inappbrowser",
+      "clobbers": [
+        "cordova.InAppBrowser.open",
+        "window.open"
+      ]
+    },
+    {
+      "id": "cordova-plugin-device.device",
+      "file": "plugins/cordova-plugin-device/www/device.js",
+      "pluginId": "cordova-plugin-device",
+      "clobbers": [
+        "device"
+      ]
+    },
+    {
+      "id": "cordova-plugin-themeablebrowser.themeablebrowser",
+      "file": "plugins/cordova-plugin-themeablebrowser/www/themeablebrowser.js",
+      "pluginId": "cordova-plugin-themeablebrowser",
+      "clobbers": [
+        "cordova.ThemeableBrowser"
+      ]
+    }
+  ];
+  module.exports.metadata = {
+    "cordova-plugin-add-swift-support": "2.0.2",
+    "cordova-plugin-fingerprint-aio": "1.7.0",
+    "cordova-plugin-touch-id": "3.3.1",
+    "cordova-plugin-whitelist": "1.3.3",
+    "cordova-plugin-file": "6.0.1",
+    "cordova-plugin-advanced-http": "2.1.1",
+    "cordova-plugin-statusbar": "2.4.2",
+    "cordova-plugin-disable-ios11-statusbar": "1.0.0",
+    "cordova-plugin-qrscanner": "3.0.1",
+    "cordova-plugin-camera": "4.0.3",
+    "cordova-plugin-inappbrowser": "3.0.0",
+    "cordova-plugin-device": "2.0.2",
+    "cordova-plugin-themeablebrowser": "0.2.17"
+  };
+});
\ No newline at end of file
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/advanced-http.js b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/advanced-http.js
new file mode 100644
index 0000000..5faece0
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/advanced-http.js
@@ -0,0 +1,23 @@
+cordova.define("cordova-plugin-advanced-http.http", function(require, exports, module) {
+/*
+ * A native HTTP Plugin for Cordova / PhoneGap.
+ */
+
+var pluginId = module.id.slice(0, module.id.lastIndexOf('.'));
+
+var exec = require('cordova/exec');
+var base64 = require('cordova/base64');
+var messages = require(pluginId + '.messages');
+var globalConfigs = require(pluginId + '.global-configs');
+var jsUtil = require(pluginId + '.js-util');
+var ToughCookie = require(pluginId + '.tough-cookie');
+var lodash = require(pluginId + '.lodash');
+var WebStorageCookieStore = require(pluginId + '.local-storage-store')(ToughCookie, lodash);
+var cookieHandler = require(pluginId + '.cookie-handler')(window.localStorage, ToughCookie, WebStorageCookieStore);
+var helpers = require(pluginId + '.helpers')(jsUtil, cookieHandler, messages, base64);
+var urlUtil = require(pluginId + '.url-util')(jsUtil);
+var publicInterface = require(pluginId + '.public-interface')(exec, cookieHandler, urlUtil, helpers, globalConfigs);
+
+module.exports = publicInterface;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/cookie-handler.js b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/cookie-handler.js
new file mode 100644
index 0000000..e7cdb39
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/cookie-handler.js
@@ -0,0 +1,73 @@
+cordova.define("cordova-plugin-advanced-http.cookie-handler", function(require, exports, module) {
+module.exports = function init(storage, ToughCookie, WebStorageCookieStore) {
+  var storeKey = '__advancedHttpCookieStore__';
+
+  var store = new WebStorageCookieStore(storage, storeKey);
+  var cookieJar = new ToughCookie.CookieJar(store);
+
+  return {
+    setCookieFromString: setCookieFromString,
+    setCookie: setCookie,
+    getCookieString: getCookieString,
+    clearCookies: clearCookies,
+    removeCookies: removeCookies
+  };
+
+  function splitCookieString(cookieStr) {
+    var cookieParts = cookieStr.split(',');
+    var splitCookies = [];
+    var processedCookie = null;
+
+    for (var i = 0; i < cookieParts.length; ++i) {
+      if (cookieParts[i].substr(-11, 8).toLowerCase() === 'expires=') {
+        processedCookie = cookieParts[i] + ',' + cookieParts[i + 1];
+        i++;
+      } else {
+        processedCookie = cookieParts[i];
+      }
+
+      processedCookie = processedCookie.trim();
+      splitCookies.push(processedCookie);
+    }
+
+    return splitCookies;
+  }
+
+  function setCookieFromString(url, cookieStr) {
+    if (!cookieStr) return;
+
+    var cookies = splitCookieString(cookieStr);
+
+    for (var i = 0; i < cookies.length; ++i) {
+      cookieJar.setCookieSync(cookies[i], url, { ignoreError: true });
+    }
+  }
+
+  function setCookie(url, cookie, options) {
+    options = options || {};
+    options.ignoreError = false;
+    cookieJar.setCookieSync(cookie, url, options);
+  }
+
+  function getCookieString(url) {
+    return cookieJar.getCookieStringSync(url);
+  }
+
+  function clearCookies() {
+    window.localStorage.removeItem(storeKey);
+  }
+
+  function removeCookies(url, cb) {
+    cookieJar.getCookies(url, function (error, cookies) {
+      if (!cookies || cookies.length === 0) {
+        return cb(null, []);
+      }
+
+      var domain = cookies[0].domain;
+
+      cookieJar.store.removeCookies(domain, null, cb);
+    });
+  }
+};
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/global-configs.js b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/global-configs.js
new file mode 100644
index 0000000..5e85416
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/global-configs.js
@@ -0,0 +1,11 @@
+cordova.define("cordova-plugin-advanced-http.global-configs", function(require, exports, module) {
+var globalConfigs = {
+  headers: {},
+  serializer: 'urlencoded',
+  followRedirect: true,
+  timeout: 60.0,
+};
+
+module.exports = globalConfigs;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/helpers.js b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/helpers.js
new file mode 100644
index 0000000..855e84c
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/helpers.js
@@ -0,0 +1,353 @@
+cordova.define("cordova-plugin-advanced-http.helpers", function(require, exports, module) {
+module.exports = function init(jsUtil, cookieHandler, messages, base64) {
+  var validSerializers = ['urlencoded', 'json', 'utf8'];
+  var validCertModes = ['default', 'nocheck', 'pinned', 'legacy'];
+  var validClientAuthModes = ['none', 'systemstore', 'buffer'];
+  var validHttpMethods = ['get', 'put', 'post', 'patch', 'head', 'delete', 'upload', 'download'];
+  var validResponseTypes = ['text','arraybuffer', 'blob'];
+
+  var interface = {
+    b64EncodeUnicode: b64EncodeUnicode,
+    checkSerializer: checkSerializer,
+    checkSSLCertMode: checkSSLCertMode,
+    checkClientAuthMode: checkClientAuthMode,
+    checkClientAuthOptions: checkClientAuthOptions,
+    checkForBlacklistedHeaderKey: checkForBlacklistedHeaderKey,
+    checkForInvalidHeaderValue: checkForInvalidHeaderValue,
+    checkTimeoutValue: checkTimeoutValue,
+    checkFollowRedirectValue: checkFollowRedirectValue,
+    injectCookieHandler: injectCookieHandler,
+    injectRawResponseHandler: injectRawResponseHandler,
+    injectFileEntryHandler: injectFileEntryHandler,
+    getMergedHeaders: getMergedHeaders,
+    getProcessedData: getProcessedData,
+    handleMissingCallbacks: handleMissingCallbacks,
+    handleMissingOptions: handleMissingOptions
+  };
+
+  // expose all functions for testing purposes
+  if (init.debug) {
+    interface.mergeHeaders = mergeHeaders;
+    interface.checkForValidStringValue = checkForValidStringValue;
+    interface.checkKeyValuePairObject = checkKeyValuePairObject;
+    interface.checkHttpMethod = checkHttpMethod;
+    interface.checkResponseType = checkResponseType;
+    interface.checkHeadersObject = checkHeadersObject;
+    interface.checkParamsObject = checkParamsObject;
+    interface.resolveCookieString = resolveCookieString;
+    interface.createFileEntry = createFileEntry;
+    interface.getCookieHeader = getCookieHeader;
+    interface.getMatchingHostHeaders = getMatchingHostHeaders;
+    interface.getAllowedDataTypes = getAllowedDataTypes;
+  }
+
+  return interface;
+
+  // Thanks Mozilla: https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_.22Unicode_Problem.22
+  function b64EncodeUnicode(str) {
+    return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
+      return String.fromCharCode('0x' + p1);
+    }));
+  }
+
+  function mergeHeaders(globalHeaders, localHeaders) {
+    var globalKeys = Object.keys(globalHeaders);
+    var key;
+
+    for (var i = 0; i < globalKeys.length; i++) {
+      key = globalKeys[i];
+
+      if (!localHeaders.hasOwnProperty(key)) {
+        localHeaders[key] = globalHeaders[key];
+      }
+    }
+
+    return localHeaders;
+  }
+
+  function checkForValidStringValue(list, value, onInvalidValueMessage) {
+    if (jsUtil.getTypeOf(value) !== 'String') {
+      throw new Error(onInvalidValueMessage + ' ' + list.join(', '));
+    }
+
+    value = value.trim().toLowerCase();
+
+    if (list.indexOf(value) === -1) {
+      throw new Error(onInvalidValueMessage + ' ' + list.join(', '));
+    }
+
+    return value;
+  }
+
+  function checkKeyValuePairObject(obj, allowedChildren, onInvalidValueMessage) {
+    if (jsUtil.getTypeOf(obj) !== 'Object') {
+      throw new Error(onInvalidValueMessage);
+    }
+
+    var keys = Object.keys(obj);
+
+    for (var i = 0; i < keys.length; i++) {
+      if (allowedChildren.indexOf(jsUtil.getTypeOf(obj[keys[i]])) === -1) {
+        throw new Error(onInvalidValueMessage);
+      }
+    }
+
+    return obj;
+  }
+
+  function checkHttpMethod(method) {
+    return checkForValidStringValue(validHttpMethods, method, messages.INVALID_HTTP_METHOD);
+  }
+
+  function checkResponseType(type) {
+    return checkForValidStringValue(validResponseTypes, type, messages.INVALID_RESPONSE_TYPE);
+  }
+
+  function checkSerializer(serializer) {
+    return checkForValidStringValue(validSerializers, serializer, messages.INVALID_DATA_SERIALIZER);
+  }
+
+  function checkSSLCertMode(mode) {
+    return checkForValidStringValue(validCertModes, mode, messages.INVALID_SSL_CERT_MODE);
+  }
+
+  function checkClientAuthMode(mode) {
+    return checkForValidStringValue(validClientAuthModes, mode, messages.INVALID_CLIENT_AUTH_MODE);
+  }
+
+  function checkClientAuthOptions(mode, options) {
+    options = options || {};
+
+    // none
+    if (mode === validClientAuthModes[0]) {
+      return {
+        alias: null,
+        rawPkcs: null,
+        pkcsPassword: ''
+      };
+    }
+
+    if (jsUtil.getTypeOf(options) !== 'Object') {
+      throw new Error(messages.INVALID_CLIENT_AUTH_OPTIONS);
+    }
+
+    // systemstore
+    if (mode === validClientAuthModes[1]) {
+      if (jsUtil.getTypeOf(options.alias) !== 'String'
+        && jsUtil.getTypeOf(options.alias) !== 'Undefined') {
+        throw new Error(messages.INVALID_CLIENT_AUTH_ALIAS);
+      }
+
+      return {
+        alias: jsUtil.getTypeOf(options.alias) === 'Undefined' ? null : options.alias,
+        rawPkcs: null,
+        pkcsPassword: ''
+      };
+    }
+
+    // buffer
+    if (mode === validClientAuthModes[2]) {
+      if (jsUtil.getTypeOf(options.rawPkcs) !== 'ArrayBuffer') {
+        throw new Error(messages.INVALID_CLIENT_AUTH_RAW_PKCS);
+      }
+
+      if (jsUtil.getTypeOf(options.pkcsPassword) !== 'String') {
+        throw new Error(messages.INVALID_CLIENT_AUTH_PKCS_PASSWORD);
+      }
+
+      return {
+        alias: null,
+        rawPkcs: options.rawPkcs,
+        pkcsPassword: options.pkcsPassword
+      }
+    }
+  }
+
+  function checkForBlacklistedHeaderKey(key) {
+    if (key.toLowerCase() === 'cookie') {
+      throw new Error(messages.ADDING_COOKIES_NOT_SUPPORTED);
+    }
+
+    return key;
+  }
+
+  function checkForInvalidHeaderValue(value) {
+    if (jsUtil.getTypeOf(value) !== 'String') {
+      throw new Error(messages.INVALID_HEADERS_VALUE);
+    }
+
+    return value;
+  }
+
+  function checkTimeoutValue(timeout) {
+    if (jsUtil.getTypeOf(timeout) !== 'Number' || timeout < 0) {
+      throw new Error(messages.INVALID_TIMEOUT_VALUE);
+    }
+
+    return timeout;
+  }
+
+  function checkFollowRedirectValue(follow) {
+    if (jsUtil.getTypeOf(follow) !== 'Boolean') {
+      throw new Error(messages.INVALID_FOLLOW_REDIRECT_VALUE);
+    }
+
+    return follow;
+  }
+
+  function checkHeadersObject(headers) {
+    return checkKeyValuePairObject(headers, ['String'], messages.INVALID_HEADERS_VALUE);
+  }
+
+  function checkParamsObject(params) {
+    return checkKeyValuePairObject(params, ['String', 'Array'], messages.INVALID_PARAMS_VALUE);
+  }
+
+  function resolveCookieString(headers) {
+    var keys = Object.keys(headers || {});
+
+    for (var i = 0; i < keys.length; ++i) {
+      if (keys[i].match(/^set-cookie$/i)) {
+        return headers[keys[i]];
+      }
+    }
+
+    return null;
+  }
+
+  function createFileEntry(rawEntry) {
+    var entry = new (require('cordova-plugin-file.FileEntry'))();
+
+    entry.isDirectory = rawEntry.isDirectory;
+    entry.isFile = rawEntry.isFile;
+    entry.name = rawEntry.name;
+    entry.fullPath = rawEntry.fullPath;
+    entry.filesystem = new FileSystem(rawEntry.filesystemName || (rawEntry.filesystem == window.PERSISTENT ? 'persistent' : 'temporary'));
+    entry.nativeURL = rawEntry.nativeURL;
+
+    return entry;
+  }
+
+  function injectCookieHandler(url, cb) {
+    return function (response) {
+      cookieHandler.setCookieFromString(url, resolveCookieString(response.headers));
+      cb(response);
+    }
+  }
+
+  function injectRawResponseHandler(responseType, cb) {
+    return function (response) {
+      var dataType = jsUtil.getTypeOf(response.data);
+
+      // don't need post-processing if it's already binary type (on browser platform)
+      if (dataType === 'ArrayBuffer' || dataType === 'Blob') {
+        return cb(response);
+      }
+
+      // arraybuffer
+      if (responseType === validResponseTypes[1]) {
+        var buffer = base64.toArrayBuffer(response.data);
+        response.data = buffer;
+      }
+
+      // blob
+      if (responseType === validResponseTypes[2]) {
+        var buffer = base64.toArrayBuffer(response.data);
+        var type = response.headers['content-type'] || '';
+        var blob = new Blob([ buffer ], { type: type });
+        response.data = blob;
+      }
+
+      cb(response);
+    }
+  }
+
+  function injectFileEntryHandler(cb) {
+    return function (response) {
+      cb(createFileEntry(response.file));
+    }
+  }
+
+  function getCookieHeader(url) {
+    var cookieString = cookieHandler.getCookieString(url);
+
+    if (cookieString.length) {
+      return { Cookie: cookieHandler.getCookieString(url) };
+    }
+
+    return {};
+  }
+
+  function getMatchingHostHeaders(url, headersList) {
+    var matches = url.match(/^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i);
+    var domain = matches && matches[1];
+
+    return headersList[domain] || null;
+  }
+
+  function getMergedHeaders(url, requestHeaders, predefinedHeaders) {
+    var globalHeaders = predefinedHeaders['*'] || {};
+    var hostHeaders = getMatchingHostHeaders(url, predefinedHeaders) || {};
+    var mergedHeaders = mergeHeaders(globalHeaders, hostHeaders);
+
+    mergedHeaders = mergeHeaders(mergedHeaders, requestHeaders);
+    mergedHeaders = mergeHeaders(mergedHeaders, getCookieHeader(url));
+
+    return mergedHeaders;
+  }
+
+  function getAllowedDataTypes(dataSerializer) {
+    switch (dataSerializer) {
+      case 'utf8':
+        return ['String'];
+      case 'urlencoded':
+        return ['Object'];
+      default:
+        return ['Array', 'Object'];
+    }
+  }
+
+  function getProcessedData(data, dataSerializer) {
+    var currentDataType = jsUtil.getTypeOf(data);
+    var allowedDataTypes = getAllowedDataTypes(dataSerializer);
+
+    if (allowedDataTypes.indexOf(currentDataType) === -1) {
+      throw new Error(messages.DATA_TYPE_MISMATCH + ' ' + allowedDataTypes.join(', '));
+    }
+
+    if (dataSerializer === 'utf8') {
+      data = { text: data };
+    }
+
+    return data;
+  }
+
+  function handleMissingCallbacks(successFn, failFn) {
+    if (jsUtil.getTypeOf(successFn) !== 'Function') {
+      throw new Error(messages.MANDATORY_SUCCESS);
+    }
+
+    if (jsUtil.getTypeOf(failFn) !== 'Function') {
+      throw new Error(messages.MANDATORY_FAIL);
+    }
+  }
+
+  function handleMissingOptions(options, globals) {
+    options = options || {};
+
+    return {
+      method: checkHttpMethod(options.method || validHttpMethods[0]),
+      responseType: checkResponseType(options.responseType || validResponseTypes[0]),
+      serializer: checkSerializer(options.serializer || globals.serializer),
+      timeout: checkTimeoutValue(options.timeout || globals.timeout),
+      followRedirect: checkFollowRedirectValue(options.followRedirect || globals.followRedirect),
+      headers: checkHeadersObject(options.headers || {}),
+      params: checkParamsObject(options.params || {}),
+      data: jsUtil.getTypeOf(options.data) === 'Undefined' ? null : options.data,
+      filePath: options.filePath || '',
+      name: options.name || ''
+    };
+  }
+};
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/js-util.js b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/js-util.js
new file mode 100644
index 0000000..cbe1c51
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/js-util.js
@@ -0,0 +1,33 @@
+cordova.define("cordova-plugin-advanced-http.js-util", function(require, exports, module) {
+module.exports = {
+  // typeof is not working reliably in JS
+  getTypeOf: function (object) {
+    switch (Object.prototype.toString.call(object)) {
+      case '[object Array]':
+        return 'Array';
+      case '[object Blob]':
+        return 'Blob';
+      case '[object ArrayBuffer]':
+        return 'ArrayBuffer';
+      case '[object Boolean]':
+        return 'Boolean';
+      case '[object Function]':
+        return 'Function';
+      case '[object Null]':
+        return 'Null';
+      case '[object Number]':
+        return 'Number';
+      case '[object Object]':
+        return 'Object';
+      case '[object String]':
+        return 'String';
+      case '[object Undefined]':
+        return 'Undefined';
+      default:
+        return 'Unknown';
+    }
+  }
+}
+
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/local-storage-store.js b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/local-storage-store.js
new file mode 100644
index 0000000..800c6b7
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/local-storage-store.js
@@ -0,0 +1,184 @@
+cordova.define("cordova-plugin-advanced-http.local-storage-store", function(require, exports, module) {
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Exponent
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Based on "tough-cookie-web-storage-store" v1.0.0
+ * Thanks James Ide: https://github.com/exponentjs/tough-cookie-web-storage-store
+ *
+ * Modified by Sefa Ilkimen for cordova plugin integration
+ *
+ */
+
+'use strict';
+
+module.exports = function init(ToughCookie, _) {
+  function WebStorageCookieStore(storage, storeKey) {
+    ToughCookie.Store.call(this);
+    this._storage = storage;
+    this._storeKey = storeKey || '__cookieStore__';
+    this.synchronous = true;
+  }
+
+  WebStorageCookieStore.prototype = Object.create(ToughCookie.Store);
+
+  WebStorageCookieStore.prototype.findCookie = function (domain, path, key, callback) {
+    var store = this._readStore();
+    var cookie = _.get(store, [domain, path, key], null);
+
+    callback(null, ToughCookie.Cookie.fromJSON(cookie));
+  };
+
+  WebStorageCookieStore.prototype.findCookies = function (domain, path, callback) {
+    if (!domain) {
+      callback(null, []);
+      return;
+    }
+
+    var that = this;
+    var cookies = [];
+    var store = this._readStore();
+    var domains = ToughCookie.permuteDomain(domain) || [domain];
+
+    domains.forEach(function (domain) {
+      if (!store[domain]) {
+        return;
+      }
+
+      var matchingPaths = Object.keys(store[domain]);
+
+      if (path != null) {
+        matchingPaths = matchingPaths.filter(function (cookiePath) {
+          return that._isOnPath(cookiePath, path);
+        });
+      }
+
+      matchingPaths.forEach(function (path) {
+        Array.prototype.push.apply(cookies, _.values(store[domain][path]));
+      });
+    });
+
+    cookies = cookies.map(function (cookie) {
+      return ToughCookie.Cookie.fromJSON(cookie);
+    });
+
+    callback(null, cookies);
+  };
+
+  /**
+   * Returns whether `cookiePath` is on the given `urlPath`
+   */
+  WebStorageCookieStore.prototype._isOnPath = function (cookiePath, urlPath) {
+    if (!cookiePath) {
+      return false;
+    }
+
+    if (cookiePath === urlPath) {
+      return true;
+    }
+
+    if (urlPath.indexOf(cookiePath) !== 0) {
+      return false;
+    }
+
+    if (cookiePath[cookiePath.length - 1] !== '/' && urlPath[cookiePath.length] !== '/') {
+      return false;
+    }
+
+    return true;
+  };
+
+  WebStorageCookieStore.prototype.putCookie = function (cookie, callback) {
+    var store = this._readStore();
+
+    _.set(store, [cookie.domain, cookie.path, cookie.key], cookie);
+    this._writeStore(store);
+    callback(null);
+  };
+
+  WebStorageCookieStore.prototype.updateCookie = function (oldCookie, newCookie, callback) {
+    this.putCookie(newCookie, callback);
+  };
+
+
+  WebStorageCookieStore.prototype.removeCookie = function (domain, path, key, callback) {
+    var store = this._readStore();
+
+    _.unset(store, [domain, path, key]);
+    this._writeStore(store);
+    callback(null);
+  };
+
+  WebStorageCookieStore.prototype.removeCookies = function (domain, path, callback) {
+    var store = this._readStore();
+
+    if (path == null) {
+      _.unset(store, [domain]);
+    } else {
+      _.unset(store, [domain, path]);
+    }
+
+    this._writeStore(store);
+    callback(null);
+  };
+
+  WebStorageCookieStore.prototype.getAllCookies = function (callback) {
+    var cookies = [];
+    var store = this._readStore();
+
+    Object.keys(store).forEach(function (domain) {
+      Object.keys(store[domain]).forEach(function (path) {
+        Array.protype.push.apply(cookies, _.values(store[domain][path]));
+      });
+    });
+
+    cookies = cookies.map(function (cookie) {
+      return ToughCookie.Cookie.fromJSON(cookie);
+    });
+
+    cookies.sort(function (c1, c2) {
+      return (c1.creationIndex || 0) - (c2.creationIndex || 0);
+    });
+
+    callback(null, cookies);
+  };
+
+  WebStorageCookieStore.prototype._readStore = function () {
+    var json = this._storage.getItem(this._storeKey);
+
+    if (json !== null) {
+      try {
+        return JSON.parse(json);
+      } catch (e) { }
+    }
+
+    return {};
+  };
+
+  WebStorageCookieStore.prototype._writeStore = function (store) {
+    this._storage.setItem(this._storeKey, JSON.stringify(store));
+  };
+
+  return WebStorageCookieStore;
+};
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/lodash.js b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/lodash.js
new file mode 100644
index 0000000..f35be77
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/lodash.js
@@ -0,0 +1,22 @@
+cordova.define("cordova-plugin-advanced-http.lodash", function(require, exports, module) {
+/**
+ * @license
+ * Lodash (Custom Build) lodash.com/license | Underscore.js 1.8.3 underscorejs.org/LICENSE
+ * Build: `lodash include="get,set,unset,values" exports="node"`
+ */
+;(function(){function t(t,e){for(var r=-1,n=null==t?0:t.length,o=Array(n);++r<n;)o[r]=e(t[r],r,t);return o}function e(t){return function(e){return t(e)}}function r(e,r){return t(r,function(t){return e[t]})}function n(){}function o(t){var e=-1,r=null==t?0:t.length;for(this.clear();++e<r;){var n=t[e];this.set(n[0],n[1])}}function u(t){var e=-1,r=null==t?0:t.length;for(this.clear();++e<r;){var n=t[e];this.set(n[0],n[1])}}function i(t){var e=-1,r=null==t?0:t.length;for(this.clear();++e<r;){var n=t[e];this.set(n[0],n[1]);
+}}function c(t,e){for(var r=t.length;r--;)if(m(t[r][0],e))return r;return-1}function a(t,e){e=h(e,t);for(var r=0,n=e.length;null!=t&&r<n;)t=t[j(e[r++])];return r&&r==n?t:E}function l(t){if(null==t)return t===E?"[object Undefined]":"[object Null]";t=Object(t);var e;if(nt&&nt in t){var r=Q.call(t,nt),n=t[nt];try{t[nt]=E,e=true}catch(t){}var o=Y.call(t);e&&(r?t[nt]=n:delete t[nt]),e=o}else e=Y.call(t);return e}function s(t){return w(t)&&"[object Arguments]"==l(t)}function f(t){return w(t)&&z(t.length)&&!!M[l(t)];
+}function p(e){if(typeof e=="string")return e;if(ft(e))return t(e,p)+"";if(x(e))return at?at.call(e):"";var r=e+"";return"0"==r&&1/e==-T?"-0":r}function h(t,e){var r;return ft(t)?r=t:(ft(t)?r=false:(r=typeof t,r=!("number"!=r&&"symbol"!=r&&"boolean"!=r&&null!=t&&!x(t))||(B.test(t)||!I.test(t)||null!=e&&t in Object(e))),r=r?[t]:lt(F(t))),r}function y(t,e){var r=t.__data__,n=typeof e;return("string"==n||"number"==n||"symbol"==n||"boolean"==n?"__proto__"!==e:null===e)?r[typeof e=="string"?"string":"hash"]:r.map;
+}function b(t,e){var r=null==t?E:t[e];return(!S(r)||X&&X in r?0:(O(r)?Z:L).test(g(r)))?r:E}function _(t,e){return e=null==e?9007199254740991:e,!!e&&(typeof t=="number"||R.test(t))&&-1<t&&0==t%1&&t<e}function j(t){if(typeof t=="string"||x(t))return t;var e=t+"";return"0"==e&&1/t==-T?"-0":e}function g(t){if(null!=t){try{return K.call(t)}catch(t){}return t+""}return""}function v(t){var e=null==t?0:t.length;return e?t[e-1]:E}function d(t,e){function r(){var n=arguments,o=e?e.apply(this,n):n[0],u=r.cache;
+return u.has(o)?u.get(o):(n=t.apply(this,n),r.cache=u.set(o,n)||u,n)}if(typeof t!="function"||null!=e&&typeof e!="function")throw new TypeError("Expected a function");return r.cache=new(d.Cache||i),r}function m(t,e){return t===e||t!==t&&e!==e}function A(t){return null!=t&&z(t.length)&&!O(t)}function O(t){return!!S(t)&&(t=l(t),"[object Function]"==t||"[object GeneratorFunction]"==t||"[object AsyncFunction]"==t||"[object Proxy]"==t)}function z(t){return typeof t=="number"&&-1<t&&0==t%1&&9007199254740991>=t;
+}function S(t){var e=typeof t;return null!=t&&("object"==e||"function"==e)}function w(t){return null!=t&&typeof t=="object"}function x(t){return typeof t=="symbol"||w(t)&&"[object Symbol]"==l(t)}function F(t){return null==t?"":p(t)}function $(t){if(A(t)){var e=ft(t),r=!e&&st(t),n=!e&&!r&&pt(t),o=!e&&!r&&!n&&ht(t);if(e=e||r||n||o){for(var r=t.length,u=String,i=-1,c=Array(r);++i<r;)c[i]=u(i);r=c}else r=[];var a,u=r.length;for(a in t)!Q.call(t,a)||e&&("length"==a||n&&("offset"==a||"parent"==a)||o&&("buffer"==a||"byteLength"==a||"byteOffset"==a)||_(a,u))||r.push(a);
+t=r}else if(a=t&&t.constructor,t===(typeof a=="function"&&a.prototype||H)){a=[];for(n in Object(t))Q.call(t,n)&&"constructor"!=n&&a.push(n);t=a}else t=ut(t);return t}function k(){return false}var E,T=1/0,I=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,B=/^\w*$/,P=/^\./,U=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,C=/\\(\\)?/g,L=/^\[object .+?Constructor\]$/,R=/^(?:0|[1-9]\d*)$/,M={};M["[object Float32Array]"]=M["[object Float64Array]"]=M["[object Int8Array]"]=M["[object Int16Array]"]=M["[object Int32Array]"]=M["[object Uint8Array]"]=M["[object Uint8ClampedArray]"]=M["[object Uint16Array]"]=M["[object Uint32Array]"]=true,
+M["[object Arguments]"]=M["[object Array]"]=M["[object ArrayBuffer]"]=M["[object Boolean]"]=M["[object DataView]"]=M["[object Date]"]=M["[object Error]"]=M["[object Function]"]=M["[object Map]"]=M["[object Number]"]=M["[object Object]"]=M["[object RegExp]"]=M["[object Set]"]=M["[object String]"]=M["[object WeakMap]"]=false;var N,D=typeof global=="object"&&global&&global.Object===Object&&global,V=typeof self=="object"&&self&&self.Object===Object&&self,q=D||V||Function("return this")(),G=(V=typeof exports=="object"&&exports&&!exports.nodeType&&exports)&&typeof module=="object"&&module&&!module.nodeType&&module,W=G&&G.exports===V,D=W&&D.process;
+t:{try{N=D&&D.binding&&D.binding("util");break t}catch(t){}N=void 0}N=N&&N.isTypedArray;var D=Array.prototype,H=Object.prototype,J=q["__core-js_shared__"],K=Function.prototype.toString,Q=H.hasOwnProperty,X=function(){var t=/[^.]+$/.exec(J&&J.keys&&J.keys.IE_PROTO||"");return t?"Symbol(src)_1."+t:""}(),Y=H.toString,Z=RegExp("^"+K.call(Q).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),tt=W?q.Buffer:E,W=q.Symbol,et=H.propertyIsEnumerable,rt=D.splice,nt=W?W.toStringTag:E,ot=function(){
+try{var t=b(Object,"defineProperty");return t({},"",{}),t}catch(t){}}(),D=tt?tt.isBuffer:E,ut=function(t,e){return function(r){return t(e(r))}}(Object.keys,Object),it=b(q,"Map"),ct=b(Object,"create"),at=(q=W?W.prototype:E)?q.toString:E;o.prototype.clear=function(){this.__data__=ct?ct(null):{},this.size=0},o.prototype.delete=function(t){return t=this.has(t)&&delete this.__data__[t],this.size-=t?1:0,t},o.prototype.get=function(t){var e=this.__data__;return ct?(t=e[t],"__lodash_hash_undefined__"===t?E:t):Q.call(e,t)?e[t]:E;
+},o.prototype.has=function(t){var e=this.__data__;return ct?e[t]!==E:Q.call(e,t)},o.prototype.set=function(t,e){var r=this.__data__;return this.size+=this.has(t)?0:1,r[t]=ct&&e===E?"__lodash_hash_undefined__":e,this},u.prototype.clear=function(){this.__data__=[],this.size=0},u.prototype.delete=function(t){var e=this.__data__;return t=c(e,t),!(0>t)&&(t==e.length-1?e.pop():rt.call(e,t,1),--this.size,true)},u.prototype.get=function(t){var e=this.__data__;return t=c(e,t),0>t?E:e[t][1]},u.prototype.has=function(t){
+return-1<c(this.__data__,t)},u.prototype.set=function(t,e){var r=this.__data__,n=c(r,t);return 0>n?(++this.size,r.push([t,e])):r[n][1]=e,this},i.prototype.clear=function(){this.size=0,this.__data__={hash:new o,map:new(it||u),string:new o}},i.prototype.delete=function(t){return t=y(this,t).delete(t),this.size-=t?1:0,t},i.prototype.get=function(t){return y(this,t).get(t)},i.prototype.has=function(t){return y(this,t).has(t)},i.prototype.set=function(t,e){var r=y(this,t),n=r.size;return r.set(t,e),this.size+=r.size==n?0:1,
+this};var lt=function(t){t=d(t,function(t){return 500===e.size&&e.clear(),t});var e=t.cache;return t}(function(t){var e=[];return P.test(t)&&e.push(""),t.replace(U,function(t,r,n,o){e.push(n?o.replace(C,"$1"):r||t)}),e});d.Cache=i;var st=s(function(){return arguments}())?s:function(t){return w(t)&&Q.call(t,"callee")&&!et.call(t,"callee")},ft=Array.isArray,pt=D||k,ht=N?e(N):f;n.keys=$,n.memoize=d,n.set=function(t,e,r){if(null!=t&&S(t)){e=h(e,t);for(var n=-1,o=e.length,u=o-1,i=t;null!=i&&++n<o;){var c=j(e[n]),a=r;
+if(n!=u){var l=i[c],a=E;a===E&&(a=S(l)?l:_(e[n+1])?[]:{})}var s=i,l=c,f=s[l];Q.call(s,l)&&m(f,a)&&(a!==E||l in s)||("__proto__"==l&&ot?ot(s,l,{configurable:true,enumerable:true,value:a,writable:true}):s[l]=a),i=i[c]}}return t},n.unset=function(t,e){var r;if(null==t)r=true;else{var n=t,o=r=h(e,n);if(!(2>o.length)){var u=0,i=-1,c=-1,l=o.length;for(0>u&&(u=-u>l?0:l+u),i=i>l?l:i,0>i&&(i+=l),l=u>i?0:i-u>>>0,u>>>=0,i=Array(l);++c<l;)i[c]=o[c+u];n=a(n,i)}r=j(v(r)),r=!(null!=n&&Q.call(n,r))||delete n[r]}return r;
+},n.values=function(t){return null==t?[]:r(t,$(t))},n.eq=m,n.get=function(t,e,r){return t=null==t?E:a(t,e),t===E?r:t},n.isArguments=st,n.isArray=ft,n.isArrayLike=A,n.isBuffer=pt,n.isFunction=O,n.isLength=z,n.isObject=S,n.isObjectLike=w,n.isSymbol=x,n.isTypedArray=ht,n.last=v,n.stubFalse=k,n.toString=F,n.VERSION="4.17.1",G&&((G.exports=n)._=n,V._=n)}).call(this);
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/messages.js b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/messages.js
new file mode 100644
index 0000000..13efb2b
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/messages.js
@@ -0,0 +1,22 @@
+cordova.define("cordova-plugin-advanced-http.messages", function(require, exports, module) {
+module.exports = {
+  ADDING_COOKIES_NOT_SUPPORTED: 'advanced-http: "setHeader" does not support adding cookies, please use "setCookie" function instead',
+  DATA_TYPE_MISMATCH: 'advanced-http: "data" argument supports only following data types:',
+  INVALID_CLIENT_AUTH_ALIAS: 'advanced-http: invalid client certificate alias, needs to be a string or undefined',
+  INVALID_CLIENT_AUTH_MODE: 'advanced-http: invalid client certificate authentication mode, supported modes are:',
+  INVALID_CLIENT_AUTH_OPTIONS: 'advanced-http: invalid client certificate authentication options, needs to be an object',
+  INVALID_CLIENT_AUTH_PKCS_PASSWORD: 'advanced-http: invalid PKCS12 container password, needs to be a string',
+  INVALID_CLIENT_AUTH_RAW_PKCS: 'advanced-http: invalid PKCS12 container, needs to be an array buffer',
+  INVALID_DATA_SERIALIZER: 'advanced-http: invalid serializer, supported serializers are:',
+  INVALID_FOLLOW_REDIRECT_VALUE: 'advanced-http: invalid follow redirect value, needs to be a boolean value',
+  INVALID_HEADERS_VALUE: 'advanced-http: header values must be strings',
+  INVALID_HTTP_METHOD: 'advanced-http: invalid HTTP method, supported methods are:',
+  INVALID_PARAMS_VALUE: 'advanced-http: invalid params object, needs to be an object with strings',
+  INVALID_RESPONSE_TYPE: 'advanced-http: invalid response type, supported types are:',
+  INVALID_SSL_CERT_MODE: 'advanced-http: invalid SSL cert mode, supported modes are:',
+  INVALID_TIMEOUT_VALUE: 'advanced-http: invalid timeout value, needs to be a positive numeric value',
+  MANDATORY_FAIL: 'advanced-http: missing mandatory "onFail" callback function',
+  MANDATORY_SUCCESS: 'advanced-http: missing mandatory "onSuccess" callback function',
+};
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/public-interface.js b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/public-interface.js
new file mode 100644
index 0000000..a77c8e0
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/public-interface.js
@@ -0,0 +1,202 @@
+cordova.define("cordova-plugin-advanced-http.public-interface", function(require, exports, module) {
+module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConfigs) {
+  const publicInterface = {
+    getBasicAuthHeader: getBasicAuthHeader,
+    useBasicAuth: useBasicAuth,
+    getHeaders: getHeaders,
+    setHeader: setHeader,
+    getDataSerializer: getDataSerializer,
+    setDataSerializer: setDataSerializer,
+    setCookie: setCookie,
+    clearCookies: clearCookies,
+    removeCookies: removeCookies,
+    getCookieString: getCookieString,
+    getRequestTimeout: getRequestTimeout,
+    setRequestTimeout: setRequestTimeout,
+    getFollowRedirect: getFollowRedirect,
+    setFollowRedirect: setFollowRedirect,
+    // @DEPRECATED
+    disableRedirect: disableRedirect,
+    // @DEPRECATED
+    setSSLCertMode: setServerTrustMode,
+    setServerTrustMode: setServerTrustMode,
+    setClientAuthMode: setClientAuthMode,
+    sendRequest: sendRequest,
+    post: post,
+    get: get,
+    put: put,
+    patch: patch,
+    delete: del,
+    head: head,
+    uploadFile: uploadFile,
+    downloadFile: downloadFile
+  };
+
+  function getBasicAuthHeader(username, password) {
+    return { 'Authorization': 'Basic ' + helpers.b64EncodeUnicode(username + ':' + password) };
+  }
+
+  function useBasicAuth(username, password) {
+    this.setHeader('*', 'Authorization', 'Basic ' + helpers.b64EncodeUnicode(username + ':' + password));
+  }
+
+  function getHeaders(host) {
+    return globalConfigs.headers[host || '*'] || null;
+  }
+
+  function setHeader() {
+    // this one is for being backward compatible
+    var host = '*';
+    var header = arguments[0];
+    var value = arguments[1];
+
+    if (arguments.length === 3) {
+      host = arguments[0];
+      header = arguments[1];
+      value = arguments[2];
+    }
+
+    helpers.checkForBlacklistedHeaderKey(header);
+    helpers.checkForInvalidHeaderValue(value);
+
+    globalConfigs.headers[host] = globalConfigs.headers[host] || {};
+    globalConfigs.headers[host][header] = value;
+  }
+
+  function getDataSerializer() {
+    return globalConfigs.serializer;
+  }
+
+  function setDataSerializer(serializer) {
+    globalConfigs.serializer = helpers.checkSerializer(serializer);
+  }
+
+  function setCookie(url, cookie, options) {
+    cookieHandler.setCookie(url, cookie, options);
+  }
+
+  function clearCookies() {
+    cookieHandler.clearCookies();
+  }
+
+  function removeCookies(url, callback) {
+    cookieHandler.removeCookies(url, callback);
+  }
+
+  function getCookieString(url) {
+    return cookieHandler.getCookieString(url);
+  }
+
+  function getRequestTimeout() {
+    return globalConfigs.timeout;
+  }
+
+  function setRequestTimeout(timeout) {
+    globalConfigs.timeout = helpers.checkTimeoutValue(timeout);
+  }
+
+  function getFollowRedirect() {
+    return globalConfigs.followRedirect;
+  }
+
+  function setFollowRedirect(follow) {
+    globalConfigs.followRedirect = helpers.checkFollowRedirectValue(follow);
+  }
+
+  // @DEPRECATED
+  function disableRedirect(disable, success, failure) {
+    helpers.handleMissingCallbacks(success, failure);
+
+    setFollowRedirect(!disable);
+    success();
+  }
+
+  function setServerTrustMode(mode, success, failure) {
+    helpers.handleMissingCallbacks(success, failure);
+
+    return exec(success, failure, 'CordovaHttpPlugin', 'setServerTrustMode', [helpers.checkSSLCertMode(mode)]);
+  }
+
+  function setClientAuthMode() {
+    var mode = arguments[0];
+    var options = null;
+    var success = arguments[1];
+    var failure = arguments[2];
+
+    if (arguments.length === 4) {
+      options = arguments[1];
+      success = arguments[2];
+      failure = arguments[3];
+    }
+
+    mode = helpers.checkClientAuthMode(mode);
+    options = helpers.checkClientAuthOptions(mode, options);
+
+    helpers.handleMissingCallbacks(success, failure);
+
+    return exec(success, failure, 'CordovaHttpPlugin', 'setClientAuthMode', [mode, options.alias, options.rawPkcs, options.pkcsPassword]);
+  }
+
+  function sendRequest(url, options, success, failure) {
+    helpers.handleMissingCallbacks(success, failure);
+
+    options = helpers.handleMissingOptions(options, globalConfigs);
+    url = urlUtil.appendQueryParamsString(url, urlUtil.serializeQueryParams(options.params, true));
+
+    var headers = helpers.getMergedHeaders(url, options.headers, globalConfigs.headers);
+
+    var onFail = helpers.injectCookieHandler(url, failure);
+    var onSuccess = helpers.injectCookieHandler(url, helpers.injectRawResponseHandler(options.responseType, success));
+
+    switch (options.method) {
+      case 'post':
+      case 'put':
+      case 'patch':
+        var data = helpers.getProcessedData(options.data, options.serializer);
+        return exec(onSuccess, onFail, 'CordovaHttpPlugin', options.method, [url, data, options.serializer, headers, options.timeout, options.followRedirect, options.responseType]);
+      case 'upload':
+        return exec(onSuccess, onFail, 'CordovaHttpPlugin', 'uploadFile', [url, headers, options.filePath, options.name, options.timeout, options.followRedirect, options.responseType]);
+      case 'download':
+        var onDownloadSuccess = helpers.injectCookieHandler(url, helpers.injectFileEntryHandler(success));
+        return exec(onDownloadSuccess, onFail, 'CordovaHttpPlugin', 'downloadFile', [url, headers, options.filePath, options.timeout, options.followRedirect]);
+      default:
+        return exec(onSuccess, onFail, 'CordovaHttpPlugin', options.method, [url, headers, options.timeout, options.followRedirect, options.responseType]);
+    }
+  }
+
+  function post(url, data, headers, success, failure) {
+    return publicInterface.sendRequest(url, { method: 'post', data: data, headers: headers }, success, failure);
+  };
+
+  function get(url, params, headers, success, failure) {
+    return publicInterface.sendRequest(url, { method: 'get', params: params, headers: headers }, success, failure);
+  };
+
+  function put(url, data, headers, success, failure) {
+    return publicInterface.sendRequest(url, { method: 'put', data: data, headers: headers }, success, failure);
+  }
+
+  function patch(url, data, headers, success, failure) {
+    return publicInterface.sendRequest(url, { method: 'patch', data: data, headers: headers }, success, failure);
+  }
+
+  function del(url, params, headers, success, failure) {
+    return publicInterface.sendRequest(url, { method: 'delete', params: params, headers: headers }, success, failure);
+  }
+
+  function head(url, params, headers, success, failure) {
+    return publicInterface.sendRequest(url, { method: 'head', params: params, headers: headers }, success, failure);
+  }
+
+  function uploadFile(url, params, headers, filePath, name, success, failure) {
+    return publicInterface.sendRequest(url, { method: 'upload', params: params, headers: headers, filePath: filePath, name: name }, success, failure);
+  }
+
+  function downloadFile(url, params, headers, filePath, success, failure) {
+    return publicInterface.sendRequest(url, { method: 'download', params: params, headers: headers, filePath: filePath }, success, failure);
+  }
+
+  return publicInterface;
+}
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/umd-tough-cookie.js b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/umd-tough-cookie.js
new file mode 100644
index 0000000..bd8ab68
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/umd-tough-cookie.js
@@ -0,0 +1,5091 @@
+cordova.define("cordova-plugin-advanced-http.tough-cookie", function(require, exports, module) {
+(function webpackUniversalModuleDefinition(root, factory) {
+	if(typeof exports === 'object' && typeof module === 'object')
+		module.exports = factory();
+	else if(typeof define === 'function' && define.amd)
+		define([], factory);
+	else if(typeof exports === 'object')
+		exports["ToughCookie"] = factory();
+	else
+		root["ToughCookie"] = factory();
+})(this, function() {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ 	// The module cache
+/******/ 	var installedModules = {};
+
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+
+/******/ 		// Check if module is in cache
+/******/ 		if(installedModules[moduleId])
+/******/ 			return installedModules[moduleId].exports;
+
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = installedModules[moduleId] = {
+/******/ 			exports: {},
+/******/ 			id: moduleId,
+/******/ 			loaded: false
+/******/ 		};
+
+/******/ 		// Execute the module function
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ 		// Flag the module as loaded
+/******/ 		module.loaded = true;
+
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+
+
+/******/ 	// expose the modules object (__webpack_modules__)
+/******/ 	__webpack_require__.m = modules;
+
+/******/ 	// expose the module cache
+/******/ 	__webpack_require__.c = installedModules;
+
+/******/ 	// __webpack_public_path__
+/******/ 	__webpack_require__.p = "";
+
+/******/ 	// Load entry module and return exports
+/******/ 	return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/*!
+	 * Copyright (c) 2015, Salesforce.com, Inc.
+	 * All rights reserved.
+	 *
+	 * Redistribution and use in source and binary forms, with or without
+	 * modification, are permitted provided that the following conditions are met:
+	 *
+	 * 1. Redistributions of source code must retain the above copyright notice,
+	 * this list of conditions and the following disclaimer.
+	 *
+	 * 2. Redistributions in binary form must reproduce the above copyright notice,
+	 * this list of conditions and the following disclaimer in the documentation
+	 * and/or other materials provided with the distribution.
+	 *
+	 * 3. Neither the name of Salesforce.com nor the names of its contributors may
+	 * be used to endorse or promote products derived from this software without
+	 * specific prior written permission.
+	 *
+	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+	 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+	 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+	 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+	 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+	 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	 * POSSIBILITY OF SUCH DAMAGE.
+	 */
+	'use strict';
+	var net = __webpack_require__(1);
+	var urlParse = __webpack_require__(2).parse;
+	var util = __webpack_require__(9);
+	var pubsuffix = __webpack_require__(13);
+	var Store = __webpack_require__(17).Store;
+	var MemoryCookieStore = __webpack_require__(18).MemoryCookieStore;
+	var pathMatch = __webpack_require__(20).pathMatch;
+	var VERSION = __webpack_require__(21).version;
+
+	var punycode;
+	try {
+	  punycode = __webpack_require__(15);
+	} catch(e) {
+	  console.warn("tough-cookie: can't load punycode; won't use punycode for domain normalization");
+	}
+
+	// From RFC6265 S4.1.1
+	// note that it excludes \x3B ";"
+	var COOKIE_OCTETS = /^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]+$/;
+
+	var CONTROL_CHARS = /[\x00-\x1F]/;
+
+	// From Chromium // '\r', '\n' and '\0' should be treated as a terminator in
+	// the "relaxed" mode, see:
+	// https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/parsed_cookie.cc#L60
+	var TERMINATORS = ['\n', '\r', '\0'];
+
+	// RFC6265 S4.1.1 defines path value as 'any CHAR except CTLs or ";"'
+	// Note ';' is \x3B
+	var PATH_VALUE = /[\x20-\x3A\x3C-\x7E]+/;
+
+	// date-time parsing constants (RFC6265 S5.1.1)
+
+	var DATE_DELIM = /[\x09\x20-\x2F\x3B-\x40\x5B-\x60\x7B-\x7E]/;
+
+	var MONTH_TO_NUM = {
+	  jan:0, feb:1, mar:2, apr:3, may:4, jun:5,
+	  jul:6, aug:7, sep:8, oct:9, nov:10, dec:11
+	};
+	var NUM_TO_MONTH = [
+	  'Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'
+	];
+	var NUM_TO_DAY = [
+	  'Sun','Mon','Tue','Wed','Thu','Fri','Sat'
+	];
+
+	var MAX_TIME = 2147483647000; // 31-bit max
+	var MIN_TIME = 0; // 31-bit min
+
+	/*
+	 * Parses a Natural number (i.e., non-negative integer) with either the
+	 *    <min>*<max>DIGIT ( non-digit *OCTET )
+	 * or
+	 *    <min>*<max>DIGIT
+	 * grammar (RFC6265 S5.1.1).
+	 *
+	 * The "trailingOK" boolean controls if the grammar accepts a
+	 * "( non-digit *OCTET )" trailer.
+	 */
+	function parseDigits(token, minDigits, maxDigits, trailingOK) {
+	  var count = 0;
+	  while (count < token.length) {
+	    var c = token.charCodeAt(count);
+	    // "non-digit = %x00-2F / %x3A-FF"
+	    if (c <= 0x2F || c >= 0x3A) {
+	      break;
+	    }
+	    count++;
+	  }
+
+	  // constrain to a minimum and maximum number of digits.
+	  if (count < minDigits || count > maxDigits) {
+	    return null;
+	  }
+
+	  if (!trailingOK && count != token.length) {
+	    return null;
+	  }
+
+	  return parseInt(token.substr(0,count), 10);
+	}
+
+	function parseTime(token) {
+	  var parts = token.split(':');
+	  var result = [0,0,0];
+
+	  /* RF6256 S5.1.1:
+	   *      time            = hms-time ( non-digit *OCTET )
+	   *      hms-time        = time-field ":" time-field ":" time-field
+	   *      time-field      = 1*2DIGIT
+	   */
+
+	  if (parts.length !== 3) {
+	    return null;
+	  }
+
+	  for (var i = 0; i < 3; i++) {
+	    // "time-field" must be strictly "1*2DIGIT", HOWEVER, "hms-time" can be
+	    // followed by "( non-digit *OCTET )" so therefore the last time-field can
+	    // have a trailer
+	    var trailingOK = (i == 2);
+	    var num = parseDigits(parts[i], 1, 2, trailingOK);
+	    if (num === null) {
+	      return null;
+	    }
+	    result[i] = num;
+	  }
+
+	  return result;
+	}
+
+	function parseMonth(token) {
+	  token = String(token).substr(0,3).toLowerCase();
+	  var num = MONTH_TO_NUM[token];
+	  return num >= 0 ? num : null;
+	}
+
+	/*
+	 * RFC6265 S5.1.1 date parser (see RFC for full grammar)
+	 */
+	function parseDate(str) {
+	  if (!str) {
+	    return;
+	  }
+
+	  /* RFC6265 S5.1.1:
+	   * 2. Process each date-token sequentially in the order the date-tokens
+	   * appear in the cookie-date
+	   */
+	  var tokens = str.split(DATE_DELIM);
+	  if (!tokens) {
+	    return;
+	  }
+
+	  var hour = null;
+	  var minute = null;
+	  var second = null;
+	  var dayOfMonth = null;
+	  var month = null;
+	  var year = null;
+
+	  for (var i=0; i<tokens.length; i++) {
+	    var token = tokens[i].trim();
+	    if (!token.length) {
+	      continue;
+	    }
+
+	    var result;
+
+	    /* 2.1. If the found-time flag is not set and the token matches the time
+	     * production, set the found-time flag and set the hour- value,
+	     * minute-value, and second-value to the numbers denoted by the digits in
+	     * the date-token, respectively.  Skip the remaining sub-steps and continue
+	     * to the next date-token.
+	     */
+	    if (second === null) {
+	      result = parseTime(token);
+	      if (result) {
+	        hour = result[0];
+	        minute = result[1];
+	        second = result[2];
+	        continue;
+	      }
+	    }
+
+	    /* 2.2. If the found-day-of-month flag is not set and the date-token matches
+	     * the day-of-month production, set the found-day-of- month flag and set
+	     * the day-of-month-value to the number denoted by the date-token.  Skip
+	     * the remaining sub-steps and continue to the next date-token.
+	     */
+	    if (dayOfMonth === null) {
+	      // "day-of-month = 1*2DIGIT ( non-digit *OCTET )"
+	      result = parseDigits(token, 1, 2, true);
+	      if (result !== null) {
+	        dayOfMonth = result;
+	        continue;
+	      }
+	    }
+
+	    /* 2.3. If the found-month flag is not set and the date-token matches the
+	     * month production, set the found-month flag and set the month-value to
+	     * the month denoted by the date-token.  Skip the remaining sub-steps and
+	     * continue to the next date-token.
+	     */
+	    if (month === null) {
+	      result = parseMonth(token);
+	      if (result !== null) {
+	        month = result;
+	        continue;
+	      }
+	    }
+
+	    /* 2.4. If the found-year flag is not set and the date-token matches the
+	     * year production, set the found-year flag and set the year-value to the
+	     * number denoted by the date-token.  Skip the remaining sub-steps and
+	     * continue to the next date-token.
+	     */
+	    if (year === null) {
+	      // "year = 2*4DIGIT ( non-digit *OCTET )"
+	      result = parseDigits(token, 2, 4, true);
+	      if (result !== null) {
+	        year = result;
+	        /* From S5.1.1:
+	         * 3.  If the year-value is greater than or equal to 70 and less
+	         * than or equal to 99, increment the year-value by 1900.
+	         * 4.  If the year-value is greater than or equal to 0 and less
+	         * than or equal to 69, increment the year-value by 2000.
+	         */
+	        if (year >= 70 && year <= 99) {
+	          year += 1900;
+	        } else if (year >= 0 && year <= 69) {
+	          year += 2000;
+	        }
+	      }
+	    }
+	  }
+
+	  /* RFC 6265 S5.1.1
+	   * "5. Abort these steps and fail to parse the cookie-date if:
+	   *     *  at least one of the found-day-of-month, found-month, found-
+	   *        year, or found-time flags is not set,
+	   *     *  the day-of-month-value is less than 1 or greater than 31,
+	   *     *  the year-value is less than 1601,
+	   *     *  the hour-value is greater than 23,
+	   *     *  the minute-value is greater than 59, or
+	   *     *  the second-value is greater than 59.
+	   *     (Note that leap seconds cannot be represented in this syntax.)"
+	   *
+	   * So, in order as above:
+	   */
+	  if (
+	    dayOfMonth === null || month === null || year === null || second === null ||
+	    dayOfMonth < 1 || dayOfMonth > 31 ||
+	    year < 1601 ||
+	    hour > 23 ||
+	    minute > 59 ||
+	    second > 59
+	  ) {
+	    return;
+	  }
+
+	  return new Date(Date.UTC(year, month, dayOfMonth, hour, minute, second));
+	}
+
+	function formatDate(date) {
+	  var d = date.getUTCDate(); d = d >= 10 ? d : '0'+d;
+	  var h = date.getUTCHours(); h = h >= 10 ? h : '0'+h;
+	  var m = date.getUTCMinutes(); m = m >= 10 ? m : '0'+m;
+	  var s = date.getUTCSeconds(); s = s >= 10 ? s : '0'+s;
+	  return NUM_TO_DAY[date.getUTCDay()] + ', ' +
+	    d+' '+ NUM_TO_MONTH[date.getUTCMonth()] +' '+ date.getUTCFullYear() +' '+
+	    h+':'+m+':'+s+' GMT';
+	}
+
+	// S5.1.2 Canonicalized Host Names
+	function canonicalDomain(str) {
+	  if (str == null) {
+	    return null;
+	  }
+	  str = str.trim().replace(/^\./,''); // S4.1.2.3 & S5.2.3: ignore leading .
+
+	  // convert to IDN if any non-ASCII characters
+	  if (punycode && /[^\u0001-\u007f]/.test(str)) {
+	    str = punycode.toASCII(str);
+	  }
+
+	  return str.toLowerCase();
+	}
+
+	// S5.1.3 Domain Matching
+	function domainMatch(str, domStr, canonicalize) {
+	  if (str == null || domStr == null) {
+	    return null;
+	  }
+	  if (canonicalize !== false) {
+	    str = canonicalDomain(str);
+	    domStr = canonicalDomain(domStr);
+	  }
+
+	  /*
+	   * "The domain string and the string are identical. (Note that both the
+	   * domain string and the string will have been canonicalized to lower case at
+	   * this point)"
+	   */
+	  if (str == domStr) {
+	    return true;
+	  }
+
+	  /* "All of the following [three] conditions hold:" (order adjusted from the RFC) */
+
+	  /* "* The string is a host name (i.e., not an IP address)." */
+	  if (net.isIP(str)) {
+	    return false;
+	  }
+
+	  /* "* The domain string is a suffix of the string" */
+	  var idx = str.indexOf(domStr);
+	  if (idx <= 0) {
+	    return false; // it's a non-match (-1) or prefix (0)
+	  }
+
+	  // e.g "a.b.c".indexOf("b.c") === 2
+	  // 5 === 3+2
+	  if (str.length !== domStr.length + idx) { // it's not a suffix
+	    return false;
+	  }
+
+	  /* "* The last character of the string that is not included in the domain
+	  * string is a %x2E (".") character." */
+	  if (str.substr(idx-1,1) !== '.') {
+	    return false;
+	  }
+
+	  return true;
+	}
+
+
+	// RFC6265 S5.1.4 Paths and Path-Match
+
+	/*
+	 * "The user agent MUST use an algorithm equivalent to the following algorithm
+	 * to compute the default-path of a cookie:"
+	 *
+	 * Assumption: the path (and not query part or absolute uri) is passed in.
+	 */
+	function defaultPath(path) {
+	  // "2. If the uri-path is empty or if the first character of the uri-path is not
+	  // a %x2F ("/") character, output %x2F ("/") and skip the remaining steps.
+	  if (!path || path.substr(0,1) !== "/") {
+	    return "/";
+	  }
+
+	  // "3. If the uri-path contains no more than one %x2F ("/") character, output
+	  // %x2F ("/") and skip the remaining step."
+	  if (path === "/") {
+	    return path;
+	  }
+
+	  var rightSlash = path.lastIndexOf("/");
+	  if (rightSlash === 0) {
+	    return "/";
+	  }
+
+	  // "4. Output the characters of the uri-path from the first character up to,
+	  // but not including, the right-most %x2F ("/")."
+	  return path.slice(0, rightSlash);
+	}
+
+	function trimTerminator(str) {
+	  for (var t = 0; t < TERMINATORS.length; t++) {
+	    var terminatorIdx = str.indexOf(TERMINATORS[t]);
+	    if (terminatorIdx !== -1) {
+	      str = str.substr(0,terminatorIdx);
+	    }
+	  }
+
+	  return str;
+	}
+
+	function parseCookiePair(cookiePair, looseMode) {
+	  cookiePair = trimTerminator(cookiePair);
+
+	  var firstEq = cookiePair.indexOf('=');
+	  if (looseMode) {
+	    if (firstEq === 0) { // '=' is immediately at start
+	      cookiePair = cookiePair.substr(1);
+	      firstEq = cookiePair.indexOf('='); // might still need to split on '='
+	    }
+	  } else { // non-loose mode
+	    if (firstEq <= 0) { // no '=' or is at start
+	      return; // needs to have non-empty "cookie-name"
+	    }
+	  }
+
+	  var cookieName, cookieValue;
+	  if (firstEq <= 0) {
+	    cookieName = "";
+	    cookieValue = cookiePair.trim();
+	  } else {
+	    cookieName = cookiePair.substr(0, firstEq).trim();
+	    cookieValue = cookiePair.substr(firstEq+1).trim();
+	  }
+
+	  if (CONTROL_CHARS.test(cookieName) || CONTROL_CHARS.test(cookieValue)) {
+	    return;
+	  }
+
+	  var c = new Cookie();
+	  c.key = cookieName;
+	  c.value = cookieValue;
+	  return c;
+	}
+
+	function parse(str, options) {
+	  if (!options || typeof options !== 'object') {
+	    options = {};
+	  }
+	  str = str.trim();
+
+	  // We use a regex to parse the "name-value-pair" part of S5.2
+	  var firstSemi = str.indexOf(';'); // S5.2 step 1
+	  var cookiePair = (firstSemi === -1) ? str : str.substr(0, firstSemi);
+	  var c = parseCookiePair(cookiePair, !!options.loose);
+	  if (!c) {
+	    return;
+	  }
+
+	  if (firstSemi === -1) {
+	    return c;
+	  }
+
+	  // S5.2.3 "unparsed-attributes consist of the remainder of the set-cookie-string
+	  // (including the %x3B (";") in question)." plus later on in the same section
+	  // "discard the first ";" and trim".
+	  var unparsed = str.slice(firstSemi + 1).trim();
+
+	  // "If the unparsed-attributes string is empty, skip the rest of these
+	  // steps."
+	  if (unparsed.length === 0) {
+	    return c;
+	  }
+
+	  /*
+	   * S5.2 says that when looping over the items "[p]rocess the attribute-name
+	   * and attribute-value according to the requirements in the following
+	   * subsections" for every item.  Plus, for many of the individual attributes
+	   * in S5.3 it says to use the "attribute-value of the last attribute in the
+	   * cookie-attribute-list".  Therefore, in this implementation, we overwrite
+	   * the previous value.
+	   */
+	  var cookie_avs = unparsed.split(';');
+	  while (cookie_avs.length) {
+	    var av = cookie_avs.shift().trim();
+	    if (av.length === 0) { // happens if ";;" appears
+	      continue;
+	    }
+	    var av_sep = av.indexOf('=');
+	    var av_key, av_value;
+
+	    if (av_sep === -1) {
+	      av_key = av;
+	      av_value = null;
+	    } else {
+	      av_key = av.substr(0,av_sep);
+	      av_value = av.substr(av_sep+1);
+	    }
+
+	    av_key = av_key.trim().toLowerCase();
+
+	    if (av_value) {
+	      av_value = av_value.trim();
+	    }
+
+	    switch(av_key) {
+	    case 'expires': // S5.2.1
+	      if (av_value) {
+	        var exp = parseDate(av_value);
+	        // "If the attribute-value failed to parse as a cookie date, ignore the
+	        // cookie-av."
+	        if (exp) {
+	          // over and underflow not realistically a concern: V8's getTime() seems to
+	          // store something larger than a 32-bit time_t (even with 32-bit node)
+	          c.expires = exp;
+	        }
+	      }
+	      break;
+
+	    case 'max-age': // S5.2.2
+	      if (av_value) {
+	        // "If the first character of the attribute-value is not a DIGIT or a "-"
+	        // character ...[or]... If the remainder of attribute-value contains a
+	        // non-DIGIT character, ignore the cookie-av."
+	        if (/^-?[0-9]+$/.test(av_value)) {
+	          var delta = parseInt(av_value, 10);
+	          // "If delta-seconds is less than or equal to zero (0), let expiry-time
+	          // be the earliest representable date and time."
+	          c.setMaxAge(delta);
+	        }
+	      }
+	      break;
+
+	    case 'domain': // S5.2.3
+	      // "If the attribute-value is empty, the behavior is undefined.  However,
+	      // the user agent SHOULD ignore the cookie-av entirely."
+	      if (av_value) {
+	        // S5.2.3 "Let cookie-domain be the attribute-value without the leading %x2E
+	        // (".") character."
+	        var domain = av_value.trim().replace(/^\./, '');
+	        if (domain) {
+	          // "Convert the cookie-domain to lower case."
+	          c.domain = domain.toLowerCase();
+	        }
+	      }
+	      break;
+
+	    case 'path': // S5.2.4
+	      /*
+	       * "If the attribute-value is empty or if the first character of the
+	       * attribute-value is not %x2F ("/"):
+	       *   Let cookie-path be the default-path.
+	       * Otherwise:
+	       *   Let cookie-path be the attribute-value."
+	       *
+	       * We'll represent the default-path as null since it depends on the
+	       * context of the parsing.
+	       */
+	      c.path = av_value && av_value[0] === "/" ? av_value : null;
+	      break;
+
+	    case 'secure': // S5.2.5
+	      /*
+	       * "If the attribute-name case-insensitively matches the string "Secure",
+	       * the user agent MUST append an attribute to the cookie-attribute-list
+	       * with an attribute-name of Secure and an empty attribute-value."
+	       */
+	      c.secure = true;
+	      break;
+
+	    case 'httponly': // S5.2.6 -- effectively the same as 'secure'
+	      c.httpOnly = true;
+	      break;
+
+	    default:
+	      c.extensions = c.extensions || [];
+	      c.extensions.push(av);
+	      break;
+	    }
+	  }
+
+	  return c;
+	}
+
+	// avoid the V8 deoptimization monster!
+	function jsonParse(str) {
+	  var obj;
+	  try {
+	    obj = JSON.parse(str);
+	  } catch (e) {
+	    return e;
+	  }
+	  return obj;
+	}
+
+	function fromJSON(str) {
+	  if (!str) {
+	    return null;
+	  }
+
+	  var obj;
+	  if (typeof str === 'string') {
+	    obj = jsonParse(str);
+	    if (obj instanceof Error) {
+	      return null;
+	    }
+	  } else {
+	    // assume it's an Object
+	    obj = str;
+	  }
+
+	  var c = new Cookie();
+	  for (var i=0; i<Cookie.serializableProperties.length; i++) {
+	    var prop = Cookie.serializableProperties[i];
+	    if (obj[prop] === undefined ||
+	        obj[prop] === Cookie.prototype[prop])
+	    {
+	      continue; // leave as prototype default
+	    }
+
+	    if (prop === 'expires' ||
+	        prop === 'creation' ||
+	        prop === 'lastAccessed')
+	    {
+	      if (obj[prop] === null) {
+	        c[prop] = null;
+	      } else {
+	        c[prop] = obj[prop] == "Infinity" ?
+	          "Infinity" : new Date(obj[prop]);
+	      }
+	    } else {
+	      c[prop] = obj[prop];
+	    }
+	  }
+
+	  return c;
+	}
+
+	/* Section 5.4 part 2:
+	 * "*  Cookies with longer paths are listed before cookies with
+	 *     shorter paths.
+	 *
+	 *  *  Among cookies that have equal-length path fields, cookies with
+	 *     earlier creation-times are listed before cookies with later
+	 *     creation-times."
+	 */
+
+	function cookieCompare(a,b) {
+	  var cmp = 0;
+
+	  // descending for length: b CMP a
+	  var aPathLen = a.path ? a.path.length : 0;
+	  var bPathLen = b.path ? b.path.length : 0;
+	  cmp = bPathLen - aPathLen;
+	  if (cmp !== 0) {
+	    return cmp;
+	  }
+
+	  // ascending for time: a CMP b
+	  var aTime = a.creation ? a.creation.getTime() : MAX_TIME;
+	  var bTime = b.creation ? b.creation.getTime() : MAX_TIME;
+	  cmp = aTime - bTime;
+	  if (cmp !== 0) {
+	    return cmp;
+	  }
+
+	  // break ties for the same millisecond (precision of JavaScript's clock)
+	  cmp = a.creationIndex - b.creationIndex;
+
+	  return cmp;
+	}
+
+	// Gives the permutation of all possible pathMatch()es of a given path. The
+	// array is in longest-to-shortest order.  Handy for indexing.
+	function permutePath(path) {
+	  if (path === '/') {
+	    return ['/'];
+	  }
+	  if (path.lastIndexOf('/') === path.length-1) {
+	    path = path.substr(0,path.length-1);
+	  }
+	  var permutations = [path];
+	  while (path.length > 1) {
+	    var lindex = path.lastIndexOf('/');
+	    if (lindex === 0) {
+	      break;
+	    }
+	    path = path.substr(0,lindex);
+	    permutations.push(path);
+	  }
+	  permutations.push('/');
+	  return permutations;
+	}
+
+	function getCookieContext(url) {
+	  if (url instanceof Object) {
+	    return url;
+	  }
+	  // NOTE: decodeURI will throw on malformed URIs (see GH-32).
+	  // Therefore, we will just skip decoding for such URIs.
+	  try {
+	    url = decodeURI(url);
+	  }
+	  catch(err) {
+	    // Silently swallow error
+	  }
+
+	  return urlParse(url);
+	}
+
+	function Cookie(options) {
+	  options = options || {};
+
+	  Object.keys(options).forEach(function(prop) {
+	    if (Cookie.prototype.hasOwnProperty(prop) &&
+	        Cookie.prototype[prop] !== options[prop] &&
+	        prop.substr(0,1) !== '_')
+	    {
+	      this[prop] = options[prop];
+	    }
+	  }, this);
+
+	  this.creation = this.creation || new Date();
+
+	  // used to break creation ties in cookieCompare():
+	  Object.defineProperty(this, 'creationIndex', {
+	    configurable: false,
+	    enumerable: false, // important for assert.deepEqual checks
+	    writable: true,
+	    value: ++Cookie.cookiesCreated
+	  });
+	}
+
+	Cookie.cookiesCreated = 0; // incremented each time a cookie is created
+
+	Cookie.parse = parse;
+	Cookie.fromJSON = fromJSON;
+
+	Cookie.prototype.key = "";
+	Cookie.prototype.value = "";
+
+	// the order in which the RFC has them:
+	Cookie.prototype.expires = "Infinity"; // coerces to literal Infinity
+	Cookie.prototype.maxAge = null; // takes precedence over expires for TTL
+	Cookie.prototype.domain = null;
+	Cookie.prototype.path = null;
+	Cookie.prototype.secure = false;
+	Cookie.prototype.httpOnly = false;
+	Cookie.prototype.extensions = null;
+
+	// set by the CookieJar:
+	Cookie.prototype.hostOnly = null; // boolean when set
+	Cookie.prototype.pathIsDefault = null; // boolean when set
+	Cookie.prototype.creation = null; // Date when set; defaulted by Cookie.parse
+	Cookie.prototype.lastAccessed = null; // Date when set
+	Object.defineProperty(Cookie.prototype, 'creationIndex', {
+	  configurable: true,
+	  enumerable: false,
+	  writable: true,
+	  value: 0
+	});
+
+	Cookie.serializableProperties = Object.keys(Cookie.prototype)
+	  .filter(function(prop) {
+	    return !(
+	      Cookie.prototype[prop] instanceof Function ||
+	      prop === 'creationIndex' ||
+	      prop.substr(0,1) === '_'
+	    );
+	  });
+
+	Cookie.prototype.inspect = function inspect() {
+	  var now = Date.now();
+	  return 'Cookie="'+this.toString() +
+	    '; hostOnly='+(this.hostOnly != null ? this.hostOnly : '?') +
+	    '; aAge='+(this.lastAccessed ? (now-this.lastAccessed.getTime())+'ms' : '?') +
+	    '; cAge='+(this.creation ? (now-this.creation.getTime())+'ms' : '?') +
+	    '"';
+	};
+
+	// Use the new custom inspection symbol to add the custom inspect function if
+	// available.
+	if (util.inspect.custom) {
+	  Cookie.prototype[util.inspect.custom] = Cookie.prototype.inspect;
+	}
+
+	Cookie.prototype.toJSON = function() {
+	  var obj = {};
+
+	  var props = Cookie.serializableProperties;
+	  for (var i=0; i<props.length; i++) {
+	    var prop = props[i];
+	    if (this[prop] === Cookie.prototype[prop]) {
+	      continue; // leave as prototype default
+	    }
+
+	    if (prop === 'expires' ||
+	        prop === 'creation' ||
+	        prop === 'lastAccessed')
+	    {
+	      if (this[prop] === null) {
+	        obj[prop] = null;
+	      } else {
+	        obj[prop] = this[prop] == "Infinity" ? // intentionally not ===
+	          "Infinity" : this[prop].toISOString();
+	      }
+	    } else if (prop === 'maxAge') {
+	      if (this[prop] !== null) {
+	        // again, intentionally not ===
+	        obj[prop] = (this[prop] == Infinity || this[prop] == -Infinity) ?
+	          this[prop].toString() : this[prop];
+	      }
+	    } else {
+	      if (this[prop] !== Cookie.prototype[prop]) {
+	        obj[prop] = this[prop];
+	      }
+	    }
+	  }
+
+	  return obj;
+	};
+
+	Cookie.prototype.clone = function() {
+	  return fromJSON(this.toJSON());
+	};
+
+	Cookie.prototype.validate = function validate() {
+	  if (!COOKIE_OCTETS.test(this.value)) {
+	    return false;
+	  }
+	  if (this.expires != Infinity && !(this.expires instanceof Date) && !parseDate(this.expires)) {
+	    return false;
+	  }
+	  if (this.maxAge != null && this.maxAge <= 0) {
+	    return false; // "Max-Age=" non-zero-digit *DIGIT
+	  }
+	  if (this.path != null && !PATH_VALUE.test(this.path)) {
+	    return false;
+	  }
+
+	  var cdomain = this.cdomain();
+	  if (cdomain) {
+	    if (cdomain.match(/\.$/)) {
+	      return false; // S4.1.2.3 suggests that this is bad. domainMatch() tests confirm this
+	    }
+	    var suffix = pubsuffix.getPublicSuffix(cdomain);
+	    if (suffix == null) { // it's a public suffix
+	      return false;
+	    }
+	  }
+	  return true;
+	};
+
+	Cookie.prototype.setExpires = function setExpires(exp) {
+	  if (exp instanceof Date) {
+	    this.expires = exp;
+	  } else {
+	    this.expires = parseDate(exp) || "Infinity";
+	  }
+	};
+
+	Cookie.prototype.setMaxAge = function setMaxAge(age) {
+	  if (age === Infinity || age === -Infinity) {
+	    this.maxAge = age.toString(); // so JSON.stringify() works
+	  } else {
+	    this.maxAge = age;
+	  }
+	};
+
+	// gives Cookie header format
+	Cookie.prototype.cookieString = function cookieString() {
+	  var val = this.value;
+	  if (val == null) {
+	    val = '';
+	  }
+	  if (this.key === '') {
+	    return val;
+	  }
+	  return this.key+'='+val;
+	};
+
+	// gives Set-Cookie header format
+	Cookie.prototype.toString = function toString() {
+	  var str = this.cookieString();
+
+	  if (this.expires != Infinity) {
+	    if (this.expires instanceof Date) {
+	      str += '; Expires='+formatDate(this.expires);
+	    } else {
+	      str += '; Expires='+this.expires;
+	    }
+	  }
+
+	  if (this.maxAge != null && this.maxAge != Infinity) {
+	    str += '; Max-Age='+this.maxAge;
+	  }
+
+	  if (this.domain && !this.hostOnly) {
+	    str += '; Domain='+this.domain;
+	  }
+	  if (this.path) {
+	    str += '; Path='+this.path;
+	  }
+
+	  if (this.secure) {
+	    str += '; Secure';
+	  }
+	  if (this.httpOnly) {
+	    str += '; HttpOnly';
+	  }
+	  if (this.extensions) {
+	    this.extensions.forEach(function(ext) {
+	      str += '; '+ext;
+	    });
+	  }
+
+	  return str;
+	};
+
+	// TTL() partially replaces the "expiry-time" parts of S5.3 step 3 (setCookie()
+	// elsewhere)
+	// S5.3 says to give the "latest representable date" for which we use Infinity
+	// For "expired" we use 0
+	Cookie.prototype.TTL = function TTL(now) {
+	  /* RFC6265 S4.1.2.2 If a cookie has both the Max-Age and the Expires
+	   * attribute, the Max-Age attribute has precedence and controls the
+	   * expiration date of the cookie.
+	   * (Concurs with S5.3 step 3)
+	   */
+	  if (this.maxAge != null) {
+	    return this.maxAge<=0 ? 0 : this.maxAge*1000;
+	  }
+
+	  var expires = this.expires;
+	  if (expires != Infinity) {
+	    if (!(expires instanceof Date)) {
+	      expires = parseDate(expires) || Infinity;
+	    }
+
+	    if (expires == Infinity) {
+	      return Infinity;
+	    }
+
+	    return expires.getTime() - (now || Date.now());
+	  }
+
+	  return Infinity;
+	};
+
+	// expiryTime() replaces the "expiry-time" parts of S5.3 step 3 (setCookie()
+	// elsewhere)
+	Cookie.prototype.expiryTime = function expiryTime(now) {
+	  if (this.maxAge != null) {
+	    var relativeTo = now || this.creation || new Date();
+	    var age = (this.maxAge <= 0) ? -Infinity : this.maxAge*1000;
+	    return relativeTo.getTime() + age;
+	  }
+
+	  if (this.expires == Infinity) {
+	    return Infinity;
+	  }
+	  return this.expires.getTime();
+	};
+
+	// expiryDate() replaces the "expiry-time" parts of S5.3 step 3 (setCookie()
+	// elsewhere), except it returns a Date
+	Cookie.prototype.expiryDate = function expiryDate(now) {
+	  var millisec = this.expiryTime(now);
+	  if (millisec == Infinity) {
+	    return new Date(MAX_TIME);
+	  } else if (millisec == -Infinity) {
+	    return new Date(MIN_TIME);
+	  } else {
+	    return new Date(millisec);
+	  }
+	};
+
+	// This replaces the "persistent-flag" parts of S5.3 step 3
+	Cookie.prototype.isPersistent = function isPersistent() {
+	  return (this.maxAge != null || this.expires != Infinity);
+	};
+
+	// Mostly S5.1.2 and S5.2.3:
+	Cookie.prototype.cdomain =
+	Cookie.prototype.canonicalizedDomain = function canonicalizedDomain() {
+	  if (this.domain == null) {
+	    return null;
+	  }
+	  return canonicalDomain(this.domain);
+	};
+
+	function CookieJar(store, options) {
+	  if (typeof options === "boolean") {
+	    options = {rejectPublicSuffixes: options};
+	  } else if (options == null) {
+	    options = {};
+	  }
+	  if (options.rejectPublicSuffixes != null) {
+	    this.rejectPublicSuffixes = options.rejectPublicSuffixes;
+	  }
+	  if (options.looseMode != null) {
+	    this.enableLooseMode = options.looseMode;
+	  }
+
+	  if (!store) {
+	    store = new MemoryCookieStore();
+	  }
+	  this.store = store;
+	}
+	CookieJar.prototype.store = null;
+	CookieJar.prototype.rejectPublicSuffixes = true;
+	CookieJar.prototype.enableLooseMode = false;
+	var CAN_BE_SYNC = [];
+
+	CAN_BE_SYNC.push('setCookie');
+	CookieJar.prototype.setCookie = function(cookie, url, options, cb) {
+	  var err;
+	  var context = getCookieContext(url);
+	  if (options instanceof Function) {
+	    cb = options;
+	    options = {};
+	  }
+
+	  var host = canonicalDomain(context.hostname);
+	  var loose = this.enableLooseMode;
+	  if (options.loose != null) {
+	    loose = options.loose;
+	  }
+
+	  // S5.3 step 1
+	  if (!(cookie instanceof Cookie)) {
+	    cookie = Cookie.parse(cookie, { loose: loose });
+	  }
+	  if (!cookie) {
+	    err = new Error("Cookie failed to parse");
+	    return cb(options.ignoreError ? null : err);
+	  }
+
+	  // S5.3 step 2
+	  var now = options.now || new Date(); // will assign later to save effort in the face of errors
+
+	  // S5.3 step 3: NOOP; persistent-flag and expiry-time is handled by getCookie()
+
+	  // S5.3 step 4: NOOP; domain is null by default
+
+	  // S5.3 step 5: public suffixes
+	  if (this.rejectPublicSuffixes && cookie.domain) {
+	    var suffix = pubsuffix.getPublicSuffix(cookie.cdomain());
+	    if (suffix == null) { // e.g. "com"
+	      err = new Error("Cookie has domain set to a public suffix");
+	      return cb(options.ignoreError ? null : err);
+	    }
+	  }
+
+	  // S5.3 step 6:
+	  if (cookie.domain) {
+	    if (!domainMatch(host, cookie.cdomain(), false)) {
+	      err = new Error("Cookie not in this host's domain. Cookie:"+cookie.cdomain()+" Request:"+host);
+	      return cb(options.ignoreError ? null : err);
+	    }
+
+	    if (cookie.hostOnly == null) { // don't reset if already set
+	      cookie.hostOnly = false;
+	    }
+
+	  } else {
+	    cookie.hostOnly = true;
+	    cookie.domain = host;
+	  }
+
+	  //S5.2.4 If the attribute-value is empty or if the first character of the
+	  //attribute-value is not %x2F ("/"):
+	  //Let cookie-path be the default-path.
+	  if (!cookie.path || cookie.path[0] !== '/') {
+	    cookie.path = defaultPath(context.pathname);
+	    cookie.pathIsDefault = true;
+	  }
+
+	  // S5.3 step 8: NOOP; secure attribute
+	  // S5.3 step 9: NOOP; httpOnly attribute
+
+	  // S5.3 step 10
+	  if (options.http === false && cookie.httpOnly) {
+	    err = new Error("Cookie is HttpOnly and this isn't an HTTP API");
+	    return cb(options.ignoreError ? null : err);
+	  }
+
+	  var store = this.store;
+
+	  if (!store.updateCookie) {
+	    store.updateCookie = function(oldCookie, newCookie, cb) {
+	      this.putCookie(newCookie, cb);
+	    };
+	  }
+
+	  function withCookie(err, oldCookie) {
+	    if (err) {
+	      return cb(err);
+	    }
+
+	    var next = function(err) {
+	      if (err) {
+	        return cb(err);
+	      } else {
+	        cb(null, cookie);
+	      }
+	    };
+
+	    if (oldCookie) {
+	      // S5.3 step 11 - "If the cookie store contains a cookie with the same name,
+	      // domain, and path as the newly created cookie:"
+	      if (options.http === false && oldCookie.httpOnly) { // step 11.2
+	        err = new Error("old Cookie is HttpOnly and this isn't an HTTP API");
+	        return cb(options.ignoreError ? null : err);
+	      }
+	      cookie.creation = oldCookie.creation; // step 11.3
+	      cookie.creationIndex = oldCookie.creationIndex; // preserve tie-breaker
+	      cookie.lastAccessed = now;
+	      // Step 11.4 (delete cookie) is implied by just setting the new one:
+	      store.updateCookie(oldCookie, cookie, next); // step 12
+
+	    } else {
+	      cookie.creation = cookie.lastAccessed = now;
+	      store.putCookie(cookie, next); // step 12
+	    }
+	  }
+
+	  store.findCookie(cookie.domain, cookie.path, cookie.key, withCookie);
+	};
+
+	// RFC6365 S5.4
+	CAN_BE_SYNC.push('getCookies');
+	CookieJar.prototype.getCookies = function(url, options, cb) {
+	  var context = getCookieContext(url);
+	  if (options instanceof Function) {
+	    cb = options;
+	    options = {};
+	  }
+
+	  var host = canonicalDomain(context.hostname);
+	  var path = context.pathname || '/';
+
+	  var secure = options.secure;
+	  if (secure == null && context.protocol &&
+	      (context.protocol == 'https:' || context.protocol == 'wss:'))
+	  {
+	    secure = true;
+	  }
+
+	  var http = options.http;
+	  if (http == null) {
+	    http = true;
+	  }
+
+	  var now = options.now || Date.now();
+	  var expireCheck = options.expire !== false;
+	  var allPaths = !!options.allPaths;
+	  var store = this.store;
+
+	  function matchingCookie(c) {
+	    // "Either:
+	    //   The cookie's host-only-flag is true and the canonicalized
+	    //   request-host is identical to the cookie's domain.
+	    // Or:
+	    //   The cookie's host-only-flag is false and the canonicalized
+	    //   request-host domain-matches the cookie's domain."
+	    if (c.hostOnly) {
+	      if (c.domain != host) {
+	        return false;
+	      }
+	    } else {
+	      if (!domainMatch(host, c.domain, false)) {
+	        return false;
+	      }
+	    }
+
+	    // "The request-uri's path path-matches the cookie's path."
+	    if (!allPaths && !pathMatch(path, c.path)) {
+	      return false;
+	    }
+
+	    // "If the cookie's secure-only-flag is true, then the request-uri's
+	    // scheme must denote a "secure" protocol"
+	    if (c.secure && !secure) {
+	      return false;
+	    }
+
+	    // "If the cookie's http-only-flag is true, then exclude the cookie if the
+	    // cookie-string is being generated for a "non-HTTP" API"
+	    if (c.httpOnly && !http) {
+	      return false;
+	    }
+
+	    // deferred from S5.3
+	    // non-RFC: allow retention of expired cookies by choice
+	    if (expireCheck && c.expiryTime() <= now) {
+	      store.removeCookie(c.domain, c.path, c.key, function(){}); // result ignored
+	      return false;
+	    }
+
+	    return true;
+	  }
+
+	  store.findCookies(host, allPaths ? null : path, function(err,cookies) {
+	    if (err) {
+	      return cb(err);
+	    }
+
+	    cookies = cookies.filter(matchingCookie);
+
+	    // sorting of S5.4 part 2
+	    if (options.sort !== false) {
+	      cookies = cookies.sort(cookieCompare);
+	    }
+
+	    // S5.4 part 3
+	    var now = new Date();
+	    cookies.forEach(function(c) {
+	      c.lastAccessed = now;
+	    });
+	    // TODO persist lastAccessed
+
+	    cb(null,cookies);
+	  });
+	};
+
+	CAN_BE_SYNC.push('getCookieString');
+	CookieJar.prototype.getCookieString = function(/*..., cb*/) {
+	  var args = Array.prototype.slice.call(arguments,0);
+	  var cb = args.pop();
+	  var next = function(err,cookies) {
+	    if (err) {
+	      cb(err);
+	    } else {
+	      cb(null, cookies
+	        .sort(cookieCompare)
+	        .map(function(c){
+	          return c.cookieString();
+	        })
+	        .join('; '));
+	    }
+	  };
+	  args.push(next);
+	  this.getCookies.apply(this,args);
+	};
+
+	CAN_BE_SYNC.push('getSetCookieStrings');
+	CookieJar.prototype.getSetCookieStrings = function(/*..., cb*/) {
+	  var args = Array.prototype.slice.call(arguments,0);
+	  var cb = args.pop();
+	  var next = function(err,cookies) {
+	    if (err) {
+	      cb(err);
+	    } else {
+	      cb(null, cookies.map(function(c){
+	        return c.toString();
+	      }));
+	    }
+	  };
+	  args.push(next);
+	  this.getCookies.apply(this,args);
+	};
+
+	CAN_BE_SYNC.push('serialize');
+	CookieJar.prototype.serialize = function(cb) {
+	  var type = this.store.constructor.name;
+	  if (type === 'Object') {
+	    type = null;
+	  }
+
+	  // update README.md "Serialization Format" if you change this, please!
+	  var serialized = {
+	    // The version of tough-cookie that serialized this jar. Generally a good
+	    // practice since future versions can make data import decisions based on
+	    // known past behavior. When/if this matters, use `semver`.
+	    version: 'tough-cookie@'+VERSION,
+
+	    // add the store type, to make humans happy:
+	    storeType: type,
+
+	    // CookieJar configuration:
+	    rejectPublicSuffixes: !!this.rejectPublicSuffixes,
+
+	    // this gets filled from getAllCookies:
+	    cookies: []
+	  };
+
+	  if (!(this.store.getAllCookies &&
+	        typeof this.store.getAllCookies === 'function'))
+	  {
+	    return cb(new Error('store does not support getAllCookies and cannot be serialized'));
+	  }
+
+	  this.store.getAllCookies(function(err,cookies) {
+	    if (err) {
+	      return cb(err);
+	    }
+
+	    serialized.cookies = cookies.map(function(cookie) {
+	      // convert to serialized 'raw' cookies
+	      cookie = (cookie instanceof Cookie) ? cookie.toJSON() : cookie;
+
+	      // Remove the index so new ones get assigned during deserialization
+	      delete cookie.creationIndex;
+
+	      return cookie;
+	    });
+
+	    return cb(null, serialized);
+	  });
+	};
+
+	// well-known name that JSON.stringify calls
+	CookieJar.prototype.toJSON = function() {
+	  return this.serializeSync();
+	};
+
+	// use the class method CookieJar.deserialize instead of calling this directly
+	CAN_BE_SYNC.push('_importCookies');
+	CookieJar.prototype._importCookies = function(serialized, cb) {
+	  var jar = this;
+	  var cookies = serialized.cookies;
+	  if (!cookies || !Array.isArray(cookies)) {
+	    return cb(new Error('serialized jar has no cookies array'));
+	  }
+	  cookies = cookies.slice(); // do not modify the original
+
+	  function putNext(err) {
+	    if (err) {
+	      return cb(err);
+	    }
+
+	    if (!cookies.length) {
+	      return cb(err, jar);
+	    }
+
+	    var cookie;
+	    try {
+	      cookie = fromJSON(cookies.shift());
+	    } catch (e) {
+	      return cb(e);
+	    }
+
+	    if (cookie === null) {
+	      return putNext(null); // skip this cookie
+	    }
+
+	    jar.store.putCookie(cookie, putNext);
+	  }
+
+	  putNext();
+	};
+
+	CookieJar.deserialize = function(strOrObj, store, cb) {
+	  if (arguments.length !== 3) {
+	    // store is optional
+	    cb = store;
+	    store = null;
+	  }
+
+	  var serialized;
+	  if (typeof strOrObj === 'string') {
+	    serialized = jsonParse(strOrObj);
+	    if (serialized instanceof Error) {
+	      return cb(serialized);
+	    }
+	  } else {
+	    serialized = strOrObj;
+	  }
+
+	  var jar = new CookieJar(store, serialized.rejectPublicSuffixes);
+	  jar._importCookies(serialized, function(err) {
+	    if (err) {
+	      return cb(err);
+	    }
+	    cb(null, jar);
+	  });
+	};
+
+	CookieJar.deserializeSync = function(strOrObj, store) {
+	  var serialized = typeof strOrObj === 'string' ?
+	    JSON.parse(strOrObj) : strOrObj;
+	  var jar = new CookieJar(store, serialized.rejectPublicSuffixes);
+
+	  // catch this mistake early:
+	  if (!jar.store.synchronous) {
+	    throw new Error('CookieJar store is not synchronous; use async API instead.');
+	  }
+
+	  jar._importCookiesSync(serialized);
+	  return jar;
+	};
+	CookieJar.fromJSON = CookieJar.deserializeSync;
+
+	CAN_BE_SYNC.push('clone');
+	CookieJar.prototype.clone = function(newStore, cb) {
+	  if (arguments.length === 1) {
+	    cb = newStore;
+	    newStore = null;
+	  }
+
+	  this.serialize(function(err,serialized) {
+	    if (err) {
+	      return cb(err);
+	    }
+	    CookieJar.deserialize(newStore, serialized, cb);
+	  });
+	};
+
+	// Use a closure to provide a true imperative API for synchronous stores.
+	function syncWrap(method) {
+	  return function() {
+	    if (!this.store.synchronous) {
+	      throw new Error('CookieJar store is not synchronous; use async API instead.');
+	    }
+
+	    var args = Array.prototype.slice.call(arguments);
+	    var syncErr, syncResult;
+	    args.push(function syncCb(err, result) {
+	      syncErr = err;
+	      syncResult = result;
+	    });
+	    this[method].apply(this, args);
+
+	    if (syncErr) {
+	      throw syncErr;
+	    }
+	    return syncResult;
+	  };
+	}
+
+	// wrap all declared CAN_BE_SYNC methods in the sync wrapper
+	CAN_BE_SYNC.forEach(function(method) {
+	  CookieJar.prototype[method+'Sync'] = syncWrap(method);
+	});
+
+	exports.CookieJar = CookieJar;
+	exports.Cookie = Cookie;
+	exports.Store = Store;
+	exports.MemoryCookieStore = MemoryCookieStore;
+	exports.parseDate = parseDate;
+	exports.formatDate = formatDate;
+	exports.parse = parse;
+	exports.fromJSON = fromJSON;
+	exports.domainMatch = domainMatch;
+	exports.defaultPath = defaultPath;
+	exports.pathMatch = pathMatch;
+	exports.getPublicSuffix = pubsuffix.getPublicSuffix;
+	exports.cookieCompare = cookieCompare;
+	exports.permuteDomain = __webpack_require__(19).permuteDomain;
+	exports.permutePath = permutePath;
+	exports.canonicalDomain = canonicalDomain;
+
+
+/***/ }),
+/* 1 */
+/***/ (function(module, exports) {
+
+	/*
+	* Tests if a given ip or host string is a valid IPv4 or IPv6 address.
+	* Regex found at: https://stackoverflow.com/questions/9208814/validate-ipv4-ipv6-and-hostname
+	*/
+
+	var patternIPv4 = /^\s*((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\s*$/g;
+	var patternIPv6 = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/g;
+
+	function isIPv4(hostOrIp) {
+	  return hostOrIp.match(patternIPv4) ? true : false;
+	}
+
+	function isIPv6(hostOrIp) {
+	  return hostOrIp.match(patternIPv6) ? true : false;
+	}
+
+	function isIP(hostOrIp) {
+	  if (isIPv4(hostOrIp)) {
+	    return 4;
+	  }
+
+	  if (isIPv6(hostOrIp)) {
+	    return 6;
+	  }
+
+	  return 0;
+	}
+
+	module.exports = {
+	  isIPv4: isIPv4,
+	  isIPv6: isIPv6,
+	  isIP: isIP
+	};
+
+
+/***/ }),
+/* 2 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	// Copyright Joyent, Inc. and other Node contributors.
+	//
+	// Permission is hereby granted, free of charge, to any person obtaining a
+	// copy of this software and associated documentation files (the
+	// "Software"), to deal in the Software without restriction, including
+	// without limitation the rights to use, copy, modify, merge, publish,
+	// distribute, sublicense, and/or sell copies of the Software, and to permit
+	// persons to whom the Software is furnished to do so, subject to the
+	// following conditions:
+	//
+	// The above copyright notice and this permission notice shall be included
+	// in all copies or substantial portions of the Software.
+	//
+	// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+	// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+	// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+	// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+	// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+	// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+	// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+	'use strict';
+
+	var punycode = __webpack_require__(3);
+	var util = __webpack_require__(5);
+
+	exports.parse = urlParse;
+	exports.resolve = urlResolve;
+	exports.resolveObject = urlResolveObject;
+	exports.format = urlFormat;
+
+	exports.Url = Url;
+
+	function Url() {
+	  this.protocol = null;
+	  this.slashes = null;
+	  this.auth = null;
+	  this.host = null;
+	  this.port = null;
+	  this.hostname = null;
+	  this.hash = null;
+	  this.search = null;
+	  this.query = null;
+	  this.pathname = null;
+	  this.path = null;
+	  this.href = null;
+	}
+
+	// Reference: RFC 3986, RFC 1808, RFC 2396
+
+	// define these here so at least they only have to be
+	// compiled once on the first module load.
+	var protocolPattern = /^([a-z0-9.+-]+:)/i,
+	    portPattern = /:[0-9]*$/,
+
+	    // Special case for a simple path URL
+	    simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,
+
+	    // RFC 2396: characters reserved for delimiting URLs.
+	    // We actually just auto-escape these.
+	    delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'],
+
+	    // RFC 2396: characters not allowed for various reasons.
+	    unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims),
+
+	    // Allowed by RFCs, but cause of XSS attacks.  Always escape these.
+	    autoEscape = ['\''].concat(unwise),
+	    // Characters that are never ever allowed in a hostname.
+	    // Note that any invalid chars are also handled, but these
+	    // are the ones that are *expected* to be seen, so we fast-path
+	    // them.
+	    nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape),
+	    hostEndingChars = ['/', '?', '#'],
+	    hostnameMaxLen = 255,
+	    hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/,
+	    hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/,
+	    // protocols that can allow "unsafe" and "unwise" chars.
+	    unsafeProtocol = {
+	      'javascript': true,
+	      'javascript:': true
+	    },
+	    // protocols that never have a hostname.
+	    hostlessProtocol = {
+	      'javascript': true,
+	      'javascript:': true
+	    },
+	    // protocols that always contain a // bit.
+	    slashedProtocol = {
+	      'http': true,
+	      'https': true,
+	      'ftp': true,
+	      'gopher': true,
+	      'file': true,
+	      'http:': true,
+	      'https:': true,
+	      'ftp:': true,
+	      'gopher:': true,
+	      'file:': true
+	    },
+	    querystring = __webpack_require__(6);
+
+	function urlParse(url, parseQueryString, slashesDenoteHost) {
+	  if (url && util.isObject(url) && url instanceof Url) return url;
+
+	  var u = new Url;
+	  u.parse(url, parseQueryString, slashesDenoteHost);
+	  return u;
+	}
+
+	Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
+	  if (!util.isString(url)) {
+	    throw new TypeError("Parameter 'url' must be a string, not " + typeof url);
+	  }
+
+	  // Copy chrome, IE, opera backslash-handling behavior.
+	  // Back slashes before the query string get converted to forward slashes
+	  // See: https://code.google.com/p/chromium/issues/detail?id=25916
+	  var queryIndex = url.indexOf('?'),
+	      splitter =
+	          (queryIndex !== -1 && queryIndex < url.indexOf('#')) ? '?' : '#',
+	      uSplit = url.split(splitter),
+	      slashRegex = /\\/g;
+	  uSplit[0] = uSplit[0].replace(slashRegex, '/');
+	  url = uSplit.join(splitter);
+
+	  var rest = url;
+
+	  // trim before proceeding.
+	  // This is to support parse stuff like "  http://foo.com  \n"
+	  rest = rest.trim();
+
+	  if (!slashesDenoteHost && url.split('#').length === 1) {
+	    // Try fast path regexp
+	    var simplePath = simplePathPattern.exec(rest);
+	    if (simplePath) {
+	      this.path = rest;
+	      this.href = rest;
+	      this.pathname = simplePath[1];
+	      if (simplePath[2]) {
+	        this.search = simplePath[2];
+	        if (parseQueryString) {
+	          this.query = querystring.parse(this.search.substr(1));
+	        } else {
+	          this.query = this.search.substr(1);
+	        }
+	      } else if (parseQueryString) {
+	        this.search = '';
+	        this.query = {};
+	      }
+	      return this;
+	    }
+	  }
+
+	  var proto = protocolPattern.exec(rest);
+	  if (proto) {
+	    proto = proto[0];
+	    var lowerProto = proto.toLowerCase();
+	    this.protocol = lowerProto;
+	    rest = rest.substr(proto.length);
+	  }
+
+	  // figure out if it's got a host
+	  // user@server is *always* interpreted as a hostname, and url
+	  // resolution will treat //foo/bar as host=foo,path=bar because that's
+	  // how the browser resolves relative URLs.
+	  if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) {
+	    var slashes = rest.substr(0, 2) === '//';
+	    if (slashes && !(proto && hostlessProtocol[proto])) {
+	      rest = rest.substr(2);
+	      this.slashes = true;
+	    }
+	  }
+
+	  if (!hostlessProtocol[proto] &&
+	      (slashes || (proto && !slashedProtocol[proto]))) {
+
+	    // there's a hostname.
+	    // the first instance of /, ?, ;, or # ends the host.
+	    //
+	    // If there is an @ in the hostname, then non-host chars *are* allowed
+	    // to the left of the last @ sign, unless some host-ending character
+	    // comes *before* the @-sign.
+	    // URLs are obnoxious.
+	    //
+	    // ex:
+	    // http://a@b@c/ => user:a@b host:c
+	    // http://a@b?@c => user:a host:c path:/?@c
+
+	    // v0.12 TODO(isaacs): This is not quite how Chrome does things.
+	    // Review our test case against browsers more comprehensively.
+
+	    // find the first instance of any hostEndingChars
+	    var hostEnd = -1;
+	    for (var i = 0; i < hostEndingChars.length; i++) {
+	      var hec = rest.indexOf(hostEndingChars[i]);
+	      if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))
+	        hostEnd = hec;
+	    }
+
+	    // at this point, either we have an explicit point where the
+	    // auth portion cannot go past, or the last @ char is the decider.
+	    var auth, atSign;
+	    if (hostEnd === -1) {
+	      // atSign can be anywhere.
+	      atSign = rest.lastIndexOf('@');
+	    } else {
+	      // atSign must be in auth portion.
+	      // http://a@b/c@d => host:b auth:a path:/c@d
+	      atSign = rest.lastIndexOf('@', hostEnd);
+	    }
+
+	    // Now we have a portion which is definitely the auth.
+	    // Pull that off.
+	    if (atSign !== -1) {
+	      auth = rest.slice(0, atSign);
+	      rest = rest.slice(atSign + 1);
+	      this.auth = decodeURIComponent(auth);
+	    }
+
+	    // the host is the remaining to the left of the first non-host char
+	    hostEnd = -1;
+	    for (var i = 0; i < nonHostChars.length; i++) {
+	      var hec = rest.indexOf(nonHostChars[i]);
+	      if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))
+	        hostEnd = hec;
+	    }
+	    // if we still have not hit it, then the entire thing is a host.
+	    if (hostEnd === -1)
+	      hostEnd = rest.length;
+
+	    this.host = rest.slice(0, hostEnd);
+	    rest = rest.slice(hostEnd);
+
+	    // pull out port.
+	    this.parseHost();
+
+	    // we've indicated that there is a hostname,
+	    // so even if it's empty, it has to be present.
+	    this.hostname = this.hostname || '';
+
+	    // if hostname begins with [ and ends with ]
+	    // assume that it's an IPv6 address.
+	    var ipv6Hostname = this.hostname[0] === '[' &&
+	        this.hostname[this.hostname.length - 1] === ']';
+
+	    // validate a little.
+	    if (!ipv6Hostname) {
+	      var hostparts = this.hostname.split(/\./);
+	      for (var i = 0, l = hostparts.length; i < l; i++) {
+	        var part = hostparts[i];
+	        if (!part) continue;
+	        if (!part.match(hostnamePartPattern)) {
+	          var newpart = '';
+	          for (var j = 0, k = part.length; j < k; j++) {
+	            if (part.charCodeAt(j) > 127) {
+	              // we replace non-ASCII char with a temporary placeholder
+	              // we need this to make sure size of hostname is not
+	              // broken by replacing non-ASCII by nothing
+	              newpart += 'x';
+	            } else {
+	              newpart += part[j];
+	            }
+	          }
+	          // we test again with ASCII char only
+	          if (!newpart.match(hostnamePartPattern)) {
+	            var validParts = hostparts.slice(0, i);
+	            var notHost = hostparts.slice(i + 1);
+	            var bit = part.match(hostnamePartStart);
+	            if (bit) {
+	              validParts.push(bit[1]);
+	              notHost.unshift(bit[2]);
+	            }
+	            if (notHost.length) {
+	              rest = '/' + notHost.join('.') + rest;
+	            }
+	            this.hostname = validParts.join('.');
+	            break;
+	          }
+	        }
+	      }
+	    }
+
+	    if (this.hostname.length > hostnameMaxLen) {
+	      this.hostname = '';
+	    } else {
+	      // hostnames are always lower case.
+	      this.hostname = this.hostname.toLowerCase();
+	    }
+
+	    if (!ipv6Hostname) {
+	      // IDNA Support: Returns a punycoded representation of "domain".
+	      // It only converts parts of the domain name that
+	      // have non-ASCII characters, i.e. it doesn't matter if
+	      // you call it with a domain that already is ASCII-only.
+	      this.hostname = punycode.toASCII(this.hostname);
+	    }
+
+	    var p = this.port ? ':' + this.port : '';
+	    var h = this.hostname || '';
+	    this.host = h + p;
+	    this.href += this.host;
+
+	    // strip [ and ] from the hostname
+	    // the host field still retains them, though
+	    if (ipv6Hostname) {
+	      this.hostname = this.hostname.substr(1, this.hostname.length - 2);
+	      if (rest[0] !== '/') {
+	        rest = '/' + rest;
+	      }
+	    }
+	  }
+
+	  // now rest is set to the post-host stuff.
+	  // chop off any delim chars.
+	  if (!unsafeProtocol[lowerProto]) {
+
+	    // First, make 100% sure that any "autoEscape" chars get
+	    // escaped, even if encodeURIComponent doesn't think they
+	    // need to be.
+	    for (var i = 0, l = autoEscape.length; i < l; i++) {
+	      var ae = autoEscape[i];
+	      if (rest.indexOf(ae) === -1)
+	        continue;
+	      var esc = encodeURIComponent(ae);
+	      if (esc === ae) {
+	        esc = escape(ae);
+	      }
+	      rest = rest.split(ae).join(esc);
+	    }
+	  }
+
+
+	  // chop off from the tail first.
+	  var hash = rest.indexOf('#');
+	  if (hash !== -1) {
+	    // got a fragment string.
+	    this.hash = rest.substr(hash);
+	    rest = rest.slice(0, hash);
+	  }
+	  var qm = rest.indexOf('?');
+	  if (qm !== -1) {
+	    this.search = rest.substr(qm);
+	    this.query = rest.substr(qm + 1);
+	    if (parseQueryString) {
+	      this.query = querystring.parse(this.query);
+	    }
+	    rest = rest.slice(0, qm);
+	  } else if (parseQueryString) {
+	    // no query string, but parseQueryString still requested
+	    this.search = '';
+	    this.query = {};
+	  }
+	  if (rest) this.pathname = rest;
+	  if (slashedProtocol[lowerProto] &&
+	      this.hostname && !this.pathname) {
+	    this.pathname = '/';
+	  }
+
+	  //to support http.request
+	  if (this.pathname || this.search) {
+	    var p = this.pathname || '';
+	    var s = this.search || '';
+	    this.path = p + s;
+	  }
+
+	  // finally, reconstruct the href based on what has been validated.
+	  this.href = this.format();
+	  return this;
+	};
+
+	// format a parsed object into a url string
+	function urlFormat(obj) {
+	  // ensure it's an object, and not a string url.
+	  // If it's an obj, this is a no-op.
+	  // this way, you can call url_format() on strings
+	  // to clean up potentially wonky urls.
+	  if (util.isString(obj)) obj = urlParse(obj);
+	  if (!(obj instanceof Url)) return Url.prototype.format.call(obj);
+	  return obj.format();
+	}
+
+	Url.prototype.format = function() {
+	  var auth = this.auth || '';
+	  if (auth) {
+	    auth = encodeURIComponent(auth);
+	    auth = auth.replace(/%3A/i, ':');
+	    auth += '@';
+	  }
+
+	  var protocol = this.protocol || '',
+	      pathname = this.pathname || '',
+	      hash = this.hash || '',
+	      host = false,
+	      query = '';
+
+	  if (this.host) {
+	    host = auth + this.host;
+	  } else if (this.hostname) {
+	    host = auth + (this.hostname.indexOf(':') === -1 ?
+	        this.hostname :
+	        '[' + this.hostname + ']');
+	    if (this.port) {
+	      host += ':' + this.port;
+	    }
+	  }
+
+	  if (this.query &&
+	      util.isObject(this.query) &&
+	      Object.keys(this.query).length) {
+	    query = querystring.stringify(this.query);
+	  }
+
+	  var search = this.search || (query && ('?' + query)) || '';
+
+	  if (protocol && protocol.substr(-1) !== ':') protocol += ':';
+
+	  // only the slashedProtocols get the //.  Not mailto:, xmpp:, etc.
+	  // unless they had them to begin with.
+	  if (this.slashes ||
+	      (!protocol || slashedProtocol[protocol]) && host !== false) {
+	    host = '//' + (host || '');
+	    if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname;
+	  } else if (!host) {
+	    host = '';
+	  }
+
+	  if (hash && hash.charAt(0) !== '#') hash = '#' + hash;
+	  if (search && search.charAt(0) !== '?') search = '?' + search;
+
+	  pathname = pathname.replace(/[?#]/g, function(match) {
+	    return encodeURIComponent(match);
+	  });
+	  search = search.replace('#', '%23');
+
+	  return protocol + host + pathname + search + hash;
+	};
+
+	function urlResolve(source, relative) {
+	  return urlParse(source, false, true).resolve(relative);
+	}
+
+	Url.prototype.resolve = function(relative) {
+	  return this.resolveObject(urlParse(relative, false, true)).format();
+	};
+
+	function urlResolveObject(source, relative) {
+	  if (!source) return relative;
+	  return urlParse(source, false, true).resolveObject(relative);
+	}
+
+	Url.prototype.resolveObject = function(relative) {
+	  if (util.isString(relative)) {
+	    var rel = new Url();
+	    rel.parse(relative, false, true);
+	    relative = rel;
+	  }
+
+	  var result = new Url();
+	  var tkeys = Object.keys(this);
+	  for (var tk = 0; tk < tkeys.length; tk++) {
+	    var tkey = tkeys[tk];
+	    result[tkey] = this[tkey];
+	  }
+
+	  // hash is always overridden, no matter what.
+	  // even href="" will remove it.
+	  result.hash = relative.hash;
+
+	  // if the relative url is empty, then there's nothing left to do here.
+	  if (relative.href === '') {
+	    result.href = result.format();
+	    return result;
+	  }
+
+	  // hrefs like //foo/bar always cut to the protocol.
+	  if (relative.slashes && !relative.protocol) {
+	    // take everything except the protocol from relative
+	    var rkeys = Object.keys(relative);
+	    for (var rk = 0; rk < rkeys.length; rk++) {
+	      var rkey = rkeys[rk];
+	      if (rkey !== 'protocol')
+	        result[rkey] = relative[rkey];
+	    }
+
+	    //urlParse appends trailing / to urls like http://www.example.com
+	    if (slashedProtocol[result.protocol] &&
+	        result.hostname && !result.pathname) {
+	      result.path = result.pathname = '/';
+	    }
+
+	    result.href = result.format();
+	    return result;
+	  }
+
+	  if (relative.protocol && relative.protocol !== result.protocol) {
+	    // if it's a known url protocol, then changing
+	    // the protocol does weird things
+	    // first, if it's not file:, then we MUST have a host,
+	    // and if there was a path
+	    // to begin with, then we MUST have a path.
+	    // if it is file:, then the host is dropped,
+	    // because that's known to be hostless.
+	    // anything else is assumed to be absolute.
+	    if (!slashedProtocol[relative.protocol]) {
+	      var keys = Object.keys(relative);
+	      for (var v = 0; v < keys.length; v++) {
+	        var k = keys[v];
+	        result[k] = relative[k];
+	      }
+	      result.href = result.format();
+	      return result;
+	    }
+
+	    result.protocol = relative.protocol;
+	    if (!relative.host && !hostlessProtocol[relative.protocol]) {
+	      var relPath = (relative.pathname || '').split('/');
+	      while (relPath.length && !(relative.host = relPath.shift()));
+	      if (!relative.host) relative.host = '';
+	      if (!relative.hostname) relative.hostname = '';
+	      if (relPath[0] !== '') relPath.unshift('');
+	      if (relPath.length < 2) relPath.unshift('');
+	      result.pathname = relPath.join('/');
+	    } else {
+	      result.pathname = relative.pathname;
+	    }
+	    result.search = relative.search;
+	    result.query = relative.query;
+	    result.host = relative.host || '';
+	    result.auth = relative.auth;
+	    result.hostname = relative.hostname || relative.host;
+	    result.port = relative.port;
+	    // to support http.request
+	    if (result.pathname || result.search) {
+	      var p = result.pathname || '';
+	      var s = result.search || '';
+	      result.path = p + s;
+	    }
+	    result.slashes = result.slashes || relative.slashes;
+	    result.href = result.format();
+	    return result;
+	  }
+
+	  var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'),
+	      isRelAbs = (
+	          relative.host ||
+	          relative.pathname && relative.pathname.charAt(0) === '/'
+	      ),
+	      mustEndAbs = (isRelAbs || isSourceAbs ||
+	                    (result.host && relative.pathname)),
+	      removeAllDots = mustEndAbs,
+	      srcPath = result.pathname && result.pathname.split('/') || [],
+	      relPath = relative.pathname && relative.pathname.split('/') || [],
+	      psychotic = result.protocol && !slashedProtocol[result.protocol];
+
+	  // if the url is a non-slashed url, then relative
+	  // links like ../.. should be able
+	  // to crawl up to the hostname, as well.  This is strange.
+	  // result.protocol has already been set by now.
+	  // Later on, put the first path part into the host field.
+	  if (psychotic) {
+	    result.hostname = '';
+	    result.port = null;
+	    if (result.host) {
+	      if (srcPath[0] === '') srcPath[0] = result.host;
+	      else srcPath.unshift(result.host);
+	    }
+	    result.host = '';
+	    if (relative.protocol) {
+	      relative.hostname = null;
+	      relative.port = null;
+	      if (relative.host) {
+	        if (relPath[0] === '') relPath[0] = relative.host;
+	        else relPath.unshift(relative.host);
+	      }
+	      relative.host = null;
+	    }
+	    mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === '');
+	  }
+
+	  if (isRelAbs) {
+	    // it's absolute.
+	    result.host = (relative.host || relative.host === '') ?
+	                  relative.host : result.host;
+	    result.hostname = (relative.hostname || relative.hostname === '') ?
+	                      relative.hostname : result.hostname;
+	    result.search = relative.search;
+	    result.query = relative.query;
+	    srcPath = relPath;
+	    // fall through to the dot-handling below.
+	  } else if (relPath.length) {
+	    // it's relative
+	    // throw away the existing file, and take the new path instead.
+	    if (!srcPath) srcPath = [];
+	    srcPath.pop();
+	    srcPath = srcPath.concat(relPath);
+	    result.search = relative.search;
+	    result.query = relative.query;
+	  } else if (!util.isNullOrUndefined(relative.search)) {
+	    // just pull out the search.
+	    // like href='?foo'.
+	    // Put this after the other two cases because it simplifies the booleans
+	    if (psychotic) {
+	      result.hostname = result.host = srcPath.shift();
+	      //occationaly the auth can get stuck only in host
+	      //this especially happens in cases like
+	      //url.resolveObject('mailto:local1@domain1', 'local2@domain2')
+	      var authInHost = result.host && result.host.indexOf('@') > 0 ?
+	                       result.host.split('@') : false;
+	      if (authInHost) {
+	        result.auth = authInHost.shift();
+	        result.host = result.hostname = authInHost.shift();
+	      }
+	    }
+	    result.search = relative.search;
+	    result.query = relative.query;
+	    //to support http.request
+	    if (!util.isNull(result.pathname) || !util.isNull(result.search)) {
+	      result.path = (result.pathname ? result.pathname : '') +
+	                    (result.search ? result.search : '');
+	    }
+	    result.href = result.format();
+	    return result;
+	  }
+
+	  if (!srcPath.length) {
+	    // no path at all.  easy.
+	    // we've already handled the other stuff above.
+	    result.pathname = null;
+	    //to support http.request
+	    if (result.search) {
+	      result.path = '/' + result.search;
+	    } else {
+	      result.path = null;
+	    }
+	    result.href = result.format();
+	    return result;
+	  }
+
+	  // if a url ENDs in . or .., then it must get a trailing slash.
+	  // however, if it ends in anything else non-slashy,
+	  // then it must NOT get a trailing slash.
+	  var last = srcPath.slice(-1)[0];
+	  var hasTrailingSlash = (
+	      (result.host || relative.host || srcPath.length > 1) &&
+	      (last === '.' || last === '..') || last === '');
+
+	  // strip single dots, resolve double dots to parent dir
+	  // if the path tries to go above the root, `up` ends up > 0
+	  var up = 0;
+	  for (var i = srcPath.length; i >= 0; i--) {
+	    last = srcPath[i];
+	    if (last === '.') {
+	      srcPath.splice(i, 1);
+	    } else if (last === '..') {
+	      srcPath.splice(i, 1);
+	      up++;
+	    } else if (up) {
+	      srcPath.splice(i, 1);
+	      up--;
+	    }
+	  }
+
+	  // if the path is allowed to go above the root, restore leading ..s
+	  if (!mustEndAbs && !removeAllDots) {
+	    for (; up--; up) {
+	      srcPath.unshift('..');
+	    }
+	  }
+
+	  if (mustEndAbs && srcPath[0] !== '' &&
+	      (!srcPath[0] || srcPath[0].charAt(0) !== '/')) {
+	    srcPath.unshift('');
+	  }
+
+	  if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) {
+	    srcPath.push('');
+	  }
+
+	  var isAbsolute = srcPath[0] === '' ||
+	      (srcPath[0] && srcPath[0].charAt(0) === '/');
+
+	  // put the host back
+	  if (psychotic) {
+	    result.hostname = result.host = isAbsolute ? '' :
+	                                    srcPath.length ? srcPath.shift() : '';
+	    //occationaly the auth can get stuck only in host
+	    //this especially happens in cases like
+	    //url.resolveObject('mailto:local1@domain1', 'local2@domain2')
+	    var authInHost = result.host && result.host.indexOf('@') > 0 ?
+	                     result.host.split('@') : false;
+	    if (authInHost) {
+	      result.auth = authInHost.shift();
+	      result.host = result.hostname = authInHost.shift();
+	    }
+	  }
+
+	  mustEndAbs = mustEndAbs || (result.host && srcPath.length);
+
+	  if (mustEndAbs && !isAbsolute) {
+	    srcPath.unshift('');
+	  }
+
+	  if (!srcPath.length) {
+	    result.pathname = null;
+	    result.path = null;
+	  } else {
+	    result.pathname = srcPath.join('/');
+	  }
+
+	  //to support request.http
+	  if (!util.isNull(result.pathname) || !util.isNull(result.search)) {
+	    result.path = (result.pathname ? result.pathname : '') +
+	                  (result.search ? result.search : '');
+	  }
+	  result.auth = relative.auth || result.auth;
+	  result.slashes = result.slashes || relative.slashes;
+	  result.href = result.format();
+	  return result;
+	};
+
+	Url.prototype.parseHost = function() {
+	  var host = this.host;
+	  var port = portPattern.exec(host);
+	  if (port) {
+	    port = port[0];
+	    if (port !== ':') {
+	      this.port = port.substr(1);
+	    }
+	    host = host.substr(0, host.length - port.length);
+	  }
+	  if (host) this.hostname = host;
+	};
+
+
+/***/ }),
+/* 3 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(module, global) {/*! https://mths.be/punycode v1.3.2 by @mathias */
+	;(function(root) {
+
+		/** Detect free variables */
+		var freeExports = typeof exports == 'object' && exports &&
+			!exports.nodeType && exports;
+		var freeModule = typeof module == 'object' && module &&
+			!module.nodeType && module;
+		var freeGlobal = typeof global == 'object' && global;
+		if (
+			freeGlobal.global === freeGlobal ||
+			freeGlobal.window === freeGlobal ||
+			freeGlobal.self === freeGlobal
+		) {
+			root = freeGlobal;
+		}
+
+		/**
+		 * The `punycode` object.
+		 * @name punycode
+		 * @type Object
+		 */
+		var punycode,
+
+		/** Highest positive signed 32-bit float value */
+		maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
+
+		/** Bootstring parameters */
+		base = 36,
+		tMin = 1,
+		tMax = 26,
+		skew = 38,
+		damp = 700,
+		initialBias = 72,
+		initialN = 128, // 0x80
+		delimiter = '-', // '\x2D'
+
+		/** Regular expressions */
+		regexPunycode = /^xn--/,
+		regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
+		regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators
+
+		/** Error messages */
+		errors = {
+			'overflow': 'Overflow: input needs wider integers to process',
+			'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
+			'invalid-input': 'Invalid input'
+		},
+
+		/** Convenience shortcuts */
+		baseMinusTMin = base - tMin,
+		floor = Math.floor,
+		stringFromCharCode = String.fromCharCode,
+
+		/** Temporary variable */
+		key;
+
+		/*--------------------------------------------------------------------------*/
+
+		/**
+		 * A generic error utility function.
+		 * @private
+		 * @param {String} type The error type.
+		 * @returns {Error} Throws a `RangeError` with the applicable error message.
+		 */
+		function error(type) {
+			throw RangeError(errors[type]);
+		}
+
+		/**
+		 * A generic `Array#map` utility function.
+		 * @private
+		 * @param {Array} array The array to iterate over.
+		 * @param {Function} callback The function that gets called for every array
+		 * item.
+		 * @returns {Array} A new array of values returned by the callback function.
+		 */
+		function map(array, fn) {
+			var length = array.length;
+			var result = [];
+			while (length--) {
+				result[length] = fn(array[length]);
+			}
+			return result;
+		}
+
+		/**
+		 * A simple `Array#map`-like wrapper to work with domain name strings or email
+		 * addresses.
+		 * @private
+		 * @param {String} domain The domain name or email address.
+		 * @param {Function} callback The function that gets called for every
+		 * character.
+		 * @returns {Array} A new string of characters returned by the callback
+		 * function.
+		 */
+		function mapDomain(string, fn) {
+			var parts = string.split('@');
+			var result = '';
+			if (parts.length > 1) {
+				// In email addresses, only the domain name should be punycoded. Leave
+				// the local part (i.e. everything up to `@`) intact.
+				result = parts[0] + '@';
+				string = parts[1];
+			}
+			// Avoid `split(regex)` for IE8 compatibility. See #17.
+			string = string.replace(regexSeparators, '\x2E');
+			var labels = string.split('.');
+			var encoded = map(labels, fn).join('.');
+			return result + encoded;
+		}
+
+		/**
+		 * Creates an array containing the numeric code points of each Unicode
+		 * character in the string. While JavaScript uses UCS-2 internally,
+		 * this function will convert a pair of surrogate halves (each of which
+		 * UCS-2 exposes as separate characters) into a single code point,
+		 * matching UTF-16.
+		 * @see `punycode.ucs2.encode`
+		 * @see <https://mathiasbynens.be/notes/javascript-encoding>
+		 * @memberOf punycode.ucs2
+		 * @name decode
+		 * @param {String} string The Unicode input string (UCS-2).
+		 * @returns {Array} The new array of code points.
+		 */
+		function ucs2decode(string) {
+			var output = [],
+			    counter = 0,
+			    length = string.length,
+			    value,
+			    extra;
+			while (counter < length) {
+				value = string.charCodeAt(counter++);
+				if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
+					// high surrogate, and there is a next character
+					extra = string.charCodeAt(counter++);
+					if ((extra & 0xFC00) == 0xDC00) { // low surrogate
+						output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+					} else {
+						// unmatched surrogate; only append this code unit, in case the next
+						// code unit is the high surrogate of a surrogate pair
+						output.push(value);
+						counter--;
+					}
+				} else {
+					output.push(value);
+				}
+			}
+			return output;
+		}
+
+		/**
+		 * Creates a string based on an array of numeric code points.
+		 * @see `punycode.ucs2.decode`
+		 * @memberOf punycode.ucs2
+		 * @name encode
+		 * @param {Array} codePoints The array of numeric code points.
+		 * @returns {String} The new Unicode string (UCS-2).
+		 */
+		function ucs2encode(array) {
+			return map(array, function(value) {
+				var output = '';
+				if (value > 0xFFFF) {
+					value -= 0x10000;
+					output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
+					value = 0xDC00 | value & 0x3FF;
+				}
+				output += stringFromCharCode(value);
+				return output;
+			}).join('');
+		}
+
+		/**
+		 * Converts a basic code point into a digit/integer.
+		 * @see `digitToBasic()`
+		 * @private
+		 * @param {Number} codePoint The basic numeric code point value.
+		 * @returns {Number} The numeric value of a basic code point (for use in
+		 * representing integers) in the range `0` to `base - 1`, or `base` if
+		 * the code point does not represent a value.
+		 */
+		function basicToDigit(codePoint) {
+			if (codePoint - 48 < 10) {
+				return codePoint - 22;
+			}
+			if (codePoint - 65 < 26) {
+				return codePoint - 65;
+			}
+			if (codePoint - 97 < 26) {
+				return codePoint - 97;
+			}
+			return base;
+		}
+
+		/**
+		 * Converts a digit/integer into a basic code point.
+		 * @see `basicToDigit()`
+		 * @private
+		 * @param {Number} digit The numeric value of a basic code point.
+		 * @returns {Number} The basic code point whose value (when used for
+		 * representing integers) is `digit`, which needs to be in the range
+		 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
+		 * used; else, the lowercase form is used. The behavior is undefined
+		 * if `flag` is non-zero and `digit` has no uppercase form.
+		 */
+		function digitToBasic(digit, flag) {
+			//  0..25 map to ASCII a..z or A..Z
+			// 26..35 map to ASCII 0..9
+			return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
+		}
+
+		/**
+		 * Bias adaptation function as per section 3.4 of RFC 3492.
+		 * http://tools.ietf.org/html/rfc3492#section-3.4
+		 * @private
+		 */
+		function adapt(delta, numPoints, firstTime) {
+			var k = 0;
+			delta = firstTime ? floor(delta / damp) : delta >> 1;
+			delta += floor(delta / numPoints);
+			for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
+				delta = floor(delta / baseMinusTMin);
+			}
+			return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
+		}
+
+		/**
+		 * Converts a Punycode string of ASCII-only symbols to a string of Unicode
+		 * symbols.
+		 * @memberOf punycode
+		 * @param {String} input The Punycode string of ASCII-only symbols.
+		 * @returns {String} The resulting string of Unicode symbols.
+		 */
+		function decode(input) {
+			// Don't use UCS-2
+			var output = [],
+			    inputLength = input.length,
+			    out,
+			    i = 0,
+			    n = initialN,
+			    bias = initialBias,
+			    basic,
+			    j,
+			    index,
+			    oldi,
+			    w,
+			    k,
+			    digit,
+			    t,
+			    /** Cached calculation results */
+			    baseMinusT;
+
+			// Handle the basic code points: let `basic` be the number of input code
+			// points before the last delimiter, or `0` if there is none, then copy
+			// the first basic code points to the output.
+
+			basic = input.lastIndexOf(delimiter);
+			if (basic < 0) {
+				basic = 0;
+			}
+
+			for (j = 0; j < basic; ++j) {
+				// if it's not a basic code point
+				if (input.charCodeAt(j) >= 0x80) {
+					error('not-basic');
+				}
+				output.push(input.charCodeAt(j));
+			}
+
+			// Main decoding loop: start just after the last delimiter if any basic code
+			// points were copied; start at the beginning otherwise.
+
+			for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
+
+				// `index` is the index of the next character to be consumed.
+				// Decode a generalized variable-length integer into `delta`,
+				// which gets added to `i`. The overflow checking is easier
+				// if we increase `i` as we go, then subtract off its starting
+				// value at the end to obtain `delta`.
+				for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
+
+					if (index >= inputLength) {
+						error('invalid-input');
+					}
+
+					digit = basicToDigit(input.charCodeAt(index++));
+
+					if (digit >= base || digit > floor((maxInt - i) / w)) {
+						error('overflow');
+					}
+
+					i += digit * w;
+					t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+
+					if (digit < t) {
+						break;
+					}
+
+					baseMinusT = base - t;
+					if (w > floor(maxInt / baseMinusT)) {
+						error('overflow');
+					}
+
+					w *= baseMinusT;
+
+				}
+
+				out = output.length + 1;
+				bias = adapt(i - oldi, out, oldi == 0);
+
+				// `i` was supposed to wrap around from `out` to `0`,
+				// incrementing `n` each time, so we'll fix that now:
+				if (floor(i / out) > maxInt - n) {
+					error('overflow');
+				}
+
+				n += floor(i / out);
+				i %= out;
+
+				// Insert `n` at position `i` of the output
+				output.splice(i++, 0, n);
+
+			}
+
+			return ucs2encode(output);
+		}
+
+		/**
+		 * Converts a string of Unicode symbols (e.g. a domain name label) to a
+		 * Punycode string of ASCII-only symbols.
+		 * @memberOf punycode
+		 * @param {String} input The string of Unicode symbols.
+		 * @returns {String} The resulting Punycode string of ASCII-only symbols.
+		 */
+		function encode(input) {
+			var n,
+			    delta,
+			    handledCPCount,
+			    basicLength,
+			    bias,
+			    j,
+			    m,
+			    q,
+			    k,
+			    t,
+			    currentValue,
+			    output = [],
+			    /** `inputLength` will hold the number of code points in `input`. */
+			    inputLength,
+			    /** Cached calculation results */
+			    handledCPCountPlusOne,
+			    baseMinusT,
+			    qMinusT;
+
+			// Convert the input in UCS-2 to Unicode
+			input = ucs2decode(input);
+
+			// Cache the length
+			inputLength = input.length;
+
+			// Initialize the state
+			n = initialN;
+			delta = 0;
+			bias = initialBias;
+
+			// Handle the basic code points
+			for (j = 0; j < inputLength; ++j) {
+				currentValue = input[j];
+				if (currentValue < 0x80) {
+					output.push(stringFromCharCode(currentValue));
+				}
+			}
+
+			handledCPCount = basicLength = output.length;
+
+			// `handledCPCount` is the number of code points that have been handled;
+			// `basicLength` is the number of basic code points.
+
+			// Finish the basic string - if it is not empty - with a delimiter
+			if (basicLength) {
+				output.push(delimiter);
+			}
+
+			// Main encoding loop:
+			while (handledCPCount < inputLength) {
+
+				// All non-basic code points < n have been handled already. Find the next
+				// larger one:
+				for (m = maxInt, j = 0; j < inputLength; ++j) {
+					currentValue = input[j];
+					if (currentValue >= n && currentValue < m) {
+						m = currentValue;
+					}
+				}
+
+				// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
+				// but guard against overflow
+				handledCPCountPlusOne = handledCPCount + 1;
+				if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
+					error('overflow');
+				}
+
+				delta += (m - n) * handledCPCountPlusOne;
+				n = m;
+
+				for (j = 0; j < inputLength; ++j) {
+					currentValue = input[j];
+
+					if (currentValue < n && ++delta > maxInt) {
+						error('overflow');
+					}
+
+					if (currentValue == n) {
+						// Represent delta as a generalized variable-length integer
+						for (q = delta, k = base; /* no condition */; k += base) {
+							t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+							if (q < t) {
+								break;
+							}
+							qMinusT = q - t;
+							baseMinusT = base - t;
+							output.push(
+								stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
+							);
+							q = floor(qMinusT / baseMinusT);
+						}
+
+						output.push(stringFromCharCode(digitToBasic(q, 0)));
+						bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
+						delta = 0;
+						++handledCPCount;
+					}
+				}
+
+				++delta;
+				++n;
+
+			}
+			return output.join('');
+		}
+
+		/**
+		 * Converts a Punycode string representing a domain name or an email address
+		 * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
+		 * it doesn't matter if you call it on a string that has already been
+		 * converted to Unicode.
+		 * @memberOf punycode
+		 * @param {String} input The Punycoded domain name or email address to
+		 * convert to Unicode.
+		 * @returns {String} The Unicode representation of the given Punycode
+		 * string.
+		 */
+		function toUnicode(input) {
+			return mapDomain(input, function(string) {
+				return regexPunycode.test(string)
+					? decode(string.slice(4).toLowerCase())
+					: string;
+			});
+		}
+
+		/**
+		 * Converts a Unicode string representing a domain name or an email address to
+		 * Punycode. Only the non-ASCII parts of the domain name will be converted,
+		 * i.e. it doesn't matter if you call it with a domain that's already in
+		 * ASCII.
+		 * @memberOf punycode
+		 * @param {String} input The domain name or email address to convert, as a
+		 * Unicode string.
+		 * @returns {String} The Punycode representation of the given domain name or
+		 * email address.
+		 */
+		function toASCII(input) {
+			return mapDomain(input, function(string) {
+				return regexNonASCII.test(string)
+					? 'xn--' + encode(string)
+					: string;
+			});
+		}
+
+		/*--------------------------------------------------------------------------*/
+
+		/** Define the public API */
+		punycode = {
+			/**
+			 * A string representing the current Punycode.js version number.
+			 * @memberOf punycode
+			 * @type String
+			 */
+			'version': '1.3.2',
+			/**
+			 * An object of methods to convert from JavaScript's internal character
+			 * representation (UCS-2) to Unicode code points, and back.
+			 * @see <https://mathiasbynens.be/notes/javascript-encoding>
+			 * @memberOf punycode
+			 * @type Object
+			 */
+			'ucs2': {
+				'decode': ucs2decode,
+				'encode': ucs2encode
+			},
+			'decode': decode,
+			'encode': encode,
+			'toASCII': toASCII,
+			'toUnicode': toUnicode
+		};
+
+		/** Expose `punycode` */
+		// Some AMD build optimizers, like r.js, check for specific condition patterns
+		// like the following:
+		if (
+			true
+		) {
+			!(__WEBPACK_AMD_DEFINE_RESULT__ = function() {
+				return punycode;
+			}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+		} else if (freeExports && freeModule) {
+			if (module.exports == freeExports) { // in Node.js or RingoJS v0.8.0+
+				freeModule.exports = punycode;
+			} else { // in Narwhal or RingoJS v0.7.0-
+				for (key in punycode) {
+					punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
+				}
+			}
+		} else { // in Rhino or a web browser
+			root.punycode = punycode;
+		}
+
+	}(this));
+
+	/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)(module), (function() { return this; }())))
+
+/***/ }),
+/* 4 */
+/***/ (function(module, exports) {
+
+	module.exports = function(module) {

+		if(!module.webpackPolyfill) {

+			module.deprecate = function() {};

+			module.paths = [];

+			// module.parent = undefined by default

+			module.children = [];

+			module.webpackPolyfill = 1;

+		}

+		return module;

+	}

+
+
+/***/ }),
+/* 5 */
+/***/ (function(module, exports) {
+
+	'use strict';
+
+	module.exports = {
+	  isString: function(arg) {
+	    return typeof(arg) === 'string';
+	  },
+	  isObject: function(arg) {
+	    return typeof(arg) === 'object' && arg !== null;
+	  },
+	  isNull: function(arg) {
+	    return arg === null;
+	  },
+	  isNullOrUndefined: function(arg) {
+	    return arg == null;
+	  }
+	};
+
+
+/***/ }),
+/* 6 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	exports.decode = exports.parse = __webpack_require__(7);
+	exports.encode = exports.stringify = __webpack_require__(8);
+
+
+/***/ }),
+/* 7 */
+/***/ (function(module, exports) {
+
+	// Copyright Joyent, Inc. and other Node contributors.
+	//
+	// Permission is hereby granted, free of charge, to any person obtaining a
+	// copy of this software and associated documentation files (the
+	// "Software"), to deal in the Software without restriction, including
+	// without limitation the rights to use, copy, modify, merge, publish,
+	// distribute, sublicense, and/or sell copies of the Software, and to permit
+	// persons to whom the Software is furnished to do so, subject to the
+	// following conditions:
+	//
+	// The above copyright notice and this permission notice shall be included
+	// in all copies or substantial portions of the Software.
+	//
+	// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+	// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+	// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+	// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+	// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+	// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+	// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+	'use strict';
+
+	// If obj.hasOwnProperty has been overridden, then calling
+	// obj.hasOwnProperty(prop) will break.
+	// See: https://github.com/joyent/node/issues/1707
+	function hasOwnProperty(obj, prop) {
+	  return Object.prototype.hasOwnProperty.call(obj, prop);
+	}
+
+	module.exports = function(qs, sep, eq, options) {
+	  sep = sep || '&';
+	  eq = eq || '=';
+	  var obj = {};
+
+	  if (typeof qs !== 'string' || qs.length === 0) {
+	    return obj;
+	  }
+
+	  var regexp = /\+/g;
+	  qs = qs.split(sep);
+
+	  var maxKeys = 1000;
+	  if (options && typeof options.maxKeys === 'number') {
+	    maxKeys = options.maxKeys;
+	  }
+
+	  var len = qs.length;
+	  // maxKeys <= 0 means that we should not limit keys count
+	  if (maxKeys > 0 && len > maxKeys) {
+	    len = maxKeys;
+	  }
+
+	  for (var i = 0; i < len; ++i) {
+	    var x = qs[i].replace(regexp, '%20'),
+	        idx = x.indexOf(eq),
+	        kstr, vstr, k, v;
+
+	    if (idx >= 0) {
+	      kstr = x.substr(0, idx);
+	      vstr = x.substr(idx + 1);
+	    } else {
+	      kstr = x;
+	      vstr = '';
+	    }
+
+	    k = decodeURIComponent(kstr);
+	    v = decodeURIComponent(vstr);
+
+	    if (!hasOwnProperty(obj, k)) {
+	      obj[k] = v;
+	    } else if (Array.isArray(obj[k])) {
+	      obj[k].push(v);
+	    } else {
+	      obj[k] = [obj[k], v];
+	    }
+	  }
+
+	  return obj;
+	};
+
+
+/***/ }),
+/* 8 */
+/***/ (function(module, exports) {
+
+	// Copyright Joyent, Inc. and other Node contributors.
+	//
+	// Permission is hereby granted, free of charge, to any person obtaining a
+	// copy of this software and associated documentation files (the
+	// "Software"), to deal in the Software without restriction, including
+	// without limitation the rights to use, copy, modify, merge, publish,
+	// distribute, sublicense, and/or sell copies of the Software, and to permit
+	// persons to whom the Software is furnished to do so, subject to the
+	// following conditions:
+	//
+	// The above copyright notice and this permission notice shall be included
+	// in all copies or substantial portions of the Software.
+	//
+	// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+	// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+	// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+	// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+	// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+	// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+	// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+	'use strict';
+
+	var stringifyPrimitive = function(v) {
+	  switch (typeof v) {
+	    case 'string':
+	      return v;
+
+	    case 'boolean':
+	      return v ? 'true' : 'false';
+
+	    case 'number':
+	      return isFinite(v) ? v : '';
+
+	    default:
+	      return '';
+	  }
+	};
+
+	module.exports = function(obj, sep, eq, name) {
+	  sep = sep || '&';
+	  eq = eq || '=';
+	  if (obj === null) {
+	    obj = undefined;
+	  }
+
+	  if (typeof obj === 'object') {
+	    return Object.keys(obj).map(function(k) {
+	      var ks = encodeURIComponent(stringifyPrimitive(k)) + eq;
+	      if (Array.isArray(obj[k])) {
+	        return obj[k].map(function(v) {
+	          return ks + encodeURIComponent(stringifyPrimitive(v));
+	        }).join(sep);
+	      } else {
+	        return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
+	      }
+	    }).join(sep);
+
+	  }
+
+	  if (!name) return '';
+	  return encodeURIComponent(stringifyPrimitive(name)) + eq +
+	         encodeURIComponent(stringifyPrimitive(obj));
+	};
+
+
+/***/ }),
+/* 9 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/* WEBPACK VAR INJECTION */(function(global, process) {// Copyright Joyent, Inc. and other Node contributors.
+	//
+	// Permission is hereby granted, free of charge, to any person obtaining a
+	// copy of this software and associated documentation files (the
+	// "Software"), to deal in the Software without restriction, including
+	// without limitation the rights to use, copy, modify, merge, publish,
+	// distribute, sublicense, and/or sell copies of the Software, and to permit
+	// persons to whom the Software is furnished to do so, subject to the
+	// following conditions:
+	//
+	// The above copyright notice and this permission notice shall be included
+	// in all copies or substantial portions of the Software.
+	//
+	// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+	// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+	// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+	// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+	// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+	// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+	// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+	var formatRegExp = /%[sdj%]/g;
+	exports.format = function(f) {
+	  if (!isString(f)) {
+	    var objects = [];
+	    for (var i = 0; i < arguments.length; i++) {
+	      objects.push(inspect(arguments[i]));
+	    }
+	    return objects.join(' ');
+	  }
+
+	  var i = 1;
+	  var args = arguments;
+	  var len = args.length;
+	  var str = String(f).replace(formatRegExp, function(x) {
+	    if (x === '%%') return '%';
+	    if (i >= len) return x;
+	    switch (x) {
+	      case '%s': return String(args[i++]);
+	      case '%d': return Number(args[i++]);
+	      case '%j':
+	        try {
+	          return JSON.stringify(args[i++]);
+	        } catch (_) {
+	          return '[Circular]';
+	        }
+	      default:
+	        return x;
+	    }
+	  });
+	  for (var x = args[i]; i < len; x = args[++i]) {
+	    if (isNull(x) || !isObject(x)) {
+	      str += ' ' + x;
+	    } else {
+	      str += ' ' + inspect(x);
+	    }
+	  }
+	  return str;
+	};
+
+
+	// Mark that a method should not be used.
+	// Returns a modified function which warns once by default.
+	// If --no-deprecation is set, then it is a no-op.
+	exports.deprecate = function(fn, msg) {
+	  // Allow for deprecating things in the process of starting up.
+	  if (isUndefined(global.process)) {
+	    return function() {
+	      return exports.deprecate(fn, msg).apply(this, arguments);
+	    };
+	  }
+
+	  if (process.noDeprecation === true) {
+	    return fn;
+	  }
+
+	  var warned = false;
+	  function deprecated() {
+	    if (!warned) {
+	      if (process.throwDeprecation) {
+	        throw new Error(msg);
+	      } else if (process.traceDeprecation) {
+	        console.trace(msg);
+	      } else {
+	        console.error(msg);
+	      }
+	      warned = true;
+	    }
+	    return fn.apply(this, arguments);
+	  }
+
+	  return deprecated;
+	};
+
+
+	var debugs = {};
+	var debugEnviron;
+	exports.debuglog = function(set) {
+	  if (isUndefined(debugEnviron))
+	    debugEnviron = process.env.NODE_DEBUG || '';
+	  set = set.toUpperCase();
+	  if (!debugs[set]) {
+	    if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
+	      var pid = process.pid;
+	      debugs[set] = function() {
+	        var msg = exports.format.apply(exports, arguments);
+	        console.error('%s %d: %s', set, pid, msg);
+	      };
+	    } else {
+	      debugs[set] = function() {};
+	    }
+	  }
+	  return debugs[set];
+	};
+
+
+	/**
+	 * Echos the value of a value. Trys to print the value out
+	 * in the best way possible given the different types.
+	 *
+	 * @param {Object} obj The object to print out.
+	 * @param {Object} opts Optional options object that alters the output.
+	 */
+	/* legacy: obj, showHidden, depth, colors*/
+	function inspect(obj, opts) {
+	  // default options
+	  var ctx = {
+	    seen: [],
+	    stylize: stylizeNoColor
+	  };
+	  // legacy...
+	  if (arguments.length >= 3) ctx.depth = arguments[2];
+	  if (arguments.length >= 4) ctx.colors = arguments[3];
+	  if (isBoolean(opts)) {
+	    // legacy...
+	    ctx.showHidden = opts;
+	  } else if (opts) {
+	    // got an "options" object
+	    exports._extend(ctx, opts);
+	  }
+	  // set default options
+	  if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
+	  if (isUndefined(ctx.depth)) ctx.depth = 2;
+	  if (isUndefined(ctx.colors)) ctx.colors = false;
+	  if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
+	  if (ctx.colors) ctx.stylize = stylizeWithColor;
+	  return formatValue(ctx, obj, ctx.depth);
+	}
+	exports.inspect = inspect;
+
+
+	// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
+	inspect.colors = {
+	  'bold' : [1, 22],
+	  'italic' : [3, 23],
+	  'underline' : [4, 24],
+	  'inverse' : [7, 27],
+	  'white' : [37, 39],
+	  'grey' : [90, 39],
+	  'black' : [30, 39],
+	  'blue' : [34, 39],
+	  'cyan' : [36, 39],
+	  'green' : [32, 39],
+	  'magenta' : [35, 39],
+	  'red' : [31, 39],
+	  'yellow' : [33, 39]
+	};
+
+	// Don't use 'blue' not visible on cmd.exe
+	inspect.styles = {
+	  'special': 'cyan',
+	  'number': 'yellow',
+	  'boolean': 'yellow',
+	  'undefined': 'grey',
+	  'null': 'bold',
+	  'string': 'green',
+	  'date': 'magenta',
+	  // "name": intentionally not styling
+	  'regexp': 'red'
+	};
+
+
+	function stylizeWithColor(str, styleType) {
+	  var style = inspect.styles[styleType];
+
+	  if (style) {
+	    return '\u001b[' + inspect.colors[style][0] + 'm' + str +
+	           '\u001b[' + inspect.colors[style][1] + 'm';
+	  } else {
+	    return str;
+	  }
+	}
+
+
+	function stylizeNoColor(str, styleType) {
+	  return str;
+	}
+
+
+	function arrayToHash(array) {
+	  var hash = {};
+
+	  array.forEach(function(val, idx) {
+	    hash[val] = true;
+	  });
+
+	  return hash;
+	}
+
+
+	function formatValue(ctx, value, recurseTimes) {
+	  // Provide a hook for user-specified inspect functions.
+	  // Check that value is an object with an inspect function on it
+	  if (ctx.customInspect &&
+	      value &&
+	      isFunction(value.inspect) &&
+	      // Filter out the util module, it's inspect function is special
+	      value.inspect !== exports.inspect &&
+	      // Also filter out any prototype objects using the circular check.
+	      !(value.constructor && value.constructor.prototype === value)) {
+	    var ret = value.inspect(recurseTimes, ctx);
+	    if (!isString(ret)) {
+	      ret = formatValue(ctx, ret, recurseTimes);
+	    }
+	    return ret;
+	  }
+
+	  // Primitive types cannot have properties
+	  var primitive = formatPrimitive(ctx, value);
+	  if (primitive) {
+	    return primitive;
+	  }
+
+	  // Look up the keys of the object.
+	  var keys = Object.keys(value);
+	  var visibleKeys = arrayToHash(keys);
+
+	  if (ctx.showHidden) {
+	    keys = Object.getOwnPropertyNames(value);
+	  }
+
+	  // IE doesn't make error fields non-enumerable
+	  // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
+	  if (isError(value)
+	      && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
+	    return formatError(value);
+	  }
+
+	  // Some type of object without properties can be shortcutted.
+	  if (keys.length === 0) {
+	    if (isFunction(value)) {
+	      var name = value.name ? ': ' + value.name : '';
+	      return ctx.stylize('[Function' + name + ']', 'special');
+	    }
+	    if (isRegExp(value)) {
+	      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
+	    }
+	    if (isDate(value)) {
+	      return ctx.stylize(Date.prototype.toString.call(value), 'date');
+	    }
+	    if (isError(value)) {
+	      return formatError(value);
+	    }
+	  }
+
+	  var base = '', array = false, braces = ['{', '}'];
+
+	  // Make Array say that they are Array
+	  if (isArray(value)) {
+	    array = true;
+	    braces = ['[', ']'];
+	  }
+
+	  // Make functions say that they are functions
+	  if (isFunction(value)) {
+	    var n = value.name ? ': ' + value.name : '';
+	    base = ' [Function' + n + ']';
+	  }
+
+	  // Make RegExps say that they are RegExps
+	  if (isRegExp(value)) {
+	    base = ' ' + RegExp.prototype.toString.call(value);
+	  }
+
+	  // Make dates with properties first say the date
+	  if (isDate(value)) {
+	    base = ' ' + Date.prototype.toUTCString.call(value);
+	  }
+
+	  // Make error with message first say the error
+	  if (isError(value)) {
+	    base = ' ' + formatError(value);
+	  }
+
+	  if (keys.length === 0 && (!array || value.length == 0)) {
+	    return braces[0] + base + braces[1];
+	  }
+
+	  if (recurseTimes < 0) {
+	    if (isRegExp(value)) {
+	      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
+	    } else {
+	      return ctx.stylize('[Object]', 'special');
+	    }
+	  }
+
+	  ctx.seen.push(value);
+
+	  var output;
+	  if (array) {
+	    output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
+	  } else {
+	    output = keys.map(function(key) {
+	      return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
+	    });
+	  }
+
+	  ctx.seen.pop();
+
+	  return reduceToSingleString(output, base, braces);
+	}
+
+
+	function formatPrimitive(ctx, value) {
+	  if (isUndefined(value))
+	    return ctx.stylize('undefined', 'undefined');
+	  if (isString(value)) {
+	    var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
+	                                             .replace(/'/g, "\\'")
+	                                             .replace(/\\"/g, '"') + '\'';
+	    return ctx.stylize(simple, 'string');
+	  }
+	  if (isNumber(value))
+	    return ctx.stylize('' + value, 'number');
+	  if (isBoolean(value))
+	    return ctx.stylize('' + value, 'boolean');
+	  // For some reason typeof null is "object", so special case here.
+	  if (isNull(value))
+	    return ctx.stylize('null', 'null');
+	}
+
+
+	function formatError(value) {
+	  return '[' + Error.prototype.toString.call(value) + ']';
+	}
+
+
+	function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
+	  var output = [];
+	  for (var i = 0, l = value.length; i < l; ++i) {
+	    if (hasOwnProperty(value, String(i))) {
+	      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
+	          String(i), true));
+	    } else {
+	      output.push('');
+	    }
+	  }
+	  keys.forEach(function(key) {
+	    if (!key.match(/^\d+$/)) {
+	      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
+	          key, true));
+	    }
+	  });
+	  return output;
+	}
+
+
+	function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
+	  var name, str, desc;
+	  desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
+	  if (desc.get) {
+	    if (desc.set) {
+	      str = ctx.stylize('[Getter/Setter]', 'special');
+	    } else {
+	      str = ctx.stylize('[Getter]', 'special');
+	    }
+	  } else {
+	    if (desc.set) {
+	      str = ctx.stylize('[Setter]', 'special');
+	    }
+	  }
+	  if (!hasOwnProperty(visibleKeys, key)) {
+	    name = '[' + key + ']';
+	  }
+	  if (!str) {
+	    if (ctx.seen.indexOf(desc.value) < 0) {
+	      if (isNull(recurseTimes)) {
+	        str = formatValue(ctx, desc.value, null);
+	      } else {
+	        str = formatValue(ctx, desc.value, recurseTimes - 1);
+	      }
+	      if (str.indexOf('\n') > -1) {
+	        if (array) {
+	          str = str.split('\n').map(function(line) {
+	            return '  ' + line;
+	          }).join('\n').substr(2);
+	        } else {
+	          str = '\n' + str.split('\n').map(function(line) {
+	            return '   ' + line;
+	          }).join('\n');
+	        }
+	      }
+	    } else {
+	      str = ctx.stylize('[Circular]', 'special');
+	    }
+	  }
+	  if (isUndefined(name)) {
+	    if (array && key.match(/^\d+$/)) {
+	      return str;
+	    }
+	    name = JSON.stringify('' + key);
+	    if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
+	      name = name.substr(1, name.length - 2);
+	      name = ctx.stylize(name, 'name');
+	    } else {
+	      name = name.replace(/'/g, "\\'")
+	                 .replace(/\\"/g, '"')
+	                 .replace(/(^"|"$)/g, "'");
+	      name = ctx.stylize(name, 'string');
+	    }
+	  }
+
+	  return name + ': ' + str;
+	}
+
+
+	function reduceToSingleString(output, base, braces) {
+	  var numLinesEst = 0;
+	  var length = output.reduce(function(prev, cur) {
+	    numLinesEst++;
+	    if (cur.indexOf('\n') >= 0) numLinesEst++;
+	    return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
+	  }, 0);
+
+	  if (length > 60) {
+	    return braces[0] +
+	           (base === '' ? '' : base + '\n ') +
+	           ' ' +
+	           output.join(',\n  ') +
+	           ' ' +
+	           braces[1];
+	  }
+
+	  return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
+	}
+
+
+	// NOTE: These type checking functions intentionally don't use `instanceof`
+	// because it is fragile and can be easily faked with `Object.create()`.
+	function isArray(ar) {
+	  return Array.isArray(ar);
+	}
+	exports.isArray = isArray;
+
+	function isBoolean(arg) {
+	  return typeof arg === 'boolean';
+	}
+	exports.isBoolean = isBoolean;
+
+	function isNull(arg) {
+	  return arg === null;
+	}
+	exports.isNull = isNull;
+
+	function isNullOrUndefined(arg) {
+	  return arg == null;
+	}
+	exports.isNullOrUndefined = isNullOrUndefined;
+
+	function isNumber(arg) {
+	  return typeof arg === 'number';
+	}
+	exports.isNumber = isNumber;
+
+	function isString(arg) {
+	  return typeof arg === 'string';
+	}
+	exports.isString = isString;
+
+	function isSymbol(arg) {
+	  return typeof arg === 'symbol';
+	}
+	exports.isSymbol = isSymbol;
+
+	function isUndefined(arg) {
+	  return arg === void 0;
+	}
+	exports.isUndefined = isUndefined;
+
+	function isRegExp(re) {
+	  return isObject(re) && objectToString(re) === '[object RegExp]';
+	}
+	exports.isRegExp = isRegExp;
+
+	function isObject(arg) {
+	  return typeof arg === 'object' && arg !== null;
+	}
+	exports.isObject = isObject;
+
+	function isDate(d) {
+	  return isObject(d) && objectToString(d) === '[object Date]';
+	}
+	exports.isDate = isDate;
+
+	function isError(e) {
+	  return isObject(e) &&
+	      (objectToString(e) === '[object Error]' || e instanceof Error);
+	}
+	exports.isError = isError;
+
+	function isFunction(arg) {
+	  return typeof arg === 'function';
+	}
+	exports.isFunction = isFunction;
+
+	function isPrimitive(arg) {
+	  return arg === null ||
+	         typeof arg === 'boolean' ||
+	         typeof arg === 'number' ||
+	         typeof arg === 'string' ||
+	         typeof arg === 'symbol' ||  // ES6 symbol
+	         typeof arg === 'undefined';
+	}
+	exports.isPrimitive = isPrimitive;
+
+	exports.isBuffer = __webpack_require__(11);
+
+	function objectToString(o) {
+	  return Object.prototype.toString.call(o);
+	}
+
+
+	function pad(n) {
+	  return n < 10 ? '0' + n.toString(10) : n.toString(10);
+	}
+
+
+	var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
+	              'Oct', 'Nov', 'Dec'];
+
+	// 26 Feb 16:19:34
+	function timestamp() {
+	  var d = new Date();
+	  var time = [pad(d.getHours()),
+	              pad(d.getMinutes()),
+	              pad(d.getSeconds())].join(':');
+	  return [d.getDate(), months[d.getMonth()], time].join(' ');
+	}
+
+
+	// log is just a thin wrapper to console.log that prepends a timestamp
+	exports.log = function() {
+	  console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
+	};
+
+
+	/**
+	 * Inherit the prototype methods from one constructor into another.
+	 *
+	 * The Function.prototype.inherits from lang.js rewritten as a standalone
+	 * function (not on Function.prototype). NOTE: If this file is to be loaded
+	 * during bootstrapping this function needs to be rewritten using some native
+	 * functions as prototype setup using normal JavaScript does not work as
+	 * expected during bootstrapping (see mirror.js in r114903).
+	 *
+	 * @param {function} ctor Constructor function which needs to inherit the
+	 *     prototype.
+	 * @param {function} superCtor Constructor function to inherit prototype from.
+	 */
+	exports.inherits = __webpack_require__(12);
+
+	exports._extend = function(origin, add) {
+	  // Don't do anything if add isn't an object
+	  if (!add || !isObject(add)) return origin;
+
+	  var keys = Object.keys(add);
+	  var i = keys.length;
+	  while (i--) {
+	    origin[keys[i]] = add[keys[i]];
+	  }
+	  return origin;
+	};
+
+	function hasOwnProperty(obj, prop) {
+	  return Object.prototype.hasOwnProperty.call(obj, prop);
+	}
+
+	/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(10)))
+
+/***/ }),
+/* 10 */
+/***/ (function(module, exports) {
+
+	// shim for using process in browser
+	var process = module.exports = {};
+
+	// cached from whatever global is present so that test runners that stub it
+	// don't break things.  But we need to wrap it in a try catch in case it is
+	// wrapped in strict mode code which doesn't define any globals.  It's inside a
+	// function because try/catches deoptimize in certain engines.
+
+	var cachedSetTimeout;
+	var cachedClearTimeout;
+
+	function defaultSetTimout() {
+	    throw new Error('setTimeout has not been defined');
+	}
+	function defaultClearTimeout () {
+	    throw new Error('clearTimeout has not been defined');
+	}
+	(function () {
+	    try {
+	        if (typeof setTimeout === 'function') {
+	            cachedSetTimeout = setTimeout;
+	        } else {
+	            cachedSetTimeout = defaultSetTimout;
+	        }
+	    } catch (e) {
+	        cachedSetTimeout = defaultSetTimout;
+	    }
+	    try {
+	        if (typeof clearTimeout === 'function') {
+	            cachedClearTimeout = clearTimeout;
+	        } else {
+	            cachedClearTimeout = defaultClearTimeout;
+	        }
+	    } catch (e) {
+	        cachedClearTimeout = defaultClearTimeout;
+	    }
+	} ())
+	function runTimeout(fun) {
+	    if (cachedSetTimeout === setTimeout) {
+	        //normal enviroments in sane situations
+	        return setTimeout(fun, 0);
+	    }
+	    // if setTimeout wasn't available but was latter defined
+	    if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
+	        cachedSetTimeout = setTimeout;
+	        return setTimeout(fun, 0);
+	    }
+	    try {
+	        // when when somebody has screwed with setTimeout but no I.E. maddness
+	        return cachedSetTimeout(fun, 0);
+	    } catch(e){
+	        try {
+	            // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
+	            return cachedSetTimeout.call(null, fun, 0);
+	        } catch(e){
+	            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
+	            return cachedSetTimeout.call(this, fun, 0);
+	        }
+	    }
+
+
+	}
+	function runClearTimeout(marker) {
+	    if (cachedClearTimeout === clearTimeout) {
+	        //normal enviroments in sane situations
+	        return clearTimeout(marker);
+	    }
+	    // if clearTimeout wasn't available but was latter defined
+	    if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
+	        cachedClearTimeout = clearTimeout;
+	        return clearTimeout(marker);
+	    }
+	    try {
+	        // when when somebody has screwed with setTimeout but no I.E. maddness
+	        return cachedClearTimeout(marker);
+	    } catch (e){
+	        try {
+	            // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
+	            return cachedClearTimeout.call(null, marker);
+	        } catch (e){
+	            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
+	            // Some versions of I.E. have different rules for clearTimeout vs setTimeout
+	            return cachedClearTimeout.call(this, marker);
+	        }
+	    }
+
+
+
+	}
+	var queue = [];
+	var draining = false;
+	var currentQueue;
+	var queueIndex = -1;
+
+	function cleanUpNextTick() {
+	    if (!draining || !currentQueue) {
+	        return;
+	    }
+	    draining = false;
+	    if (currentQueue.length) {
+	        queue = currentQueue.concat(queue);
+	    } else {
+	        queueIndex = -1;
+	    }
+	    if (queue.length) {
+	        drainQueue();
+	    }
+	}
+
+	function drainQueue() {
+	    if (draining) {
+	        return;
+	    }
+	    var timeout = runTimeout(cleanUpNextTick);
+	    draining = true;
+
+	    var len = queue.length;
+	    while(len) {
+	        currentQueue = queue;
+	        queue = [];
+	        while (++queueIndex < len) {
+	            if (currentQueue) {
+	                currentQueue[queueIndex].run();
+	            }
+	        }
+	        queueIndex = -1;
+	        len = queue.length;
+	    }
+	    currentQueue = null;
+	    draining = false;
+	    runClearTimeout(timeout);
+	}
+
+	process.nextTick = function (fun) {
+	    var args = new Array(arguments.length - 1);
+	    if (arguments.length > 1) {
+	        for (var i = 1; i < arguments.length; i++) {
+	            args[i - 1] = arguments[i];
+	        }
+	    }
+	    queue.push(new Item(fun, args));
+	    if (queue.length === 1 && !draining) {
+	        runTimeout(drainQueue);
+	    }
+	};
+
+	// v8 likes predictible objects
+	function Item(fun, array) {
+	    this.fun = fun;
+	    this.array = array;
+	}
+	Item.prototype.run = function () {
+	    this.fun.apply(null, this.array);
+	};
+	process.title = 'browser';
+	process.browser = true;
+	process.env = {};
+	process.argv = [];
+	process.version = ''; // empty string to avoid regexp issues
+	process.versions = {};
+
+	function noop() {}
+
+	process.on = noop;
+	process.addListener = noop;
+	process.once = noop;
+	process.off = noop;
+	process.removeListener = noop;
+	process.removeAllListeners = noop;
+	process.emit = noop;
+	process.prependListener = noop;
+	process.prependOnceListener = noop;
+
+	process.listeners = function (name) { return [] }
+
+	process.binding = function (name) {
+	    throw new Error('process.binding is not supported');
+	};
+
+	process.cwd = function () { return '/' };
+	process.chdir = function (dir) {
+	    throw new Error('process.chdir is not supported');
+	};
+	process.umask = function() { return 0; };
+
+
+/***/ }),
+/* 11 */
+/***/ (function(module, exports) {
+
+	module.exports = function isBuffer(arg) {
+	  return arg && typeof arg === 'object'
+	    && typeof arg.copy === 'function'
+	    && typeof arg.fill === 'function'
+	    && typeof arg.readUInt8 === 'function';
+	}
+
+/***/ }),
+/* 12 */
+/***/ (function(module, exports) {
+
+	if (typeof Object.create === 'function') {
+	  // implementation from standard node.js 'util' module
+	  module.exports = function inherits(ctor, superCtor) {
+	    ctor.super_ = superCtor
+	    ctor.prototype = Object.create(superCtor.prototype, {
+	      constructor: {
+	        value: ctor,
+	        enumerable: false,
+	        writable: true,
+	        configurable: true
+	      }
+	    });
+	  };
+	} else {
+	  // old school shim for old browsers
+	  module.exports = function inherits(ctor, superCtor) {
+	    ctor.super_ = superCtor
+	    var TempCtor = function () {}
+	    TempCtor.prototype = superCtor.prototype
+	    ctor.prototype = new TempCtor()
+	    ctor.prototype.constructor = ctor
+	  }
+	}
+
+
+/***/ }),
+/* 13 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/*!
+	 * Copyright (c) 2018, Salesforce.com, Inc.
+	 * All rights reserved.
+	 *
+	 * Redistribution and use in source and binary forms, with or without
+	 * modification, are permitted provided that the following conditions are met:
+	 *
+	 * 1. Redistributions of source code must retain the above copyright notice,
+	 * this list of conditions and the following disclaimer.
+	 *
+	 * 2. Redistributions in binary form must reproduce the above copyright notice,
+	 * this list of conditions and the following disclaimer in the documentation
+	 * and/or other materials provided with the distribution.
+	 *
+	 * 3. Neither the name of Salesforce.com nor the names of its contributors may
+	 * be used to endorse or promote products derived from this software without
+	 * specific prior written permission.
+	 *
+	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+	 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+	 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+	 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+	 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+	 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	 * POSSIBILITY OF SUCH DAMAGE.
+	 */
+	'use strict';
+	var psl = __webpack_require__(14);
+
+	function getPublicSuffix(domain) {
+	  return psl.get(domain);
+	}
+
+	exports.getPublicSuffix = getPublicSuffix;
+
+
+/***/ }),
+/* 14 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/*eslint no-var:0, prefer-arrow-callback: 0, object-shorthand: 0 */
+	'use strict';
+
+
+	var Punycode = __webpack_require__(15);
+
+
+	var internals = {};
+
+
+	//
+	// Read rules from file.
+	//
+	internals.rules = __webpack_require__(16).map(function (rule) {
+
+	  return {
+	    rule: rule,
+	    suffix: rule.replace(/^(\*\.|\!)/, ''),
+	    punySuffix: -1,
+	    wildcard: rule.charAt(0) === '*',
+	    exception: rule.charAt(0) === '!'
+	  };
+	});
+
+
+	//
+	// Check is given string ends with `suffix`.
+	//
+	internals.endsWith = function (str, suffix) {
+
+	  return str.indexOf(suffix, str.length - suffix.length) !== -1;
+	};
+
+
+	//
+	// Find rule for a given domain.
+	//
+	internals.findRule = function (domain) {
+
+	  var punyDomain = Punycode.toASCII(domain);
+	  return internals.rules.reduce(function (memo, rule) {
+
+	    if (rule.punySuffix === -1){
+	      rule.punySuffix = Punycode.toASCII(rule.suffix);
+	    }
+	    if (!internals.endsWith(punyDomain, '.' + rule.punySuffix) && punyDomain !== rule.punySuffix) {
+	      return memo;
+	    }
+	    // This has been commented out as it never seems to run. This is because
+	    // sub tlds always appear after their parents and we never find a shorter
+	    // match.
+	    //if (memo) {
+	    //  var memoSuffix = Punycode.toASCII(memo.suffix);
+	    //  if (memoSuffix.length >= punySuffix.length) {
+	    //    return memo;
+	    //  }
+	    //}
+	    return rule;
+	  }, null);
+	};
+
+
+	//
+	// Error codes and messages.
+	//
+	exports.errorCodes = {
+	  DOMAIN_TOO_SHORT: 'Domain name too short.',
+	  DOMAIN_TOO_LONG: 'Domain name too long. It should be no more than 255 chars.',
+	  LABEL_STARTS_WITH_DASH: 'Domain name label can not start with a dash.',
+	  LABEL_ENDS_WITH_DASH: 'Domain name label can not end with a dash.',
+	  LABEL_TOO_LONG: 'Domain name label should be at most 63 chars long.',
+	  LABEL_TOO_SHORT: 'Domain name label should be at least 1 character long.',
+	  LABEL_INVALID_CHARS: 'Domain name label can only contain alphanumeric characters or dashes.'
+	};
+
+
+	//
+	// Validate domain name and throw if not valid.
+	//
+	// From wikipedia:
+	//
+	// Hostnames are composed of series of labels concatenated with dots, as are all
+	// domain names. Each label must be between 1 and 63 characters long, and the
+	// entire hostname (including the delimiting dots) has a maximum of 255 chars.
+	//
+	// Allowed chars:
+	//
+	// * `a-z`
+	// * `0-9`
+	// * `-` but not as a starting or ending character
+	// * `.` as a separator for the textual portions of a domain name
+	//
+	// * http://en.wikipedia.org/wiki/Domain_name
+	// * http://en.wikipedia.org/wiki/Hostname
+	//
+	internals.validate = function (input) {
+
+	  // Before we can validate we need to take care of IDNs with unicode chars.
+	  var ascii = Punycode.toASCII(input);
+
+	  if (ascii.length < 1) {
+	    return 'DOMAIN_TOO_SHORT';
+	  }
+	  if (ascii.length > 255) {
+	    return 'DOMAIN_TOO_LONG';
+	  }
+
+	  // Check each part's length and allowed chars.
+	  var labels = ascii.split('.');
+	  var label;
+
+	  for (var i = 0; i < labels.length; ++i) {
+	    label = labels[i];
+	    if (!label.length) {
+	      return 'LABEL_TOO_SHORT';
+	    }
+	    if (label.length > 63) {
+	      return 'LABEL_TOO_LONG';
+	    }
+	    if (label.charAt(0) === '-') {
+	      return 'LABEL_STARTS_WITH_DASH';
+	    }
+	    if (label.charAt(label.length - 1) === '-') {
+	      return 'LABEL_ENDS_WITH_DASH';
+	    }
+	    if (!/^[a-z0-9\-]+$/.test(label)) {
+	      return 'LABEL_INVALID_CHARS';
+	    }
+	  }
+	};
+
+
+	//
+	// Public API
+	//
+
+
+	//
+	// Parse domain.
+	//
+	exports.parse = function (input) {
+
+	  if (typeof input !== 'string') {
+	    throw new TypeError('Domain name must be a string.');
+	  }
+
+	  // Force domain to lowercase.
+	  var domain = input.slice(0).toLowerCase();
+
+	  // Handle FQDN.
+	  // TODO: Simply remove trailing dot?
+	  if (domain.charAt(domain.length - 1) === '.') {
+	    domain = domain.slice(0, domain.length - 1);
+	  }
+
+	  // Validate and sanitise input.
+	  var error = internals.validate(domain);
+	  if (error) {
+	    return {
+	      input: input,
+	      error: {
+	        message: exports.errorCodes[error],
+	        code: error
+	      }
+	    };
+	  }
+
+	  var parsed = {
+	    input: input,
+	    tld: null,
+	    sld: null,
+	    domain: null,
+	    subdomain: null,
+	    listed: false
+	  };
+
+	  var domainParts = domain.split('.');
+
+	  // Non-Internet TLD
+	  if (domainParts[domainParts.length - 1] === 'local') {
+	    return parsed;
+	  }
+
+	  var handlePunycode = function () {
+
+	    if (!/xn--/.test(domain)) {
+	      return parsed;
+	    }
+	    if (parsed.domain) {
+	      parsed.domain = Punycode.toASCII(parsed.domain);
+	    }
+	    if (parsed.subdomain) {
+	      parsed.subdomain = Punycode.toASCII(parsed.subdomain);
+	    }
+	    return parsed;
+	  };
+
+	  var rule = internals.findRule(domain);
+
+	  // Unlisted tld.
+	  if (!rule) {
+	    if (domainParts.length < 2) {
+	      return parsed;
+	    }
+	    parsed.tld = domainParts.pop();
+	    parsed.sld = domainParts.pop();
+	    parsed.domain = [parsed.sld, parsed.tld].join('.');
+	    if (domainParts.length) {
+	      parsed.subdomain = domainParts.pop();
+	    }
+	    return handlePunycode();
+	  }
+
+	  // At this point we know the public suffix is listed.
+	  parsed.listed = true;
+
+	  var tldParts = rule.suffix.split('.');
+	  var privateParts = domainParts.slice(0, domainParts.length - tldParts.length);
+
+	  if (rule.exception) {
+	    privateParts.push(tldParts.shift());
+	  }
+
+	  parsed.tld = tldParts.join('.');
+
+	  if (!privateParts.length) {
+	    return handlePunycode();
+	  }
+
+	  if (rule.wildcard) {
+	    tldParts.unshift(privateParts.pop());
+	    parsed.tld = tldParts.join('.');
+	  }
+
+	  if (!privateParts.length) {
+	    return handlePunycode();
+	  }
+
+	  parsed.sld = privateParts.pop();
+	  parsed.domain = [parsed.sld,  parsed.tld].join('.');
+
+	  if (privateParts.length) {
+	    parsed.subdomain = privateParts.join('.');
+	  }
+
+	  return handlePunycode();
+	};
+
+
+	//
+	// Get domain.
+	//
+	exports.get = function (domain) {
+
+	  if (!domain) {
+	    return null;
+	  }
+	  return exports.parse(domain).domain || null;
+	};
+
+
+	//
+	// Check whether domain belongs to a known public suffix.
+	//
+	exports.isValid = function (domain) {
+
+	  var parsed = exports.parse(domain);
+	  return Boolean(parsed.domain && parsed.listed);
+	};
+
+
+/***/ }),
+/* 15 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(module, global) {/*! https://mths.be/punycode v1.4.1 by @mathias */
+	;(function(root) {
+
+		/** Detect free variables */
+		var freeExports = typeof exports == 'object' && exports &&
+			!exports.nodeType && exports;
+		var freeModule = typeof module == 'object' && module &&
+			!module.nodeType && module;
+		var freeGlobal = typeof global == 'object' && global;
+		if (
+			freeGlobal.global === freeGlobal ||
+			freeGlobal.window === freeGlobal ||
+			freeGlobal.self === freeGlobal
+		) {
+			root = freeGlobal;
+		}
+
+		/**
+		 * The `punycode` object.
+		 * @name punycode
+		 * @type Object
+		 */
+		var punycode,
+
+		/** Highest positive signed 32-bit float value */
+		maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
+
+		/** Bootstring parameters */
+		base = 36,
+		tMin = 1,
+		tMax = 26,
+		skew = 38,
+		damp = 700,
+		initialBias = 72,
+		initialN = 128, // 0x80
+		delimiter = '-', // '\x2D'
+
+		/** Regular expressions */
+		regexPunycode = /^xn--/,
+		regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
+		regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators
+
+		/** Error messages */
+		errors = {
+			'overflow': 'Overflow: input needs wider integers to process',
+			'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
+			'invalid-input': 'Invalid input'
+		},
+
+		/** Convenience shortcuts */
+		baseMinusTMin = base - tMin,
+		floor = Math.floor,
+		stringFromCharCode = String.fromCharCode,
+
+		/** Temporary variable */
+		key;
+
+		/*--------------------------------------------------------------------------*/
+
+		/**
+		 * A generic error utility function.
+		 * @private
+		 * @param {String} type The error type.
+		 * @returns {Error} Throws a `RangeError` with the applicable error message.
+		 */
+		function error(type) {
+			throw new RangeError(errors[type]);
+		}
+
+		/**
+		 * A generic `Array#map` utility function.
+		 * @private
+		 * @param {Array} array The array to iterate over.
+		 * @param {Function} callback The function that gets called for every array
+		 * item.
+		 * @returns {Array} A new array of values returned by the callback function.
+		 */
+		function map(array, fn) {
+			var length = array.length;
+			var result = [];
+			while (length--) {
+				result[length] = fn(array[length]);
+			}
+			return result;
+		}
+
+		/**
+		 * A simple `Array#map`-like wrapper to work with domain name strings or email
+		 * addresses.
+		 * @private
+		 * @param {String} domain The domain name or email address.
+		 * @param {Function} callback The function that gets called for every
+		 * character.
+		 * @returns {Array} A new string of characters returned by the callback
+		 * function.
+		 */
+		function mapDomain(string, fn) {
+			var parts = string.split('@');
+			var result = '';
+			if (parts.length > 1) {
+				// In email addresses, only the domain name should be punycoded. Leave
+				// the local part (i.e. everything up to `@`) intact.
+				result = parts[0] + '@';
+				string = parts[1];
+			}
+			// Avoid `split(regex)` for IE8 compatibility. See #17.
+			string = string.replace(regexSeparators, '\x2E');
+			var labels = string.split('.');
+			var encoded = map(labels, fn).join('.');
+			return result + encoded;
+		}
+
+		/**
+		 * Creates an array containing the numeric code points of each Unicode
+		 * character in the string. While JavaScript uses UCS-2 internally,
+		 * this function will convert a pair of surrogate halves (each of which
+		 * UCS-2 exposes as separate characters) into a single code point,
+		 * matching UTF-16.
+		 * @see `punycode.ucs2.encode`
+		 * @see <https://mathiasbynens.be/notes/javascript-encoding>
+		 * @memberOf punycode.ucs2
+		 * @name decode
+		 * @param {String} string The Unicode input string (UCS-2).
+		 * @returns {Array} The new array of code points.
+		 */
+		function ucs2decode(string) {
+			var output = [],
+			    counter = 0,
+			    length = string.length,
+			    value,
+			    extra;
+			while (counter < length) {
+				value = string.charCodeAt(counter++);
+				if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
+					// high surrogate, and there is a next character
+					extra = string.charCodeAt(counter++);
+					if ((extra & 0xFC00) == 0xDC00) { // low surrogate
+						output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+					} else {
+						// unmatched surrogate; only append this code unit, in case the next
+						// code unit is the high surrogate of a surrogate pair
+						output.push(value);
+						counter--;
+					}
+				} else {
+					output.push(value);
+				}
+			}
+			return output;
+		}
+
+		/**
+		 * Creates a string based on an array of numeric code points.
+		 * @see `punycode.ucs2.decode`
+		 * @memberOf punycode.ucs2
+		 * @name encode
+		 * @param {Array} codePoints The array of numeric code points.
+		 * @returns {String} The new Unicode string (UCS-2).
+		 */
+		function ucs2encode(array) {
+			return map(array, function(value) {
+				var output = '';
+				if (value > 0xFFFF) {
+					value -= 0x10000;
+					output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
+					value = 0xDC00 | value & 0x3FF;
+				}
+				output += stringFromCharCode(value);
+				return output;
+			}).join('');
+		}
+
+		/**
+		 * Converts a basic code point into a digit/integer.
+		 * @see `digitToBasic()`
+		 * @private
+		 * @param {Number} codePoint The basic numeric code point value.
+		 * @returns {Number} The numeric value of a basic code point (for use in
+		 * representing integers) in the range `0` to `base - 1`, or `base` if
+		 * the code point does not represent a value.
+		 */
+		function basicToDigit(codePoint) {
+			if (codePoint - 48 < 10) {
+				return codePoint - 22;
+			}
+			if (codePoint - 65 < 26) {
+				return codePoint - 65;
+			}
+			if (codePoint - 97 < 26) {
+				return codePoint - 97;
+			}
+			return base;
+		}
+
+		/**
+		 * Converts a digit/integer into a basic code point.
+		 * @see `basicToDigit()`
+		 * @private
+		 * @param {Number} digit The numeric value of a basic code point.
+		 * @returns {Number} The basic code point whose value (when used for
+		 * representing integers) is `digit`, which needs to be in the range
+		 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
+		 * used; else, the lowercase form is used. The behavior is undefined
+		 * if `flag` is non-zero and `digit` has no uppercase form.
+		 */
+		function digitToBasic(digit, flag) {
+			//  0..25 map to ASCII a..z or A..Z
+			// 26..35 map to ASCII 0..9
+			return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
+		}
+
+		/**
+		 * Bias adaptation function as per section 3.4 of RFC 3492.
+		 * https://tools.ietf.org/html/rfc3492#section-3.4
+		 * @private
+		 */
+		function adapt(delta, numPoints, firstTime) {
+			var k = 0;
+			delta = firstTime ? floor(delta / damp) : delta >> 1;
+			delta += floor(delta / numPoints);
+			for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
+				delta = floor(delta / baseMinusTMin);
+			}
+			return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
+		}
+
+		/**
+		 * Converts a Punycode string of ASCII-only symbols to a string of Unicode
+		 * symbols.
+		 * @memberOf punycode
+		 * @param {String} input The Punycode string of ASCII-only symbols.
+		 * @returns {String} The resulting string of Unicode symbols.
+		 */
+		function decode(input) {
+			// Don't use UCS-2
+			var output = [],
+			    inputLength = input.length,
+			    out,
+			    i = 0,
+			    n = initialN,
+			    bias = initialBias,
+			    basic,
+			    j,
+			    index,
+			    oldi,
+			    w,
+			    k,
+			    digit,
+			    t,
+			    /** Cached calculation results */
+			    baseMinusT;
+
+			// Handle the basic code points: let `basic` be the number of input code
+			// points before the last delimiter, or `0` if there is none, then copy
+			// the first basic code points to the output.
+
+			basic = input.lastIndexOf(delimiter);
+			if (basic < 0) {
+				basic = 0;
+			}
+
+			for (j = 0; j < basic; ++j) {
+				// if it's not a basic code point
+				if (input.charCodeAt(j) >= 0x80) {
+					error('not-basic');
+				}
+				output.push(input.charCodeAt(j));
+			}
+
+			// Main decoding loop: start just after the last delimiter if any basic code
+			// points were copied; start at the beginning otherwise.
+
+			for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
+
+				// `index` is the index of the next character to be consumed.
+				// Decode a generalized variable-length integer into `delta`,
+				// which gets added to `i`. The overflow checking is easier
+				// if we increase `i` as we go, then subtract off its starting
+				// value at the end to obtain `delta`.
+				for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
+
+					if (index >= inputLength) {
+						error('invalid-input');
+					}
+
+					digit = basicToDigit(input.charCodeAt(index++));
+
+					if (digit >= base || digit > floor((maxInt - i) / w)) {
+						error('overflow');
+					}
+
+					i += digit * w;
+					t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+
+					if (digit < t) {
+						break;
+					}
+
+					baseMinusT = base - t;
+					if (w > floor(maxInt / baseMinusT)) {
+						error('overflow');
+					}
+
+					w *= baseMinusT;
+
+				}
+
+				out = output.length + 1;
+				bias = adapt(i - oldi, out, oldi == 0);
+
+				// `i` was supposed to wrap around from `out` to `0`,
+				// incrementing `n` each time, so we'll fix that now:
+				if (floor(i / out) > maxInt - n) {
+					error('overflow');
+				}
+
+				n += floor(i / out);
+				i %= out;
+
+				// Insert `n` at position `i` of the output
+				output.splice(i++, 0, n);
+
+			}
+
+			return ucs2encode(output);
+		}
+
+		/**
+		 * Converts a string of Unicode symbols (e.g. a domain name label) to a
+		 * Punycode string of ASCII-only symbols.
+		 * @memberOf punycode
+		 * @param {String} input The string of Unicode symbols.
+		 * @returns {String} The resulting Punycode string of ASCII-only symbols.
+		 */
+		function encode(input) {
+			var n,
+			    delta,
+			    handledCPCount,
+			    basicLength,
+			    bias,
+			    j,
+			    m,
+			    q,
+			    k,
+			    t,
+			    currentValue,
+			    output = [],
+			    /** `inputLength` will hold the number of code points in `input`. */
+			    inputLength,
+			    /** Cached calculation results */
+			    handledCPCountPlusOne,
+			    baseMinusT,
+			    qMinusT;
+
+			// Convert the input in UCS-2 to Unicode
+			input = ucs2decode(input);
+
+			// Cache the length
+			inputLength = input.length;
+
+			// Initialize the state
+			n = initialN;
+			delta = 0;
+			bias = initialBias;
+
+			// Handle the basic code points
+			for (j = 0; j < inputLength; ++j) {
+				currentValue = input[j];
+				if (currentValue < 0x80) {
+					output.push(stringFromCharCode(currentValue));
+				}
+			}
+
+			handledCPCount = basicLength = output.length;
+
+			// `handledCPCount` is the number of code points that have been handled;
+			// `basicLength` is the number of basic code points.
+
+			// Finish the basic string - if it is not empty - with a delimiter
+			if (basicLength) {
+				output.push(delimiter);
+			}
+
+			// Main encoding loop:
+			while (handledCPCount < inputLength) {
+
+				// All non-basic code points < n have been handled already. Find the next
+				// larger one:
+				for (m = maxInt, j = 0; j < inputLength; ++j) {
+					currentValue = input[j];
+					if (currentValue >= n && currentValue < m) {
+						m = currentValue;
+					}
+				}
+
+				// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
+				// but guard against overflow
+				handledCPCountPlusOne = handledCPCount + 1;
+				if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
+					error('overflow');
+				}
+
+				delta += (m - n) * handledCPCountPlusOne;
+				n = m;
+
+				for (j = 0; j < inputLength; ++j) {
+					currentValue = input[j];
+
+					if (currentValue < n && ++delta > maxInt) {
+						error('overflow');
+					}
+
+					if (currentValue == n) {
+						// Represent delta as a generalized variable-length integer
+						for (q = delta, k = base; /* no condition */; k += base) {
+							t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+							if (q < t) {
+								break;
+							}
+							qMinusT = q - t;
+							baseMinusT = base - t;
+							output.push(
+								stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
+							);
+							q = floor(qMinusT / baseMinusT);
+						}
+
+						output.push(stringFromCharCode(digitToBasic(q, 0)));
+						bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
+						delta = 0;
+						++handledCPCount;
+					}
+				}
+
+				++delta;
+				++n;
+
+			}
+			return output.join('');
+		}
+
+		/**
+		 * Converts a Punycode string representing a domain name or an email address
+		 * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
+		 * it doesn't matter if you call it on a string that has already been
+		 * converted to Unicode.
+		 * @memberOf punycode
+		 * @param {String} input The Punycoded domain name or email address to
+		 * convert to Unicode.
+		 * @returns {String} The Unicode representation of the given Punycode
+		 * string.
+		 */
+		function toUnicode(input) {
+			return mapDomain(input, function(string) {
+				return regexPunycode.test(string)
+					? decode(string.slice(4).toLowerCase())
+					: string;
+			});
+		}
+
+		/**
+		 * Converts a Unicode string representing a domain name or an email address to
+		 * Punycode. Only the non-ASCII parts of the domain name will be converted,
+		 * i.e. it doesn't matter if you call it with a domain that's already in
+		 * ASCII.
+		 * @memberOf punycode
+		 * @param {String} input The domain name or email address to convert, as a
+		 * Unicode string.
+		 * @returns {String} The Punycode representation of the given domain name or
+		 * email address.
+		 */
+		function toASCII(input) {
+			return mapDomain(input, function(string) {
+				return regexNonASCII.test(string)
+					? 'xn--' + encode(string)
+					: string;
+			});
+		}
+
+		/*--------------------------------------------------------------------------*/
+
+		/** Define the public API */
+		punycode = {
+			/**
+			 * A string representing the current Punycode.js version number.
+			 * @memberOf punycode
+			 * @type String
+			 */
+			'version': '1.4.1',
+			/**
+			 * An object of methods to convert from JavaScript's internal character
+			 * representation (UCS-2) to Unicode code points, and back.
+			 * @see <https://mathiasbynens.be/notes/javascript-encoding>
+			 * @memberOf punycode
+			 * @type Object
+			 */
+			'ucs2': {
+				'decode': ucs2decode,
+				'encode': ucs2encode
+			},
+			'decode': decode,
+			'encode': encode,
+			'toASCII': toASCII,
+			'toUnicode': toUnicode
+		};
+
+		/** Expose `punycode` */
+		// Some AMD build optimizers, like r.js, check for specific condition patterns
+		// like the following:
+		if (
+			true
+		) {
+			!(__WEBPACK_AMD_DEFINE_RESULT__ = function() {
+				return punycode;
+			}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+		} else if (freeExports && freeModule) {
+			if (module.exports == freeExports) {
+				// in Node.js, io.js, or RingoJS v0.8.0+
+				freeModule.exports = punycode;
+			} else {
+				// in Narwhal or RingoJS v0.7.0-
+				for (key in punycode) {
+					punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
+				}
+			}
+		} else {
+			// in Rhino or a web browser
+			root.punycode = punycode;
+		}
+
+	}(this));
+
+	/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)(module), (function() { return this; }())))
+
+/***/ }),
+/* 16 */
+/***/ (function(module, exports) {
+
+	module.exports = ["ac","com.ac","edu.ac","gov.ac","net.ac","mil.ac","org.ac","ad","nom.ad","ae","co.ae","net.ae","org.ae","sch.ae","ac.ae","gov.ae","mil.ae","aero","accident-investigation.aero","accident-prevention.aero","aerobatic.aero","aeroclub.aero","aerodrome.aero","agents.aero","aircraft.aero","airline.aero","airport.aero","air-surveillance.aero","airtraffic.aero","air-traffic-control.aero","ambulance.aero","amusement.aero","association.aero","author.aero","ballooning.aero","broker.aero","caa.aero","cargo.aero","catering.aero","certification.aero","championship.aero","charter.aero","civilaviation.aero","club.aero","conference.aero","consultant.aero","consulting.aero","control.aero","council.aero","crew.aero","design.aero","dgca.aero","educator.aero","emergency.aero","engine.aero","engineer.aero","entertainment.aero","equipment.aero","exchange.aero","express.aero","federation.aero","flight.aero","freight.aero","fuel.aero","gliding.aero","government.aero","groundhandling.aero","group.aero","hanggliding.aero","homebuilt.aero","insurance.aero","journal.aero","journalist.aero","leasing.aero","logistics.aero","magazine.aero","maintenance.aero","media.aero","microlight.aero","modelling.aero","navigation.aero","parachuting.aero","paragliding.aero","passenger-association.aero","pilot.aero","press.aero","production.aero","recreation.aero","repbody.aero","res.aero","research.aero","rotorcraft.aero","safety.aero","scientist.aero","services.aero","show.aero","skydiving.aero","software.aero","student.aero","trader.aero","trading.aero","trainer.aero","union.aero","workinggroup.aero","works.aero","af","gov.af","com.af","org.af","net.af","edu.af","ag","com.ag","org.ag","net.ag","co.ag","nom.ag","ai","off.ai","com.ai","net.ai","org.ai","al","com.al","edu.al","gov.al","mil.al","net.al","org.al","am","ao","ed.ao","gv.ao","og.ao","co.ao","pb.ao","it.ao","aq","ar","com.ar","edu.ar","gob.ar","gov.ar","int.ar","mil.ar","musica.ar","net.ar","org.ar","tur.ar","arpa","e164.arpa","in-addr.arpa","ip6.arpa","iris.arpa","uri.arpa","urn.arpa","as","gov.as","asia","at","ac.at","co.at","gv.at","or.at","au","com.au","net.au","org.au","edu.au","gov.au","asn.au","id.au","info.au","conf.au","oz.au","act.au","nsw.au","nt.au","qld.au","sa.au","tas.au","vic.au","wa.au","act.edu.au","nsw.edu.au","nt.edu.au","qld.edu.au","sa.edu.au","tas.edu.au","vic.edu.au","wa.edu.au","qld.gov.au","sa.gov.au","tas.gov.au","vic.gov.au","wa.gov.au","aw","com.aw","ax","az","com.az","net.az","int.az","gov.az","org.az","edu.az","info.az","pp.az","mil.az","name.az","pro.az","biz.az","ba","com.ba","edu.ba","gov.ba","mil.ba","net.ba","org.ba","bb","biz.bb","co.bb","com.bb","edu.bb","gov.bb","info.bb","net.bb","org.bb","store.bb","tv.bb","*.bd","be","ac.be","bf","gov.bf","bg","a.bg","b.bg","c.bg","d.bg","e.bg","f.bg","g.bg","h.bg","i.bg","j.bg","k.bg","l.bg","m.bg","n.bg","o.bg","p.bg","q.bg","r.bg","s.bg","t.bg","u.bg","v.bg","w.bg","x.bg","y.bg","z.bg","0.bg","1.bg","2.bg","3.bg","4.bg","5.bg","6.bg","7.bg","8.bg","9.bg","bh","com.bh","edu.bh","net.bh","org.bh","gov.bh","bi","co.bi","com.bi","edu.bi","or.bi","org.bi","biz","bj","asso.bj","barreau.bj","gouv.bj","bm","com.bm","edu.bm","gov.bm","net.bm","org.bm","*.bn","bo","com.bo","edu.bo","gob.bo","int.bo","org.bo","net.bo","mil.bo","tv.bo","web.bo","academia.bo","agro.bo","arte.bo","blog.bo","bolivia.bo","ciencia.bo","cooperativa.bo","democracia.bo","deporte.bo","ecologia.bo","economia.bo","empresa.bo","indigena.bo","industria.bo","info.bo","medicina.bo","movimiento.bo","musica.bo","natural.bo","nombre.bo","noticias.bo","patria.bo","politica.bo","profesional.bo","plurinacional.bo","pueblo.bo","revista.bo","salud.bo","tecnologia.bo","tksat.bo","transporte.bo","wiki.bo","br","9guacu.br","abc.br","adm.br","adv.br","agr.br","aju.br","am.br","anani.br","aparecida.br","arq.br","art.br","ato.br","b.br","barueri.br","belem.br","bhz.br","bio.br","blog.br","bmd.br","boavista.br","bsb.br","campinagrande.br","campinas.br","caxias.br","cim.br","cng.br","cnt.br","com.br","contagem.br","coop.br","cri.br","cuiaba.br","curitiba.br","def.br","ecn.br","eco.br","edu.br","emp.br","eng.br","esp.br","etc.br","eti.br","far.br","feira.br","flog.br","floripa.br","fm.br","fnd.br","fortal.br","fot.br","foz.br","fst.br","g12.br","ggf.br","goiania.br","gov.br","ac.gov.br","al.gov.br","am.gov.br","ap.gov.br","ba.gov.br","ce.gov.br","df.gov.br","es.gov.br","go.gov.br","ma.gov.br","mg.gov.br","ms.gov.br","mt.gov.br","pa.gov.br","pb.gov.br","pe.gov.br","pi.gov.br","pr.gov.br","rj.gov.br","rn.gov.br","ro.gov.br","rr.gov.br","rs.gov.br","sc.gov.br","se.gov.br","sp.gov.br","to.gov.br","gru.br","imb.br","ind.br","inf.br","jab.br","jampa.br","jdf.br","joinville.br","jor.br","jus.br","leg.br","lel.br","londrina.br","macapa.br","maceio.br","manaus.br","maringa.br","mat.br","med.br","mil.br","morena.br","mp.br","mus.br","natal.br","net.br","niteroi.br","*.nom.br","not.br","ntr.br","odo.br","org.br","osasco.br","palmas.br","poa.br","ppg.br","pro.br","psc.br","psi.br","pvh.br","qsl.br","radio.br","rec.br","recife.br","ribeirao.br","rio.br","riobranco.br","riopreto.br","salvador.br","sampa.br","santamaria.br","santoandre.br","saobernardo.br","saogonca.br","sjc.br","slg.br","slz.br","sorocaba.br","srv.br","taxi.br","teo.br","the.br","tmp.br","trd.br","tur.br","tv.br","udi.br","vet.br","vix.br","vlog.br","wiki.br","zlg.br","bs","com.bs","net.bs","org.bs","edu.bs","gov.bs","bt","com.bt","edu.bt","gov.bt","net.bt","org.bt","bv","bw","co.bw","org.bw","by","gov.by","mil.by","com.by","of.by","bz","com.bz","net.bz","org.bz","edu.bz","gov.bz","ca","ab.ca","bc.ca","mb.ca","nb.ca","nf.ca","nl.ca","ns.ca","nt.ca","nu.ca","on.ca","pe.ca","qc.ca","sk.ca","yk.ca","gc.ca","cat","cc","cd","gov.cd","cf","cg","ch","ci","org.ci","or.ci","com.ci","co.ci","edu.ci","ed.ci","ac.ci","net.ci","go.ci","asso.ci","aéroport.ci","int.ci","presse.ci","md.ci","gouv.ci","*.ck","!www.ck","cl","gov.cl","gob.cl","co.cl","mil.cl","cm","co.cm","com.cm","gov.cm","net.cm","cn","ac.cn","com.cn","edu.cn","gov.cn","net.cn","org.cn","mil.cn","公司.cn","网络.cn","網絡.cn","ah.cn","bj.cn","cq.cn","fj.cn","gd.cn","gs.cn","gz.cn","gx.cn","ha.cn","hb.cn","he.cn","hi.cn","hl.cn","hn.cn","jl.cn","js.cn","jx.cn","ln.cn","nm.cn","nx.cn","qh.cn","sc.cn","sd.cn","sh.cn","sn.cn","sx.cn","tj.cn","xj.cn","xz.cn","yn.cn","zj.cn","hk.cn","mo.cn","tw.cn","co","arts.co","com.co","edu.co","firm.co","gov.co","info.co","int.co","mil.co","net.co","nom.co","org.co","rec.co","web.co","com","coop","cr","ac.cr","co.cr","ed.cr","fi.cr","go.cr","or.cr","sa.cr","cu","com.cu","edu.cu","org.cu","net.cu","gov.cu","inf.cu","cv","cw","com.cw","edu.cw","net.cw","org.cw","cx","gov.cx","cy","ac.cy","biz.cy","com.cy","ekloges.cy","gov.cy","ltd.cy","name.cy","net.cy","org.cy","parliament.cy","press.cy","pro.cy","tm.cy","cz","de","dj","dk","dm","com.dm","net.dm","org.dm","edu.dm","gov.dm","do","art.do","com.do","edu.do","gob.do","gov.do","mil.do","net.do","org.do","sld.do","web.do","dz","com.dz","org.dz","net.dz","gov.dz","edu.dz","asso.dz","pol.dz","art.dz","ec","com.ec","info.ec","net.ec","fin.ec","k12.ec","med.ec","pro.ec","org.ec","edu.ec","gov.ec","gob.ec","mil.ec","edu","ee","edu.ee","gov.ee","riik.ee","lib.ee","med.ee","com.ee","pri.ee","aip.ee","org.ee","fie.ee","eg","com.eg","edu.eg","eun.eg","gov.eg","mil.eg","name.eg","net.eg","org.eg","sci.eg","*.er","es","com.es","nom.es","org.es","gob.es","edu.es","et","com.et","gov.et","org.et","edu.et","biz.et","name.et","info.et","net.et","eu","fi","aland.fi","*.fj","*.fk","fm","fo","fr","com.fr","asso.fr","nom.fr","prd.fr","presse.fr","tm.fr","aeroport.fr","assedic.fr","avocat.fr","avoues.fr","cci.fr","chambagri.fr","chirurgiens-dentistes.fr","experts-comptables.fr","geometre-expert.fr","gouv.fr","greta.fr","huissier-justice.fr","medecin.fr","notaires.fr","pharmacien.fr","port.fr","veterinaire.fr","ga","gb","gd","ge","com.ge","edu.ge","gov.ge","org.ge","mil.ge","net.ge","pvt.ge","gf","gg","co.gg","net.gg","org.gg","gh","com.gh","edu.gh","gov.gh","org.gh","mil.gh","gi","com.gi","ltd.gi","gov.gi","mod.gi","edu.gi","org.gi","gl","co.gl","com.gl","edu.gl","net.gl","org.gl","gm","gn","ac.gn","com.gn","edu.gn","gov.gn","org.gn","net.gn","gov","gp","com.gp","net.gp","mobi.gp","edu.gp","org.gp","asso.gp","gq","gr","com.gr","edu.gr","net.gr","org.gr","gov.gr","gs","gt","com.gt","edu.gt","gob.gt","ind.gt","mil.gt","net.gt","org.gt","gu","com.gu","edu.gu","gov.gu","guam.gu","info.gu","net.gu","org.gu","web.gu","gw","gy","co.gy","com.gy","edu.gy","gov.gy","net.gy","org.gy","hk","com.hk","edu.hk","gov.hk","idv.hk","net.hk","org.hk","公司.hk","教育.hk","敎育.hk","政府.hk","個人.hk","个人.hk","箇人.hk","網络.hk","网络.hk","组織.hk","網絡.hk","网絡.hk","组织.hk","組織.hk","組织.hk","hm","hn","com.hn","edu.hn","org.hn","net.hn","mil.hn","gob.hn","hr","iz.hr","from.hr","name.hr","com.hr","ht","com.ht","shop.ht","firm.ht","info.ht","adult.ht","net.ht","pro.ht","org.ht","med.ht","art.ht","coop.ht","pol.ht","asso.ht","edu.ht","rel.ht","gouv.ht","perso.ht","hu","co.hu","info.hu","org.hu","priv.hu","sport.hu","tm.hu","2000.hu","agrar.hu","bolt.hu","casino.hu","city.hu","erotica.hu","erotika.hu","film.hu","forum.hu","games.hu","hotel.hu","ingatlan.hu","jogasz.hu","konyvelo.hu","lakas.hu","media.hu","news.hu","reklam.hu","sex.hu","shop.hu","suli.hu","szex.hu","tozsde.hu","utazas.hu","video.hu","id","ac.id","biz.id","co.id","desa.id","go.id","mil.id","my.id","net.id","or.id","sch.id","web.id","ie","gov.ie","il","ac.il","co.il","gov.il","idf.il","k12.il","muni.il","net.il","org.il","im","ac.im","co.im","com.im","ltd.co.im","net.im","org.im","plc.co.im","tt.im","tv.im","in","co.in","firm.in","net.in","org.in","gen.in","ind.in","nic.in","ac.in","edu.in","res.in","gov.in","mil.in","info","int","eu.int","io","com.io","iq","gov.iq","edu.iq","mil.iq","com.iq","org.iq","net.iq","ir","ac.ir","co.ir","gov.ir","id.ir","net.ir","org.ir","sch.ir","ایران.ir","ايران.ir","is","net.is","com.is","edu.is","gov.is","org.is","int.is","it","gov.it","edu.it","abr.it","abruzzo.it","aosta-valley.it","aostavalley.it","bas.it","basilicata.it","cal.it","calabria.it","cam.it","campania.it","emilia-romagna.it","emiliaromagna.it","emr.it","friuli-v-giulia.it","friuli-ve-giulia.it","friuli-vegiulia.it","friuli-venezia-giulia.it","friuli-veneziagiulia.it","friuli-vgiulia.it","friuliv-giulia.it","friulive-giulia.it","friulivegiulia.it","friulivenezia-giulia.it","friuliveneziagiulia.it","friulivgiulia.it","fvg.it","laz.it","lazio.it","lig.it","liguria.it","lom.it","lombardia.it","lombardy.it","lucania.it","mar.it","marche.it","mol.it","molise.it","piedmont.it","piemonte.it","pmn.it","pug.it","puglia.it","sar.it","sardegna.it","sardinia.it","sic.it","sicilia.it","sicily.it","taa.it","tos.it","toscana.it","trentin-sud-tirol.it","trentin-süd-tirol.it","trentin-sudtirol.it","trentin-südtirol.it","trentin-sued-tirol.it","trentin-suedtirol.it","trentino-a-adige.it","trentino-aadige.it","trentino-alto-adige.it","trentino-altoadige.it","trentino-s-tirol.it","trentino-stirol.it","trentino-sud-tirol.it","trentino-süd-tirol.it","trentino-sudtirol.it","trentino-südtirol.it","trentino-sued-tirol.it","trentino-suedtirol.it","trentino.it","trentinoa-adige.it","trentinoaadige.it","trentinoalto-adige.it","trentinoaltoadige.it","trentinos-tirol.it","trentinostirol.it","trentinosud-tirol.it","trentinosüd-tirol.it","trentinosudtirol.it","trentinosüdtirol.it","trentinosued-tirol.it","trentinosuedtirol.it","trentinsud-tirol.it","trentinsüd-tirol.it","trentinsudtirol.it","trentinsüdtirol.it","trentinsued-tirol.it","trentinsuedtirol.it","tuscany.it","umb.it","umbria.it","val-d-aosta.it","val-daosta.it","vald-aosta.it","valdaosta.it","valle-aosta.it","valle-d-aosta.it","valle-daosta.it","valleaosta.it","valled-aosta.it","valledaosta.it","vallee-aoste.it","vallée-aoste.it","vallee-d-aoste.it","vallée-d-aoste.it","valleeaoste.it","valléeaoste.it","valleedaoste.it","valléedaoste.it","vao.it","vda.it","ven.it","veneto.it","ag.it","agrigento.it","al.it","alessandria.it","alto-adige.it","altoadige.it","an.it","ancona.it","andria-barletta-trani.it","andria-trani-barletta.it","andriabarlettatrani.it","andriatranibarletta.it","ao.it","aosta.it","aoste.it","ap.it","aq.it","aquila.it","ar.it","arezzo.it","ascoli-piceno.it","ascolipiceno.it","asti.it","at.it","av.it","avellino.it","ba.it","balsan-sudtirol.it","balsan-südtirol.it","balsan-suedtirol.it","balsan.it","bari.it","barletta-trani-andria.it","barlettatraniandria.it","belluno.it","benevento.it","bergamo.it","bg.it","bi.it","biella.it","bl.it","bn.it","bo.it","bologna.it","bolzano-altoadige.it","bolzano.it","bozen-sudtirol.it","bozen-südtirol.it","bozen-suedtirol.it","bozen.it","br.it","brescia.it","brindisi.it","bs.it","bt.it","bulsan-sudtirol.it","bulsan-südtirol.it","bulsan-suedtirol.it","bulsan.it","bz.it","ca.it","cagliari.it","caltanissetta.it","campidano-medio.it","campidanomedio.it","campobasso.it","carbonia-iglesias.it","carboniaiglesias.it","carrara-massa.it","carraramassa.it","caserta.it","catania.it","catanzaro.it","cb.it","ce.it","cesena-forli.it","cesena-forlì.it","cesenaforli.it","cesenaforlì.it","ch.it","chieti.it","ci.it","cl.it","cn.it","co.it","como.it","cosenza.it","cr.it","cremona.it","crotone.it","cs.it","ct.it","cuneo.it","cz.it","dell-ogliastra.it","dellogliastra.it","en.it","enna.it","fc.it","fe.it","fermo.it","ferrara.it","fg.it","fi.it","firenze.it","florence.it","fm.it","foggia.it","forli-cesena.it","forlì-cesena.it","forlicesena.it","forlìcesena.it","fr.it","frosinone.it","ge.it","genoa.it","genova.it","go.it","gorizia.it","gr.it","grosseto.it","iglesias-carbonia.it","iglesiascarbonia.it","im.it","imperia.it","is.it","isernia.it","kr.it","la-spezia.it","laquila.it","laspezia.it","latina.it","lc.it","le.it","lecce.it","lecco.it","li.it","livorno.it","lo.it","lodi.it","lt.it","lu.it","lucca.it","macerata.it","mantova.it","massa-carrara.it","massacarrara.it","matera.it","mb.it","mc.it","me.it","medio-campidano.it","mediocampidano.it","messina.it","mi.it","milan.it","milano.it","mn.it","mo.it","modena.it","monza-brianza.it","monza-e-della-brianza.it","monza.it","monzabrianza.it","monzaebrianza.it","monzaedellabrianza.it","ms.it","mt.it","na.it","naples.it","napoli.it","no.it","novara.it","nu.it","nuoro.it","og.it","ogliastra.it","olbia-tempio.it","olbiatempio.it","or.it","oristano.it","ot.it","pa.it","padova.it","padua.it","palermo.it","parma.it","pavia.it","pc.it","pd.it","pe.it","perugia.it","pesaro-urbino.it","pesarourbino.it","pescara.it","pg.it","pi.it","piacenza.it","pisa.it","pistoia.it","pn.it","po.it","pordenone.it","potenza.it","pr.it","prato.it","pt.it","pu.it","pv.it","pz.it","ra.it","ragusa.it","ravenna.it","rc.it","re.it","reggio-calabria.it","reggio-emilia.it","reggiocalabria.it","reggioemilia.it","rg.it","ri.it","rieti.it","rimini.it","rm.it","rn.it","ro.it","roma.it","rome.it","rovigo.it","sa.it","salerno.it","sassari.it","savona.it","si.it","siena.it","siracusa.it","so.it","sondrio.it","sp.it","sr.it","ss.it","suedtirol.it","südtirol.it","sv.it","ta.it","taranto.it","te.it","tempio-olbia.it","tempioolbia.it","teramo.it","terni.it","tn.it","to.it","torino.it","tp.it","tr.it","trani-andria-barletta.it","trani-barletta-andria.it","traniandriabarletta.it","tranibarlettaandria.it","trapani.it","trento.it","treviso.it","trieste.it","ts.it","turin.it","tv.it","ud.it","udine.it","urbino-pesaro.it","urbinopesaro.it","va.it","varese.it","vb.it","vc.it","ve.it","venezia.it","venice.it","verbania.it","vercelli.it","verona.it","vi.it","vibo-valentia.it","vibovalentia.it","vicenza.it","viterbo.it","vr.it","vs.it","vt.it","vv.it","je","co.je","net.je","org.je","*.jm","jo","com.jo","org.jo","net.jo","edu.jo","sch.jo","gov.jo","mil.jo","name.jo","jobs","jp","ac.jp","ad.jp","co.jp","ed.jp","go.jp","gr.jp","lg.jp","ne.jp","or.jp","aichi.jp","akita.jp","aomori.jp","chiba.jp","ehime.jp","fukui.jp","fukuoka.jp","fukushima.jp","gifu.jp","gunma.jp","hiroshima.jp","hokkaido.jp","hyogo.jp","ibaraki.jp","ishikawa.jp","iwate.jp","kagawa.jp","kagoshima.jp","kanagawa.jp","kochi.jp","kumamoto.jp","kyoto.jp","mie.jp","miyagi.jp","miyazaki.jp","nagano.jp","nagasaki.jp","nara.jp","niigata.jp","oita.jp","okayama.jp","okinawa.jp","osaka.jp","saga.jp","saitama.jp","shiga.jp","shimane.jp","shizuoka.jp","tochigi.jp","tokushima.jp","tokyo.jp","tottori.jp","toyama.jp","wakayama.jp","yamagata.jp","yamaguchi.jp","yamanashi.jp","栃木.jp","愛知.jp","愛媛.jp","兵庫.jp","熊本.jp","茨城.jp","北海道.jp","千葉.jp","和歌山.jp","長崎.jp","長野.jp","新潟.jp","青森.jp","静岡.jp","東京.jp","石川.jp","埼玉.jp","三重.jp","京都.jp","佐賀.jp","大分.jp","大阪.jp","奈良.jp","宮城.jp","宮崎.jp","富山.jp","山口.jp","山形.jp","山梨.jp","岩手.jp","岐阜.jp","岡山.jp","島根.jp","広島.jp","徳島.jp","沖縄.jp","滋賀.jp","神奈川.jp","福井.jp","福岡.jp","福島.jp","秋田.jp","群馬.jp","香川.jp","高知.jp","鳥取.jp","鹿児島.jp","*.kawasaki.jp","*.kitakyushu.jp","*.kobe.jp","*.nagoya.jp","*.sapporo.jp","*.sendai.jp","*.yokohama.jp","!city.kawasaki.jp","!city.kitakyushu.jp","!city.kobe.jp","!city.nagoya.jp","!city.sapporo.jp","!city.sendai.jp","!city.yokohama.jp","aisai.aichi.jp","ama.aichi.jp","anjo.aichi.jp","asuke.aichi.jp","chiryu.aichi.jp","chita.aichi.jp","fuso.aichi.jp","gamagori.aichi.jp","handa.aichi.jp","hazu.aichi.jp","hekinan.aichi.jp","higashiura.aichi.jp","ichinomiya.aichi.jp","inazawa.aichi.jp","inuyama.aichi.jp","isshiki.aichi.jp","iwakura.aichi.jp","kanie.aichi.jp","kariya.aichi.jp","kasugai.aichi.jp","kira.aichi.jp","kiyosu.aichi.jp","komaki.aichi.jp","konan.aichi.jp","kota.aichi.jp","mihama.aichi.jp","miyoshi.aichi.jp","nishio.aichi.jp","nisshin.aichi.jp","obu.aichi.jp","oguchi.aichi.jp","oharu.aichi.jp","okazaki.aichi.jp","owariasahi.aichi.jp","seto.aichi.jp","shikatsu.aichi.jp","shinshiro.aichi.jp","shitara.aichi.jp","tahara.aichi.jp","takahama.aichi.jp","tobishima.aichi.jp","toei.aichi.jp","togo.aichi.jp","tokai.aichi.jp","tokoname.aichi.jp","toyoake.aichi.jp","toyohashi.aichi.jp","toyokawa.aichi.jp","toyone.aichi.jp","toyota.aichi.jp","tsushima.aichi.jp","yatomi.aichi.jp","akita.akita.jp","daisen.akita.jp","fujisato.akita.jp","gojome.akita.jp","hachirogata.akita.jp","happou.akita.jp","higashinaruse.akita.jp","honjo.akita.jp","honjyo.akita.jp","ikawa.akita.jp","kamikoani.akita.jp","kamioka.akita.jp","katagami.akita.jp","kazuno.akita.jp","kitaakita.akita.jp","kosaka.akita.jp","kyowa.akita.jp","misato.akita.jp","mitane.akita.jp","moriyoshi.akita.jp","nikaho.akita.jp","noshiro.akita.jp","odate.akita.jp","oga.akita.jp","ogata.akita.jp","semboku.akita.jp","yokote.akita.jp","yurihonjo.akita.jp","aomori.aomori.jp","gonohe.aomori.jp","hachinohe.aomori.jp","hashikami.aomori.jp","hiranai.aomori.jp","hirosaki.aomori.jp","itayanagi.aomori.jp","kuroishi.aomori.jp","misawa.aomori.jp","mutsu.aomori.jp","nakadomari.aomori.jp","noheji.aomori.jp","oirase.aomori.jp","owani.aomori.jp","rokunohe.aomori.jp","sannohe.aomori.jp","shichinohe.aomori.jp","shingo.aomori.jp","takko.aomori.jp","towada.aomori.jp","tsugaru.aomori.jp","tsuruta.aomori.jp","abiko.chiba.jp","asahi.chiba.jp","chonan.chiba.jp","chosei.chiba.jp","choshi.chiba.jp","chuo.chiba.jp","funabashi.chiba.jp","futtsu.chiba.jp","hanamigawa.chiba.jp","ichihara.chiba.jp","ichikawa.chiba.jp","ichinomiya.chiba.jp","inzai.chiba.jp","isumi.chiba.jp","kamagaya.chiba.jp","kamogawa.chiba.jp","kashiwa.chiba.jp","katori.chiba.jp","katsuura.chiba.jp","kimitsu.chiba.jp","kisarazu.chiba.jp","kozaki.chiba.jp","kujukuri.chiba.jp","kyonan.chiba.jp","matsudo.chiba.jp","midori.chiba.jp","mihama.chiba.jp","minamiboso.chiba.jp","mobara.chiba.jp","mutsuzawa.chiba.jp","nagara.chiba.jp","nagareyama.chiba.jp","narashino.chiba.jp","narita.chiba.jp","noda.chiba.jp","oamishirasato.chiba.jp","omigawa.chiba.jp","onjuku.chiba.jp","otaki.chiba.jp","sakae.chiba.jp","sakura.chiba.jp","shimofusa.chiba.jp","shirako.chiba.jp","shiroi.chiba.jp","shisui.chiba.jp","sodegaura.chiba.jp","sosa.chiba.jp","tako.chiba.jp","tateyama.chiba.jp","togane.chiba.jp","tohnosho.chiba.jp","tomisato.chiba.jp","urayasu.chiba.jp","yachimata.chiba.jp","yachiyo.chiba.jp","yokaichiba.chiba.jp","yokoshibahikari.chiba.jp","yotsukaido.chiba.jp","ainan.ehime.jp","honai.ehime.jp","ikata.ehime.jp","imabari.ehime.jp","iyo.ehime.jp","kamijima.ehime.jp","kihoku.ehime.jp","kumakogen.ehime.jp","masaki.ehime.jp","matsuno.ehime.jp","matsuyama.ehime.jp","namikata.ehime.jp","niihama.ehime.jp","ozu.ehime.jp","saijo.ehime.jp","seiyo.ehime.jp","shikokuchuo.ehime.jp","tobe.ehime.jp","toon.ehime.jp","uchiko.ehime.jp","uwajima.ehime.jp","yawatahama.ehime.jp","echizen.fukui.jp","eiheiji.fukui.jp","fukui.fukui.jp","ikeda.fukui.jp","katsuyama.fukui.jp","mihama.fukui.jp","minamiechizen.fukui.jp","obama.fukui.jp","ohi.fukui.jp","ono.fukui.jp","sabae.fukui.jp","sakai.fukui.jp","takahama.fukui.jp","tsuruga.fukui.jp","wakasa.fukui.jp","ashiya.fukuoka.jp","buzen.fukuoka.jp","chikugo.fukuoka.jp","chikuho.fukuoka.jp","chikujo.fukuoka.jp","chikushino.fukuoka.jp","chikuzen.fukuoka.jp","chuo.fukuoka.jp","dazaifu.fukuoka.jp","fukuchi.fukuoka.jp","hakata.fukuoka.jp","higashi.fukuoka.jp","hirokawa.fukuoka.jp","hisayama.fukuoka.jp","iizuka.fukuoka.jp","inatsuki.fukuoka.jp","kaho.fukuoka.jp","kasuga.fukuoka.jp","kasuya.fukuoka.jp","kawara.fukuoka.jp","keisen.fukuoka.jp","koga.fukuoka.jp","kurate.fukuoka.jp","kurogi.fukuoka.jp","kurume.fukuoka.jp","minami.fukuoka.jp","miyako.fukuoka.jp","miyama.fukuoka.jp","miyawaka.fukuoka.jp","mizumaki.fukuoka.jp","munakata.fukuoka.jp","nakagawa.fukuoka.jp","nakama.fukuoka.jp","nishi.fukuoka.jp","nogata.fukuoka.jp","ogori.fukuoka.jp","okagaki.fukuoka.jp","okawa.fukuoka.jp","oki.fukuoka.jp","omuta.fukuoka.jp","onga.fukuoka.jp","onojo.fukuoka.jp","oto.fukuoka.jp","saigawa.fukuoka.jp","sasaguri.fukuoka.jp","shingu.fukuoka.jp","shinyoshitomi.fukuoka.jp","shonai.fukuoka.jp","soeda.fukuoka.jp","sue.fukuoka.jp","tachiarai.fukuoka.jp","tagawa.fukuoka.jp","takata.fukuoka.jp","toho.fukuoka.jp","toyotsu.fukuoka.jp","tsuiki.fukuoka.jp","ukiha.fukuoka.jp","umi.fukuoka.jp","usui.fukuoka.jp","yamada.fukuoka.jp","yame.fukuoka.jp","yanagawa.fukuoka.jp","yukuhashi.fukuoka.jp","aizubange.fukushima.jp","aizumisato.fukushima.jp","aizuwakamatsu.fukushima.jp","asakawa.fukushima.jp","bandai.fukushima.jp","date.fukushima.jp","fukushima.fukushima.jp","furudono.fukushima.jp","futaba.fukushima.jp","hanawa.fukushima.jp","higashi.fukushima.jp","hirata.fukushima.jp","hirono.fukushima.jp","iitate.fukushima.jp","inawashiro.fukushima.jp","ishikawa.fukushima.jp","iwaki.fukushima.jp","izumizaki.fukushima.jp","kagamiishi.fukushima.jp","kaneyama.fukushima.jp","kawamata.fukushima.jp","kitakata.fukushima.jp","kitashiobara.fukushima.jp","koori.fukushima.jp","koriyama.fukushima.jp","kunimi.fukushima.jp","miharu.fukushima.jp","mishima.fukushima.jp","namie.fukushima.jp","nango.fukushima.jp","nishiaizu.fukushima.jp","nishigo.fukushima.jp","okuma.fukushima.jp","omotego.fukushima.jp","ono.fukushima.jp","otama.fukushima.jp","samegawa.fukushima.jp","shimogo.fukushima.jp","shirakawa.fukushima.jp","showa.fukushima.jp","soma.fukushima.jp","sukagawa.fukushima.jp","taishin.fukushima.jp","tamakawa.fukushima.jp","tanagura.fukushima.jp","tenei.fukushima.jp","yabuki.fukushima.jp","yamato.fukushima.jp","yamatsuri.fukushima.jp","yanaizu.fukushima.jp","yugawa.fukushima.jp","anpachi.gifu.jp","ena.gifu.jp","gifu.gifu.jp","ginan.gifu.jp","godo.gifu.jp","gujo.gifu.jp","hashima.gifu.jp","hichiso.gifu.jp","hida.gifu.jp","higashishirakawa.gifu.jp","ibigawa.gifu.jp","ikeda.gifu.jp","kakamigahara.gifu.jp","kani.gifu.jp","kasahara.gifu.jp","kasamatsu.gifu.jp","kawaue.gifu.jp","kitagata.gifu.jp","mino.gifu.jp","minokamo.gifu.jp","mitake.gifu.jp","mizunami.gifu.jp","motosu.gifu.jp","nakatsugawa.gifu.jp","ogaki.gifu.jp","sakahogi.gifu.jp","seki.gifu.jp","sekigahara.gifu.jp","shirakawa.gifu.jp","tajimi.gifu.jp","takayama.gifu.jp","tarui.gifu.jp","toki.gifu.jp","tomika.gifu.jp","wanouchi.gifu.jp","yamagata.gifu.jp","yaotsu.gifu.jp","yoro.gifu.jp","annaka.gunma.jp","chiyoda.gunma.jp","fujioka.gunma.jp","higashiagatsuma.gunma.jp","isesaki.gunma.jp","itakura.gunma.jp","kanna.gunma.jp","kanra.gunma.jp","katashina.gunma.jp","kawaba.gunma.jp","kiryu.gunma.jp","kusatsu.gunma.jp","maebashi.gunma.jp","meiwa.gunma.jp","midori.gunma.jp","minakami.gunma.jp","naganohara.gunma.jp","nakanojo.gunma.jp","nanmoku.gunma.jp","numata.gunma.jp","oizumi.gunma.jp","ora.gunma.jp","ota.gunma.jp","shibukawa.gunma.jp","shimonita.gunma.jp","shinto.gunma.jp","showa.gunma.jp","takasaki.gunma.jp","takayama.gunma.jp","tamamura.gunma.jp","tatebayashi.gunma.jp","tomioka.gunma.jp","tsukiyono.gunma.jp","tsumagoi.gunma.jp","ueno.gunma.jp","yoshioka.gunma.jp","asaminami.hiroshima.jp","daiwa.hiroshima.jp","etajima.hiroshima.jp","fuchu.hiroshima.jp","fukuyama.hiroshima.jp","hatsukaichi.hiroshima.jp","higashihiroshima.hiroshima.jp","hongo.hiroshima.jp","jinsekikogen.hiroshima.jp","kaita.hiroshima.jp","kui.hiroshima.jp","kumano.hiroshima.jp","kure.hiroshima.jp","mihara.hiroshima.jp","miyoshi.hiroshima.jp","naka.hiroshima.jp","onomichi.hiroshima.jp","osakikamijima.hiroshima.jp","otake.hiroshima.jp","saka.hiroshima.jp","sera.hiroshima.jp","seranishi.hiroshima.jp","shinichi.hiroshima.jp","shobara.hiroshima.jp","takehara.hiroshima.jp","abashiri.hokkaido.jp","abira.hokkaido.jp","aibetsu.hokkaido.jp","akabira.hokkaido.jp","akkeshi.hokkaido.jp","asahikawa.hokkaido.jp","ashibetsu.hokkaido.jp","ashoro.hokkaido.jp","assabu.hokkaido.jp","atsuma.hokkaido.jp","bibai.hokkaido.jp","biei.hokkaido.jp","bifuka.hokkaido.jp","bihoro.hokkaido.jp","biratori.hokkaido.jp","chippubetsu.hokkaido.jp","chitose.hokkaido.jp","date.hokkaido.jp","ebetsu.hokkaido.jp","embetsu.hokkaido.jp","eniwa.hokkaido.jp","erimo.hokkaido.jp","esan.hokkaido.jp","esashi.hokkaido.jp","fukagawa.hokkaido.jp","fukushima.hokkaido.jp","furano.hokkaido.jp","furubira.hokkaido.jp","haboro.hokkaido.jp","hakodate.hokkaido.jp","hamatonbetsu.hokkaido.jp","hidaka.hokkaido.jp","higashikagura.hokkaido.jp","higashikawa.hokkaido.jp","hiroo.hokkaido.jp","hokuryu.hokkaido.jp","hokuto.hokkaido.jp","honbetsu.hokkaido.jp","horokanai.hokkaido.jp","horonobe.hokkaido.jp","ikeda.hokkaido.jp","imakane.hokkaido.jp","ishikari.hokkaido.jp","iwamizawa.hokkaido.jp","iwanai.hokkaido.jp","kamifurano.hokkaido.jp","kamikawa.hokkaido.jp","kamishihoro.hokkaido.jp","kamisunagawa.hokkaido.jp","kamoenai.hokkaido.jp","kayabe.hokkaido.jp","kembuchi.hokkaido.jp","kikonai.hokkaido.jp","kimobetsu.hokkaido.jp","kitahiroshima.hokkaido.jp","kitami.hokkaido.jp","kiyosato.hokkaido.jp","koshimizu.hokkaido.jp","kunneppu.hokkaido.jp","kuriyama.hokkaido.jp","kuromatsunai.hokkaido.jp","kushiro.hokkaido.jp","kutchan.hokkaido.jp","kyowa.hokkaido.jp","mashike.hokkaido.jp","matsumae.hokkaido.jp","mikasa.hokkaido.jp","minamifurano.hokkaido.jp","mombetsu.hokkaido.jp","moseushi.hokkaido.jp","mukawa.hokkaido.jp","muroran.hokkaido.jp","naie.hokkaido.jp","nakagawa.hokkaido.jp","nakasatsunai.hokkaido.jp","nakatombetsu.hokkaido.jp","nanae.hokkaido.jp","nanporo.hokkaido.jp","nayoro.hokkaido.jp","nemuro.hokkaido.jp","niikappu.hokkaido.jp","niki.hokkaido.jp","nishiokoppe.hokkaido.jp","noboribetsu.hokkaido.jp","numata.hokkaido.jp","obihiro.hokkaido.jp","obira.hokkaido.jp","oketo.hokkaido.jp","okoppe.hokkaido.jp","otaru.hokkaido.jp","otobe.hokkaido.jp","otofuke.hokkaido.jp","otoineppu.hokkaido.jp","oumu.hokkaido.jp","ozora.hokkaido.jp","pippu.hokkaido.jp","rankoshi.hokkaido.jp","rebun.hokkaido.jp","rikubetsu.hokkaido.jp","rishiri.hokkaido.jp","rishirifuji.hokkaido.jp","saroma.hokkaido.jp","sarufutsu.hokkaido.jp","shakotan.hokkaido.jp","shari.hokkaido.jp","shibecha.hokkaido.jp","shibetsu.hokkaido.jp","shikabe.hokkaido.jp","shikaoi.hokkaido.jp","shimamaki.hokkaido.jp","shimizu.hokkaido.jp","shimokawa.hokkaido.jp","shinshinotsu.hokkaido.jp","shintoku.hokkaido.jp","shiranuka.hokkaido.jp","shiraoi.hokkaido.jp","shiriuchi.hokkaido.jp","sobetsu.hokkaido.jp","sunagawa.hokkaido.jp","taiki.hokkaido.jp","takasu.hokkaido.jp","takikawa.hokkaido.jp","takinoue.hokkaido.jp","teshikaga.hokkaido.jp","tobetsu.hokkaido.jp","tohma.hokkaido.jp","tomakomai.hokkaido.jp","tomari.hokkaido.jp","toya.hokkaido.jp","toyako.hokkaido.jp","toyotomi.hokkaido.jp","toyoura.hokkaido.jp","tsubetsu.hokkaido.jp","tsukigata.hokkaido.jp","urakawa.hokkaido.jp","urausu.hokkaido.jp","uryu.hokkaido.jp","utashinai.hokkaido.jp","wakkanai.hokkaido.jp","wassamu.hokkaido.jp","yakumo.hokkaido.jp","yoichi.hokkaido.jp","aioi.hyogo.jp","akashi.hyogo.jp","ako.hyogo.jp","amagasaki.hyogo.jp","aogaki.hyogo.jp","asago.hyogo.jp","ashiya.hyogo.jp","awaji.hyogo.jp","fukusaki.hyogo.jp","goshiki.hyogo.jp","harima.hyogo.jp","himeji.hyogo.jp","ichikawa.hyogo.jp","inagawa.hyogo.jp","itami.hyogo.jp","kakogawa.hyogo.jp","kamigori.hyogo.jp","kamikawa.hyogo.jp","kasai.hyogo.jp","kasuga.hyogo.jp","kawanishi.hyogo.jp","miki.hyogo.jp","minamiawaji.hyogo.jp","nishinomiya.hyogo.jp","nishiwaki.hyogo.jp","ono.hyogo.jp","sanda.hyogo.jp","sannan.hyogo.jp","sasayama.hyogo.jp","sayo.hyogo.jp","shingu.hyogo.jp","shinonsen.hyogo.jp","shiso.hyogo.jp","sumoto.hyogo.jp","taishi.hyogo.jp","taka.hyogo.jp","takarazuka.hyogo.jp","takasago.hyogo.jp","takino.hyogo.jp","tamba.hyogo.jp","tatsuno.hyogo.jp","toyooka.hyogo.jp","yabu.hyogo.jp","yashiro.hyogo.jp","yoka.hyogo.jp","yokawa.hyogo.jp","ami.ibaraki.jp","asahi.ibaraki.jp","bando.ibaraki.jp","chikusei.ibaraki.jp","daigo.ibaraki.jp","fujishiro.ibaraki.jp","hitachi.ibaraki.jp","hitachinaka.ibaraki.jp","hitachiomiya.ibaraki.jp","hitachiota.ibaraki.jp","ibaraki.ibaraki.jp","ina.ibaraki.jp","inashiki.ibaraki.jp","itako.ibaraki.jp","iwama.ibaraki.jp","joso.ibaraki.jp","kamisu.ibaraki.jp","kasama.ibaraki.jp","kashima.ibaraki.jp","kasumigaura.ibaraki.jp","koga.ibaraki.jp","miho.ibaraki.jp","mito.ibaraki.jp","moriya.ibaraki.jp","naka.ibaraki.jp","namegata.ibaraki.jp","oarai.ibaraki.jp","ogawa.ibaraki.jp","omitama.ibaraki.jp","ryugasaki.ibaraki.jp","sakai.ibaraki.jp","sakuragawa.ibaraki.jp","shimodate.ibaraki.jp","shimotsuma.ibaraki.jp","shirosato.ibaraki.jp","sowa.ibaraki.jp","suifu.ibaraki.jp","takahagi.ibaraki.jp","tamatsukuri.ibaraki.jp","tokai.ibaraki.jp","tomobe.ibaraki.jp","tone.ibaraki.jp","toride.ibaraki.jp","tsuchiura.ibaraki.jp","tsukuba.ibaraki.jp","uchihara.ibaraki.jp","ushiku.ibaraki.jp","yachiyo.ibaraki.jp","yamagata.ibaraki.jp","yawara.ibaraki.jp","yuki.ibaraki.jp","anamizu.ishikawa.jp","hakui.ishikawa.jp","hakusan.ishikawa.jp","kaga.ishikawa.jp","kahoku.ishikawa.jp","kanazawa.ishikawa.jp","kawakita.ishikawa.jp","komatsu.ishikawa.jp","nakanoto.ishikawa.jp","nanao.ishikawa.jp","nomi.ishikawa.jp","nonoichi.ishikawa.jp","noto.ishikawa.jp","shika.ishikawa.jp","suzu.ishikawa.jp","tsubata.ishikawa.jp","tsurugi.ishikawa.jp","uchinada.ishikawa.jp","wajima.ishikawa.jp","fudai.iwate.jp","fujisawa.iwate.jp","hanamaki.iwate.jp","hiraizumi.iwate.jp","hirono.iwate.jp","ichinohe.iwate.jp","ichinoseki.iwate.jp","iwaizumi.iwate.jp","iwate.iwate.jp","joboji.iwate.jp","kamaishi.iwate.jp","kanegasaki.iwate.jp","karumai.iwate.jp","kawai.iwate.jp","kitakami.iwate.jp","kuji.iwate.jp","kunohe.iwate.jp","kuzumaki.iwate.jp","miyako.iwate.jp","mizusawa.iwate.jp","morioka.iwate.jp","ninohe.iwate.jp","noda.iwate.jp","ofunato.iwate.jp","oshu.iwate.jp","otsuchi.iwate.jp","rikuzentakata.iwate.jp","shiwa.iwate.jp","shizukuishi.iwate.jp","sumita.iwate.jp","tanohata.iwate.jp","tono.iwate.jp","yahaba.iwate.jp","yamada.iwate.jp","ayagawa.kagawa.jp","higashikagawa.kagawa.jp","kanonji.kagawa.jp","kotohira.kagawa.jp","manno.kagawa.jp","marugame.kagawa.jp","mitoyo.kagawa.jp","naoshima.kagawa.jp","sanuki.kagawa.jp","tadotsu.kagawa.jp","takamatsu.kagawa.jp","tonosho.kagawa.jp","uchinomi.kagawa.jp","utazu.kagawa.jp","zentsuji.kagawa.jp","akune.kagoshima.jp","amami.kagoshima.jp","hioki.kagoshima.jp","isa.kagoshima.jp","isen.kagoshima.jp","izumi.kagoshima.jp","kagoshima.kagoshima.jp","kanoya.kagoshima.jp","kawanabe.kagoshima.jp","kinko.kagoshima.jp","kouyama.kagoshima.jp","makurazaki.kagoshima.jp","matsumoto.kagoshima.jp","minamitane.kagoshima.jp","nakatane.kagoshima.jp","nishinoomote.kagoshima.jp","satsumasendai.kagoshima.jp","soo.kagoshima.jp","tarumizu.kagoshima.jp","yusui.kagoshima.jp","aikawa.kanagawa.jp","atsugi.kanagawa.jp","ayase.kanagawa.jp","chigasaki.kanagawa.jp","ebina.kanagawa.jp","fujisawa.kanagawa.jp","hadano.kanagawa.jp","hakone.kanagawa.jp","hiratsuka.kanagawa.jp","isehara.kanagawa.jp","kaisei.kanagawa.jp","kamakura.kanagawa.jp","kiyokawa.kanagawa.jp","matsuda.kanagawa.jp","minamiashigara.kanagawa.jp","miura.kanagawa.jp","nakai.kanagawa.jp","ninomiya.kanagawa.jp","odawara.kanagawa.jp","oi.kanagawa.jp","oiso.kanagawa.jp","sagamihara.kanagawa.jp","samukawa.kanagawa.jp","tsukui.kanagawa.jp","yamakita.kanagawa.jp","yamato.kanagawa.jp","yokosuka.kanagawa.jp","yugawara.kanagawa.jp","zama.kanagawa.jp","zushi.kanagawa.jp","aki.kochi.jp","geisei.kochi.jp","hidaka.kochi.jp","higashitsuno.kochi.jp","ino.kochi.jp","kagami.kochi.jp","kami.kochi.jp","kitagawa.kochi.jp","kochi.kochi.jp","mihara.kochi.jp","motoyama.kochi.jp","muroto.kochi.jp","nahari.kochi.jp","nakamura.kochi.jp","nankoku.kochi.jp","nishitosa.kochi.jp","niyodogawa.kochi.jp","ochi.kochi.jp","okawa.kochi.jp","otoyo.kochi.jp","otsuki.kochi.jp","sakawa.kochi.jp","sukumo.kochi.jp","susaki.kochi.jp","tosa.kochi.jp","tosashimizu.kochi.jp","toyo.kochi.jp","tsuno.kochi.jp","umaji.kochi.jp","yasuda.kochi.jp","yusuhara.kochi.jp","amakusa.kumamoto.jp","arao.kumamoto.jp","aso.kumamoto.jp","choyo.kumamoto.jp","gyokuto.kumamoto.jp","kamiamakusa.kumamoto.jp","kikuchi.kumamoto.jp","kumamoto.kumamoto.jp","mashiki.kumamoto.jp","mifune.kumamoto.jp","minamata.kumamoto.jp","minamioguni.kumamoto.jp","nagasu.kumamoto.jp","nishihara.kumamoto.jp","oguni.kumamoto.jp","ozu.kumamoto.jp","sumoto.kumamoto.jp","takamori.kumamoto.jp","uki.kumamoto.jp","uto.kumamoto.jp","yamaga.kumamoto.jp","yamato.kumamoto.jp","yatsushiro.kumamoto.jp","ayabe.kyoto.jp","fukuchiyama.kyoto.jp","higashiyama.kyoto.jp","ide.kyoto.jp","ine.kyoto.jp","joyo.kyoto.jp","kameoka.kyoto.jp","kamo.kyoto.jp","kita.kyoto.jp","kizu.kyoto.jp","kumiyama.kyoto.jp","kyotamba.kyoto.jp","kyotanabe.kyoto.jp","kyotango.kyoto.jp","maizuru.kyoto.jp","minami.kyoto.jp","minamiyamashiro.kyoto.jp","miyazu.kyoto.jp","muko.kyoto.jp","nagaokakyo.kyoto.jp","nakagyo.kyoto.jp","nantan.kyoto.jp","oyamazaki.kyoto.jp","sakyo.kyoto.jp","seika.kyoto.jp","tanabe.kyoto.jp","uji.kyoto.jp","ujitawara.kyoto.jp","wazuka.kyoto.jp","yamashina.kyoto.jp","yawata.kyoto.jp","asahi.mie.jp","inabe.mie.jp","ise.mie.jp","kameyama.mie.jp","kawagoe.mie.jp","kiho.mie.jp","kisosaki.mie.jp","kiwa.mie.jp","komono.mie.jp","kumano.mie.jp","kuwana.mie.jp","matsusaka.mie.jp","meiwa.mie.jp","mihama.mie.jp","minamiise.mie.jp","misugi.mie.jp","miyama.mie.jp","nabari.mie.jp","shima.mie.jp","suzuka.mie.jp","tado.mie.jp","taiki.mie.jp","taki.mie.jp","tamaki.mie.jp","toba.mie.jp","tsu.mie.jp","udono.mie.jp","ureshino.mie.jp","watarai.mie.jp","yokkaichi.mie.jp","furukawa.miyagi.jp","higashimatsushima.miyagi.jp","ishinomaki.miyagi.jp","iwanuma.miyagi.jp","kakuda.miyagi.jp","kami.miyagi.jp","kawasaki.miyagi.jp","marumori.miyagi.jp","matsushima.miyagi.jp","minamisanriku.miyagi.jp","misato.miyagi.jp","murata.miyagi.jp","natori.miyagi.jp","ogawara.miyagi.jp","ohira.miyagi.jp","onagawa.miyagi.jp","osaki.miyagi.jp","rifu.miyagi.jp","semine.miyagi.jp","shibata.miyagi.jp","shichikashuku.miyagi.jp","shikama.miyagi.jp","shiogama.miyagi.jp","shiroishi.miyagi.jp","tagajo.miyagi.jp","taiwa.miyagi.jp","tome.miyagi.jp","tomiya.miyagi.jp","wakuya.miyagi.jp","watari.miyagi.jp","yamamoto.miyagi.jp","zao.miyagi.jp","aya.miyazaki.jp","ebino.miyazaki.jp","gokase.miyazaki.jp","hyuga.miyazaki.jp","kadogawa.miyazaki.jp","kawaminami.miyazaki.jp","kijo.miyazaki.jp","kitagawa.miyazaki.jp","kitakata.miyazaki.jp","kitaura.miyazaki.jp","kobayashi.miyazaki.jp","kunitomi.miyazaki.jp","kushima.miyazaki.jp","mimata.miyazaki.jp","miyakonojo.miyazaki.jp","miyazaki.miyazaki.jp","morotsuka.miyazaki.jp","nichinan.miyazaki.jp","nishimera.miyazaki.jp","nobeoka.miyazaki.jp","saito.miyazaki.jp","shiiba.miyazaki.jp","shintomi.miyazaki.jp","takaharu.miyazaki.jp","takanabe.miyazaki.jp","takazaki.miyazaki.jp","tsuno.miyazaki.jp","achi.nagano.jp","agematsu.nagano.jp","anan.nagano.jp","aoki.nagano.jp","asahi.nagano.jp","azumino.nagano.jp","chikuhoku.nagano.jp","chikuma.nagano.jp","chino.nagano.jp","fujimi.nagano.jp","hakuba.nagano.jp","hara.nagano.jp","hiraya.nagano.jp","iida.nagano.jp","iijima.nagano.jp","iiyama.nagano.jp","iizuna.nagano.jp","ikeda.nagano.jp","ikusaka.nagano.jp","ina.nagano.jp","karuizawa.nagano.jp","kawakami.nagano.jp","kiso.nagano.jp","kisofukushima.nagano.jp","kitaaiki.nagano.jp","komagane.nagano.jp","komoro.nagano.jp","matsukawa.nagano.jp","matsumoto.nagano.jp","miasa.nagano.jp","minamiaiki.nagano.jp","minamimaki.nagano.jp","minamiminowa.nagano.jp","minowa.nagano.jp","miyada.nagano.jp","miyota.nagano.jp","mochizuki.nagano.jp","nagano.nagano.jp","nagawa.nagano.jp","nagiso.nagano.jp","nakagawa.nagano.jp","nakano.nagano.jp","nozawaonsen.nagano.jp","obuse.nagano.jp","ogawa.nagano.jp","okaya.nagano.jp","omachi.nagano.jp","omi.nagano.jp","ookuwa.nagano.jp","ooshika.nagano.jp","otaki.nagano.jp","otari.nagano.jp","sakae.nagano.jp","sakaki.nagano.jp","saku.nagano.jp","sakuho.nagano.jp","shimosuwa.nagano.jp","shinanomachi.nagano.jp","shiojiri.nagano.jp","suwa.nagano.jp","suzaka.nagano.jp","takagi.nagano.jp","takamori.nagano.jp","takayama.nagano.jp","tateshina.nagano.jp","tatsuno.nagano.jp","togakushi.nagano.jp","togura.nagano.jp","tomi.nagano.jp","ueda.nagano.jp","wada.nagano.jp","yamagata.nagano.jp","yamanouchi.nagano.jp","yasaka.nagano.jp","yasuoka.nagano.jp","chijiwa.nagasaki.jp","futsu.nagasaki.jp","goto.nagasaki.jp","hasami.nagasaki.jp","hirado.nagasaki.jp","iki.nagasaki.jp","isahaya.nagasaki.jp","kawatana.nagasaki.jp","kuchinotsu.nagasaki.jp","matsuura.nagasaki.jp","nagasaki.nagasaki.jp","obama.nagasaki.jp","omura.nagasaki.jp","oseto.nagasaki.jp","saikai.nagasaki.jp","sasebo.nagasaki.jp","seihi.nagasaki.jp","shimabara.nagasaki.jp","shinkamigoto.nagasaki.jp","togitsu.nagasaki.jp","tsushima.nagasaki.jp","unzen.nagasaki.jp","ando.nara.jp","gose.nara.jp","heguri.nara.jp","higashiyoshino.nara.jp","ikaruga.nara.jp","ikoma.nara.jp","kamikitayama.nara.jp","kanmaki.nara.jp","kashiba.nara.jp","kashihara.nara.jp","katsuragi.nara.jp","kawai.nara.jp","kawakami.nara.jp","kawanishi.nara.jp","koryo.nara.jp","kurotaki.nara.jp","mitsue.nara.jp","miyake.nara.jp","nara.nara.jp","nosegawa.nara.jp","oji.nara.jp","ouda.nara.jp","oyodo.nara.jp","sakurai.nara.jp","sango.nara.jp","shimoichi.nara.jp","shimokitayama.nara.jp","shinjo.nara.jp","soni.nara.jp","takatori.nara.jp","tawaramoto.nara.jp","tenkawa.nara.jp","tenri.nara.jp","uda.nara.jp","yamatokoriyama.nara.jp","yamatotakada.nara.jp","yamazoe.nara.jp","yoshino.nara.jp","aga.niigata.jp","agano.niigata.jp","gosen.niigata.jp","itoigawa.niigata.jp","izumozaki.niigata.jp","joetsu.niigata.jp","kamo.niigata.jp","kariwa.niigata.jp","kashiwazaki.niigata.jp","minamiuonuma.niigata.jp","mitsuke.niigata.jp","muika.niigata.jp","murakami.niigata.jp","myoko.niigata.jp","nagaoka.niigata.jp","niigata.niigata.jp","ojiya.niigata.jp","omi.niigata.jp","sado.niigata.jp","sanjo.niigata.jp","seiro.niigata.jp","seirou.niigata.jp","sekikawa.niigata.jp","shibata.niigata.jp","tagami.niigata.jp","tainai.niigata.jp","tochio.niigata.jp","tokamachi.niigata.jp","tsubame.niigata.jp","tsunan.niigata.jp","uonuma.niigata.jp","yahiko.niigata.jp","yoita.niigata.jp","yuzawa.niigata.jp","beppu.oita.jp","bungoono.oita.jp","bungotakada.oita.jp","hasama.oita.jp","hiji.oita.jp","himeshima.oita.jp","hita.oita.jp","kamitsue.oita.jp","kokonoe.oita.jp","kuju.oita.jp","kunisaki.oita.jp","kusu.oita.jp","oita.oita.jp","saiki.oita.jp","taketa.oita.jp","tsukumi.oita.jp","usa.oita.jp","usuki.oita.jp","yufu.oita.jp","akaiwa.okayama.jp","asakuchi.okayama.jp","bizen.okayama.jp","hayashima.okayama.jp","ibara.okayama.jp","kagamino.okayama.jp","kasaoka.okayama.jp","kibichuo.okayama.jp","kumenan.okayama.jp","kurashiki.okayama.jp","maniwa.okayama.jp","misaki.okayama.jp","nagi.okayama.jp","niimi.okayama.jp","nishiawakura.okayama.jp","okayama.okayama.jp","satosho.okayama.jp","setouchi.okayama.jp","shinjo.okayama.jp","shoo.okayama.jp","soja.okayama.jp","takahashi.okayama.jp","tamano.okayama.jp","tsuyama.okayama.jp","wake.okayama.jp","yakage.okayama.jp","aguni.okinawa.jp","ginowan.okinawa.jp","ginoza.okinawa.jp","gushikami.okinawa.jp","haebaru.okinawa.jp","higashi.okinawa.jp","hirara.okinawa.jp","iheya.okinawa.jp","ishigaki.okinawa.jp","ishikawa.okinawa.jp","itoman.okinawa.jp","izena.okinawa.jp","kadena.okinawa.jp","kin.okinawa.jp","kitadaito.okinawa.jp","kitanakagusuku.okinawa.jp","kumejima.okinawa.jp","kunigami.okinawa.jp","minamidaito.okinawa.jp","motobu.okinawa.jp","nago.okinawa.jp","naha.okinawa.jp","nakagusuku.okinawa.jp","nakijin.okinawa.jp","nanjo.okinawa.jp","nishihara.okinawa.jp","ogimi.okinawa.jp","okinawa.okinawa.jp","onna.okinawa.jp","shimoji.okinawa.jp","taketomi.okinawa.jp","tarama.okinawa.jp","tokashiki.okinawa.jp","tomigusuku.okinawa.jp","tonaki.okinawa.jp","urasoe.okinawa.jp","uruma.okinawa.jp","yaese.okinawa.jp","yomitan.okinawa.jp","yonabaru.okinawa.jp","yonaguni.okinawa.jp","zamami.okinawa.jp","abeno.osaka.jp","chihayaakasaka.osaka.jp","chuo.osaka.jp","daito.osaka.jp","fujiidera.osaka.jp","habikino.osaka.jp","hannan.osaka.jp","higashiosaka.osaka.jp","higashisumiyoshi.osaka.jp","higashiyodogawa.osaka.jp","hirakata.osaka.jp","ibaraki.osaka.jp","ikeda.osaka.jp","izumi.osaka.jp","izumiotsu.osaka.jp","izumisano.osaka.jp","kadoma.osaka.jp","kaizuka.osaka.jp","kanan.osaka.jp","kashiwara.osaka.jp","katano.osaka.jp","kawachinagano.osaka.jp","kishiwada.osaka.jp","kita.osaka.jp","kumatori.osaka.jp","matsubara.osaka.jp","minato.osaka.jp","minoh.osaka.jp","misaki.osaka.jp","moriguchi.osaka.jp","neyagawa.osaka.jp","nishi.osaka.jp","nose.osaka.jp","osakasayama.osaka.jp","sakai.osaka.jp","sayama.osaka.jp","sennan.osaka.jp","settsu.osaka.jp","shijonawate.osaka.jp","shimamoto.osaka.jp","suita.osaka.jp","tadaoka.osaka.jp","taishi.osaka.jp","tajiri.osaka.jp","takaishi.osaka.jp","takatsuki.osaka.jp","tondabayashi.osaka.jp","toyonaka.osaka.jp","toyono.osaka.jp","yao.osaka.jp","ariake.saga.jp","arita.saga.jp","fukudomi.saga.jp","genkai.saga.jp","hamatama.saga.jp","hizen.saga.jp","imari.saga.jp","kamimine.saga.jp","kanzaki.saga.jp","karatsu.saga.jp","kashima.saga.jp","kitagata.saga.jp","kitahata.saga.jp","kiyama.saga.jp","kouhoku.saga.jp","kyuragi.saga.jp","nishiarita.saga.jp","ogi.saga.jp","omachi.saga.jp","ouchi.saga.jp","saga.saga.jp","shiroishi.saga.jp","taku.saga.jp","tara.saga.jp","tosu.saga.jp","yoshinogari.saga.jp","arakawa.saitama.jp","asaka.saitama.jp","chichibu.saitama.jp","fujimi.saitama.jp","fujimino.saitama.jp","fukaya.saitama.jp","hanno.saitama.jp","hanyu.saitama.jp","hasuda.saitama.jp","hatogaya.saitama.jp","hatoyama.saitama.jp","hidaka.saitama.jp","higashichichibu.saitama.jp","higashimatsuyama.saitama.jp","honjo.saitama.jp","ina.saitama.jp","iruma.saitama.jp","iwatsuki.saitama.jp","kamiizumi.saitama.jp","kamikawa.saitama.jp","kamisato.saitama.jp","kasukabe.saitama.jp","kawagoe.saitama.jp","kawaguchi.saitama.jp","kawajima.saitama.jp","kazo.saitama.jp","kitamoto.saitama.jp","koshigaya.saitama.jp","kounosu.saitama.jp","kuki.saitama.jp","kumagaya.saitama.jp","matsubushi.saitama.jp","minano.saitama.jp","misato.saitama.jp","miyashiro.saitama.jp","miyoshi.saitama.jp","moroyama.saitama.jp","nagatoro.saitama.jp","namegawa.saitama.jp","niiza.saitama.jp","ogano.saitama.jp","ogawa.saitama.jp","ogose.saitama.jp","okegawa.saitama.jp","omiya.saitama.jp","otaki.saitama.jp","ranzan.saitama.jp","ryokami.saitama.jp","saitama.saitama.jp","sakado.saitama.jp","satte.saitama.jp","sayama.saitama.jp","shiki.saitama.jp","shiraoka.saitama.jp","soka.saitama.jp","sugito.saitama.jp","toda.saitama.jp","tokigawa.saitama.jp","tokorozawa.saitama.jp","tsurugashima.saitama.jp","urawa.saitama.jp","warabi.saitama.jp","yashio.saitama.jp","yokoze.saitama.jp","yono.saitama.jp","yorii.saitama.jp","yoshida.saitama.jp","yoshikawa.saitama.jp","yoshimi.saitama.jp","aisho.shiga.jp","gamo.shiga.jp","higashiomi.shiga.jp","hikone.shiga.jp","koka.shiga.jp","konan.shiga.jp","kosei.shiga.jp","koto.shiga.jp","kusatsu.shiga.jp","maibara.shiga.jp","moriyama.shiga.jp","nagahama.shiga.jp","nishiazai.shiga.jp","notogawa.shiga.jp","omihachiman.shiga.jp","otsu.shiga.jp","ritto.shiga.jp","ryuoh.shiga.jp","takashima.shiga.jp","takatsuki.shiga.jp","torahime.shiga.jp","toyosato.shiga.jp","yasu.shiga.jp","akagi.shimane.jp","ama.shimane.jp","gotsu.shimane.jp","hamada.shimane.jp","higashiizumo.shimane.jp","hikawa.shimane.jp","hikimi.shimane.jp","izumo.shimane.jp","kakinoki.shimane.jp","masuda.shimane.jp","matsue.shimane.jp","misato.shimane.jp","nishinoshima.shimane.jp","ohda.shimane.jp","okinoshima.shimane.jp","okuizumo.shimane.jp","shimane.shimane.jp","tamayu.shimane.jp","tsuwano.shimane.jp","unnan.shimane.jp","yakumo.shimane.jp","yasugi.shimane.jp","yatsuka.shimane.jp","arai.shizuoka.jp","atami.shizuoka.jp","fuji.shizuoka.jp","fujieda.shizuoka.jp","fujikawa.shizuoka.jp","fujinomiya.shizuoka.jp","fukuroi.shizuoka.jp","gotemba.shizuoka.jp","haibara.shizuoka.jp","hamamatsu.shizuoka.jp","higashiizu.shizuoka.jp","ito.shizuoka.jp","iwata.shizuoka.jp","izu.shizuoka.jp","izunokuni.shizuoka.jp","kakegawa.shizuoka.jp","kannami.shizuoka.jp","kawanehon.shizuoka.jp","kawazu.shizuoka.jp","kikugawa.shizuoka.jp","kosai.shizuoka.jp","makinohara.shizuoka.jp","matsuzaki.shizuoka.jp","minamiizu.shizuoka.jp","mishima.shizuoka.jp","morimachi.shizuoka.jp","nishiizu.shizuoka.jp","numazu.shizuoka.jp","omaezaki.shizuoka.jp","shimada.shizuoka.jp","shimizu.shizuoka.jp","shimoda.shizuoka.jp","shizuoka.shizuoka.jp","susono.shizuoka.jp","yaizu.shizuoka.jp","yoshida.shizuoka.jp","ashikaga.tochigi.jp","bato.tochigi.jp","haga.tochigi.jp","ichikai.tochigi.jp","iwafune.tochigi.jp","kaminokawa.tochigi.jp","kanuma.tochigi.jp","karasuyama.tochigi.jp","kuroiso.tochigi.jp","mashiko.tochigi.jp","mibu.tochigi.jp","moka.tochigi.jp","motegi.tochigi.jp","nasu.tochigi.jp","nasushiobara.tochigi.jp","nikko.tochigi.jp","nishikata.tochigi.jp","nogi.tochigi.jp","ohira.tochigi.jp","ohtawara.tochigi.jp","oyama.tochigi.jp","sakura.tochigi.jp","sano.tochigi.jp","shimotsuke.tochigi.jp","shioya.tochigi.jp","takanezawa.tochigi.jp","tochigi.tochigi.jp","tsuga.tochigi.jp","ujiie.tochigi.jp","utsunomiya.tochigi.jp","yaita.tochigi.jp","aizumi.tokushima.jp","anan.tokushima.jp","ichiba.tokushima.jp","itano.tokushima.jp","kainan.tokushima.jp","komatsushima.tokushima.jp","matsushige.tokushima.jp","mima.tokushima.jp","minami.tokushima.jp","miyoshi.tokushima.jp","mugi.tokushima.jp","nakagawa.tokushima.jp","naruto.tokushima.jp","sanagochi.tokushima.jp","shishikui.tokushima.jp","tokushima.tokushima.jp","wajiki.tokushima.jp","adachi.tokyo.jp","akiruno.tokyo.jp","akishima.tokyo.jp","aogashima.tokyo.jp","arakawa.tokyo.jp","bunkyo.tokyo.jp","chiyoda.tokyo.jp","chofu.tokyo.jp","chuo.tokyo.jp","edogawa.tokyo.jp","fuchu.tokyo.jp","fussa.tokyo.jp","hachijo.tokyo.jp","hachioji.tokyo.jp","hamura.tokyo.jp","higashikurume.tokyo.jp","higashimurayama.tokyo.jp","higashiyamato.tokyo.jp","hino.tokyo.jp","hinode.tokyo.jp","hinohara.tokyo.jp","inagi.tokyo.jp","itabashi.tokyo.jp","katsushika.tokyo.jp","kita.tokyo.jp","kiyose.tokyo.jp","kodaira.tokyo.jp","koganei.tokyo.jp","kokubunji.tokyo.jp","komae.tokyo.jp","koto.tokyo.jp","kouzushima.tokyo.jp","kunitachi.tokyo.jp","machida.tokyo.jp","meguro.tokyo.jp","minato.tokyo.jp","mitaka.tokyo.jp","mizuho.tokyo.jp","musashimurayama.tokyo.jp","musashino.tokyo.jp","nakano.tokyo.jp","nerima.tokyo.jp","ogasawara.tokyo.jp","okutama.tokyo.jp","ome.tokyo.jp","oshima.tokyo.jp","ota.tokyo.jp","setagaya.tokyo.jp","shibuya.tokyo.jp","shinagawa.tokyo.jp","shinjuku.tokyo.jp","suginami.tokyo.jp","sumida.tokyo.jp","tachikawa.tokyo.jp","taito.tokyo.jp","tama.tokyo.jp","toshima.tokyo.jp","chizu.tottori.jp","hino.tottori.jp","kawahara.tottori.jp","koge.tottori.jp","kotoura.tottori.jp","misasa.tottori.jp","nanbu.tottori.jp","nichinan.tottori.jp","sakaiminato.tottori.jp","tottori.tottori.jp","wakasa.tottori.jp","yazu.tottori.jp","yonago.tottori.jp","asahi.toyama.jp","fuchu.toyama.jp","fukumitsu.toyama.jp","funahashi.toyama.jp","himi.toyama.jp","imizu.toyama.jp","inami.toyama.jp","johana.toyama.jp","kamiichi.toyama.jp","kurobe.toyama.jp","nakaniikawa.toyama.jp","namerikawa.toyama.jp","nanto.toyama.jp","nyuzen.toyama.jp","oyabe.toyama.jp","taira.toyama.jp","takaoka.toyama.jp","tateyama.toyama.jp","toga.toyama.jp","tonami.toyama.jp","toyama.toyama.jp","unazuki.toyama.jp","uozu.toyama.jp","yamada.toyama.jp","arida.wakayama.jp","aridagawa.wakayama.jp","gobo.wakayama.jp","hashimoto.wakayama.jp","hidaka.wakayama.jp","hirogawa.wakayama.jp","inami.wakayama.jp","iwade.wakayama.jp","kainan.wakayama.jp","kamitonda.wakayama.jp","katsuragi.wakayama.jp","kimino.wakayama.jp","kinokawa.wakayama.jp","kitayama.wakayama.jp","koya.wakayama.jp","koza.wakayama.jp","kozagawa.wakayama.jp","kudoyama.wakayama.jp","kushimoto.wakayama.jp","mihama.wakayama.jp","misato.wakayama.jp","nachikatsuura.wakayama.jp","shingu.wakayama.jp","shirahama.wakayama.jp","taiji.wakayama.jp","tanabe.wakayama.jp","wakayama.wakayama.jp","yuasa.wakayama.jp","yura.wakayama.jp","asahi.yamagata.jp","funagata.yamagata.jp","higashine.yamagata.jp","iide.yamagata.jp","kahoku.yamagata.jp","kaminoyama.yamagata.jp","kaneyama.yamagata.jp","kawanishi.yamagata.jp","mamurogawa.yamagata.jp","mikawa.yamagata.jp","murayama.yamagata.jp","nagai.yamagata.jp","nakayama.yamagata.jp","nanyo.yamagata.jp","nishikawa.yamagata.jp","obanazawa.yamagata.jp","oe.yamagata.jp","oguni.yamagata.jp","ohkura.yamagata.jp","oishida.yamagata.jp","sagae.yamagata.jp","sakata.yamagata.jp","sakegawa.yamagata.jp","shinjo.yamagata.jp","shirataka.yamagata.jp","shonai.yamagata.jp","takahata.yamagata.jp","tendo.yamagata.jp","tozawa.yamagata.jp","tsuruoka.yamagata.jp","yamagata.yamagata.jp","yamanobe.yamagata.jp","yonezawa.yamagata.jp","yuza.yamagata.jp","abu.yamaguchi.jp","hagi.yamaguchi.jp","hikari.yamaguchi.jp","hofu.yamaguchi.jp","iwakuni.yamaguchi.jp","kudamatsu.yamaguchi.jp","mitou.yamaguchi.jp","nagato.yamaguchi.jp","oshima.yamaguchi.jp","shimonoseki.yamaguchi.jp","shunan.yamaguchi.jp","tabuse.yamaguchi.jp","tokuyama.yamaguchi.jp","toyota.yamaguchi.jp","ube.yamaguchi.jp","yuu.yamaguchi.jp","chuo.yamanashi.jp","doshi.yamanashi.jp","fuefuki.yamanashi.jp","fujikawa.yamanashi.jp","fujikawaguchiko.yamanashi.jp","fujiyoshida.yamanashi.jp","hayakawa.yamanashi.jp","hokuto.yamanashi.jp","ichikawamisato.yamanashi.jp","kai.yamanashi.jp","kofu.yamanashi.jp","koshu.yamanashi.jp","kosuge.yamanashi.jp","minami-alps.yamanashi.jp","minobu.yamanashi.jp","nakamichi.yamanashi.jp","nanbu.yamanashi.jp","narusawa.yamanashi.jp","nirasaki.yamanashi.jp","nishikatsura.yamanashi.jp","oshino.yamanashi.jp","otsuki.yamanashi.jp","showa.yamanashi.jp","tabayama.yamanashi.jp","tsuru.yamanashi.jp","uenohara.yamanashi.jp","yamanakako.yamanashi.jp","yamanashi.yamanashi.jp","ke","ac.ke","co.ke","go.ke","info.ke","me.ke","mobi.ke","ne.ke","or.ke","sc.ke","kg","org.kg","net.kg","com.kg","edu.kg","gov.kg","mil.kg","*.kh","ki","edu.ki","biz.ki","net.ki","org.ki","gov.ki","info.ki","com.ki","km","org.km","nom.km","gov.km","prd.km","tm.km","edu.km","mil.km","ass.km","com.km","coop.km","asso.km","presse.km","medecin.km","notaires.km","pharmaciens.km","veterinaire.km","gouv.km","kn","net.kn","org.kn","edu.kn","gov.kn","kp","com.kp","edu.kp","gov.kp","org.kp","rep.kp","tra.kp","kr","ac.kr","co.kr","es.kr","go.kr","hs.kr","kg.kr","mil.kr","ms.kr","ne.kr","or.kr","pe.kr","re.kr","sc.kr","busan.kr","chungbuk.kr","chungnam.kr","daegu.kr","daejeon.kr","gangwon.kr","gwangju.kr","gyeongbuk.kr","gyeonggi.kr","gyeongnam.kr","incheon.kr","jeju.kr","jeonbuk.kr","jeonnam.kr","seoul.kr","ulsan.kr","kw","com.kw","edu.kw","emb.kw","gov.kw","ind.kw","net.kw","org.kw","ky","edu.ky","gov.ky","com.ky","org.ky","net.ky","kz","org.kz","edu.kz","net.kz","gov.kz","mil.kz","com.kz","la","int.la","net.la","info.la","edu.la","gov.la","per.la","com.la","org.la","lb","com.lb","edu.lb","gov.lb","net.lb","org.lb","lc","com.lc","net.lc","co.lc","org.lc","edu.lc","gov.lc","li","lk","gov.lk","sch.lk","net.lk","int.lk","com.lk","org.lk","edu.lk","ngo.lk","soc.lk","web.lk","ltd.lk","assn.lk","grp.lk","hotel.lk","ac.lk","lr","com.lr","edu.lr","gov.lr","org.lr","net.lr","ls","co.ls","org.ls","lt","gov.lt","lu","lv","com.lv","edu.lv","gov.lv","org.lv","mil.lv","id.lv","net.lv","asn.lv","conf.lv","ly","com.ly","net.ly","gov.ly","plc.ly","edu.ly","sch.ly","med.ly","org.ly","id.ly","ma","co.ma","net.ma","gov.ma","org.ma","ac.ma","press.ma","mc","tm.mc","asso.mc","md","me","co.me","net.me","org.me","edu.me","ac.me","gov.me","its.me","priv.me","mg","org.mg","nom.mg","gov.mg","prd.mg","tm.mg","edu.mg","mil.mg","com.mg","co.mg","mh","mil","mk","com.mk","org.mk","net.mk","edu.mk","gov.mk","inf.mk","name.mk","ml","com.ml","edu.ml","gouv.ml","gov.ml","net.ml","org.ml","presse.ml","*.mm","mn","gov.mn","edu.mn","org.mn","mo","com.mo","net.mo","org.mo","edu.mo","gov.mo","mobi","mp","mq","mr","gov.mr","ms","com.ms","edu.ms","gov.ms","net.ms","org.ms","mt","com.mt","edu.mt","net.mt","org.mt","mu","com.mu","net.mu","org.mu","gov.mu","ac.mu","co.mu","or.mu","museum","academy.museum","agriculture.museum","air.museum","airguard.museum","alabama.museum","alaska.museum","amber.museum","ambulance.museum","american.museum","americana.museum","americanantiques.museum","americanart.museum","amsterdam.museum","and.museum","annefrank.museum","anthro.museum","anthropology.museum","antiques.museum","aquarium.museum","arboretum.museum","archaeological.museum","archaeology.museum","architecture.museum","art.museum","artanddesign.museum","artcenter.museum","artdeco.museum","arteducation.museum","artgallery.museum","arts.museum","artsandcrafts.museum","asmatart.museum","assassination.museum","assisi.museum","association.museum","astronomy.museum","atlanta.museum","austin.museum","australia.museum","automotive.museum","aviation.museum","axis.museum","badajoz.museum","baghdad.museum","bahn.museum","bale.museum","baltimore.museum","barcelona.museum","baseball.museum","basel.museum","baths.museum","bauern.museum","beauxarts.museum","beeldengeluid.museum","bellevue.museum","bergbau.museum","berkeley.museum","berlin.museum","bern.museum","bible.museum","bilbao.museum","bill.museum","birdart.museum","birthplace.museum","bonn.museum","boston.museum","botanical.museum","botanicalgarden.museum","botanicgarden.museum","botany.museum","brandywinevalley.museum","brasil.museum","bristol.museum","british.museum","britishcolumbia.museum","broadcast.museum","brunel.museum","brussel.museum","brussels.museum","bruxelles.museum","building.museum","burghof.museum","bus.museum","bushey.museum","cadaques.museum","california.museum","cambridge.museum","can.museum","canada.museum","capebreton.museum","carrier.museum","cartoonart.museum","casadelamoneda.museum","castle.museum","castres.museum","celtic.museum","center.museum","chattanooga.museum","cheltenham.museum","chesapeakebay.museum","chicago.museum","children.museum","childrens.museum","childrensgarden.museum","chiropractic.museum","chocolate.museum","christiansburg.museum","cincinnati.museum","cinema.museum","circus.museum","civilisation.museum","civilization.museum","civilwar.museum","clinton.museum","clock.museum","coal.museum","coastaldefence.museum","cody.museum","coldwar.museum","collection.museum","colonialwilliamsburg.museum","coloradoplateau.museum","columbia.museum","columbus.museum","communication.museum","communications.museum","community.museum","computer.museum","computerhistory.museum","comunicações.museum","contemporary.museum","contemporaryart.museum","convent.museum","copenhagen.museum","corporation.museum","correios-e-telecomunicações.museum","corvette.museum","costume.museum","countryestate.museum","county.museum","crafts.museum","cranbrook.museum","creation.museum","cultural.museum","culturalcenter.museum","culture.museum","cyber.museum","cymru.museum","dali.museum","dallas.museum","database.museum","ddr.museum","decorativearts.museum","delaware.museum","delmenhorst.museum","denmark.museum","depot.museum","design.museum","detroit.museum","dinosaur.museum","discovery.museum","dolls.museum","donostia.museum","durham.museum","eastafrica.museum","eastcoast.museum","education.museum","educational.museum","egyptian.museum","eisenbahn.museum","elburg.museum","elvendrell.museum","embroidery.museum","encyclopedic.museum","england.museum","entomology.museum","environment.museum","environmentalconservation.museum","epilepsy.museum","essex.museum","estate.museum","ethnology.museum","exeter.museum","exhibition.museum","family.museum","farm.museum","farmequipment.museum","farmers.museum","farmstead.museum","field.museum","figueres.museum","filatelia.museum","film.museum","fineart.museum","finearts.museum","finland.museum","flanders.museum","florida.museum","force.museum","fortmissoula.museum","fortworth.museum","foundation.museum","francaise.museum","frankfurt.museum","franziskaner.museum","freemasonry.museum","freiburg.museum","fribourg.museum","frog.museum","fundacio.museum","furniture.museum","gallery.museum","garden.museum","gateway.museum","geelvinck.museum","gemological.museum","geology.museum","georgia.museum","giessen.museum","glas.museum","glass.museum","gorge.museum","grandrapids.museum","graz.museum","guernsey.museum","halloffame.museum","hamburg.museum","handson.museum","harvestcelebration.museum","hawaii.museum","health.museum","heimatunduhren.museum","hellas.museum","helsinki.museum","hembygdsforbund.museum","heritage.museum","histoire.museum","historical.museum","historicalsociety.museum","historichouses.museum","historisch.museum","historisches.museum","history.museum","historyofscience.museum","horology.museum","house.museum","humanities.museum","illustration.museum","imageandsound.museum","indian.museum","indiana.museum","indianapolis.museum","indianmarket.museum","intelligence.museum","interactive.museum","iraq.museum","iron.museum","isleofman.museum","jamison.museum","jefferson.museum","jerusalem.museum","jewelry.museum","jewish.museum","jewishart.museum","jfk.museum","journalism.museum","judaica.museum","judygarland.museum","juedisches.museum","juif.museum","karate.museum","karikatur.museum","kids.museum","koebenhavn.museum","koeln.museum","kunst.museum","kunstsammlung.museum","kunstunddesign.museum","labor.museum","labour.museum","lajolla.museum","lancashire.museum","landes.museum","lans.museum","läns.museum","larsson.museum","lewismiller.museum","lincoln.museum","linz.museum","living.museum","livinghistory.museum","localhistory.museum","london.museum","losangeles.museum","louvre.museum","loyalist.museum","lucerne.museum","luxembourg.museum","luzern.museum","mad.museum","madrid.museum","mallorca.museum","manchester.museum","mansion.museum","mansions.museum","manx.museum","marburg.museum","maritime.museum","maritimo.museum","maryland.museum","marylhurst.museum","media.museum","medical.museum","medizinhistorisches.museum","meeres.museum","memorial.museum","mesaverde.museum","michigan.museum","midatlantic.museum","military.museum","mill.museum","miners.museum","mining.museum","minnesota.museum","missile.museum","missoula.museum","modern.museum","moma.museum","money.museum","monmouth.museum","monticello.museum","montreal.museum","moscow.museum","motorcycle.museum","muenchen.museum","muenster.museum","mulhouse.museum","muncie.museum","museet.museum","museumcenter.museum","museumvereniging.museum","music.museum","national.museum","nationalfirearms.museum","nationalheritage.museum","nativeamerican.museum","naturalhistory.museum","naturalhistorymuseum.museum","naturalsciences.museum","nature.museum","naturhistorisches.museum","natuurwetenschappen.museum","naumburg.museum","naval.museum","nebraska.museum","neues.museum","newhampshire.museum","newjersey.museum","newmexico.museum","newport.museum","newspaper.museum","newyork.museum","niepce.museum","norfolk.museum","north.museum","nrw.museum","nuernberg.museum","nuremberg.museum","nyc.museum","nyny.museum","oceanographic.museum","oceanographique.museum","omaha.museum","online.museum","ontario.museum","openair.museum","oregon.museum","oregontrail.museum","otago.museum","oxford.museum","pacific.museum","paderborn.museum","palace.museum","paleo.museum","palmsprings.museum","panama.museum","paris.museum","pasadena.museum","pharmacy.museum","philadelphia.museum","philadelphiaarea.museum","philately.museum","phoenix.museum","photography.museum","pilots.museum","pittsburgh.museum","planetarium.museum","plantation.museum","plants.museum","plaza.museum","portal.museum","portland.museum","portlligat.museum","posts-and-telecommunications.museum","preservation.museum","presidio.museum","press.museum","project.museum","public.museum","pubol.museum","quebec.museum","railroad.museum","railway.museum","research.museum","resistance.museum","riodejaneiro.museum","rochester.museum","rockart.museum","roma.museum","russia.museum","saintlouis.museum","salem.museum","salvadordali.museum","salzburg.museum","sandiego.museum","sanfrancisco.museum","santabarbara.museum","santacruz.museum","santafe.museum","saskatchewan.museum","satx.museum","savannahga.museum","schlesisches.museum","schoenbrunn.museum","schokoladen.museum","school.museum","schweiz.museum","science.museum","scienceandhistory.museum","scienceandindustry.museum","sciencecenter.museum","sciencecenters.museum","science-fiction.museum","sciencehistory.museum","sciences.museum","sciencesnaturelles.museum","scotland.museum","seaport.museum","settlement.museum","settlers.museum","shell.museum","sherbrooke.museum","sibenik.museum","silk.museum","ski.museum","skole.museum","society.museum","sologne.museum","soundandvision.museum","southcarolina.museum","southwest.museum","space.museum","spy.museum","square.museum","stadt.museum","stalbans.museum","starnberg.museum","state.museum","stateofdelaware.museum","station.museum","steam.museum","steiermark.museum","stjohn.museum","stockholm.museum","stpetersburg.museum","stuttgart.museum","suisse.museum","surgeonshall.museum","surrey.museum","svizzera.museum","sweden.museum","sydney.museum","tank.museum","tcm.museum","technology.museum","telekommunikation.museum","television.museum","texas.museum","textile.museum","theater.museum","time.museum","timekeeping.museum","topology.museum","torino.museum","touch.museum","town.museum","transport.museum","tree.museum","trolley.museum","trust.museum","trustee.museum","uhren.museum","ulm.museum","undersea.museum","university.museum","usa.museum","usantiques.museum","usarts.museum","uscountryestate.museum","usculture.museum","usdecorativearts.museum","usgarden.museum","ushistory.museum","ushuaia.museum","uslivinghistory.museum","utah.museum","uvic.museum","valley.museum","vantaa.museum","versailles.museum","viking.museum","village.museum","virginia.museum","virtual.museum","virtuel.museum","vlaanderen.museum","volkenkunde.museum","wales.museum","wallonie.museum","war.museum","washingtondc.museum","watchandclock.museum","watch-and-clock.museum","western.museum","westfalen.museum","whaling.museum","wildlife.museum","williamsburg.museum","windmill.museum","workshop.museum","york.museum","yorkshire.museum","yosemite.museum","youth.museum","zoological.museum","zoology.museum","ירושלים.museum","иком.museum","mv","aero.mv","biz.mv","com.mv","coop.mv","edu.mv","gov.mv","info.mv","int.mv","mil.mv","museum.mv","name.mv","net.mv","org.mv","pro.mv","mw","ac.mw","biz.mw","co.mw","com.mw","coop.mw","edu.mw","gov.mw","int.mw","museum.mw","net.mw","org.mw","mx","com.mx","org.mx","gob.mx","edu.mx","net.mx","my","com.my","net.my","org.my","gov.my","edu.my","mil.my","name.my","mz","ac.mz","adv.mz","co.mz","edu.mz","gov.mz","mil.mz","net.mz","org.mz","na","info.na","pro.na","name.na","school.na","or.na","dr.na","us.na","mx.na","ca.na","in.na","cc.na","tv.na","ws.na","mobi.na","co.na","com.na","org.na","name","nc","asso.nc","nom.nc","ne","net","nf","com.nf","net.nf","per.nf","rec.nf","web.nf","arts.nf","firm.nf","info.nf","other.nf","store.nf","ng","com.ng","edu.ng","gov.ng","i.ng","mil.ng","mobi.ng","name.ng","net.ng","org.ng","sch.ng","ni","ac.ni","biz.ni","co.ni","com.ni","edu.ni","gob.ni","in.ni","info.ni","int.ni","mil.ni","net.ni","nom.ni","org.ni","web.ni","nl","bv.nl","no","fhs.no","vgs.no","fylkesbibl.no","folkebibl.no","museum.no","idrett.no","priv.no","mil.no","stat.no","dep.no","kommune.no","herad.no","aa.no","ah.no","bu.no","fm.no","hl.no","hm.no","jan-mayen.no","mr.no","nl.no","nt.no","of.no","ol.no","oslo.no","rl.no","sf.no","st.no","svalbard.no","tm.no","tr.no","va.no","vf.no","gs.aa.no","gs.ah.no","gs.bu.no","gs.fm.no","gs.hl.no","gs.hm.no","gs.jan-mayen.no","gs.mr.no","gs.nl.no","gs.nt.no","gs.of.no","gs.ol.no","gs.oslo.no","gs.rl.no","gs.sf.no","gs.st.no","gs.svalbard.no","gs.tm.no","gs.tr.no","gs.va.no","gs.vf.no","akrehamn.no","åkrehamn.no","algard.no","ålgård.no","arna.no","brumunddal.no","bryne.no","bronnoysund.no","brønnøysund.no","drobak.no","drøbak.no","egersund.no","fetsund.no","floro.no","florø.no","fredrikstad.no","hokksund.no","honefoss.no","hønefoss.no","jessheim.no","jorpeland.no","jørpeland.no","kirkenes.no","kopervik.no","krokstadelva.no","langevag.no","langevåg.no","leirvik.no","mjondalen.no","mjøndalen.no","mo-i-rana.no","mosjoen.no","mosjøen.no","nesoddtangen.no","orkanger.no","osoyro.no","osøyro.no","raholt.no","råholt.no","sandnessjoen.no","sandnessjøen.no","skedsmokorset.no","slattum.no","spjelkavik.no","stathelle.no","stavern.no","stjordalshalsen.no","stjørdalshalsen.no","tananger.no","tranby.no","vossevangen.no","afjord.no","åfjord.no","agdenes.no","al.no","ål.no","alesund.no","ålesund.no","alstahaug.no","alta.no","áltá.no","alaheadju.no","álaheadju.no","alvdal.no","amli.no","åmli.no","amot.no","åmot.no","andebu.no","andoy.no","andøy.no","andasuolo.no","ardal.no","årdal.no","aremark.no","arendal.no","ås.no","aseral.no","åseral.no","asker.no","askim.no","askvoll.no","askoy.no","askøy.no","asnes.no","åsnes.no","audnedaln.no","aukra.no","aure.no","aurland.no","aurskog-holand.no","aurskog-høland.no","austevoll.no","austrheim.no","averoy.no","averøy.no","balestrand.no","ballangen.no","balat.no","bálát.no","balsfjord.no","bahccavuotna.no","báhccavuotna.no","bamble.no","bardu.no","beardu.no","beiarn.no","bajddar.no","bájddar.no","baidar.no","báidár.no","berg.no","bergen.no","berlevag.no","berlevåg.no","bearalvahki.no","bearalváhki.no","bindal.no","birkenes.no","bjarkoy.no","bjarkøy.no","bjerkreim.no","bjugn.no","bodo.no","bodø.no","badaddja.no","bådåddjå.no","budejju.no","bokn.no","bremanger.no","bronnoy.no","brønnøy.no","bygland.no","bykle.no","barum.no","bærum.no","bo.telemark.no","bø.telemark.no","bo.nordland.no","bø.nordland.no","bievat.no","bievát.no","bomlo.no","bømlo.no","batsfjord.no","båtsfjord.no","bahcavuotna.no","báhcavuotna.no","dovre.no","drammen.no","drangedal.no","dyroy.no","dyrøy.no","donna.no","dønna.no","eid.no","eidfjord.no","eidsberg.no","eidskog.no","eidsvoll.no","eigersund.no","elverum.no","enebakk.no","engerdal.no","etne.no","etnedal.no","evenes.no","evenassi.no","evenášši.no","evje-og-hornnes.no","farsund.no","fauske.no","fuossko.no","fuoisku.no","fedje.no","fet.no","finnoy.no","finnøy.no","fitjar.no","fjaler.no","fjell.no","flakstad.no","flatanger.no","flekkefjord.no","flesberg.no","flora.no","fla.no","flå.no","folldal.no","forsand.no","fosnes.no","frei.no","frogn.no","froland.no","frosta.no","frana.no","fræna.no","froya.no","frøya.no","fusa.no","fyresdal.no","forde.no","førde.no","gamvik.no","gangaviika.no","gáŋgaviika.no","gaular.no","gausdal.no","gildeskal.no","gildeskål.no","giske.no","gjemnes.no","gjerdrum.no","gjerstad.no","gjesdal.no","gjovik.no","gjøvik.no","gloppen.no","gol.no","gran.no","grane.no","granvin.no","gratangen.no","grimstad.no","grong.no","kraanghke.no","kråanghke.no","grue.no","gulen.no","hadsel.no","halden.no","halsa.no","hamar.no","hamaroy.no","habmer.no","hábmer.no","hapmir.no","hápmir.no","hammerfest.no","hammarfeasta.no","hámmárfeasta.no","haram.no","hareid.no","harstad.no","hasvik.no","aknoluokta.no","ákŋoluokta.no","hattfjelldal.no","aarborte.no","haugesund.no","hemne.no","hemnes.no","hemsedal.no","heroy.more-og-romsdal.no","herøy.møre-og-romsdal.no","heroy.nordland.no","herøy.nordland.no","hitra.no","hjartdal.no","hjelmeland.no","hobol.no","hobøl.no","hof.no","hol.no","hole.no","holmestrand.no","holtalen.no","holtålen.no","hornindal.no","horten.no","hurdal.no","hurum.no","hvaler.no","hyllestad.no","hagebostad.no","hægebostad.no","hoyanger.no","høyanger.no","hoylandet.no","høylandet.no","ha.no","hå.no","ibestad.no","inderoy.no","inderøy.no","iveland.no","jevnaker.no","jondal.no","jolster.no","jølster.no","karasjok.no","karasjohka.no","kárášjohka.no","karlsoy.no","galsa.no","gálsá.no","karmoy.no","karmøy.no","kautokeino.no","guovdageaidnu.no","klepp.no","klabu.no","klæbu.no","kongsberg.no","kongsvinger.no","kragero.no","kragerø.no","kristiansand.no","kristiansund.no","krodsherad.no","krødsherad.no","kvalsund.no","rahkkeravju.no","ráhkkerávju.no","kvam.no","kvinesdal.no","kvinnherad.no","kviteseid.no","kvitsoy.no","kvitsøy.no","kvafjord.no","kvæfjord.no","giehtavuoatna.no","kvanangen.no","kvænangen.no","navuotna.no","návuotna.no","kafjord.no","kåfjord.no","gaivuotna.no","gáivuotna.no","larvik.no","lavangen.no","lavagis.no","loabat.no","loabát.no","lebesby.no","davvesiida.no","leikanger.no","leirfjord.no","leka.no","leksvik.no","lenvik.no","leangaviika.no","leaŋgaviika.no","lesja.no","levanger.no","lier.no","lierne.no","lillehammer.no","lillesand.no","lindesnes.no","lindas.no","lindås.no","lom.no","loppa.no","lahppi.no","láhppi.no","lund.no","lunner.no","luroy.no","lurøy.no","luster.no","lyngdal.no","lyngen.no","ivgu.no","lardal.no","lerdal.no","lærdal.no","lodingen.no","lødingen.no","lorenskog.no","lørenskog.no","loten.no","løten.no","malvik.no","masoy.no","måsøy.no","muosat.no","muosát.no","mandal.no","marker.no","marnardal.no","masfjorden.no","meland.no","meldal.no","melhus.no","meloy.no","meløy.no","meraker.no","meråker.no","moareke.no","moåreke.no","midsund.no","midtre-gauldal.no","modalen.no","modum.no","molde.no","moskenes.no","moss.no","mosvik.no","malselv.no","målselv.no","malatvuopmi.no","málatvuopmi.no","namdalseid.no","aejrie.no","namsos.no","namsskogan.no","naamesjevuemie.no","nååmesjevuemie.no","laakesvuemie.no","nannestad.no","narvik.no","narviika.no","naustdal.no","nedre-eiker.no","nes.akershus.no","nes.buskerud.no","nesna.no","nesodden.no","nesseby.no","unjarga.no","unjárga.no","nesset.no","nissedal.no","nittedal.no","nord-aurdal.no","nord-fron.no","nord-odal.no","norddal.no","nordkapp.no","davvenjarga.no","davvenjárga.no","nordre-land.no","nordreisa.no","raisa.no","ráisa.no","nore-og-uvdal.no","notodden.no","naroy.no","nærøy.no","notteroy.no","nøtterøy.no","odda.no","oksnes.no","øksnes.no","oppdal.no","oppegard.no","oppegård.no","orkdal.no","orland.no","ørland.no","orskog.no","ørskog.no","orsta.no","ørsta.no","os.hedmark.no","os.hordaland.no","osen.no","osteroy.no","osterøy.no","ostre-toten.no","østre-toten.no","overhalla.no","ovre-eiker.no","øvre-eiker.no","oyer.no","øyer.no","oygarden.no","øygarden.no","oystre-slidre.no","øystre-slidre.no","porsanger.no","porsangu.no","porsáŋgu.no","porsgrunn.no","radoy.no","radøy.no","rakkestad.no","rana.no","ruovat.no","randaberg.no","rauma.no","rendalen.no","rennebu.no","rennesoy.no","rennesøy.no","rindal.no","ringebu.no","ringerike.no","ringsaker.no","rissa.no","risor.no","risør.no","roan.no","rollag.no","rygge.no","ralingen.no","rælingen.no","rodoy.no","rødøy.no","romskog.no","rømskog.no","roros.no","røros.no","rost.no","røst.no","royken.no","røyken.no","royrvik.no","røyrvik.no","rade.no","råde.no","salangen.no","siellak.no","saltdal.no","salat.no","sálát.no","sálat.no","samnanger.no","sande.more-og-romsdal.no","sande.møre-og-romsdal.no","sande.vestfold.no","sandefjord.no","sandnes.no","sandoy.no","sandøy.no","sarpsborg.no","sauda.no","sauherad.no","sel.no","selbu.no","selje.no","seljord.no","sigdal.no","siljan.no","sirdal.no","skaun.no","skedsmo.no","ski.no","skien.no","skiptvet.no","skjervoy.no","skjervøy.no","skierva.no","skiervá.no","skjak.no","skjåk.no","skodje.no","skanland.no","skånland.no","skanit.no","skánit.no","smola.no","smøla.no","snillfjord.no","snasa.no","snåsa.no","snoasa.no","snaase.no","snåase.no","sogndal.no","sokndal.no","sola.no","solund.no","songdalen.no","sortland.no","spydeberg.no","stange.no","stavanger.no","steigen.no","steinkjer.no","stjordal.no","stjørdal.no","stokke.no","stor-elvdal.no","stord.no","stordal.no","storfjord.no","omasvuotna.no","strand.no","stranda.no","stryn.no","sula.no","suldal.no","sund.no","sunndal.no","surnadal.no","sveio.no","svelvik.no","sykkylven.no","sogne.no","søgne.no","somna.no","sømna.no","sondre-land.no","søndre-land.no","sor-aurdal.no","sør-aurdal.no","sor-fron.no","sør-fron.no","sor-odal.no","sør-odal.no","sor-varanger.no","sør-varanger.no","matta-varjjat.no","mátta-várjjat.no","sorfold.no","sørfold.no","sorreisa.no","sørreisa.no","sorum.no","sørum.no","tana.no","deatnu.no","time.no","tingvoll.no","tinn.no","tjeldsund.no","dielddanuorri.no","tjome.no","tjøme.no","tokke.no","tolga.no","torsken.no","tranoy.no","tranøy.no","tromso.no","tromsø.no","tromsa.no","romsa.no","trondheim.no","troandin.no","trysil.no","trana.no","træna.no","trogstad.no","trøgstad.no","tvedestrand.no","tydal.no","tynset.no","tysfjord.no","divtasvuodna.no","divttasvuotna.no","tysnes.no","tysvar.no","tysvær.no","tonsberg.no","tønsberg.no","ullensaker.no","ullensvang.no","ulvik.no","utsira.no","vadso.no","vadsø.no","cahcesuolo.no","čáhcesuolo.no","vaksdal.no","valle.no","vang.no","vanylven.no","vardo.no","vardø.no","varggat.no","várggát.no","vefsn.no","vaapste.no","vega.no","vegarshei.no","vegårshei.no","vennesla.no","verdal.no","verran.no","vestby.no","vestnes.no","vestre-slidre.no","vestre-toten.no","vestvagoy.no","vestvågøy.no","vevelstad.no","vik.no","vikna.no","vindafjord.no","volda.no","voss.no","varoy.no","værøy.no","vagan.no","vågan.no","voagat.no","vagsoy.no","vågsøy.no","vaga.no","vågå.no","valer.ostfold.no","våler.østfold.no","valer.hedmark.no","våler.hedmark.no","*.np","nr","biz.nr","info.nr","gov.nr","edu.nr","org.nr","net.nr","com.nr","nu","nz","ac.nz","co.nz","cri.nz","geek.nz","gen.nz","govt.nz","health.nz","iwi.nz","kiwi.nz","maori.nz","mil.nz","māori.nz","net.nz","org.nz","parliament.nz","school.nz","om","co.om","com.om","edu.om","gov.om","med.om","museum.om","net.om","org.om","pro.om","onion","org","pa","ac.pa","gob.pa","com.pa","org.pa","sld.pa","edu.pa","net.pa","ing.pa","abo.pa","med.pa","nom.pa","pe","edu.pe","gob.pe","nom.pe","mil.pe","org.pe","com.pe","net.pe","pf","com.pf","org.pf","edu.pf","*.pg","ph","com.ph","net.ph","org.ph","gov.ph","edu.ph","ngo.ph","mil.ph","i.ph","pk","com.pk","net.pk","edu.pk","org.pk","fam.pk","biz.pk","web.pk","gov.pk","gob.pk","gok.pk","gon.pk","gop.pk","gos.pk","info.pk","pl","com.pl","net.pl","org.pl","aid.pl","agro.pl","atm.pl","auto.pl","biz.pl","edu.pl","gmina.pl","gsm.pl","info.pl","mail.pl","miasta.pl","media.pl","mil.pl","nieruchomosci.pl","nom.pl","pc.pl","powiat.pl","priv.pl","realestate.pl","rel.pl","sex.pl","shop.pl","sklep.pl","sos.pl","szkola.pl","targi.pl","tm.pl","tourism.pl","travel.pl","turystyka.pl","gov.pl","ap.gov.pl","ic.gov.pl","is.gov.pl","us.gov.pl","kmpsp.gov.pl","kppsp.gov.pl","kwpsp.gov.pl","psp.gov.pl","wskr.gov.pl","kwp.gov.pl","mw.gov.pl","ug.gov.pl","um.gov.pl","umig.gov.pl","ugim.gov.pl","upow.gov.pl","uw.gov.pl","starostwo.gov.pl","pa.gov.pl","po.gov.pl","psse.gov.pl","pup.gov.pl","rzgw.gov.pl","sa.gov.pl","so.gov.pl","sr.gov.pl","wsa.gov.pl","sko.gov.pl","uzs.gov.pl","wiih.gov.pl","winb.gov.pl","pinb.gov.pl","wios.gov.pl","witd.gov.pl","wzmiuw.gov.pl","piw.gov.pl","wiw.gov.pl","griw.gov.pl","wif.gov.pl","oum.gov.pl","sdn.gov.pl","zp.gov.pl","uppo.gov.pl","mup.gov.pl","wuoz.gov.pl","konsulat.gov.pl","oirm.gov.pl","augustow.pl","babia-gora.pl","bedzin.pl","beskidy.pl","bialowieza.pl","bialystok.pl","bielawa.pl","bieszczady.pl","boleslawiec.pl","bydgoszcz.pl","bytom.pl","cieszyn.pl","czeladz.pl","czest.pl","dlugoleka.pl","elblag.pl","elk.pl","glogow.pl","gniezno.pl","gorlice.pl","grajewo.pl","ilawa.pl","jaworzno.pl","jelenia-gora.pl","jgora.pl","kalisz.pl","kazimierz-dolny.pl","karpacz.pl","kartuzy.pl","kaszuby.pl","katowice.pl","kepno.pl","ketrzyn.pl","klodzko.pl","kobierzyce.pl","kolobrzeg.pl","konin.pl","konskowola.pl","kutno.pl","lapy.pl","lebork.pl","legnica.pl","lezajsk.pl","limanowa.pl","lomza.pl","lowicz.pl","lubin.pl","lukow.pl","malbork.pl","malopolska.pl","mazowsze.pl","mazury.pl","mielec.pl","mielno.pl","mragowo.pl","naklo.pl","nowaruda.pl","nysa.pl","olawa.pl","olecko.pl","olkusz.pl","olsztyn.pl","opoczno.pl","opole.pl","ostroda.pl","ostroleka.pl","ostrowiec.pl","ostrowwlkp.pl","pila.pl","pisz.pl","podhale.pl","podlasie.pl","polkowice.pl","pomorze.pl","pomorskie.pl","prochowice.pl","pruszkow.pl","przeworsk.pl","pulawy.pl","radom.pl","rawa-maz.pl","rybnik.pl","rzeszow.pl","sanok.pl","sejny.pl","slask.pl","slupsk.pl","sosnowiec.pl","stalowa-wola.pl","skoczow.pl","starachowice.pl","stargard.pl","suwalki.pl","swidnica.pl","swiebodzin.pl","swinoujscie.pl","szczecin.pl","szczytno.pl","tarnobrzeg.pl","tgory.pl","turek.pl","tychy.pl","ustka.pl","walbrzych.pl","warmia.pl","warszawa.pl","waw.pl","wegrow.pl","wielun.pl","wlocl.pl","wloclawek.pl","wodzislaw.pl","wolomin.pl","wroclaw.pl","zachpomor.pl","zagan.pl","zarow.pl","zgora.pl","zgorzelec.pl","pm","pn","gov.pn","co.pn","org.pn","edu.pn","net.pn","post","pr","com.pr","net.pr","org.pr","gov.pr","edu.pr","isla.pr","pro.pr","biz.pr","info.pr","name.pr","est.pr","prof.pr","ac.pr","pro","aaa.pro","aca.pro","acct.pro","avocat.pro","bar.pro","cpa.pro","eng.pro","jur.pro","law.pro","med.pro","recht.pro","ps","edu.ps","gov.ps","sec.ps","plo.ps","com.ps","org.ps","net.ps","pt","net.pt","gov.pt","org.pt","edu.pt","int.pt","publ.pt","com.pt","nome.pt","pw","co.pw","ne.pw","or.pw","ed.pw","go.pw","belau.pw","py","com.py","coop.py","edu.py","gov.py","mil.py","net.py","org.py","qa","com.qa","edu.qa","gov.qa","mil.qa","name.qa","net.qa","org.qa","sch.qa","re","asso.re","com.re","nom.re","ro","arts.ro","com.ro","firm.ro","info.ro","nom.ro","nt.ro","org.ro","rec.ro","store.ro","tm.ro","www.ro","rs","ac.rs","co.rs","edu.rs","gov.rs","in.rs","org.rs","ru","ac.ru","edu.ru","gov.ru","int.ru","mil.ru","test.ru","rw","gov.rw","net.rw","edu.rw","ac.rw","com.rw","co.rw","int.rw","mil.rw","gouv.rw","sa","com.sa","net.sa","org.sa","gov.sa","med.sa","pub.sa","edu.sa","sch.sa","sb","com.sb","edu.sb","gov.sb","net.sb","org.sb","sc","com.sc","gov.sc","net.sc","org.sc","edu.sc","sd","com.sd","net.sd","org.sd","edu.sd","med.sd","tv.sd","gov.sd","info.sd","se","a.se","ac.se","b.se","bd.se","brand.se","c.se","d.se","e.se","f.se","fh.se","fhsk.se","fhv.se","g.se","h.se","i.se","k.se","komforb.se","kommunalforbund.se","komvux.se","l.se","lanbib.se","m.se","n.se","naturbruksgymn.se","o.se","org.se","p.se","parti.se","pp.se","press.se","r.se","s.se","t.se","tm.se","u.se","w.se","x.se","y.se","z.se","sg","com.sg","net.sg","org.sg","gov.sg","edu.sg","per.sg","sh","com.sh","net.sh","gov.sh","org.sh","mil.sh","si","sj","sk","sl","com.sl","net.sl","edu.sl","gov.sl","org.sl","sm","sn","art.sn","com.sn","edu.sn","gouv.sn","org.sn","perso.sn","univ.sn","so","com.so","net.so","org.so","sr","st","co.st","com.st","consulado.st","edu.st","embaixada.st","gov.st","mil.st","net.st","org.st","principe.st","saotome.st","store.st","su","sv","com.sv","edu.sv","gob.sv","org.sv","red.sv","sx","gov.sx","sy","edu.sy","gov.sy","net.sy","mil.sy","com.sy","org.sy","sz","co.sz","ac.sz","org.sz","tc","td","tel","tf","tg","th","ac.th","co.th","go.th","in.th","mi.th","net.th","or.th","tj","ac.tj","biz.tj","co.tj","com.tj","edu.tj","go.tj","gov.tj","int.tj","mil.tj","name.tj","net.tj","nic.tj","org.tj","test.tj","web.tj","tk","tl","gov.tl","tm","com.tm","co.tm","org.tm","net.tm","nom.tm","gov.tm","mil.tm","edu.tm","tn","com.tn","ens.tn","fin.tn","gov.tn","ind.tn","intl.tn","nat.tn","net.tn","org.tn","info.tn","perso.tn","tourism.tn","edunet.tn","rnrt.tn","rns.tn","rnu.tn","mincom.tn","agrinet.tn","defense.tn","turen.tn","to","com.to","gov.to","net.to","org.to","edu.to","mil.to","tr","com.tr","info.tr","biz.tr","net.tr","org.tr","web.tr","gen.tr","tv.tr","av.tr","dr.tr","bbs.tr","name.tr","tel.tr","gov.tr","bel.tr","pol.tr","mil.tr","k12.tr","edu.tr","kep.tr","nc.tr","gov.nc.tr","tt","co.tt","com.tt","org.tt","net.tt","biz.tt","info.tt","pro.tt","int.tt","coop.tt","jobs.tt","mobi.tt","travel.tt","museum.tt","aero.tt","name.tt","gov.tt","edu.tt","tv","tw","edu.tw","gov.tw","mil.tw","com.tw","net.tw","org.tw","idv.tw","game.tw","ebiz.tw","club.tw","網路.tw","組織.tw","商業.tw","tz","ac.tz","co.tz","go.tz","hotel.tz","info.tz","me.tz","mil.tz","mobi.tz","ne.tz","or.tz","sc.tz","tv.tz","ua","com.ua","edu.ua","gov.ua","in.ua","net.ua","org.ua","cherkassy.ua","cherkasy.ua","chernigov.ua","chernihiv.ua","chernivtsi.ua","chernovtsy.ua","ck.ua","cn.ua","cr.ua","crimea.ua","cv.ua","dn.ua","dnepropetrovsk.ua","dnipropetrovsk.ua","dominic.ua","donetsk.ua","dp.ua","if.ua","ivano-frankivsk.ua","kh.ua","kharkiv.ua","kharkov.ua","kherson.ua","khmelnitskiy.ua","khmelnytskyi.ua","kiev.ua","kirovograd.ua","km.ua","kr.ua","krym.ua","ks.ua","kv.ua","kyiv.ua","lg.ua","lt.ua","lugansk.ua","lutsk.ua","lv.ua","lviv.ua","mk.ua","mykolaiv.ua","nikolaev.ua","od.ua","odesa.ua","odessa.ua","pl.ua","poltava.ua","rivne.ua","rovno.ua","rv.ua","sb.ua","sebastopol.ua","sevastopol.ua","sm.ua","sumy.ua","te.ua","ternopil.ua","uz.ua","uzhgorod.ua","vinnica.ua","vinnytsia.ua","vn.ua","volyn.ua","yalta.ua","zaporizhzhe.ua","zaporizhzhia.ua","zhitomir.ua","zhytomyr.ua","zp.ua","zt.ua","ug","co.ug","or.ug","ac.ug","sc.ug","go.ug","ne.ug","com.ug","org.ug","uk","ac.uk","co.uk","gov.uk","ltd.uk","me.uk","net.uk","nhs.uk","org.uk","plc.uk","police.uk","*.sch.uk","us","dni.us","fed.us","isa.us","kids.us","nsn.us","ak.us","al.us","ar.us","as.us","az.us","ca.us","co.us","ct.us","dc.us","de.us","fl.us","ga.us","gu.us","hi.us","ia.us","id.us","il.us","in.us","ks.us","ky.us","la.us","ma.us","md.us","me.us","mi.us","mn.us","mo.us","ms.us","mt.us","nc.us","nd.us","ne.us","nh.us","nj.us","nm.us","nv.us","ny.us","oh.us","ok.us","or.us","pa.us","pr.us","ri.us","sc.us","sd.us","tn.us","tx.us","ut.us","vi.us","vt.us","va.us","wa.us","wi.us","wv.us","wy.us","k12.ak.us","k12.al.us","k12.ar.us","k12.as.us","k12.az.us","k12.ca.us","k12.co.us","k12.ct.us","k12.dc.us","k12.de.us","k12.fl.us","k12.ga.us","k12.gu.us","k12.ia.us","k12.id.us","k12.il.us","k12.in.us","k12.ks.us","k12.ky.us","k12.la.us","k12.ma.us","k12.md.us","k12.me.us","k12.mi.us","k12.mn.us","k12.mo.us","k12.ms.us","k12.mt.us","k12.nc.us","k12.ne.us","k12.nh.us","k12.nj.us","k12.nm.us","k12.nv.us","k12.ny.us","k12.oh.us","k12.ok.us","k12.or.us","k12.pa.us","k12.pr.us","k12.ri.us","k12.sc.us","k12.tn.us","k12.tx.us","k12.ut.us","k12.vi.us","k12.vt.us","k12.va.us","k12.wa.us","k12.wi.us","k12.wy.us","cc.ak.us","cc.al.us","cc.ar.us","cc.as.us","cc.az.us","cc.ca.us","cc.co.us","cc.ct.us","cc.dc.us","cc.de.us","cc.fl.us","cc.ga.us","cc.gu.us","cc.hi.us","cc.ia.us","cc.id.us","cc.il.us","cc.in.us","cc.ks.us","cc.ky.us","cc.la.us","cc.ma.us","cc.md.us","cc.me.us","cc.mi.us","cc.mn.us","cc.mo.us","cc.ms.us","cc.mt.us","cc.nc.us","cc.nd.us","cc.ne.us","cc.nh.us","cc.nj.us","cc.nm.us","cc.nv.us","cc.ny.us","cc.oh.us","cc.ok.us","cc.or.us","cc.pa.us","cc.pr.us","cc.ri.us","cc.sc.us","cc.sd.us","cc.tn.us","cc.tx.us","cc.ut.us","cc.vi.us","cc.vt.us","cc.va.us","cc.wa.us","cc.wi.us","cc.wv.us","cc.wy.us","lib.ak.us","lib.al.us","lib.ar.us","lib.as.us","lib.az.us","lib.ca.us","lib.co.us","lib.ct.us","lib.dc.us","lib.fl.us","lib.ga.us","lib.gu.us","lib.hi.us","lib.ia.us","lib.id.us","lib.il.us","lib.in.us","lib.ks.us","lib.ky.us","lib.la.us","lib.ma.us","lib.md.us","lib.me.us","lib.mi.us","lib.mn.us","lib.mo.us","lib.ms.us","lib.mt.us","lib.nc.us","lib.nd.us","lib.ne.us","lib.nh.us","lib.nj.us","lib.nm.us","lib.nv.us","lib.ny.us","lib.oh.us","lib.ok.us","lib.or.us","lib.pa.us","lib.pr.us","lib.ri.us","lib.sc.us","lib.sd.us","lib.tn.us","lib.tx.us","lib.ut.us","lib.vi.us","lib.vt.us","lib.va.us","lib.wa.us","lib.wi.us","lib.wy.us","pvt.k12.ma.us","chtr.k12.ma.us","paroch.k12.ma.us","ann-arbor.mi.us","cog.mi.us","dst.mi.us","eaton.mi.us","gen.mi.us","mus.mi.us","tec.mi.us","washtenaw.mi.us","uy","com.uy","edu.uy","gub.uy","mil.uy","net.uy","org.uy","uz","co.uz","com.uz","net.uz","org.uz","va","vc","com.vc","net.vc","org.vc","gov.vc","mil.vc","edu.vc","ve","arts.ve","co.ve","com.ve","e12.ve","edu.ve","firm.ve","gob.ve","gov.ve","info.ve","int.ve","mil.ve","net.ve","org.ve","rec.ve","store.ve","tec.ve","web.ve","vg","vi","co.vi","com.vi","k12.vi","net.vi","org.vi","vn","com.vn","net.vn","org.vn","edu.vn","gov.vn","int.vn","ac.vn","biz.vn","info.vn","name.vn","pro.vn","health.vn","vu","com.vu","edu.vu","net.vu","org.vu","wf","ws","com.ws","net.ws","org.ws","gov.ws","edu.ws","yt","امارات","հայ","বাংলা","бг","бел","中国","中國","الجزائر","مصر","ею","გე","ελ","香港","公司.香港","教育.香港","政府.香港","個人.香港","網絡.香港","組織.香港","ಭಾರತ","ଭାରତ","ভাৰত","भारतम्","भारोत","ڀارت","ഭാരതം","भारत","بارت","بھارت","భారత్","ભારત","ਭਾਰਤ","ভারত","இந்தியா","ایران","ايران","عراق","الاردن","한국","қаз","ලංකා","இலங்கை","المغرب","мкд","мон","澳門","澳门","مليسيا","عمان","پاکستان","پاكستان","فلسطين","срб","пр.срб","орг.срб","обр.срб","од.срб","упр.срб","ак.срб","рф","قطر","السعودية","السعودیة","السعودیۃ","السعوديه","سودان","新加坡","சிங்கப்பூர்","سورية","سوريا","ไทย","ศึกษา.ไทย","ธุรกิจ.ไทย","รัฐบาล.ไทย","ทหาร.ไทย","เน็ต.ไทย","องค์กร.ไทย","تونس","台灣","台湾","臺灣","укр","اليمن","xxx","*.ye","ac.za","agric.za","alt.za","co.za","edu.za","gov.za","grondar.za","law.za","mil.za","net.za","ngo.za","nis.za","nom.za","org.za","school.za","tm.za","web.za","zm","ac.zm","biz.zm","co.zm","com.zm","edu.zm","gov.zm","info.zm","mil.zm","net.zm","org.zm","sch.zm","zw","ac.zw","co.zw","gov.zw","mil.zw","org.zw","aaa","aarp","abarth","abb","abbott","abbvie","abc","able","abogado","abudhabi","academy","accenture","accountant","accountants","aco","active","actor","adac","ads","adult","aeg","aetna","afamilycompany","afl","africa","agakhan","agency","aig","aigo","airbus","airforce","airtel","akdn","alfaromeo","alibaba","alipay","allfinanz","allstate","ally","alsace","alstom","americanexpress","americanfamily","amex","amfam","amica","amsterdam","analytics","android","anquan","anz","aol","apartments","app","apple","aquarelle","arab","aramco","archi","army","art","arte","asda","associates","athleta","attorney","auction","audi","audible","audio","auspost","author","auto","autos","avianca","aws","axa","azure","baby","baidu","banamex","bananarepublic","band","bank","bar","barcelona","barclaycard","barclays","barefoot","bargains","baseball","basketball","bauhaus","bayern","bbc","bbt","bbva","bcg","bcn","beats","beauty","beer","bentley","berlin","best","bestbuy","bet","bharti","bible","bid","bike","bing","bingo","bio","black","blackfriday","blanco","blockbuster","blog","bloomberg","blue","bms","bmw","bnl","bnpparibas","boats","boehringer","bofa","bom","bond","boo","book","booking","bosch","bostik","boston","bot","boutique","box","bradesco","bridgestone","broadway","broker","brother","brussels","budapest","bugatti","build","builders","business","buy","buzz","bzh","cab","cafe","cal","call","calvinklein","cam","camera","camp","cancerresearch","canon","capetown","capital","capitalone","car","caravan","cards","care","career","careers","cars","cartier","casa","case","caseih","cash","casino","catering","catholic","cba","cbn","cbre","cbs","ceb","center","ceo","cern","cfa","cfd","chanel","channel","charity","chase","chat","cheap","chintai","christmas","chrome","chrysler","church","cipriani","circle","cisco","citadel","citi","citic","city","cityeats","claims","cleaning","click","clinic","clinique","clothing","cloud","club","clubmed","coach","codes","coffee","college","cologne","comcast","commbank","community","company","compare","computer","comsec","condos","construction","consulting","contact","contractors","cooking","cookingchannel","cool","corsica","country","coupon","coupons","courses","credit","creditcard","creditunion","cricket","crown","crs","cruise","cruises","csc","cuisinella","cymru","cyou","dabur","dad","dance","data","date","dating","datsun","day","dclk","dds","deal","dealer","deals","degree","delivery","dell","deloitte","delta","democrat","dental","dentist","desi","design","dev","dhl","diamonds","diet","digital","direct","directory","discount","discover","dish","diy","dnp","docs","doctor","dodge","dog","doha","domains","dot","download","drive","dtv","dubai","duck","dunlop","duns","dupont","durban","dvag","dvr","earth","eat","eco","edeka","education","email","emerck","energy","engineer","engineering","enterprises","epost","epson","equipment","ericsson","erni","esq","estate","esurance","etisalat","eurovision","eus","events","everbank","exchange","expert","exposed","express","extraspace","fage","fail","fairwinds","faith","family","fan","fans","farm","farmers","fashion","fast","fedex","feedback","ferrari","ferrero","fiat","fidelity","fido","film","final","finance","financial","fire","firestone","firmdale","fish","fishing","fit","fitness","flickr","flights","flir","florist","flowers","fly","foo","food","foodnetwork","football","ford","forex","forsale","forum","foundation","fox","free","fresenius","frl","frogans","frontdoor","frontier","ftr","fujitsu","fujixerox","fun","fund","furniture","futbol","fyi","gal","gallery","gallo","gallup","game","games","gap","garden","gbiz","gdn","gea","gent","genting","george","ggee","gift","gifts","gives","giving","glade","glass","gle","global","globo","gmail","gmbh","gmo","gmx","godaddy","gold","goldpoint","golf","goo","goodhands","goodyear","goog","google","gop","got","grainger","graphics","gratis","green","gripe","grocery","group","guardian","gucci","guge","guide","guitars","guru","hair","hamburg","hangout","haus","hbo","hdfc","hdfcbank","health","healthcare","help","helsinki","here","hermes","hgtv","hiphop","hisamitsu","hitachi","hiv","hkt","hockey","holdings","holiday","homedepot","homegoods","homes","homesense","honda","honeywell","horse","hospital","host","hosting","hot","hoteles","hotels","hotmail","house","how","hsbc","hughes","hyatt","hyundai","ibm","icbc","ice","icu","ieee","ifm","ikano","imamat","imdb","immo","immobilien","inc","industries","infiniti","ing","ink","institute","insurance","insure","intel","international","intuit","investments","ipiranga","irish","iselect","ismaili","ist","istanbul","itau","itv","iveco","jaguar","java","jcb","jcp","jeep","jetzt","jewelry","jio","jlc","jll","jmp","jnj","joburg","jot","joy","jpmorgan","jprs","juegos","juniper","kaufen","kddi","kerryhotels","kerrylogistics","kerryproperties","kfh","kia","kim","kinder","kindle","kitchen","kiwi","koeln","komatsu","kosher","kpmg","kpn","krd","kred","kuokgroup","kyoto","lacaixa","ladbrokes","lamborghini","lamer","lancaster","lancia","lancome","land","landrover","lanxess","lasalle","lat","latino","latrobe","law","lawyer","lds","lease","leclerc","lefrak","legal","lego","lexus","lgbt","liaison","lidl","life","lifeinsurance","lifestyle","lighting","like","lilly","limited","limo","lincoln","linde","link","lipsy","live","living","lixil","llc","loan","loans","locker","locus","loft","lol","london","lotte","lotto","love","lpl","lplfinancial","ltd","ltda","lundbeck","lupin","luxe","luxury","macys","madrid","maif","maison","makeup","man","management","mango","map","market","marketing","markets","marriott","marshalls","maserati","mattel","mba","mckinsey","med","media","meet","melbourne","meme","memorial","men","menu","merckmsd","metlife","miami","microsoft","mini","mint","mit","mitsubishi","mlb","mls","mma","mobile","mobily","moda","moe","moi","mom","monash","money","monster","mopar","mormon","mortgage","moscow","moto","motorcycles","mov","movie","movistar","msd","mtn","mtr","mutual","nab","nadex","nagoya","nationwide","natura","navy","nba","nec","netbank","netflix","network","neustar","new","newholland","news","next","nextdirect","nexus","nfl","ngo","nhk","nico","nike","nikon","ninja","nissan","nissay","nokia","northwesternmutual","norton","now","nowruz","nowtv","nra","nrw","ntt","nyc","obi","observer","off","office","okinawa","olayan","olayangroup","oldnavy","ollo","omega","one","ong","onl","online","onyourside","ooo","open","oracle","orange","organic","origins","osaka","otsuka","ott","ovh","page","panasonic","panerai","paris","pars","partners","parts","party","passagens","pay","pccw","pet","pfizer","pharmacy","phd","philips","phone","photo","photography","photos","physio","piaget","pics","pictet","pictures","pid","pin","ping","pink","pioneer","pizza","place","play","playstation","plumbing","plus","pnc","pohl","poker","politie","porn","pramerica","praxi","press","prime","prod","productions","prof","progressive","promo","properties","property","protection","pru","prudential","pub","pwc","qpon","quebec","quest","qvc","racing","radio","raid","read","realestate","realtor","realty","recipes","red","redstone","redumbrella","rehab","reise","reisen","reit","reliance","ren","rent","rentals","repair","report","republican","rest","restaurant","review","reviews","rexroth","rich","richardli","ricoh","rightathome","ril","rio","rip","rmit","rocher","rocks","rodeo","rogers","room","rsvp","rugby","ruhr","run","rwe","ryukyu","saarland","safe","safety","sakura","sale","salon","samsclub","samsung","sandvik","sandvikcoromant","sanofi","sap","sarl","sas","save","saxo","sbi","sbs","sca","scb","schaeffler","schmidt","scholarships","school","schule","schwarz","science","scjohnson","scor","scot","search","seat","secure","security","seek","select","sener","services","ses","seven","sew","sex","sexy","sfr","shangrila","sharp","shaw","shell","shia","shiksha","shoes","shop","shopping","shouji","show","showtime","shriram","silk","sina","singles","site","ski","skin","sky","skype","sling","smart","smile","sncf","soccer","social","softbank","software","sohu","solar","solutions","song","sony","soy","space","spiegel","sport","spot","spreadbetting","srl","srt","stada","staples","star","starhub","statebank","statefarm","statoil","stc","stcgroup","stockholm","storage","store","stream","studio","study","style","sucks","supplies","supply","support","surf","surgery","suzuki","swatch","swiftcover","swiss","sydney","symantec","systems","tab","taipei","talk","taobao","target","tatamotors","tatar","tattoo","tax","taxi","tci","tdk","team","tech","technology","telecity","telefonica","temasek","tennis","teva","thd","theater","theatre","tiaa","tickets","tienda","tiffany","tips","tires","tirol","tjmaxx","tjx","tkmaxx","tmall","today","tokyo","tools","top","toray","toshiba","total","tours","town","toyota","toys","trade","trading","training","travel","travelchannel","travelers","travelersinsurance","trust","trv","tube","tui","tunes","tushu","tvs","ubank","ubs","uconnect","unicom","university","uno","uol","ups","vacations","vana","vanguard","vegas","ventures","verisign","versicherung","vet","viajes","video","vig","viking","villas","vin","vip","virgin","visa","vision","vista","vistaprint","viva","vivo","vlaanderen","vodka","volkswagen","volvo","vote","voting","voto","voyage","vuelos","wales","walmart","walter","wang","wanggou","warman","watch","watches","weather","weatherchannel","webcam","weber","website","wed","wedding","weibo","weir","whoswho","wien","wiki","williamhill","win","windows","wine","winners","wme","wolterskluwer","woodside","work","works","world","wow","wtc","wtf","xbox","xerox","xfinity","xihuan","xin","कॉम","セール","佛山","慈善","集团","在线","大众汽车","点看","คอม","八卦","موقع","公益","公司","香格里拉","网站","移动","我爱你","москва","католик","онлайн","сайт","联通","קום","时尚","微博","淡马锡","ファッション","орг","नेट","ストア","삼성","商标","商店","商城","дети","ポイント","新闻","工行","家電","كوم","中文网","中信","娱乐","谷歌","電訊盈科","购物","クラウド","通販","网店","संगठन","餐厅","网络","ком","诺基亚","食品","飞利浦","手表","手机","ارامكو","العليان","اتصالات","بازار","موبايلي","ابوظبي","كاثوليك","همراه","닷컴","政府","شبكة","بيتك","عرب","机构","组织机构","健康","招聘","рус","珠宝","大拿","みんな","グーグル","世界","書籍","网址","닷넷","コム","天主教","游戏","vermögensberater","vermögensberatung","企业","信息","嘉里大酒店","嘉里","广东","政务","xyz","yachts","yahoo","yamaxun","yandex","yodobashi","yoga","yokohama","you","youtube","yun","zappos","zara","zero","zip","zippo","zone","zuerich","cc.ua","inf.ua","ltd.ua","beep.pl","*.compute.estate","*.alces.network","alwaysdata.net","cloudfront.net","*.compute.amazonaws.com","*.compute-1.amazonaws.com","*.compute.amazonaws.com.cn","us-east-1.amazonaws.com","cn-north-1.eb.amazonaws.com.cn","elasticbeanstalk.com","ap-northeast-1.elasticbeanstalk.com","ap-northeast-2.elasticbeanstalk.com","ap-northeast-3.elasticbeanstalk.com","ap-south-1.elasticbeanstalk.com","ap-southeast-1.elasticbeanstalk.com","ap-southeast-2.elasticbeanstalk.com","ca-central-1.elasticbeanstalk.com","eu-central-1.elasticbeanstalk.com","eu-west-1.elasticbeanstalk.com","eu-west-2.elasticbeanstalk.com","eu-west-3.elasticbeanstalk.com","sa-east-1.elasticbeanstalk.com","us-east-1.elasticbeanstalk.com","us-east-2.elasticbeanstalk.com","us-gov-west-1.elasticbeanstalk.com","us-west-1.elasticbeanstalk.com","us-west-2.elasticbeanstalk.com","*.elb.amazonaws.com","*.elb.amazonaws.com.cn","s3.amazonaws.com","s3-ap-northeast-1.amazonaws.com","s3-ap-northeast-2.amazonaws.com","s3-ap-south-1.amazonaws.com","s3-ap-southeast-1.amazonaws.com","s3-ap-southeast-2.amazonaws.com","s3-ca-central-1.amazonaws.com","s3-eu-central-1.amazonaws.com","s3-eu-west-1.amazonaws.com","s3-eu-west-2.amazonaws.com","s3-eu-west-3.amazonaws.com","s3-external-1.amazonaws.com","s3-fips-us-gov-west-1.amazonaws.com","s3-sa-east-1.amazonaws.com","s3-us-gov-west-1.amazonaws.com","s3-us-east-2.amazonaws.com","s3-us-west-1.amazonaws.com","s3-us-west-2.amazonaws.com","s3.ap-northeast-2.amazonaws.com","s3.ap-south-1.amazonaws.com","s3.cn-north-1.amazonaws.com.cn","s3.ca-central-1.amazonaws.com","s3.eu-central-1.amazonaws.com","s3.eu-west-2.amazonaws.com","s3.eu-west-3.amazonaws.com","s3.us-east-2.amazonaws.com","s3.dualstack.ap-northeast-1.amazonaws.com","s3.dualstack.ap-northeast-2.amazonaws.com","s3.dualstack.ap-south-1.amazonaws.com","s3.dualstack.ap-southeast-1.amazonaws.com","s3.dualstack.ap-southeast-2.amazonaws.com","s3.dualstack.ca-central-1.amazonaws.com","s3.dualstack.eu-central-1.amazonaws.com","s3.dualstack.eu-west-1.amazonaws.com","s3.dualstack.eu-west-2.amazonaws.com","s3.dualstack.eu-west-3.amazonaws.com","s3.dualstack.sa-east-1.amazonaws.com","s3.dualstack.us-east-1.amazonaws.com","s3.dualstack.us-east-2.amazonaws.com","s3-website-us-east-1.amazonaws.com","s3-website-us-west-1.amazonaws.com","s3-website-us-west-2.amazonaws.com","s3-website-ap-northeast-1.amazonaws.com","s3-website-ap-southeast-1.amazonaws.com","s3-website-ap-southeast-2.amazonaws.com","s3-website-eu-west-1.amazonaws.com","s3-website-sa-east-1.amazonaws.com","s3-website.ap-northeast-2.amazonaws.com","s3-website.ap-south-1.amazonaws.com","s3-website.ca-central-1.amazonaws.com","s3-website.eu-central-1.amazonaws.com","s3-website.eu-west-2.amazonaws.com","s3-website.eu-west-3.amazonaws.com","s3-website.us-east-2.amazonaws.com","t3l3p0rt.net","tele.amune.org","on-aptible.com","user.party.eus","pimienta.org","poivron.org","potager.org","sweetpepper.org","myasustor.com","myfritz.net","*.awdev.ca","*.advisor.ws","backplaneapp.io","betainabox.com","bnr.la","blackbaudcdn.net","boomla.net","boxfuse.io","square7.ch","bplaced.com","bplaced.de","square7.de","bplaced.net","square7.net","browsersafetymark.io","mycd.eu","ae.org","ar.com","br.com","cn.com","com.de","com.se","de.com","eu.com","gb.com","gb.net","hu.com","hu.net","jp.net","jpn.com","kr.com","mex.com","no.com","qc.com","ru.com","sa.com","se.net","uk.com","uk.net","us.com","uy.com","za.bz","za.com","africa.com","gr.com","in.net","us.org","co.com","c.la","certmgr.org","xenapponazure.com","virtueeldomein.nl","cleverapps.io","c66.me","cloud66.ws","jdevcloud.com","wpdevcloud.com","cloudaccess.host","freesite.host","cloudaccess.net","cloudcontrolled.com","cloudcontrolapp.com","co.ca","*.otap.co","co.cz","c.cdn77.org","cdn77-ssl.net","r.cdn77.net","rsc.cdn77.org","ssl.origin.cdn77-secure.org","cloudns.asia","cloudns.biz","cloudns.club","cloudns.cc","cloudns.eu","cloudns.in","cloudns.info","cloudns.org","cloudns.pro","cloudns.pw","cloudns.us","cloudeity.net","cnpy.gdn","co.nl","co.no","webhosting.be","hosting-cluster.nl","dyn.cosidns.de","dynamisches-dns.de","dnsupdater.de","internet-dns.de","l-o-g-i-n.de","dynamic-dns.info","feste-ip.net","knx-server.net","static-access.net","realm.cz","*.cryptonomic.net","cupcake.is","cyon.link","cyon.site","daplie.me","localhost.daplie.me","dattolocal.com","dattorelay.com","dattoweb.com","mydatto.com","dattolocal.net","mydatto.net","biz.dk","co.dk","firm.dk","reg.dk","store.dk","debian.net","dedyn.io","dnshome.de","drayddns.com","dreamhosters.com","mydrobo.com","drud.io","drud.us","duckdns.org","dy.fi","tunk.org","dyndns-at-home.com","dyndns-at-work.com","dyndns-blog.com","dyndns-free.com","dyndns-home.com","dyndns-ip.com","dyndns-mail.com","dyndns-office.com","dyndns-pics.com","dyndns-remote.com","dyndns-server.com","dyndns-web.com","dyndns-wiki.com","dyndns-work.com","dyndns.biz","dyndns.info","dyndns.org","dyndns.tv","at-band-camp.net","ath.cx","barrel-of-knowledge.info","barrell-of-knowledge.info","better-than.tv","blogdns.com","blogdns.net","blogdns.org","blogsite.org","boldlygoingnowhere.org","broke-it.net","buyshouses.net","cechire.com","dnsalias.com","dnsalias.net","dnsalias.org","dnsdojo.com","dnsdojo.net","dnsdojo.org","does-it.net","doesntexist.com","doesntexist.org","dontexist.com","dontexist.net","dontexist.org","doomdns.com","doomdns.org","dvrdns.org","dyn-o-saur.com","dynalias.com","dynalias.net","dynalias.org","dynathome.net","dyndns.ws","endofinternet.net","endofinternet.org","endoftheinternet.org","est-a-la-maison.com","est-a-la-masion.com","est-le-patron.com","est-mon-blogueur.com","for-better.biz","for-more.biz","for-our.info","for-some.biz","for-the.biz","forgot.her.name","forgot.his.name","from-ak.com","from-al.com","from-ar.com","from-az.net","from-ca.com","from-co.net","from-ct.com","from-dc.com","from-de.com","from-fl.com","from-ga.com","from-hi.com","from-ia.com","from-id.com","from-il.com","from-in.com","from-ks.com","from-ky.com","from-la.net","from-ma.com","from-md.com","from-me.org","from-mi.com","from-mn.com","from-mo.com","from-ms.com","from-mt.com","from-nc.com","from-nd.com","from-ne.com","from-nh.com","from-nj.com","from-nm.com","from-nv.com","from-ny.net","from-oh.com","from-ok.com","from-or.com","from-pa.com","from-pr.com","from-ri.com","from-sc.com","from-sd.com","from-tn.com","from-tx.com","from-ut.com","from-va.com","from-vt.com","from-wa.com","from-wi.com","from-wv.com","from-wy.com","ftpaccess.cc","fuettertdasnetz.de","game-host.org","game-server.cc","getmyip.com","gets-it.net","go.dyndns.org","gotdns.com","gotdns.org","groks-the.info","groks-this.info","ham-radio-op.net","here-for-more.info","hobby-site.com","hobby-site.org","home.dyndns.org","homedns.org","homeftp.net","homeftp.org","homeip.net","homelinux.com","homelinux.net","homelinux.org","homeunix.com","homeunix.net","homeunix.org","iamallama.com","in-the-band.net","is-a-anarchist.com","is-a-blogger.com","is-a-bookkeeper.com","is-a-bruinsfan.org","is-a-bulls-fan.com","is-a-candidate.org","is-a-caterer.com","is-a-celticsfan.org","is-a-chef.com","is-a-chef.net","is-a-chef.org","is-a-conservative.com","is-a-cpa.com","is-a-cubicle-slave.com","is-a-democrat.com","is-a-designer.com","is-a-doctor.com","is-a-financialadvisor.com","is-a-geek.com","is-a-geek.net","is-a-geek.org","is-a-green.com","is-a-guru.com","is-a-hard-worker.com","is-a-hunter.com","is-a-knight.org","is-a-landscaper.com","is-a-lawyer.com","is-a-liberal.com","is-a-libertarian.com","is-a-linux-user.org","is-a-llama.com","is-a-musician.com","is-a-nascarfan.com","is-a-nurse.com","is-a-painter.com","is-a-patsfan.org","is-a-personaltrainer.com","is-a-photographer.com","is-a-player.com","is-a-republican.com","is-a-rockstar.com","is-a-socialist.com","is-a-soxfan.org","is-a-student.com","is-a-teacher.com","is-a-techie.com","is-a-therapist.com","is-an-accountant.com","is-an-actor.com","is-an-actress.com","is-an-anarchist.com","is-an-artist.com","is-an-engineer.com","is-an-entertainer.com","is-by.us","is-certified.com","is-found.org","is-gone.com","is-into-anime.com","is-into-cars.com","is-into-cartoons.com","is-into-games.com","is-leet.com","is-lost.org","is-not-certified.com","is-saved.org","is-slick.com","is-uberleet.com","is-very-bad.org","is-very-evil.org","is-very-good.org","is-very-nice.org","is-very-sweet.org","is-with-theband.com","isa-geek.com","isa-geek.net","isa-geek.org","isa-hockeynut.com","issmarterthanyou.com","isteingeek.de","istmein.de","kicks-ass.net","kicks-ass.org","knowsitall.info","land-4-sale.us","lebtimnetz.de","leitungsen.de","likes-pie.com","likescandy.com","merseine.nu","mine.nu","misconfused.org","mypets.ws","myphotos.cc","neat-url.com","office-on-the.net","on-the-web.tv","podzone.net","podzone.org","readmyblog.org","saves-the-whales.com","scrapper-site.net","scrapping.cc","selfip.biz","selfip.com","selfip.info","selfip.net","selfip.org","sells-for-less.com","sells-for-u.com","sells-it.net","sellsyourhome.org","servebbs.com","servebbs.net","servebbs.org","serveftp.net","serveftp.org","servegame.org","shacknet.nu","simple-url.com","space-to-rent.com","stuff-4-sale.org","stuff-4-sale.us","teaches-yoga.com","thruhere.net","traeumtgerade.de","webhop.biz","webhop.info","webhop.net","webhop.org","worse-than.tv","writesthisblog.com","ddnss.de","dyn.ddnss.de","dyndns.ddnss.de","dyndns1.de","dyn-ip24.de","home-webserver.de","dyn.home-webserver.de","myhome-server.de","ddnss.org","definima.net","definima.io","bci.dnstrace.pro","ddnsfree.com","ddnsgeek.com","giize.com","gleeze.com","kozow.com","loseyourip.com","ooguy.com","theworkpc.com","casacam.net","dynu.net","accesscam.org","camdvr.org","freeddns.org","mywire.org","webredirect.org","myddns.rocks","blogsite.xyz","dynv6.net","e4.cz","mytuleap.com","enonic.io","customer.enonic.io","eu.org","al.eu.org","asso.eu.org","at.eu.org","au.eu.org","be.eu.org","bg.eu.org","ca.eu.org","cd.eu.org","ch.eu.org","cn.eu.org","cy.eu.org","cz.eu.org","de.eu.org","dk.eu.org","edu.eu.org","ee.eu.org","es.eu.org","fi.eu.org","fr.eu.org","gr.eu.org","hr.eu.org","hu.eu.org","ie.eu.org","il.eu.org","in.eu.org","int.eu.org","is.eu.org","it.eu.org","jp.eu.org","kr.eu.org","lt.eu.org","lu.eu.org","lv.eu.org","mc.eu.org","me.eu.org","mk.eu.org","mt.eu.org","my.eu.org","net.eu.org","ng.eu.org","nl.eu.org","no.eu.org","nz.eu.org","paris.eu.org","pl.eu.org","pt.eu.org","q-a.eu.org","ro.eu.org","ru.eu.org","se.eu.org","si.eu.org","sk.eu.org","tr.eu.org","uk.eu.org","us.eu.org","eu-1.evennode.com","eu-2.evennode.com","eu-3.evennode.com","eu-4.evennode.com","us-1.evennode.com","us-2.evennode.com","us-3.evennode.com","us-4.evennode.com","twmail.cc","twmail.net","twmail.org","mymailer.com.tw","url.tw","apps.fbsbx.com","ru.net","adygeya.ru","bashkiria.ru","bir.ru","cbg.ru","com.ru","dagestan.ru","grozny.ru","kalmykia.ru","kustanai.ru","marine.ru","mordovia.ru","msk.ru","mytis.ru","nalchik.ru","nov.ru","pyatigorsk.ru","spb.ru","vladikavkaz.ru","vladimir.ru","abkhazia.su","adygeya.su","aktyubinsk.su","arkhangelsk.su","armenia.su","ashgabad.su","azerbaijan.su","balashov.su","bashkiria.su","bryansk.su","bukhara.su","chimkent.su","dagestan.su","east-kazakhstan.su","exnet.su","georgia.su","grozny.su","ivanovo.su","jambyl.su","kalmykia.su","kaluga.su","karacol.su","karaganda.su","karelia.su","khakassia.su","krasnodar.su","kurgan.su","kustanai.su","lenug.su","mangyshlak.su","mordovia.su","msk.su","murmansk.su","nalchik.su","navoi.su","north-kazakhstan.su","nov.su","obninsk.su","penza.su","pokrovsk.su","sochi.su","spb.su","tashkent.su","termez.su","togliatti.su","troitsk.su","tselinograd.su","tula.su","tuva.su","vladikavkaz.su","vladimir.su","vologda.su","channelsdvr.net","fastlylb.net","map.fastlylb.net","freetls.fastly.net","map.fastly.net","a.prod.fastly.net","global.prod.fastly.net","a.ssl.fastly.net","b.ssl.fastly.net","global.ssl.fastly.net","fastpanel.direct","fastvps-server.com","fhapp.xyz","fedorainfracloud.org","fedorapeople.org","cloud.fedoraproject.org","app.os.fedoraproject.org","app.os.stg.fedoraproject.org","filegear.me","firebaseapp.com","flynnhub.com","flynnhosting.net","freebox-os.com","freeboxos.com","fbx-os.fr","fbxos.fr","freebox-os.fr","freeboxos.fr","freedesktop.org","*.futurecms.at","*.ex.futurecms.at","*.in.futurecms.at","futurehosting.at","futuremailing.at","*.ex.ortsinfo.at","*.kunden.ortsinfo.at","*.statics.cloud","service.gov.uk","github.io","githubusercontent.com","gitlab.io","homeoffice.gov.uk","ro.im","shop.ro","goip.de","*.0emm.com","appspot.com","blogspot.ae","blogspot.al","blogspot.am","blogspot.ba","blogspot.be","blogspot.bg","blogspot.bj","blogspot.ca","blogspot.cf","blogspot.ch","blogspot.cl","blogspot.co.at","blogspot.co.id","blogspot.co.il","blogspot.co.ke","blogspot.co.nz","blogspot.co.uk","blogspot.co.za","blogspot.com","blogspot.com.ar","blogspot.com.au","blogspot.com.br","blogspot.com.by","blogspot.com.co","blogspot.com.cy","blogspot.com.ee","blogspot.com.eg","blogspot.com.es","blogspot.com.mt","blogspot.com.ng","blogspot.com.tr","blogspot.com.uy","blogspot.cv","blogspot.cz","blogspot.de","blogspot.dk","blogspot.fi","blogspot.fr","blogspot.gr","blogspot.hk","blogspot.hr","blogspot.hu","blogspot.ie","blogspot.in","blogspot.is","blogspot.it","blogspot.jp","blogspot.kr","blogspot.li","blogspot.lt","blogspot.lu","blogspot.md","blogspot.mk","blogspot.mr","blogspot.mx","blogspot.my","blogspot.nl","blogspot.no","blogspot.pe","blogspot.pt","blogspot.qa","blogspot.re","blogspot.ro","blogspot.rs","blogspot.ru","blogspot.se","blogspot.sg","blogspot.si","blogspot.sk","blogspot.sn","blogspot.td","blogspot.tw","blogspot.ug","blogspot.vn","cloudfunctions.net","cloud.goog","codespot.com","googleapis.com","googlecode.com","pagespeedmobilizer.com","publishproxy.com","withgoogle.com","withyoutube.com","hashbang.sh","hasura.app","hasura-app.io","hepforge.org","herokuapp.com","herokussl.com","myravendb.com","ravendb.community","ravendb.me","development.run","ravendb.run","moonscale.net","iki.fi","biz.at","info.at","info.cx","ac.leg.br","al.leg.br","am.leg.br","ap.leg.br","ba.leg.br","ce.leg.br","df.leg.br","es.leg.br","go.leg.br","ma.leg.br","mg.leg.br","ms.leg.br","mt.leg.br","pa.leg.br","pb.leg.br","pe.leg.br","pi.leg.br","pr.leg.br","rj.leg.br","rn.leg.br","ro.leg.br","rr.leg.br","rs.leg.br","sc.leg.br","se.leg.br","sp.leg.br","to.leg.br","pixolino.com","ipifony.net","mein-iserv.de","test-iserv.de","myjino.ru","*.hosting.myjino.ru","*.landing.myjino.ru","*.spectrum.myjino.ru","*.vps.myjino.ru","*.triton.zone","*.cns.joyent.com","js.org","keymachine.de","knightpoint.systems","co.krd","edu.krd","git-repos.de","lcube-server.de","svn-repos.de","app.lmpm.com","linkitools.space","linkyard.cloud","linkyard-cloud.ch","we.bs","uklugs.org","glug.org.uk","lug.org.uk","lugs.org.uk","barsy.bg","barsy.co.uk","barsyonline.co.uk","barsycenter.com","barsyonline.com","barsy.club","barsy.de","barsy.eu","barsy.in","barsy.info","barsy.io","barsy.me","barsy.menu","barsy.mobi","barsy.net","barsy.online","barsy.org","barsy.pro","barsy.pub","barsy.shop","barsy.site","barsy.support","barsy.uk","*.magentosite.cloud","mayfirst.info","mayfirst.org","hb.cldmail.ru","miniserver.com","memset.net","cloud.metacentrum.cz","custom.metacentrum.cz","flt.cloud.muni.cz","usr.cloud.muni.cz","meteorapp.com","eu.meteorapp.com","co.pl","azurecontainer.io","azurewebsites.net","azure-mobile.net","cloudapp.net","mozilla-iot.org","bmoattachments.org","net.ru","org.ru","pp.ru","bitballoon.com","netlify.com","4u.com","ngrok.io","nh-serv.co.uk","nfshost.com","dnsking.ch","mypi.co","n4t.co","001www.com","ddnslive.com","myiphost.com","forumz.info","16-b.it","32-b.it","64-b.it","soundcast.me","tcp4.me","dnsup.net","hicam.net","now-dns.net","ownip.net","vpndns.net","dynserv.org","now-dns.org","x443.pw","now-dns.top","ntdll.top","freeddns.us","crafting.xyz","zapto.xyz","nsupdate.info","nerdpol.ovh","blogsyte.com","brasilia.me","cable-modem.org","ciscofreak.com","collegefan.org","couchpotatofries.org","damnserver.com","ddns.me","ditchyourip.com","dnsfor.me","dnsiskinky.com","dvrcam.info","dynns.com","eating-organic.net","fantasyleague.cc","geekgalaxy.com","golffan.us","health-carereform.com","homesecuritymac.com","homesecuritypc.com","hopto.me","ilovecollege.info","loginto.me","mlbfan.org","mmafan.biz","myactivedirectory.com","mydissent.net","myeffect.net","mymediapc.net","mypsx.net","mysecuritycamera.com","mysecuritycamera.net","mysecuritycamera.org","net-freaks.com","nflfan.org","nhlfan.net","no-ip.ca","no-ip.co.uk","no-ip.net","noip.us","onthewifi.com","pgafan.net","point2this.com","pointto.us","privatizehealthinsurance.net","quicksytes.com","read-books.org","securitytactics.com","serveexchange.com","servehumour.com","servep2p.com","servesarcasm.com","stufftoread.com","ufcfan.org","unusualperson.com","workisboring.com","3utilities.com","bounceme.net","ddns.net","ddnsking.com","gotdns.ch","hopto.org","myftp.biz","myftp.org","myvnc.com","no-ip.biz","no-ip.info","no-ip.org","noip.me","redirectme.net","servebeer.com","serveblog.net","servecounterstrike.com","serveftp.com","servegame.com","servehalflife.com","servehttp.com","serveirc.com","serveminecraft.net","servemp3.com","servepics.com","servequake.com","sytes.net","webhop.me","zapto.org","stage.nodeart.io","nodum.co","nodum.io","pcloud.host","nyc.mn","nom.ae","nom.af","nom.ai","nom.al","nym.by","nym.bz","nom.cl","nom.gd","nom.ge","nom.gl","nym.gr","nom.gt","nym.gy","nom.hn","nym.ie","nom.im","nom.ke","nym.kz","nym.la","nym.lc","nom.li","nym.li","nym.lt","nym.lu","nym.me","nom.mk","nym.mn","nym.mx","nom.nu","nym.nz","nym.pe","nym.pt","nom.pw","nom.qa","nym.ro","nom.rs","nom.si","nym.sk","nom.st","nym.su","nym.sx","nom.tj","nym.tw","nom.ug","nom.uy","nom.vc","nom.vg","cya.gg","cloudycluster.net","nid.io","opencraft.hosting","operaunite.com","outsystemscloud.com","ownprovider.com","own.pm","ox.rs","oy.lc","pgfog.com","pagefrontapp.com","art.pl","gliwice.pl","krakow.pl","poznan.pl","wroc.pl","zakopane.pl","pantheonsite.io","gotpantheon.com","mypep.link","on-web.fr","*.platform.sh","*.platformsh.site","xen.prgmr.com","priv.at","protonet.io","chirurgiens-dentistes-en-france.fr","byen.site","ras.ru","qa2.com","dev-myqnapcloud.com","alpha-myqnapcloud.com","myqnapcloud.com","*.quipelements.com","vapor.cloud","vaporcloud.io","rackmaze.com","rackmaze.net","rhcloud.com","resindevice.io","devices.resinstaging.io","hzc.io","wellbeingzone.eu","ptplus.fit","wellbeingzone.co.uk","sandcats.io","logoip.de","logoip.com","schokokeks.net","scrysec.com","firewall-gateway.com","firewall-gateway.de","my-gateway.de","my-router.de","spdns.de","spdns.eu","firewall-gateway.net","my-firewall.org","myfirewall.org","spdns.org","*.s5y.io","*.sensiosite.cloud","biz.ua","co.ua","pp.ua","shiftedit.io","myshopblocks.com","1kapp.com","appchizi.com","applinzi.com","sinaapp.com","vipsinaapp.com","bounty-full.com","alpha.bounty-full.com","beta.bounty-full.com","static.land","dev.static.land","sites.static.land","apps.lair.io","*.stolos.io","spacekit.io","customer.speedpartner.de","storj.farm","utwente.io","temp-dns.com","diskstation.me","dscloud.biz","dscloud.me","dscloud.mobi","dsmynas.com","dsmynas.net","dsmynas.org","familyds.com","familyds.net","familyds.org","i234.me","myds.me","synology.me","vpnplus.to","taifun-dns.de","gda.pl","gdansk.pl","gdynia.pl","med.pl","sopot.pl","gwiddle.co.uk","cust.dev.thingdust.io","cust.disrec.thingdust.io","cust.prod.thingdust.io","cust.testing.thingdust.io","bloxcms.com","townnews-staging.com","12hp.at","2ix.at","4lima.at","lima-city.at","12hp.ch","2ix.ch","4lima.ch","lima-city.ch","trafficplex.cloud","de.cool","12hp.de","2ix.de","4lima.de","lima-city.de","1337.pictures","clan.rip","lima-city.rocks","webspace.rocks","lima.zone","*.transurl.be","*.transurl.eu","*.transurl.nl","tuxfamily.org","dd-dns.de","diskstation.eu","diskstation.org","dray-dns.de","draydns.de","dyn-vpn.de","dynvpn.de","mein-vigor.de","my-vigor.de","my-wan.de","syno-ds.de","synology-diskstation.de","synology-ds.de","uber.space","*.uberspace.de","hk.com","hk.org","ltd.hk","inc.hk","virtualuser.de","virtual-user.de","lib.de.us","2038.io","router.management","v-info.info","wedeploy.io","wedeploy.me","wedeploy.sh","remotewd.com","wmflabs.org","half.host","xnbay.com","u2.xnbay.com","u2-local.xnbay.com","cistron.nl","demon.nl","xs4all.space","official.academy","yolasite.com","ybo.faith","yombo.me","homelink.one","ybo.party","ybo.review","ybo.science","ybo.trade","nohost.me","noho.st","za.net","za.org","now.sh","zone.id"]
+
+/***/ }),
+/* 17 */
+/***/ (function(module, exports) {
+
+	/*!
+	 * Copyright (c) 2015, Salesforce.com, Inc.
+	 * All rights reserved.
+	 *
+	 * Redistribution and use in source and binary forms, with or without
+	 * modification, are permitted provided that the following conditions are met:
+	 *
+	 * 1. Redistributions of source code must retain the above copyright notice,
+	 * this list of conditions and the following disclaimer.
+	 *
+	 * 2. Redistributions in binary form must reproduce the above copyright notice,
+	 * this list of conditions and the following disclaimer in the documentation
+	 * and/or other materials provided with the distribution.
+	 *
+	 * 3. Neither the name of Salesforce.com nor the names of its contributors may
+	 * be used to endorse or promote products derived from this software without
+	 * specific prior written permission.
+	 *
+	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+	 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+	 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+	 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+	 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+	 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	 * POSSIBILITY OF SUCH DAMAGE.
+	 */
+	'use strict';
+	/*jshint unused:false */
+
+	function Store() {
+	}
+	exports.Store = Store;
+
+	// Stores may be synchronous, but are still required to use a
+	// Continuation-Passing Style API.  The CookieJar itself will expose a "*Sync"
+	// API that converts from synchronous-callbacks to imperative style.
+	Store.prototype.synchronous = false;
+
+	Store.prototype.findCookie = function(domain, path, key, cb) {
+	  throw new Error('findCookie is not implemented');
+	};
+
+	Store.prototype.findCookies = function(domain, path, cb) {
+	  throw new Error('findCookies is not implemented');
+	};
+
+	Store.prototype.putCookie = function(cookie, cb) {
+	  throw new Error('putCookie is not implemented');
+	};
+
+	Store.prototype.updateCookie = function(oldCookie, newCookie, cb) {
+	  // recommended default implementation:
+	  // return this.putCookie(newCookie, cb);
+	  throw new Error('updateCookie is not implemented');
+	};
+
+	Store.prototype.removeCookie = function(domain, path, key, cb) {
+	  throw new Error('removeCookie is not implemented');
+	};
+
+	Store.prototype.removeCookies = function(domain, path, cb) {
+	  throw new Error('removeCookies is not implemented');
+	};
+
+	Store.prototype.getAllCookies = function(cb) {
+	  throw new Error('getAllCookies is not implemented (therefore jar cannot be serialized)');
+	};
+
+
+/***/ }),
+/* 18 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/*!
+	 * Copyright (c) 2015, Salesforce.com, Inc.
+	 * All rights reserved.
+	 *
+	 * Redistribution and use in source and binary forms, with or without
+	 * modification, are permitted provided that the following conditions are met:
+	 *
+	 * 1. Redistributions of source code must retain the above copyright notice,
+	 * this list of conditions and the following disclaimer.
+	 *
+	 * 2. Redistributions in binary form must reproduce the above copyright notice,
+	 * this list of conditions and the following disclaimer in the documentation
+	 * and/or other materials provided with the distribution.
+	 *
+	 * 3. Neither the name of Salesforce.com nor the names of its contributors may
+	 * be used to endorse or promote products derived from this software without
+	 * specific prior written permission.
+	 *
+	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+	 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+	 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+	 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+	 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+	 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	 * POSSIBILITY OF SUCH DAMAGE.
+	 */
+	'use strict';
+	var Store = __webpack_require__(17).Store;
+	var permuteDomain = __webpack_require__(19).permuteDomain;
+	var pathMatch = __webpack_require__(20).pathMatch;
+	var util = __webpack_require__(9);
+
+	function MemoryCookieStore() {
+	  Store.call(this);
+	  this.idx = {};
+	}
+	util.inherits(MemoryCookieStore, Store);
+	exports.MemoryCookieStore = MemoryCookieStore;
+	MemoryCookieStore.prototype.idx = null;
+
+	// Since it's just a struct in RAM, this Store is synchronous
+	MemoryCookieStore.prototype.synchronous = true;
+
+	// force a default depth:
+	MemoryCookieStore.prototype.inspect = function() {
+	  return "{ idx: "+util.inspect(this.idx, false, 2)+' }';
+	};
+
+	// Use the new custom inspection symbol to add the custom inspect function if
+	// available.
+	if (util.inspect.custom) {
+	  MemoryCookieStore.prototype[util.inspect.custom] = MemoryCookieStore.prototype.inspect;
+	}
+
+	MemoryCookieStore.prototype.findCookie = function(domain, path, key, cb) {
+	  if (!this.idx[domain]) {
+	    return cb(null,undefined);
+	  }
+	  if (!this.idx[domain][path]) {
+	    return cb(null,undefined);
+	  }
+	  return cb(null,this.idx[domain][path][key]||null);
+	};
+
+	MemoryCookieStore.prototype.findCookies = function(domain, path, cb) {
+	  var results = [];
+	  if (!domain) {
+	    return cb(null,[]);
+	  }
+
+	  var pathMatcher;
+	  if (!path) {
+	    // null means "all paths"
+	    pathMatcher = function matchAll(domainIndex) {
+	      for (var curPath in domainIndex) {
+	        var pathIndex = domainIndex[curPath];
+	        for (var key in pathIndex) {
+	          results.push(pathIndex[key]);
+	        }
+	      }
+	    };
+
+	  } else {
+	    pathMatcher = function matchRFC(domainIndex) {
+	       //NOTE: we should use path-match algorithm from S5.1.4 here
+	       //(see : https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/canonical_cookie.cc#L299)
+	       Object.keys(domainIndex).forEach(function (cookiePath) {
+	         if (pathMatch(path, cookiePath)) {
+	           var pathIndex = domainIndex[cookiePath];
+
+	           for (var key in pathIndex) {
+	             results.push(pathIndex[key]);
+	           }
+	         }
+	       });
+	     };
+	  }
+
+	  var domains = permuteDomain(domain) || [domain];
+	  var idx = this.idx;
+	  domains.forEach(function(curDomain) {
+	    var domainIndex = idx[curDomain];
+	    if (!domainIndex) {
+	      return;
+	    }
+	    pathMatcher(domainIndex);
+	  });
+
+	  cb(null,results);
+	};
+
+	MemoryCookieStore.prototype.putCookie = function(cookie, cb) {
+	  if (!this.idx[cookie.domain]) {
+	    this.idx[cookie.domain] = {};
+	  }
+	  if (!this.idx[cookie.domain][cookie.path]) {
+	    this.idx[cookie.domain][cookie.path] = {};
+	  }
+	  this.idx[cookie.domain][cookie.path][cookie.key] = cookie;
+	  cb(null);
+	};
+
+	MemoryCookieStore.prototype.updateCookie = function(oldCookie, newCookie, cb) {
+	  // updateCookie() may avoid updating cookies that are identical.  For example,
+	  // lastAccessed may not be important to some stores and an equality
+	  // comparison could exclude that field.
+	  this.putCookie(newCookie,cb);
+	};
+
+	MemoryCookieStore.prototype.removeCookie = function(domain, path, key, cb) {
+	  if (this.idx[domain] && this.idx[domain][path] && this.idx[domain][path][key]) {
+	    delete this.idx[domain][path][key];
+	  }
+	  cb(null);
+	};
+
+	MemoryCookieStore.prototype.removeCookies = function(domain, path, cb) {
+	  if (this.idx[domain]) {
+	    if (path) {
+	      delete this.idx[domain][path];
+	    } else {
+	      delete this.idx[domain];
+	    }
+	  }
+	  return cb(null);
+	};
+
+	MemoryCookieStore.prototype.getAllCookies = function(cb) {
+	  var cookies = [];
+	  var idx = this.idx;
+
+	  var domains = Object.keys(idx);
+	  domains.forEach(function(domain) {
+	    var paths = Object.keys(idx[domain]);
+	    paths.forEach(function(path) {
+	      var keys = Object.keys(idx[domain][path]);
+	      keys.forEach(function(key) {
+	        if (key !== null) {
+	          cookies.push(idx[domain][path][key]);
+	        }
+	      });
+	    });
+	  });
+
+	  // Sort by creationIndex so deserializing retains the creation order.
+	  // When implementing your own store, this SHOULD retain the order too
+	  cookies.sort(function(a,b) {
+	    return (a.creationIndex||0) - (b.creationIndex||0);
+	  });
+
+	  cb(null, cookies);
+	};
+
+
+/***/ }),
+/* 19 */
+/***/ (function(module, exports, __webpack_require__) {
+
+	/*!
+	 * Copyright (c) 2015, Salesforce.com, Inc.
+	 * All rights reserved.
+	 *
+	 * Redistribution and use in source and binary forms, with or without
+	 * modification, are permitted provided that the following conditions are met:
+	 *
+	 * 1. Redistributions of source code must retain the above copyright notice,
+	 * this list of conditions and the following disclaimer.
+	 *
+	 * 2. Redistributions in binary form must reproduce the above copyright notice,
+	 * this list of conditions and the following disclaimer in the documentation
+	 * and/or other materials provided with the distribution.
+	 *
+	 * 3. Neither the name of Salesforce.com nor the names of its contributors may
+	 * be used to endorse or promote products derived from this software without
+	 * specific prior written permission.
+	 *
+	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+	 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+	 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+	 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+	 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+	 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	 * POSSIBILITY OF SUCH DAMAGE.
+	 */
+	"use strict";
+	var pubsuffix = __webpack_require__(13);
+
+	// Gives the permutation of all possible domainMatch()es of a given domain. The
+	// array is in shortest-to-longest order.  Handy for indexing.
+	function permuteDomain (domain) {
+	  var pubSuf = pubsuffix.getPublicSuffix(domain);
+	  if (!pubSuf) {
+	    return null;
+	  }
+	  if (pubSuf == domain) {
+	    return [domain];
+	  }
+
+	  var prefix = domain.slice(0, -(pubSuf.length + 1)); // ".example.com"
+	  var parts = prefix.split('.').reverse();
+	  var cur = pubSuf;
+	  var permutations = [cur];
+	  while (parts.length) {
+	    cur = parts.shift() + '.' + cur;
+	    permutations.push(cur);
+	  }
+	  return permutations;
+	}
+
+	exports.permuteDomain = permuteDomain;
+
+
+/***/ }),
+/* 20 */
+/***/ (function(module, exports) {
+
+	/*!
+	 * Copyright (c) 2015, Salesforce.com, Inc.
+	 * All rights reserved.
+	 *
+	 * Redistribution and use in source and binary forms, with or without
+	 * modification, are permitted provided that the following conditions are met:
+	 *
+	 * 1. Redistributions of source code must retain the above copyright notice,
+	 * this list of conditions and the following disclaimer.
+	 *
+	 * 2. Redistributions in binary form must reproduce the above copyright notice,
+	 * this list of conditions and the following disclaimer in the documentation
+	 * and/or other materials provided with the distribution.
+	 *
+	 * 3. Neither the name of Salesforce.com nor the names of its contributors may
+	 * be used to endorse or promote products derived from this software without
+	 * specific prior written permission.
+	 *
+	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+	 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+	 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+	 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+	 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+	 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	 * POSSIBILITY OF SUCH DAMAGE.
+	 */
+	"use strict";
+	/*
+	 * "A request-path path-matches a given cookie-path if at least one of the
+	 * following conditions holds:"
+	 */
+	function pathMatch (reqPath, cookiePath) {
+	  // "o  The cookie-path and the request-path are identical."
+	  if (cookiePath === reqPath) {
+	    return true;
+	  }
+
+	  var idx = reqPath.indexOf(cookiePath);
+	  if (idx === 0) {
+	    // "o  The cookie-path is a prefix of the request-path, and the last
+	    // character of the cookie-path is %x2F ("/")."
+	    if (cookiePath.substr(-1) === "/") {
+	      return true;
+	    }
+
+	    // " o  The cookie-path is a prefix of the request-path, and the first
+	    // character of the request-path that is not included in the cookie- path
+	    // is a %x2F ("/") character."
+	    if (reqPath.substr(cookiePath.length, 1) === "/") {
+	      return true;
+	    }
+	  }
+
+	  return false;
+	}
+
+	exports.pathMatch = pathMatch;
+
+
+/***/ }),
+/* 21 */
+/***/ (function(module, exports) {
+
+	module.exports = {"_from":"tough-cookie@2.4.3","_id":"tough-cookie@2.4.3","_inBundle":false,"_integrity":"sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==","_location":"/tough-cookie","_phantomChildren":{},"_requested":{"type":"version","registry":true,"raw":"tough-cookie@2.4.3","name":"tough-cookie","escapedName":"tough-cookie","rawSpec":"2.4.3","saveSpec":null,"fetchSpec":"2.4.3"},"_requiredBy":["#DEV:/"],"_resolved":"https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz","_shasum":"53f36da3f47783b0925afa06ff9f3b165280f781","_spec":"tough-cookie@2.4.3","_where":"/Users/sefa/Entwicklung/umd-tough-cookie","author":{"name":"Jeremy Stashewsky","email":"jstash@gmail.com"},"bugs":{"url":"https://github.com/salesforce/tough-cookie/issues"},"bundleDependencies":false,"contributors":[{"name":"Alexander Savin"},{"name":"Ian Livingstone"},{"name":"Ivan Nikulin"},{"name":"Lalit Kapoor"},{"name":"Sam Thompson"},{"name":"Sebastian Mayr"}],"dependencies":{"psl":"^1.1.24","punycode":"^1.4.1"},"deprecated":false,"description":"RFC6265 Cookies and Cookie Jar for node.js","devDependencies":{"async":"^1.4.2","nyc":"^11.6.0","string.prototype.repeat":"^0.2.0","vows":"^0.8.1"},"engines":{"node":">=0.8"},"files":["lib"],"homepage":"https://github.com/salesforce/tough-cookie","keywords":["HTTP","cookie","cookies","set-cookie","cookiejar","jar","RFC6265","RFC2965"],"license":"BSD-3-Clause","main":"./lib/cookie","name":"tough-cookie","repository":{"type":"git","url":"git://github.com/salesforce/tough-cookie.git"},"scripts":{"cover":"nyc --reporter=lcov --reporter=html vows test/*_test.js","test":"vows test/*_test.js"},"version":"2.4.3"}
+
+/***/ })
+/******/ ])
+});
+;
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/url-util.js b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/url-util.js
new file mode 100644
index 0000000..8d9228a
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-advanced-http/www/url-util.js
@@ -0,0 +1,106 @@
+cordova.define("cordova-plugin-advanced-http.url-util", function(require, exports, module) {
+module.exports = function init(jsUtil) {
+  return {
+    parseUrl: parseUrl,
+    appendQueryParamsString: appendQueryParamsString,
+    serializeQueryParams: serializeQueryParams
+  }
+
+  function parseUrl(url) {
+    var match = url.match(/^(https?\:)\/\/(([^:\/?#]*)(?:\:([0-9]+))?)([\/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/);
+
+    return match && {
+        protocol: match[1],
+        host: match[2],
+        hostname: match[3],
+        port: match[4] || '',
+        pathname: match[5],
+        search: match[6],
+        hash: match[7]
+    }
+  }
+
+  function appendQueryParamsString(url, params) {
+    if (!url.length || !params.length) {
+      return url;
+    }
+
+    var parsed = parseUrl(url);
+
+    return parsed.protocol
+      + '//'
+      + parsed.host
+      + parsed.pathname
+      + (parsed.search.length ? parsed.search + '&' + params : '?' + params)
+      + parsed.hash;
+  }
+
+  function serializeQueryParams(params, encode) {
+    return serializeObject('', params, encode);
+  }
+
+  function serializeObject(parentKey, object, encode) {
+    var parts = [];
+
+    for (var key in object) {
+      if (!object.hasOwnProperty(key)) {
+        continue;
+      }
+
+      var identifier = parentKey.length ? parentKey + '[' + key + ']' : key;
+
+      if (jsUtil.getTypeOf(object[key]) === 'Array') {
+        parts.push(serializeArray(identifier, object[key], encode));
+        continue;
+      } else if (jsUtil.getTypeOf(object[key]) === 'Object') {
+        parts.push(serializeObject(identifier, object[key], encode));
+        continue;
+      }
+
+      parts.push(serializeIdentifier(parentKey, key, encode) + '=' + serializeValue(object[key], encode));
+    }
+
+    return parts.join('&');
+  }
+
+  function serializeArray(parentKey, array, encode) {
+    var parts = [];
+
+    for (var i = 0; i < array.length; ++i) {
+      if (jsUtil.getTypeOf(array[i]) === 'Array') {
+        parts.push(serializeArray(parentKey + '[]', array[i], encode));
+        continue;
+      } else if (jsUtil.getTypeOf(array[i]) === 'Object') {
+        parts.push(serializeObject(parentKey + '[]' + array[i], encode));
+        continue;
+      }
+
+      parts.push(serializeIdentifier(parentKey, '', encode) + '=' + serializeValue(array[i], encode));
+    }
+
+    return parts.join('&');
+  }
+
+  function serializeIdentifier(parentKey, key, encode) {
+    if (!parentKey.length) {
+      return encode ? encodeURIComponent(key) : key;
+    }
+
+    if (encode) {
+      return encodeURIComponent(parentKey) + '[' + encodeURIComponent(key) + ']';
+    } else {
+      return parentKey + '[' + key + ']';
+    }
+  }
+
+  function serializeValue(value, encode) {
+    if (encode) {
+      return encodeURIComponent(value);
+    } else {
+      return value;
+    }
+  }
+};
+
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-camera/www/Camera.js b/platforms/android/platform_www/plugins/cordova-plugin-camera/www/Camera.js
new file mode 100644
index 0000000..3f614ec
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-camera/www/Camera.js
@@ -0,0 +1,188 @@
+cordova.define("cordova-plugin-camera.camera", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var argscheck = require('cordova/argscheck');
+var exec = require('cordova/exec');
+var Camera = require('./Camera');
+// XXX: commented out
+// CameraPopoverHandle = require('./CameraPopoverHandle');
+
+/**
+ * @namespace navigator
+ */
+
+/**
+ * @exports camera
+ */
+var cameraExport = {};
+
+// Tack on the Camera Constants to the base camera plugin.
+for (var key in Camera) {
+    cameraExport[key] = Camera[key];
+}
+
+/**
+ * Callback function that provides an error message.
+ * @callback module:camera.onError
+ * @param {string} message - The message is provided by the device's native code.
+ */
+
+/**
+ * Callback function that provides the image data.
+ * @callback module:camera.onSuccess
+ * @param {string} imageData - Base64 encoding of the image data, _or_ the image file URI, depending on [`cameraOptions`]{@link module:camera.CameraOptions} in effect.
+ * @example
+ * // Show image
+ * //
+ * function cameraCallback(imageData) {
+ *    var image = document.getElementById('myImage');
+ *    image.src = "data:image/jpeg;base64," + imageData;
+ * }
+ */
+
+/**
+ * Optional parameters to customize the camera settings.
+ * * [Quirks](#CameraOptions-quirks)
+ * @typedef module:camera.CameraOptions
+ * @type {Object}
+ * @property {number} [quality=50] - Quality of the saved image, expressed as a range of 0-100, where 100 is typically full resolution with no loss from file compression. (Note that information about the camera's resolution is unavailable.)
+ * @property {module:Camera.DestinationType} [destinationType=FILE_URI] - Choose the format of the return value.
+ * @property {module:Camera.PictureSourceType} [sourceType=CAMERA] - Set the source of the picture.
+ * @property {Boolean} [allowEdit=false] - Allow simple editing of image before selection.
+ * @property {module:Camera.EncodingType} [encodingType=JPEG] - Choose the  returned image file's encoding.
+ * @property {number} [targetWidth] - Width in pixels to scale image. Must be used with `targetHeight`. Aspect ratio remains constant.
+ * @property {number} [targetHeight] - Height in pixels to scale image. Must be used with `targetWidth`. Aspect ratio remains constant.
+ * @property {module:Camera.MediaType} [mediaType=PICTURE] - Set the type of media to select from.  Only works when `PictureSourceType` is `PHOTOLIBRARY` or `SAVEDPHOTOALBUM`.
+ * @property {Boolean} [correctOrientation] - Rotate the image to correct for the orientation of the device during capture.
+ * @property {Boolean} [saveToPhotoAlbum] - Save the image to the photo album on the device after capture.
+ * @property {module:CameraPopoverOptions} [popoverOptions] - iOS-only options that specify popover location in iPad.
+ * @property {module:Camera.Direction} [cameraDirection=BACK] - Choose the camera to use (front- or back-facing).
+ */
+
+/**
+ * @description Takes a photo using the camera, or retrieves a photo from the device's
+ * image gallery.  The image is passed to the success callback as a
+ * Base64-encoded `String`, or as the URI for the image file.
+ *
+ * The `camera.getPicture` function opens the device's default camera
+ * application that allows users to snap pictures by default - this behavior occurs,
+ * when `Camera.sourceType` equals [`Camera.PictureSourceType.CAMERA`]{@link module:Camera.PictureSourceType}.
+ * Once the user snaps the photo, the camera application closes and the application is restored.
+ *
+ * If `Camera.sourceType` is `Camera.PictureSourceType.PHOTOLIBRARY` or
+ * `Camera.PictureSourceType.SAVEDPHOTOALBUM`, then a dialog displays
+ * that allows users to select an existing image.
+ *
+ * The return value is sent to the [`cameraSuccess`]{@link module:camera.onSuccess} callback function, in
+ * one of the following formats, depending on the specified
+ * `cameraOptions`:
+ *
+ * - A `String` containing the Base64-encoded photo image.
+ * - A `String` representing the image file location on local storage (default).
+ *
+ * You can do whatever you want with the encoded image or URI, for
+ * example:
+ *
+ * - Render the image in an `<img>` tag, as in the example below
+ * - Save the data locally (`LocalStorage`, [Lawnchair](http://brianleroux.github.com/lawnchair/), etc.)
+ * - Post the data to a remote server
+ *
+ * __NOTE__: Photo resolution on newer devices is quite good. Photos
+ * selected from the device's gallery are not downscaled to a lower
+ * quality, even if a `quality` parameter is specified.  To avoid common
+ * memory problems, set `Camera.destinationType` to `FILE_URI` rather
+ * than `DATA_URL`.
+ *
+ * __Supported Platforms__
+ *
+ * - Android
+ * - BlackBerry
+ * - Browser
+ * - Firefox
+ * - FireOS
+ * - iOS
+ * - Windows
+ * - WP8
+ * - Ubuntu
+ *
+ * More examples [here](#camera-getPicture-examples). Quirks [here](#camera-getPicture-quirks).
+ *
+ * @example
+ * navigator.camera.getPicture(cameraSuccess, cameraError, cameraOptions);
+ * @param {module:camera.onSuccess} successCallback
+ * @param {module:camera.onError} errorCallback
+ * @param {module:camera.CameraOptions} options CameraOptions
+ */
+cameraExport.getPicture = function (successCallback, errorCallback, options) {
+    argscheck.checkArgs('fFO', 'Camera.getPicture', arguments);
+    options = options || {};
+    var getValue = argscheck.getValue;
+
+    var quality = getValue(options.quality, 50);
+    var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI);
+    var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA);
+    var targetWidth = getValue(options.targetWidth, -1);
+    var targetHeight = getValue(options.targetHeight, -1);
+    var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG);
+    var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE);
+    var allowEdit = !!options.allowEdit;
+    var correctOrientation = !!options.correctOrientation;
+    var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
+    var popoverOptions = getValue(options.popoverOptions, null);
+    var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
+
+    var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
+        mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
+
+    exec(successCallback, errorCallback, 'Camera', 'takePicture', args);
+    // XXX: commented out
+    // return new CameraPopoverHandle();
+};
+
+/**
+ * Removes intermediate image files that are kept in temporary storage
+ * after calling [`camera.getPicture`]{@link module:camera.getPicture}. Applies only when the value of
+ * `Camera.sourceType` equals `Camera.PictureSourceType.CAMERA` and the
+ * `Camera.destinationType` equals `Camera.DestinationType.FILE_URI`.
+ *
+ * __Supported Platforms__
+ *
+ * - iOS
+ *
+ * @example
+ * navigator.camera.cleanup(onSuccess, onFail);
+ *
+ * function onSuccess() {
+ *     console.log("Camera cleanup success.")
+ * }
+ *
+ * function onFail(message) {
+ *     alert('Failed because: ' + message);
+ * }
+ */
+cameraExport.cleanup = function (successCallback, errorCallback) {
+    exec(successCallback, errorCallback, 'Camera', 'cleanup', []);
+};
+
+module.exports = cameraExport;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-camera/www/CameraConstants.js b/platforms/android/platform_www/plugins/cordova-plugin-camera/www/CameraConstants.js
new file mode 100644
index 0000000..4f4b046
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-camera/www/CameraConstants.js
@@ -0,0 +1,104 @@
+cordova.define("cordova-plugin-camera.Camera", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * @module Camera
+ */
+module.exports = {
+    /**
+     * @description
+     * Defines the output format of `Camera.getPicture` call.
+     * _Note:_ On iOS passing `DestinationType.NATIVE_URI` along with
+     * `PictureSourceType.PHOTOLIBRARY` or `PictureSourceType.SAVEDPHOTOALBUM` will
+     * disable any image modifications (resize, quality change, cropping, etc.) due
+     * to implementation specific.
+     *
+     * @enum {number}
+     */
+    DestinationType: {
+        /** Return base64 encoded string. DATA_URL can be very memory intensive and cause app crashes or out of memory errors. Use FILE_URI or NATIVE_URI if possible */
+        DATA_URL: 0,
+        /** Return file uri (content://media/external/images/media/2 for Android) */
+        FILE_URI: 1,
+        /** Return native uri (eg. asset-library://... for iOS) */
+        NATIVE_URI: 2
+    },
+    /**
+     * @enum {number}
+     */
+    EncodingType: {
+        /** Return JPEG encoded image */
+        JPEG: 0,
+        /** Return PNG encoded image */
+        PNG: 1
+    },
+    /**
+     * @enum {number}
+     */
+    MediaType: {
+        /** Allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType */
+        PICTURE: 0,
+        /** Allow selection of video only, ONLY RETURNS URL */
+        VIDEO: 1,
+        /** Allow selection from all media types */
+        ALLMEDIA: 2
+    },
+    /**
+     * @description
+     * Defines the output format of `Camera.getPicture` call.
+     * _Note:_ On iOS passing `PictureSourceType.PHOTOLIBRARY` or `PictureSourceType.SAVEDPHOTOALBUM`
+     * along with `DestinationType.NATIVE_URI` will disable any image modifications (resize, quality
+     * change, cropping, etc.) due to implementation specific.
+     *
+     * @enum {number}
+     */
+    PictureSourceType: {
+        /** Choose image from the device's photo library (same as SAVEDPHOTOALBUM for Android) */
+        PHOTOLIBRARY: 0,
+        /** Take picture from camera */
+        CAMERA: 1,
+        /** Choose image only from the device's Camera Roll album (same as PHOTOLIBRARY for Android) */
+        SAVEDPHOTOALBUM: 2
+    },
+    /**
+     * Matches iOS UIPopoverArrowDirection constants to specify arrow location on popover.
+     * @enum {number}
+     */
+    PopoverArrowDirection: {
+        ARROW_UP: 1,
+        ARROW_DOWN: 2,
+        ARROW_LEFT: 4,
+        ARROW_RIGHT: 8,
+        ARROW_ANY: 15
+    },
+    /**
+     * @enum {number}
+     */
+    Direction: {
+        /** Use the back-facing camera */
+        BACK: 0,
+        /** Use the front-facing camera */
+        FRONT: 1
+    }
+};
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-camera/www/CameraPopoverHandle.js b/platforms/android/platform_www/plugins/cordova-plugin-camera/www/CameraPopoverHandle.js
new file mode 100644
index 0000000..c970f55
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-camera/www/CameraPopoverHandle.js
@@ -0,0 +1,35 @@
+cordova.define("cordova-plugin-camera.CameraPopoverHandle", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * @ignore in favour of iOS' one
+ * A handle to an image picker popover.
+ */
+var CameraPopoverHandle = function () {
+    this.setPosition = function (popoverOptions) {
+        console.log('CameraPopoverHandle.setPosition is only supported on iOS.');
+    };
+};
+
+module.exports = CameraPopoverHandle;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-camera/www/CameraPopoverOptions.js b/platforms/android/platform_www/plugins/cordova-plugin-camera/www/CameraPopoverOptions.js
new file mode 100644
index 0000000..81d7d20
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-camera/www/CameraPopoverOptions.js
@@ -0,0 +1,55 @@
+cordova.define("cordova-plugin-camera.CameraPopoverOptions", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var Camera = require('./Camera');
+
+/**
+ * @namespace navigator
+ */
+
+/**
+ * iOS-only parameters that specify the anchor element location and arrow
+ * direction of the popover when selecting images from an iPad's library
+ * or album.
+ * Note that the size of the popover may change to adjust to the
+ * direction of the arrow and orientation of the screen.  Make sure to
+ * account for orientation changes when specifying the anchor element
+ * location.
+ * @module CameraPopoverOptions
+ * @param {Number} [x=0] - x pixel coordinate of screen element onto which to anchor the popover.
+ * @param {Number} [y=32] - y pixel coordinate of screen element onto which to anchor the popover.
+ * @param {Number} [width=320] - width, in pixels, of the screen element onto which to anchor the popover.
+ * @param {Number} [height=480] - height, in pixels, of the screen element onto which to anchor the popover.
+ * @param {module:Camera.PopoverArrowDirection} [arrowDir=ARROW_ANY] - Direction the arrow on the popover should point.
+ */
+var CameraPopoverOptions = function (x, y, width, height, arrowDir) {
+    // information of rectangle that popover should be anchored to
+    this.x = x || 0;
+    this.y = y || 32;
+    this.width = width || 320;
+    this.height = height || 480;
+    this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY;
+};
+
+module.exports = CameraPopoverOptions;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-device/www/device.js b/platforms/android/platform_www/plugins/cordova-plugin-device/www/device.js
new file mode 100644
index 0000000..ae48e35
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-device/www/device.js
@@ -0,0 +1,86 @@
+cordova.define("cordova-plugin-device.device", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var argscheck = require('cordova/argscheck');
+var channel = require('cordova/channel');
+var utils = require('cordova/utils');
+var exec = require('cordova/exec');
+var cordova = require('cordova');
+
+channel.createSticky('onCordovaInfoReady');
+// Tell cordova channel to wait on the CordovaInfoReady event
+channel.waitForInitialization('onCordovaInfoReady');
+
+/**
+ * This represents the mobile device, and provides properties for inspecting the model, version, UUID of the
+ * phone, etc.
+ * @constructor
+ */
+function Device () {
+    this.available = false;
+    this.platform = null;
+    this.version = null;
+    this.uuid = null;
+    this.cordova = null;
+    this.model = null;
+    this.manufacturer = null;
+    this.isVirtual = null;
+    this.serial = null;
+
+    var me = this;
+
+    channel.onCordovaReady.subscribe(function () {
+        me.getInfo(function (info) {
+            // ignoring info.cordova returning from native, we should use value from cordova.version defined in cordova.js
+            // TODO: CB-5105 native implementations should not return info.cordova
+            var buildLabel = cordova.version;
+            me.available = true;
+            me.platform = info.platform;
+            me.version = info.version;
+            me.uuid = info.uuid;
+            me.cordova = buildLabel;
+            me.model = info.model;
+            me.isVirtual = info.isVirtual;
+            me.manufacturer = info.manufacturer || 'unknown';
+            me.serial = info.serial || 'unknown';
+            channel.onCordovaInfoReady.fire();
+        }, function (e) {
+            me.available = false;
+            utils.alert('[ERROR] Error initializing Cordova: ' + e);
+        });
+    });
+}
+
+/**
+ * Get device info
+ *
+ * @param {Function} successCallback The function to call when the heading data is available
+ * @param {Function} errorCallback The function to call when there is an error getting the heading data. (OPTIONAL)
+ */
+Device.prototype.getInfo = function (successCallback, errorCallback) {
+    argscheck.checkArgs('fF', 'Device.getInfo', arguments);
+    exec(successCallback, errorCallback, 'Device', 'getDeviceInfo', []);
+};
+
+module.exports = new Device();
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/DirectoryEntry.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/DirectoryEntry.js
new file mode 100644
index 0000000..bb676eb
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/DirectoryEntry.js
@@ -0,0 +1,120 @@
+cordova.define("cordova-plugin-file.DirectoryEntry", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var argscheck = require('cordova/argscheck');
+var utils = require('cordova/utils');
+var exec = require('cordova/exec');
+var Entry = require('./Entry');
+var FileError = require('./FileError');
+var DirectoryReader = require('./DirectoryReader');
+
+/**
+ * An interface representing a directory on the file system.
+ *
+ * {boolean} isFile always false (readonly)
+ * {boolean} isDirectory always true (readonly)
+ * {DOMString} name of the directory, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the directory (readonly)
+ * {FileSystem} filesystem on which the directory resides (readonly)
+ */
+var DirectoryEntry = function (name, fullPath, fileSystem, nativeURL) {
+
+    // add trailing slash if it is missing
+    if ((fullPath) && !/\/$/.test(fullPath)) {
+        fullPath += '/';
+    }
+    // add trailing slash if it is missing
+    if (nativeURL && !/\/$/.test(nativeURL)) {
+        nativeURL += '/';
+    }
+    DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath, fileSystem, nativeURL);
+};
+
+utils.extend(DirectoryEntry, Entry);
+
+/**
+ * Creates a new DirectoryReader to read entries from this directory
+ */
+DirectoryEntry.prototype.createReader = function () {
+    return new DirectoryReader(this.toInternalURL());
+};
+
+/**
+ * Creates or looks up a directory
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory
+ * @param {Flags} options to create or exclusively create the directory
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getDirectory = function (path, options, successCallback, errorCallback) {
+    argscheck.checkArgs('sOFF', 'DirectoryEntry.getDirectory', arguments);
+    var fs = this.filesystem;
+    var win = successCallback && function (result) {
+        var entry = new DirectoryEntry(result.name, result.fullPath, fs, result.nativeURL);
+        successCallback(entry);
+    };
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, 'File', 'getDirectory', [this.toInternalURL(), path, options]);
+};
+
+/**
+ * Deletes a directory and all of it's contents
+ *
+ * @param {Function} successCallback is called with no parameters
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.removeRecursively = function (successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'DirectoryEntry.removeRecursively', arguments);
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    exec(successCallback, fail, 'File', 'removeRecursively', [this.toInternalURL()]);
+};
+
+/**
+ * Creates or looks up a file
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file
+ * @param {Flags} options to create or exclusively create the file
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getFile = function (path, options, successCallback, errorCallback) {
+    argscheck.checkArgs('sOFF', 'DirectoryEntry.getFile', arguments);
+    var fs = this.filesystem;
+    var win = successCallback && function (result) {
+        var FileEntry = require('./FileEntry');
+        var entry = new FileEntry(result.name, result.fullPath, fs, result.nativeURL);
+        successCallback(entry);
+    };
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, 'File', 'getFile', [this.toInternalURL(), path, options]);
+};
+
+module.exports = DirectoryEntry;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/DirectoryReader.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/DirectoryReader.js
new file mode 100644
index 0000000..417c85f
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/DirectoryReader.js
@@ -0,0 +1,75 @@
+cordova.define("cordova-plugin-file.DirectoryReader", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var exec = require('cordova/exec');
+var FileError = require('./FileError');
+
+/**
+ * An interface that lists the files and directories in a directory.
+ */
+function DirectoryReader (localURL) {
+    this.localURL = localURL || null;
+    this.hasReadEntries = false;
+}
+
+/**
+ * Returns a list of entries from a directory.
+ *
+ * @param {Function} successCallback is called with a list of entries
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryReader.prototype.readEntries = function (successCallback, errorCallback) {
+    // If we've already read and passed on this directory's entries, return an empty list.
+    if (this.hasReadEntries) {
+        successCallback([]);
+        return;
+    }
+    var reader = this;
+    var win = typeof successCallback !== 'function' ? null : function (result) {
+        var retVal = [];
+        for (var i = 0; i < result.length; i++) {
+            var entry = null;
+            if (result[i].isDirectory) {
+                entry = new (require('./DirectoryEntry'))();
+            } else if (result[i].isFile) {
+                entry = new (require('./FileEntry'))();
+            }
+            entry.isDirectory = result[i].isDirectory;
+            entry.isFile = result[i].isFile;
+            entry.name = result[i].name;
+            entry.fullPath = result[i].fullPath;
+            entry.filesystem = new (require('./FileSystem'))(result[i].filesystemName);
+            entry.nativeURL = result[i].nativeURL;
+            retVal.push(entry);
+        }
+        reader.hasReadEntries = true;
+        successCallback(retVal);
+    };
+    var fail = typeof errorCallback !== 'function' ? null : function (code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, 'File', 'readEntries', [this.localURL]);
+};
+
+module.exports = DirectoryReader;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/Entry.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/Entry.js
new file mode 100644
index 0000000..b296d99
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/Entry.js
@@ -0,0 +1,263 @@
+cordova.define("cordova-plugin-file.Entry", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var argscheck = require('cordova/argscheck');
+var exec = require('cordova/exec');
+var FileError = require('./FileError');
+var Metadata = require('./Metadata');
+
+/**
+ * Represents a file or directory on the local file system.
+ *
+ * @param isFile
+ *            {boolean} true if Entry is a file (readonly)
+ * @param isDirectory
+ *            {boolean} true if Entry is a directory (readonly)
+ * @param name
+ *            {DOMString} name of the file or directory, excluding the path
+ *            leading to it (readonly)
+ * @param fullPath
+ *            {DOMString} the absolute full path to the file or directory
+ *            (readonly)
+ * @param fileSystem
+ *            {FileSystem} the filesystem on which this entry resides
+ *            (readonly)
+ * @param nativeURL
+ *            {DOMString} an alternate URL which can be used by native
+ *            webview controls, for example media players.
+ *            (optional, readonly)
+ */
+function Entry (isFile, isDirectory, name, fullPath, fileSystem, nativeURL) {
+    this.isFile = !!isFile;
+    this.isDirectory = !!isDirectory;
+    this.name = name || '';
+    this.fullPath = fullPath || '';
+    this.filesystem = fileSystem || null;
+    this.nativeURL = nativeURL || null;
+}
+
+/**
+ * Look up the metadata of the entry.
+ *
+ * @param successCallback
+ *            {Function} is called with a Metadata object
+ * @param errorCallback
+ *            {Function} is called with a FileError
+ */
+Entry.prototype.getMetadata = function (successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'Entry.getMetadata', arguments);
+    var success = successCallback && function (entryMetadata) {
+        var metadata = new Metadata({
+            size: entryMetadata.size,
+            modificationTime: entryMetadata.lastModifiedDate
+        });
+        successCallback(metadata);
+    };
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    exec(success, fail, 'File', 'getFileMetadata', [this.toInternalURL()]);
+};
+
+/**
+ * Set the metadata of the entry.
+ *
+ * @param successCallback
+ *            {Function} is called with a Metadata object
+ * @param errorCallback
+ *            {Function} is called with a FileError
+ * @param metadataObject
+ *            {Object} keys and values to set
+ */
+Entry.prototype.setMetadata = function (successCallback, errorCallback, metadataObject) {
+    argscheck.checkArgs('FFO', 'Entry.setMetadata', arguments);
+    exec(successCallback, errorCallback, 'File', 'setMetadata', [this.toInternalURL(), metadataObject]);
+};
+
+/**
+ * Move a file or directory to a new location.
+ *
+ * @param parent
+ *            {DirectoryEntry} the directory to which to move this entry
+ * @param newName
+ *            {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ *            {Function} called with the new DirectoryEntry object
+ * @param errorCallback
+ *            {Function} called with a FileError
+ */
+Entry.prototype.moveTo = function (parent, newName, successCallback, errorCallback) {
+    argscheck.checkArgs('oSFF', 'Entry.moveTo', arguments);
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    var srcURL = this.toInternalURL();
+    // entry name
+    var name = newName || this.name;
+    var success = function (entry) {
+        if (entry) {
+            if (successCallback) {
+                // create appropriate Entry object
+                var newFSName = entry.filesystemName || (entry.filesystem && entry.filesystem.name);
+                var fs = newFSName ? new FileSystem(newFSName, { name: '', fullPath: '/' }) : new FileSystem(parent.filesystem.name, { name: '', fullPath: '/' }); // eslint-disable-line no-undef
+                var result = (entry.isDirectory) ? new (require('./DirectoryEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL) : new (require('cordova-plugin-file.FileEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL);
+                successCallback(result);
+            }
+        } else {
+            // no Entry object returned
+            if (fail) {
+                fail(FileError.NOT_FOUND_ERR);
+            }
+        }
+    };
+
+    // copy
+    exec(success, fail, 'File', 'moveTo', [srcURL, parent.toInternalURL(), name]);
+};
+
+/**
+ * Copy a directory to a different location.
+ *
+ * @param parent
+ *            {DirectoryEntry} the directory to which to copy the entry
+ * @param newName
+ *            {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ *            {Function} called with the new Entry object
+ * @param errorCallback
+ *            {Function} called with a FileError
+ */
+Entry.prototype.copyTo = function (parent, newName, successCallback, errorCallback) {
+    argscheck.checkArgs('oSFF', 'Entry.copyTo', arguments);
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    var srcURL = this.toInternalURL();
+        // entry name
+    var name = newName || this.name;
+    // success callback
+    var success = function (entry) {
+        if (entry) {
+            if (successCallback) {
+                // create appropriate Entry object
+                var newFSName = entry.filesystemName || (entry.filesystem && entry.filesystem.name);
+                var fs = newFSName ? new FileSystem(newFSName, { name: '', fullPath: '/' }) : new FileSystem(parent.filesystem.name, { name: '', fullPath: '/' }); // eslint-disable-line no-undef
+                var result = (entry.isDirectory) ? new (require('./DirectoryEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL) : new (require('cordova-plugin-file.FileEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL);
+                successCallback(result);
+            }
+        } else {
+            // no Entry object returned
+            if (fail) {
+                fail(FileError.NOT_FOUND_ERR);
+            }
+        }
+    };
+
+    // copy
+    exec(success, fail, 'File', 'copyTo', [srcURL, parent.toInternalURL(), name]);
+};
+
+/**
+ * Return a URL that can be passed across the bridge to identify this entry.
+ */
+Entry.prototype.toInternalURL = function () {
+    if (this.filesystem && this.filesystem.__format__) {
+        return this.filesystem.__format__(this.fullPath, this.nativeURL);
+    }
+};
+
+/**
+ * Return a URL that can be used to identify this entry.
+ * Use a URL that can be used to as the src attribute of a <video> or
+ * <audio> tag. If that is not possible, construct a cdvfile:// URL.
+ */
+Entry.prototype.toURL = function () {
+    if (this.nativeURL) {
+        return this.nativeURL;
+    }
+    // fullPath attribute may contain the full URL in the case that
+    // toInternalURL fails.
+    return this.toInternalURL() || 'file://localhost' + this.fullPath;
+};
+
+/**
+ * Backwards-compatibility: In v1.0.0 - 1.0.2, .toURL would only return a
+ * cdvfile:// URL, and this method was necessary to obtain URLs usable by the
+ * webview.
+ * See CB-6051, CB-6106, CB-6117, CB-6152, CB-6199, CB-6201, CB-6243, CB-6249,
+ * and CB-6300.
+ */
+Entry.prototype.toNativeURL = function () {
+    console.log("DEPRECATED: Update your code to use 'toURL'");
+    return this.toURL();
+};
+
+/**
+ * Returns a URI that can be used to identify this entry.
+ *
+ * @param {DOMString} mimeType for a FileEntry, the mime type to be used to interpret the file, when loaded through this URI.
+ * @return uri
+ */
+Entry.prototype.toURI = function (mimeType) {
+    console.log("DEPRECATED: Update your code to use 'toURL'");
+    return this.toURL();
+};
+
+/**
+ * Remove a file or directory. It is an error to attempt to delete a
+ * directory that is not empty. It is an error to attempt to delete a
+ * root directory of a file system.
+ *
+ * @param successCallback {Function} called with no parameters
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.remove = function (successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'Entry.remove', arguments);
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    exec(successCallback, fail, 'File', 'remove', [this.toInternalURL()]);
+};
+
+/**
+ * Look up the parent DirectoryEntry of this entry.
+ *
+ * @param successCallback {Function} called with the parent DirectoryEntry object
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.getParent = function (successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'Entry.getParent', arguments);
+    var fs = this.filesystem;
+    var win = successCallback && function (result) {
+        var DirectoryEntry = require('./DirectoryEntry');
+        var entry = new DirectoryEntry(result.name, result.fullPath, fs, result.nativeURL);
+        successCallback(entry);
+    };
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, 'File', 'getParent', [this.toInternalURL()]);
+};
+
+module.exports = Entry;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/File.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/File.js
new file mode 100644
index 0000000..c771786
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/File.js
@@ -0,0 +1,81 @@
+cordova.define("cordova-plugin-file.File", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * Constructor.
+ * name {DOMString} name of the file, without path information
+ * fullPath {DOMString} the full path of the file, including the name
+ * type {DOMString} mime type
+ * lastModifiedDate {Date} last modified date
+ * size {Number} size of the file in bytes
+ */
+
+var File = function (name, localURL, type, lastModifiedDate, size) {
+    this.name = name || '';
+    this.localURL = localURL || null;
+    this.type = type || null;
+    this.lastModified = lastModifiedDate || null;
+    // For backwards compatibility, store the timestamp in lastModifiedDate as well
+    this.lastModifiedDate = lastModifiedDate || null;
+    this.size = size || 0;
+
+    // These store the absolute start and end for slicing the file.
+    this.start = 0;
+    this.end = this.size;
+};
+
+/**
+ * Returns a "slice" of the file. Since Cordova Files don't contain the actual
+ * content, this really returns a File with adjusted start and end.
+ * Slices of slices are supported.
+ * start {Number} The index at which to start the slice (inclusive).
+ * end {Number} The index at which to end the slice (exclusive).
+ */
+File.prototype.slice = function (start, end) {
+    var size = this.end - this.start;
+    var newStart = 0;
+    var newEnd = size;
+    if (arguments.length) {
+        if (start < 0) {
+            newStart = Math.max(size + start, 0);
+        } else {
+            newStart = Math.min(size, start);
+        }
+    }
+
+    if (arguments.length >= 2) {
+        if (end < 0) {
+            newEnd = Math.max(size + end, 0);
+        } else {
+            newEnd = Math.min(end, size);
+        }
+    }
+
+    var newFile = new File(this.name, this.localURL, this.type, this.lastModified, this.size);
+    newFile.start = this.start + newStart;
+    newFile.end = this.start + newEnd;
+    return newFile;
+};
+
+module.exports = File;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileEntry.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileEntry.js
new file mode 100644
index 0000000..6651b55
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileEntry.js
@@ -0,0 +1,95 @@
+cordova.define("cordova-plugin-file.FileEntry", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var utils = require('cordova/utils');
+var exec = require('cordova/exec');
+var Entry = require('./Entry');
+var FileWriter = require('./FileWriter');
+var File = require('./File');
+var FileError = require('./FileError');
+
+/**
+ * An interface representing a file on the file system.
+ *
+ * {boolean} isFile always true (readonly)
+ * {boolean} isDirectory always false (readonly)
+ * {DOMString} name of the file, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the file (readonly)
+ * {FileSystem} filesystem on which the file resides (readonly)
+ */
+var FileEntry = function (name, fullPath, fileSystem, nativeURL) {
+    // remove trailing slash if it is present
+    if (fullPath && /\/$/.test(fullPath)) {
+        fullPath = fullPath.substring(0, fullPath.length - 1);
+    }
+    if (nativeURL && /\/$/.test(nativeURL)) {
+        nativeURL = nativeURL.substring(0, nativeURL.length - 1);
+    }
+
+    FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath, fileSystem, nativeURL]);
+};
+
+utils.extend(FileEntry, Entry);
+
+/**
+ * Creates a new FileWriter associated with the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new FileWriter
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.createWriter = function (successCallback, errorCallback) {
+    this.file(function (filePointer) {
+        var writer = new FileWriter(filePointer);
+
+        if (writer.localURL === null || writer.localURL === '') {
+            if (errorCallback) {
+                errorCallback(new FileError(FileError.INVALID_STATE_ERR));
+            }
+        } else {
+            if (successCallback) {
+                successCallback(writer);
+            }
+        }
+    }, errorCallback);
+};
+
+/**
+ * Returns a File that represents the current state of the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new File object
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.file = function (successCallback, errorCallback) {
+    var localURL = this.toInternalURL();
+    var win = successCallback && function (f) {
+        var file = new File(f.name, localURL, f.type, f.lastModifiedDate, f.size);
+        successCallback(file);
+    };
+    var fail = errorCallback && function (code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, 'File', 'getFileMetadata', [localURL]);
+};
+
+module.exports = FileEntry;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileError.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileError.js
new file mode 100644
index 0000000..f378c38
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileError.js
@@ -0,0 +1,49 @@
+cordova.define("cordova-plugin-file.FileError", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * FileError
+ */
+function FileError (error) {
+    this.code = error || null;
+}
+
+// File error codes
+// Found in DOMException
+FileError.NOT_FOUND_ERR = 1;
+FileError.SECURITY_ERR = 2;
+FileError.ABORT_ERR = 3;
+
+// Added by File API specification
+FileError.NOT_READABLE_ERR = 4;
+FileError.ENCODING_ERR = 5;
+FileError.NO_MODIFICATION_ALLOWED_ERR = 6;
+FileError.INVALID_STATE_ERR = 7;
+FileError.SYNTAX_ERR = 8;
+FileError.INVALID_MODIFICATION_ERR = 9;
+FileError.QUOTA_EXCEEDED_ERR = 10;
+FileError.TYPE_MISMATCH_ERR = 11;
+FileError.PATH_EXISTS_ERR = 12;
+
+module.exports = FileError;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileReader.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileReader.js
new file mode 100644
index 0000000..5c03091
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileReader.js
@@ -0,0 +1,301 @@
+cordova.define("cordova-plugin-file.FileReader", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var exec = require('cordova/exec');
+var modulemapper = require('cordova/modulemapper');
+var utils = require('cordova/utils');
+var FileError = require('./FileError');
+var ProgressEvent = require('./ProgressEvent');
+var origFileReader = modulemapper.getOriginalSymbol(window, 'FileReader');
+
+/**
+ * This class reads the mobile device file system.
+ *
+ * For Android:
+ *      The root directory is the root of the file system.
+ *      To read from the SD card, the file name is "sdcard/my_file.txt"
+ * @constructor
+ */
+var FileReader = function () {
+    this._readyState = 0;
+    this._error = null;
+    this._result = null;
+    this._progress = null;
+    this._localURL = '';
+    this._realReader = origFileReader ? new origFileReader() : {}; // eslint-disable-line new-cap
+};
+
+/**
+ * Defines the maximum size to read at a time via the native API. The default value is a compromise between
+ * minimizing the overhead of many exec() calls while still reporting progress frequently enough for large files.
+ * (Note attempts to allocate more than a few MB of contiguous memory on the native side are likely to cause
+ * OOM exceptions, while the JS engine seems to have fewer problems managing large strings or ArrayBuffers.)
+ */
+FileReader.READ_CHUNK_SIZE = 256 * 1024;
+
+// States
+FileReader.EMPTY = 0;
+FileReader.LOADING = 1;
+FileReader.DONE = 2;
+
+utils.defineGetter(FileReader.prototype, 'readyState', function () {
+    return this._localURL ? this._readyState : this._realReader.readyState;
+});
+
+utils.defineGetter(FileReader.prototype, 'error', function () {
+    return this._localURL ? this._error : this._realReader.error;
+});
+
+utils.defineGetter(FileReader.prototype, 'result', function () {
+    return this._localURL ? this._result : this._realReader.result;
+});
+
+function defineEvent (eventName) {
+    utils.defineGetterSetter(FileReader.prototype, eventName, function () {
+        return this._realReader[eventName] || null;
+    }, function (value) {
+        this._realReader[eventName] = value;
+    });
+}
+defineEvent('onloadstart');    // When the read starts.
+defineEvent('onprogress');     // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total)
+defineEvent('onload');         // When the read has successfully completed.
+defineEvent('onerror');        // When the read has failed (see errors).
+defineEvent('onloadend');      // When the request has completed (either in success or failure).
+defineEvent('onabort');        // When the read has been aborted. For instance, by invoking the abort() method.
+
+function initRead (reader, file) {
+    // Already loading something
+    if (reader.readyState === FileReader.LOADING) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    reader._result = null;
+    reader._error = null;
+    reader._progress = 0;
+    reader._readyState = FileReader.LOADING;
+
+    if (typeof file.localURL === 'string') {
+        reader._localURL = file.localURL;
+    } else {
+        reader._localURL = '';
+        return true;
+    }
+
+    if (reader.onloadstart) {
+        reader.onloadstart(new ProgressEvent('loadstart', {target: reader}));
+    }
+}
+
+/**
+ * Callback used by the following read* functions to handle incremental or final success.
+ * Must be bound to the FileReader's this along with all but the last parameter,
+ * e.g. readSuccessCallback.bind(this, "readAsText", "UTF-8", offset, totalSize, accumulate)
+ * @param readType The name of the read function to call.
+ * @param encoding Text encoding, or null if this is not a text type read.
+ * @param offset Starting offset of the read.
+ * @param totalSize Total number of bytes or chars to read.
+ * @param accumulate A function that takes the callback result and accumulates it in this._result.
+ * @param r Callback result returned by the last read exec() call, or null to begin reading.
+ */
+function readSuccessCallback (readType, encoding, offset, totalSize, accumulate, r) {
+    if (this._readyState === FileReader.DONE) {
+        return;
+    }
+
+    var CHUNK_SIZE = FileReader.READ_CHUNK_SIZE;
+    if (readType === 'readAsDataURL') {
+        // Windows proxy does not support reading file slices as Data URLs
+        // so read the whole file at once.
+        CHUNK_SIZE = cordova.platformId === 'windows' ? totalSize : // eslint-disable-line no-undef
+            // Calculate new chunk size for data URLs to be multiply of 3
+            // Otherwise concatenated base64 chunks won't be valid base64 data
+            FileReader.READ_CHUNK_SIZE - (FileReader.READ_CHUNK_SIZE % 3) + 3;
+    }
+
+    if (typeof r !== 'undefined') {
+        accumulate(r);
+        this._progress = Math.min(this._progress + CHUNK_SIZE, totalSize);
+
+        if (typeof this.onprogress === 'function') {
+            this.onprogress(new ProgressEvent('progress', {loaded: this._progress, total: totalSize}));
+        }
+    }
+
+    if (typeof r === 'undefined' || this._progress < totalSize) {
+        var execArgs = [
+            this._localURL,
+            offset + this._progress,
+            offset + this._progress + Math.min(totalSize - this._progress, CHUNK_SIZE)];
+        if (encoding) {
+            execArgs.splice(1, 0, encoding);
+        }
+        exec(
+            readSuccessCallback.bind(this, readType, encoding, offset, totalSize, accumulate),
+            readFailureCallback.bind(this),
+            'File', readType, execArgs);
+    } else {
+        this._readyState = FileReader.DONE;
+
+        if (typeof this.onload === 'function') {
+            this.onload(new ProgressEvent('load', {target: this}));
+        }
+
+        if (typeof this.onloadend === 'function') {
+            this.onloadend(new ProgressEvent('loadend', {target: this}));
+        }
+    }
+}
+
+/**
+ * Callback used by the following read* functions to handle errors.
+ * Must be bound to the FileReader's this, e.g. readFailureCallback.bind(this)
+ */
+function readFailureCallback (e) {
+    if (this._readyState === FileReader.DONE) {
+        return;
+    }
+
+    this._readyState = FileReader.DONE;
+    this._result = null;
+    this._error = new FileError(e);
+
+    if (typeof this.onerror === 'function') {
+        this.onerror(new ProgressEvent('error', {target: this}));
+    }
+
+    if (typeof this.onloadend === 'function') {
+        this.onloadend(new ProgressEvent('loadend', {target: this}));
+    }
+}
+
+/**
+ * Abort reading file.
+ */
+FileReader.prototype.abort = function () {
+    if (origFileReader && !this._localURL) {
+        return this._realReader.abort();
+    }
+    this._result = null;
+
+    if (this._readyState === FileReader.DONE || this._readyState === FileReader.EMPTY) {
+        return;
+    }
+
+    this._readyState = FileReader.DONE;
+
+    // If abort callback
+    if (typeof this.onabort === 'function') {
+        this.onabort(new ProgressEvent('abort', {target: this}));
+    }
+    // If load end callback
+    if (typeof this.onloadend === 'function') {
+        this.onloadend(new ProgressEvent('loadend', {target: this}));
+    }
+};
+
+/**
+ * Read text file.
+ *
+ * @param file          {File} File object containing file properties
+ * @param encoding      [Optional] (see http://www.iana.org/assignments/character-sets)
+ */
+FileReader.prototype.readAsText = function (file, encoding) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsText(file, encoding);
+    }
+
+    // Default encoding is UTF-8
+    var enc = encoding || 'UTF-8';
+
+    var totalSize = file.end - file.start;
+    readSuccessCallback.bind(this)('readAsText', enc, file.start, totalSize, function (r) {
+        if (this._progress === 0) {
+            this._result = '';
+        }
+        this._result += r;
+    }.bind(this));
+};
+
+/**
+ * Read file and return data as a base64 encoded data url.
+ * A data url is of the form:
+ *      data:[<mediatype>][;base64],<data>
+ *
+ * @param file          {File} File object containing file properties
+ */
+FileReader.prototype.readAsDataURL = function (file) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsDataURL(file);
+    }
+
+    var totalSize = file.end - file.start;
+    readSuccessCallback.bind(this)('readAsDataURL', null, file.start, totalSize, function (r) {
+        var commaIndex = r.indexOf(',');
+        if (this._progress === 0) {
+            this._result = r;
+        } else {
+            this._result += r.substring(commaIndex + 1);
+        }
+    }.bind(this));
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file          {File} File object containing file properties
+ */
+FileReader.prototype.readAsBinaryString = function (file) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsBinaryString(file);
+    }
+
+    var totalSize = file.end - file.start;
+    readSuccessCallback.bind(this)('readAsBinaryString', null, file.start, totalSize, function (r) {
+        if (this._progress === 0) {
+            this._result = '';
+        }
+        this._result += r;
+    }.bind(this));
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file          {File} File object containing file properties
+ */
+FileReader.prototype.readAsArrayBuffer = function (file) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsArrayBuffer(file);
+    }
+
+    var totalSize = file.end - file.start;
+    readSuccessCallback.bind(this)('readAsArrayBuffer', null, file.start, totalSize, function (r) {
+        var resultArray = (this._progress === 0 ? new Uint8Array(totalSize) : new Uint8Array(this._result));
+        resultArray.set(new Uint8Array(r), this._progress);
+        this._result = resultArray.buffer;
+    }.bind(this));
+};
+
+module.exports = FileReader;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileSystem.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileSystem.js
new file mode 100644
index 0000000..ad9ea78
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileSystem.js
@@ -0,0 +1,58 @@
+cordova.define("cordova-plugin-file.FileSystem", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var DirectoryEntry = require('./DirectoryEntry');
+
+/**
+ * An interface representing a file system
+ *
+ * @constructor
+ * {DOMString} name the unique name of the file system (readonly)
+ * {DirectoryEntry} root directory of the file system (readonly)
+ */
+var FileSystem = function (name, root) {
+    this.name = name;
+    if (root) {
+        this.root = new DirectoryEntry(root.name, root.fullPath, this, root.nativeURL);
+    } else {
+        this.root = new DirectoryEntry(this.name, '/', this);
+    }
+};
+
+FileSystem.prototype.__format__ = function (fullPath, nativeUrl) {
+    return fullPath;
+};
+
+FileSystem.prototype.toJSON = function () {
+    return '<FileSystem: ' + this.name + '>';
+};
+
+// Use instead of encodeURI() when encoding just the path part of a URI rather than an entire URI.
+FileSystem.encodeURIPath = function (path) {
+    // Because # is a valid filename character, it must be encoded to prevent part of the
+    // path from being parsed as a URI fragment.
+    return encodeURI(path).replace(/#/g, '%23');
+};
+
+module.exports = FileSystem;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileUploadOptions.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileUploadOptions.js
new file mode 100644
index 0000000..6acd093
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileUploadOptions.js
@@ -0,0 +1,44 @@
+cordova.define("cordova-plugin-file.FileUploadOptions", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * Options to customize the HTTP request used to upload files.
+ * @constructor
+ * @param fileKey {String}   Name of file request parameter.
+ * @param fileName {String}  Filename to be used by the server. Defaults to image.jpg.
+ * @param mimeType {String}  Mimetype of the uploaded file. Defaults to image/jpeg.
+ * @param params {Object}    Object with key: value params to send to the server.
+ * @param headers {Object}   Keys are header names, values are header values. Multiple
+ *                           headers of the same name are not supported.
+ */
+var FileUploadOptions = function (fileKey, fileName, mimeType, params, headers, httpMethod) {
+    this.fileKey = fileKey || null;
+    this.fileName = fileName || null;
+    this.mimeType = mimeType || null;
+    this.params = params || null;
+    this.headers = headers || null;
+    this.httpMethod = httpMethod || null;
+};
+
+module.exports = FileUploadOptions;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileUploadResult.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileUploadResult.js
new file mode 100644
index 0000000..e3c3a74
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileUploadResult.js
@@ -0,0 +1,33 @@
+cordova.define("cordova-plugin-file.FileUploadResult", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * FileUploadResult
+ * @constructor
+ */
+module.exports = function FileUploadResult (size, code, content) {
+    this.bytesSent = size;
+    this.responseCode = code;
+    this.response = content;
+};
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileWriter.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileWriter.js
new file mode 100644
index 0000000..d48a089
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/FileWriter.js
@@ -0,0 +1,327 @@
+cordova.define("cordova-plugin-file.FileWriter", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var exec = require('cordova/exec');
+var FileError = require('./FileError');
+var ProgressEvent = require('./ProgressEvent');
+
+/**
+ * This class writes to the mobile device file system.
+ *
+ * For Android:
+ *      The root directory is the root of the file system.
+ *      To write to the SD card, the file name is "sdcard/my_file.txt"
+ *
+ * @constructor
+ * @param file {File} File object containing file properties
+ * @param append if true write to the end of the file, otherwise overwrite the file
+ */
+var FileWriter = function (file) {
+    this.fileName = '';
+    this.length = 0;
+    if (file) {
+        this.localURL = file.localURL || file;
+        this.length = file.size || 0;
+    }
+    // default is to write at the beginning of the file
+    this.position = 0;
+
+    this.readyState = 0; // EMPTY
+
+    this.result = null;
+
+    // Error
+    this.error = null;
+
+    // Event handlers
+    this.onwritestart = null;   // When writing starts
+    this.onprogress = null;     // While writing the file, and reporting partial file data
+    this.onwrite = null;        // When the write has successfully completed.
+    this.onwriteend = null;     // When the request has completed (either in success or failure).
+    this.onabort = null;        // When the write has been aborted. For instance, by invoking the abort() method.
+    this.onerror = null;        // When the write has failed (see errors).
+};
+
+// States
+FileWriter.INIT = 0;
+FileWriter.WRITING = 1;
+FileWriter.DONE = 2;
+
+/**
+ * Abort writing file.
+ */
+FileWriter.prototype.abort = function () {
+    // check for invalid state
+    if (this.readyState === FileWriter.DONE || this.readyState === FileWriter.INIT) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    // set error
+    this.error = new FileError(FileError.ABORT_ERR);
+
+    this.readyState = FileWriter.DONE;
+
+    // If abort callback
+    if (typeof this.onabort === 'function') {
+        this.onabort(new ProgressEvent('abort', {'target': this}));
+    }
+
+    // If write end callback
+    if (typeof this.onwriteend === 'function') {
+        this.onwriteend(new ProgressEvent('writeend', {'target': this}));
+    }
+};
+
+/**
+ * Writes data to the file
+ *
+ * @param data text or blob to be written
+ * @param isPendingBlobReadResult {Boolean} true if the data is the pending blob read operation result
+ */
+FileWriter.prototype.write = function (data, isPendingBlobReadResult) {
+
+    var that = this;
+    var supportsBinary = (typeof window.Blob !== 'undefined' && typeof window.ArrayBuffer !== 'undefined');
+    /* eslint-disable no-undef */
+    var isProxySupportBlobNatively = (cordova.platformId === 'windows8' || cordova.platformId === 'windows');
+    var isBinary;
+
+    // Check to see if the incoming data is a blob
+    if (data instanceof File || (!isProxySupportBlobNatively && supportsBinary && data instanceof Blob)) {
+        var fileReader = new FileReader();
+        /* eslint-enable no-undef */
+        fileReader.onload = function () {
+            // Call this method again, with the arraybuffer as argument
+            FileWriter.prototype.write.call(that, this.result, true /* isPendingBlobReadResult */);
+        };
+        fileReader.onerror = function () {
+            // DONE state
+            that.readyState = FileWriter.DONE;
+
+            // Save error
+            that.error = this.error;
+
+            // If onerror callback
+            if (typeof that.onerror === 'function') {
+                that.onerror(new ProgressEvent('error', {'target': that}));
+            }
+
+            // If onwriteend callback
+            if (typeof that.onwriteend === 'function') {
+                that.onwriteend(new ProgressEvent('writeend', {'target': that}));
+            }
+        };
+
+        // WRITING state
+        this.readyState = FileWriter.WRITING;
+
+        if (supportsBinary) {
+            fileReader.readAsArrayBuffer(data);
+        } else {
+            fileReader.readAsText(data);
+        }
+        return;
+    }
+
+    // Mark data type for safer transport over the binary bridge
+    isBinary = supportsBinary && (data instanceof ArrayBuffer);
+    if (isBinary && cordova.platformId === 'windowsphone') { // eslint-disable-line no-undef
+        // create a plain array, using the keys from the Uint8Array view so that we can serialize it
+        data = Array.apply(null, new Uint8Array(data));
+    }
+
+    // Throw an exception if we are already writing a file
+    if (this.readyState === FileWriter.WRITING && !isPendingBlobReadResult) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    // WRITING state
+    this.readyState = FileWriter.WRITING;
+
+    var me = this;
+
+    // If onwritestart callback
+    if (typeof me.onwritestart === 'function') {
+        me.onwritestart(new ProgressEvent('writestart', {'target': me}));
+    }
+
+    // Write file
+    exec(
+        // Success callback
+        function (r) {
+            // If DONE (cancelled), then don't do anything
+            if (me.readyState === FileWriter.DONE) {
+                return;
+            }
+
+            // position always increases by bytes written because file would be extended
+            me.position += r;
+            // The length of the file is now where we are done writing.
+
+            me.length = me.position;
+
+            // DONE state
+            me.readyState = FileWriter.DONE;
+
+            // If onwrite callback
+            if (typeof me.onwrite === 'function') {
+                me.onwrite(new ProgressEvent('write', {'target': me}));
+            }
+
+            // If onwriteend callback
+            if (typeof me.onwriteend === 'function') {
+                me.onwriteend(new ProgressEvent('writeend', {'target': me}));
+            }
+        },
+        // Error callback
+        function (e) {
+            // If DONE (cancelled), then don't do anything
+            if (me.readyState === FileWriter.DONE) {
+                return;
+            }
+
+            // DONE state
+            me.readyState = FileWriter.DONE;
+
+            // Save error
+            me.error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === 'function') {
+                me.onerror(new ProgressEvent('error', {'target': me}));
+            }
+
+            // If onwriteend callback
+            if (typeof me.onwriteend === 'function') {
+                me.onwriteend(new ProgressEvent('writeend', {'target': me}));
+            }
+        }, 'File', 'write', [this.localURL, data, this.position, isBinary]);
+};
+
+/**
+ * Moves the file pointer to the location specified.
+ *
+ * If the offset is a negative number the position of the file
+ * pointer is rewound.  If the offset is greater than the file
+ * size the position is set to the end of the file.
+ *
+ * @param offset is the location to move the file pointer to.
+ */
+FileWriter.prototype.seek = function (offset) {
+    // Throw an exception if we are already writing a file
+    if (this.readyState === FileWriter.WRITING) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    if (!offset && offset !== 0) {
+        return;
+    }
+
+    // See back from end of file.
+    if (offset < 0) {
+        this.position = Math.max(offset + this.length, 0);
+    // Offset is bigger than file size so set position
+    // to the end of the file.
+    } else if (offset > this.length) {
+        this.position = this.length;
+    // Offset is between 0 and file size so set the position
+    // to start writing.
+    } else {
+        this.position = offset;
+    }
+};
+
+/**
+ * Truncates the file to the size specified.
+ *
+ * @param size to chop the file at.
+ */
+FileWriter.prototype.truncate = function (size) {
+    // Throw an exception if we are already writing a file
+    if (this.readyState === FileWriter.WRITING) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    // WRITING state
+    this.readyState = FileWriter.WRITING;
+
+    var me = this;
+
+    // If onwritestart callback
+    if (typeof me.onwritestart === 'function') {
+        me.onwritestart(new ProgressEvent('writestart', {'target': this}));
+    }
+
+    // Write file
+    exec(
+        // Success callback
+        function (r) {
+            // If DONE (cancelled), then don't do anything
+            if (me.readyState === FileWriter.DONE) {
+                return;
+            }
+
+            // DONE state
+            me.readyState = FileWriter.DONE;
+
+            // Update the length of the file
+            me.length = r;
+            me.position = Math.min(me.position, r);
+
+            // If onwrite callback
+            if (typeof me.onwrite === 'function') {
+                me.onwrite(new ProgressEvent('write', {'target': me}));
+            }
+
+            // If onwriteend callback
+            if (typeof me.onwriteend === 'function') {
+                me.onwriteend(new ProgressEvent('writeend', {'target': me}));
+            }
+        },
+        // Error callback
+        function (e) {
+            // If DONE (cancelled), then don't do anything
+            if (me.readyState === FileWriter.DONE) {
+                return;
+            }
+
+            // DONE state
+            me.readyState = FileWriter.DONE;
+
+            // Save error
+            me.error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === 'function') {
+                me.onerror(new ProgressEvent('error', {'target': me}));
+            }
+
+            // If onwriteend callback
+            if (typeof me.onwriteend === 'function') {
+                me.onwriteend(new ProgressEvent('writeend', {'target': me}));
+            }
+        }, 'File', 'truncate', [this.localURL, size]);
+};
+
+module.exports = FileWriter;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/Flags.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/Flags.js
new file mode 100644
index 0000000..cdb12bb
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/Flags.js
@@ -0,0 +1,39 @@
+cordova.define("cordova-plugin-file.Flags", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * Supplies arguments to methods that lookup or create files and directories.
+ *
+ * @param create
+ *            {boolean} file or directory if it doesn't exist
+ * @param exclusive
+ *            {boolean} used with create; if true the command will fail if
+ *            target path exists
+ */
+function Flags (create, exclusive) {
+    this.create = create || false;
+    this.exclusive = exclusive || false;
+}
+
+module.exports = Flags;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/LocalFileSystem.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/LocalFileSystem.js
new file mode 100644
index 0000000..4ce6848
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/LocalFileSystem.js
@@ -0,0 +1,26 @@
+cordova.define("cordova-plugin-file.LocalFileSystem", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+exports.TEMPORARY = 0;
+exports.PERSISTENT = 1;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/Metadata.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/Metadata.js
new file mode 100644
index 0000000..22366e1
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/Metadata.js
@@ -0,0 +1,43 @@
+cordova.define("cordova-plugin-file.Metadata", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * Information about the state of the file or directory
+ *
+ * {Date} modificationTime (readonly)
+ */
+var Metadata = function (metadata) {
+    if (typeof metadata === 'object') {
+        this.modificationTime = new Date(metadata.modificationTime);
+        this.size = metadata.size || 0;
+    } else if (typeof metadata === 'undefined') {
+        this.modificationTime = null;
+        this.size = 0;
+    } else {
+        /* Backwards compatiblity with platforms that only return a timestamp */
+        this.modificationTime = new Date(metadata);
+    }
+};
+
+module.exports = Metadata;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/ProgressEvent.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/ProgressEvent.js
new file mode 100644
index 0000000..cbecdb1
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/ProgressEvent.js
@@ -0,0 +1,70 @@
+cordova.define("cordova-plugin-file.ProgressEvent", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+// If ProgressEvent exists in global context, use it already, otherwise use our own polyfill
+// Feature test: See if we can instantiate a native ProgressEvent;
+// if so, use that approach,
+// otherwise fill-in with our own implementation.
+//
+// NOTE: right now we always fill in with our own. Down the road would be nice if we can use whatever is native in the webview.
+var ProgressEvent = (function () {
+    /*
+    var createEvent = function(data) {
+        var event = document.createEvent('Events');
+        event.initEvent('ProgressEvent', false, false);
+        if (data) {
+            for (var i in data) {
+                if (data.hasOwnProperty(i)) {
+                    event[i] = data[i];
+                }
+            }
+            if (data.target) {
+                // TODO: cannot call <some_custom_object>.dispatchEvent
+                // need to first figure out how to implement EventTarget
+            }
+        }
+        return event;
+    };
+    try {
+        var ev = createEvent({type:"abort",target:document});
+        return function ProgressEvent(type, data) {
+            data.type = type;
+            return createEvent(data);
+        };
+    } catch(e){
+    */
+    return function ProgressEvent (type, dict) {
+        this.type = type;
+        this.bubbles = false;
+        this.cancelBubble = false;
+        this.cancelable = false;
+        this.lengthComputable = false;
+        this.loaded = dict && dict.loaded ? dict.loaded : 0;
+        this.total = dict && dict.total ? dict.total : 0;
+        this.target = dict && dict.target ? dict.target : null;
+    };
+    // }
+})();
+
+module.exports = ProgressEvent;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/android/FileSystem.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/android/FileSystem.js
new file mode 100644
index 0000000..0124fa6
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/android/FileSystem.js
@@ -0,0 +1,51 @@
+cordova.define("cordova-plugin-file.androidFileSystem", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+FILESYSTEM_PROTOCOL = 'cdvfile'; // eslint-disable-line no-undef
+
+module.exports = {
+    __format__: function (fullPath, nativeUrl) {
+        var path;
+        var contentUrlMatch = /^content:\/\//.exec(nativeUrl);
+        if (contentUrlMatch) {
+            // When available, use the path from a native content URL, which was already encoded by Android.
+            // This is necessary because JavaScript's encodeURI() does not encode as many characters as
+            // Android, which can result in permission exceptions when the encoding of a content URI
+            // doesn't match the string for which permission was originally granted.
+            path = nativeUrl.substring(contentUrlMatch[0].length - 1);
+        } else {
+            path = FileSystem.encodeURIPath(fullPath); // eslint-disable-line no-undef
+            if (!/^\//.test(path)) {
+                path = '/' + path;
+            }
+
+            var m = /\?.*/.exec(nativeUrl);
+            if (m) {
+                path += m[0];
+            }
+        }
+
+        return FILESYSTEM_PROTOCOL + '://localhost/' + this.name + path; // eslint-disable-line no-undef
+    }
+};
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/browser/isChrome.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/browser/isChrome.js
new file mode 100644
index 0000000..c74fd9c
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/browser/isChrome.js
@@ -0,0 +1,29 @@
+cordova.define("cordova-plugin-file.isChrome", function(require, exports, module) {
+/*

+ *

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ *

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ *

+ */

+

+module.exports = function () {

+    // window.webkitRequestFileSystem and window.webkitResolveLocalFileSystemURL are available only in Chrome and

+    // possibly a good flag to indicate that we're running in Chrome

+    return window.webkitRequestFileSystem && window.webkitResolveLocalFileSystemURL;

+};

+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/fileSystemPaths.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/fileSystemPaths.js
new file mode 100644
index 0000000..4bfc0f6
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/fileSystemPaths.js
@@ -0,0 +1,65 @@
+cordova.define("cordova-plugin-file.fileSystemPaths", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var exec = require('cordova/exec');
+var channel = require('cordova/channel');
+
+exports.file = {
+    // Read-only directory where the application is installed.
+    applicationDirectory: null,
+    // Root of app's private writable storage
+    applicationStorageDirectory: null,
+    // Where to put app-specific data files.
+    dataDirectory: null,
+    // Cached files that should survive app restarts.
+    // Apps should not rely on the OS to delete files in here.
+    cacheDirectory: null,
+    // Android: the application space on external storage.
+    externalApplicationStorageDirectory: null,
+    // Android: Where to put app-specific data files on external storage.
+    externalDataDirectory: null,
+    // Android: the application cache on external storage.
+    externalCacheDirectory: null,
+    // Android: the external storage (SD card) root.
+    externalRootDirectory: null,
+    // iOS: Temp directory that the OS can clear at will.
+    tempDirectory: null,
+    // iOS: Holds app-specific files that should be synced (e.g. to iCloud).
+    syncedDataDirectory: null,
+    // iOS: Files private to the app, but that are meaningful to other applications (e.g. Office files)
+    documentsDirectory: null,
+    // BlackBerry10: Files globally available to all apps
+    sharedDirectory: null
+};
+
+channel.waitForInitialization('onFileSystemPathsReady');
+channel.onCordovaReady.subscribe(function () {
+    function after (paths) {
+        for (var k in paths) {
+            exports.file[k] = paths[k];
+        }
+        channel.initializationComplete('onFileSystemPathsReady');
+    }
+    exec(after, null, 'File', 'requestAllPaths', []);
+});
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/fileSystems-roots.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/fileSystems-roots.js
new file mode 100644
index 0000000..9351132
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/fileSystems-roots.js
@@ -0,0 +1,47 @@
+cordova.define("cordova-plugin-file.fileSystems-roots", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+// Map of fsName -> FileSystem.
+var fsMap = null;
+var FileSystem = require('./FileSystem');
+var exec = require('cordova/exec');
+
+// Overridden by Android, BlackBerry 10 and iOS to populate fsMap.
+require('./fileSystems').getFs = function (name, callback) {
+    function success (response) {
+        fsMap = {};
+        for (var i = 0; i < response.length; ++i) {
+            var fsRoot = response[i];
+            var fs = new FileSystem(fsRoot.filesystemName, fsRoot);
+            fsMap[fs.name] = fs;
+        }
+        callback(fsMap[name]);
+    }
+
+    if (fsMap) {
+        callback(fsMap[name]);
+    } else {
+        exec(success, null, 'File', 'requestAllFileSystems', []);
+    }
+};
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/fileSystems.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/fileSystems.js
new file mode 100644
index 0000000..e61ceaf
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/fileSystems.js
@@ -0,0 +1,28 @@
+cordova.define("cordova-plugin-file.fileSystems", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+// Overridden by Android, BlackBerry 10 and iOS to populate fsMap.
+module.exports.getFs = function (name, callback) {
+    callback(null);
+};
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/requestFileSystem.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/requestFileSystem.js
new file mode 100644
index 0000000..7f65219
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/requestFileSystem.js
@@ -0,0 +1,84 @@
+cordova.define("cordova-plugin-file.requestFileSystem", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+(function () {
+    // For browser platform: not all browsers use this file.
+    function checkBrowser () {
+        if (cordova.platformId === 'browser' && require('./isChrome')()) { // eslint-disable-line no-undef
+            module.exports = window.requestFileSystem || window.webkitRequestFileSystem;
+            return true;
+        }
+        return false;
+    }
+    if (checkBrowser()) {
+        return;
+    }
+
+    var argscheck = require('cordova/argscheck');
+    var FileError = require('./FileError');
+    var FileSystem = require('./FileSystem');
+    var exec = require('cordova/exec');
+    var fileSystems = require('./fileSystems');
+
+    /**
+     * Request a file system in which to store application data.
+     * @param type  local file system type
+     * @param size  indicates how much storage space, in bytes, the application expects to need
+     * @param successCallback  invoked with a FileSystem object
+     * @param errorCallback  invoked if error occurs retrieving file system
+     */
+    var requestFileSystem = function (type, size, successCallback, errorCallback) {
+        argscheck.checkArgs('nnFF', 'requestFileSystem', arguments);
+        var fail = function (code) {
+            if (errorCallback) {
+                errorCallback(new FileError(code));
+            }
+        };
+
+        if (type < 0) {
+            fail(FileError.SYNTAX_ERR);
+        } else {
+            // if successful, return a FileSystem object
+            var success = function (file_system) {
+                if (file_system) {
+                    if (successCallback) {
+                        fileSystems.getFs(file_system.name, function (fs) {
+                            // This should happen only on platforms that haven't implemented requestAllFileSystems (windows)
+                            if (!fs) {
+                                fs = new FileSystem(file_system.name, file_system.root);
+                            }
+                            successCallback(fs);
+                        });
+                    }
+                } else {
+                    // no FileSystem object returned
+                    fail(FileError.NOT_FOUND_ERR);
+                }
+            };
+            exec(success, fail, 'File', 'requestFileSystem', [type, size]);
+        }
+    };
+
+    module.exports = requestFileSystem;
+})();
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-file/www/resolveLocalFileSystemURI.js b/platforms/android/platform_www/plugins/cordova-plugin-file/www/resolveLocalFileSystemURI.js
new file mode 100644
index 0000000..73715bc
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-file/www/resolveLocalFileSystemURI.js
@@ -0,0 +1,94 @@
+cordova.define("cordova-plugin-file.resolveLocalFileSystemURI", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+(function () {
+    // For browser platform: not all browsers use overrided `resolveLocalFileSystemURL`.
+    function checkBrowser () {
+        if (cordova.platformId === 'browser' && require('./isChrome')()) { // eslint-disable-line no-undef
+            module.exports.resolveLocalFileSystemURL = window.resolveLocalFileSystemURL || window.webkitResolveLocalFileSystemURL;
+            return true;
+        }
+        return false;
+    }
+    if (checkBrowser()) {
+        return;
+    }
+
+    var argscheck = require('cordova/argscheck');
+    var DirectoryEntry = require('./DirectoryEntry');
+    var FileEntry = require('./FileEntry');
+    var FileError = require('./FileError');
+    var exec = require('cordova/exec');
+    var fileSystems = require('./fileSystems');
+
+    /**
+     * Look up file system Entry referred to by local URI.
+     * @param {DOMString} uri  URI referring to a local file or directory
+     * @param successCallback  invoked with Entry object corresponding to URI
+     * @param errorCallback    invoked if error occurs retrieving file system entry
+     */
+    module.exports.resolveLocalFileSystemURL = module.exports.resolveLocalFileSystemURL || function (uri, successCallback, errorCallback) {
+        argscheck.checkArgs('sFF', 'resolveLocalFileSystemURI', arguments);
+        // error callback
+        var fail = function (error) {
+            if (errorCallback) {
+                errorCallback(new FileError(error));
+            }
+        };
+        // sanity check for 'not:valid:filename' or '/not:valid:filename'
+        // file.spec.12 window.resolveLocalFileSystemURI should error (ENCODING_ERR) when resolving invalid URI with leading /.
+        if (!uri || uri.split(':').length > 2) {
+            setTimeout(function () {
+                fail(FileError.ENCODING_ERR);
+            }, 0);
+            return;
+        }
+        // if successful, return either a file or directory entry
+        var success = function (entry) {
+            if (entry) {
+                if (successCallback) {
+                    // create appropriate Entry object
+                    var fsName = entry.filesystemName || (entry.filesystem && entry.filesystem.name) || (entry.filesystem === window.PERSISTENT ? 'persistent' : 'temporary'); // eslint-disable-line no-undef
+                    fileSystems.getFs(fsName, function (fs) {
+                        // This should happen only on platforms that haven't implemented requestAllFileSystems (windows)
+                        if (!fs) {
+                            fs = new FileSystem(fsName, {name: '', fullPath: '/'}); // eslint-disable-line no-undef
+                        }
+                        var result = (entry.isDirectory) ? new DirectoryEntry(entry.name, entry.fullPath, fs, entry.nativeURL) : new FileEntry(entry.name, entry.fullPath, fs, entry.nativeURL);
+                        successCallback(result);
+                    });
+                }
+            } else {
+                // no Entry object returned
+                fail(FileError.NOT_FOUND_ERR);
+            }
+        };
+
+        exec(success, fail, 'File', 'resolveLocalFileSystemURI', [uri]);
+    };
+
+    module.exports.resolveLocalFileSystemURI = function () {
+        console.log('resolveLocalFileSystemURI is deprecated. Please call resolveLocalFileSystemURL instead.');
+        module.exports.resolveLocalFileSystemURL.apply(this, arguments);
+    };
+})();
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-fingerprint-aio/www/Fingerprint.js b/platforms/android/platform_www/plugins/cordova-plugin-fingerprint-aio/www/Fingerprint.js
new file mode 100644
index 0000000..3982139
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-fingerprint-aio/www/Fingerprint.js
@@ -0,0 +1,29 @@
+cordova.define("cordova-plugin-fingerprint-aio.Fingerprint", function(require, exports, module) {
+/*global cordova */
+
+function Fingerprint() {
+}
+
+Fingerprint.prototype.show = function (params, successCallback, errorCallback) {
+  cordova.exec(
+    successCallback,
+    errorCallback,
+    "Fingerprint",
+    "authenticate",
+    [params]
+  );
+};
+
+Fingerprint.prototype.isAvailable = function (successCallback, errorCallback) {
+  cordova.exec(
+    successCallback,
+    errorCallback,
+    "Fingerprint",
+    "isAvailable",
+    [{}]
+  );
+};
+
+module.exports = new Fingerprint();
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-inappbrowser/www/inappbrowser.js b/platforms/android/platform_www/plugins/cordova-plugin-inappbrowser/www/inappbrowser.js
new file mode 100644
index 0000000..a3021c2
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-inappbrowser/www/inappbrowser.js
@@ -0,0 +1,118 @@
+cordova.define("cordova-plugin-inappbrowser.inappbrowser", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+(function () {
+    // special patch to correctly work on Ripple emulator (CB-9760)
+    if (window.parent && !!window.parent.ripple) { // https://gist.github.com/triceam/4658021
+        module.exports = window.open.bind(window); // fallback to default window.open behaviour
+        return;
+    }
+
+    var exec = require('cordova/exec');
+    var channel = require('cordova/channel');
+    var modulemapper = require('cordova/modulemapper');
+    var urlutil = require('cordova/urlutil');
+
+    function InAppBrowser () {
+        this.channels = {
+            'loadstart': channel.create('loadstart'),
+            'loadstop': channel.create('loadstop'),
+            'loaderror': channel.create('loaderror'),
+            'exit': channel.create('exit'),
+            'customscheme': channel.create('customscheme')
+        };
+    }
+
+    InAppBrowser.prototype = {
+        _eventHandler: function (event) {
+            if (event && (event.type in this.channels)) {
+                this.channels[event.type].fire(event);
+            }
+        },
+        close: function (eventname) {
+            exec(null, null, 'InAppBrowser', 'close', []);
+        },
+        show: function (eventname) {
+            exec(null, null, 'InAppBrowser', 'show', []);
+        },
+        hide: function (eventname) {
+            exec(null, null, 'InAppBrowser', 'hide', []);
+        },
+        addEventListener: function (eventname, f) {
+            if (eventname in this.channels) {
+                this.channels[eventname].subscribe(f);
+            }
+        },
+        removeEventListener: function (eventname, f) {
+            if (eventname in this.channels) {
+                this.channels[eventname].unsubscribe(f);
+            }
+        },
+
+        executeScript: function (injectDetails, cb) {
+            if (injectDetails.code) {
+                exec(cb, null, 'InAppBrowser', 'injectScriptCode', [injectDetails.code, !!cb]);
+            } else if (injectDetails.file) {
+                exec(cb, null, 'InAppBrowser', 'injectScriptFile', [injectDetails.file, !!cb]);
+            } else {
+                throw new Error('executeScript requires exactly one of code or file to be specified');
+            }
+        },
+
+        insertCSS: function (injectDetails, cb) {
+            if (injectDetails.code) {
+                exec(cb, null, 'InAppBrowser', 'injectStyleCode', [injectDetails.code, !!cb]);
+            } else if (injectDetails.file) {
+                exec(cb, null, 'InAppBrowser', 'injectStyleFile', [injectDetails.file, !!cb]);
+            } else {
+                throw new Error('insertCSS requires exactly one of code or file to be specified');
+            }
+        }
+    };
+
+    module.exports = function (strUrl, strWindowName, strWindowFeatures, callbacks) {
+        // Don't catch calls that write to existing frames (e.g. named iframes).
+        if (window.frames && window.frames[strWindowName]) {
+            var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open');
+            return origOpenFunc.apply(window, arguments);
+        }
+
+        strUrl = urlutil.makeAbsolute(strUrl);
+        var iab = new InAppBrowser();
+
+        callbacks = callbacks || {};
+        for (var callbackName in callbacks) {
+            iab.addEventListener(callbackName, callbacks[callbackName]);
+        }
+
+        var cb = function (eventname) {
+            iab._eventHandler(eventname);
+        };
+
+        strWindowFeatures = strWindowFeatures || '';
+
+        exec(cb, cb, 'InAppBrowser', 'open', [strUrl, strWindowName, strWindowFeatures]);
+        return iab;
+    };
+})();
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-qrscanner/www/www.min.js b/platforms/android/platform_www/plugins/cordova-plugin-qrscanner/www/www.min.js
new file mode 100644
index 0000000..2469e9e
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-qrscanner/www/www.min.js
@@ -0,0 +1,344 @@
+cordova.define("cordova-plugin-qrscanner.QRScanner", function(require, exports, module) {
+// This file is generated by `npm run build`.
+
+/*global exports:false*/
+/*jshint unused:false */
+// remap parameter names from cordova.define
+// see `externals` in webpack.cordova.config.js
+var cordovaRequire = require;
+var cordovaExports = exports;
+var cordovaModule = module;
+/******/ (function(modules) { // webpackBootstrap
+/******/ 	// The module cache
+/******/ 	var installedModules = {};
+/******/
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+/******/
+/******/ 		// Check if module is in cache
+/******/ 		if(installedModules[moduleId]) {
+/******/ 			return installedModules[moduleId].exports;
+/******/ 		}
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = installedModules[moduleId] = {
+/******/ 			i: moduleId,
+/******/ 			l: false,
+/******/ 			exports: {}
+/******/ 		};
+/******/
+/******/ 		// Execute the module function
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ 		// Flag the module as loaded
+/******/ 		module.l = true;
+/******/
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+/******/
+/******/
+/******/ 	// expose the modules object (__webpack_modules__)
+/******/ 	__webpack_require__.m = modules;
+/******/
+/******/ 	// expose the module cache
+/******/ 	__webpack_require__.c = installedModules;
+/******/
+/******/ 	// identity function for calling harmony imports with the correct context
+/******/ 	__webpack_require__.i = function(value) { return value; };
+/******/
+/******/ 	// define getter function for harmony exports
+/******/ 	__webpack_require__.d = function(exports, name, getter) {
+/******/ 		if(!__webpack_require__.o(exports, name)) {
+/******/ 			Object.defineProperty(exports, name, {
+/******/ 				configurable: false,
+/******/ 				enumerable: true,
+/******/ 				get: getter
+/******/ 			});
+/******/ 		}
+/******/ 	};
+/******/
+/******/ 	// getDefaultExport function for compatibility with non-harmony modules
+/******/ 	__webpack_require__.n = function(module) {
+/******/ 		var getter = module && module.__esModule ?
+/******/ 			function getDefault() { return module['default']; } :
+/******/ 			function getModuleExports() { return module; };
+/******/ 		__webpack_require__.d(getter, 'a', getter);
+/******/ 		return getter;
+/******/ 	};
+/******/
+/******/ 	// Object.prototype.hasOwnProperty.call
+/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+/******/
+/******/ 	// __webpack_public_path__
+/******/ 	__webpack_require__.p = "";
+/******/
+/******/ 	// Load entry module and return exports
+/******/ 	return __webpack_require__(__webpack_require__.s = 18);
+/******/ })
+/************************************************************************/
+/******/ ({
+
+/***/ 1:
+/***/ (function(module, exports) {
+
+module.exports = cordovaModule;
+
+/***/ }),
+
+/***/ 18:
+/***/ (function(module, exports, __webpack_require__) {
+
+var globalCordova = __webpack_require__(4);
+var cordovaModule = __webpack_require__(1);
+
+var createQRScannerAdapter = __webpack_require__(3);
+
+// pass in global cordova object to expose cordova.exec
+var QRScannerAdapter = createQRScannerAdapter(globalCordova);
+cordovaModule.exports = QRScannerAdapter;
+
+
+/***/ }),
+
+/***/ 3:
+/***/ (function(module, exports) {
+
+module.exports = function createQRScanner(cordova){
+// The native implementations should return their status as ['string':'string']
+// dictionaries. Boolean values are encoded to '0' and '1', respectively.
+function stringToBool(string) {
+  switch (string) {
+    case '1':
+      return true;
+    case '0':
+      return false;
+    default:
+    throw new Error('QRScanner plugin returned an invalid boolean number-string: ' + string);
+  }
+}
+
+// Converts the returned ['string':'string'] dictionary to a status object.
+function convertStatus(statusDictionary) {
+  return {
+    authorized: stringToBool(statusDictionary.authorized),
+    denied: stringToBool(statusDictionary.denied),
+    restricted: stringToBool(statusDictionary.restricted),
+    prepared: stringToBool(statusDictionary.prepared),
+    scanning: stringToBool(statusDictionary.scanning),
+    previewing: stringToBool(statusDictionary.previewing),
+    showing: stringToBool(statusDictionary.showing),
+    lightEnabled: stringToBool(statusDictionary.lightEnabled),
+    canOpenSettings: stringToBool(statusDictionary.canOpenSettings),
+    canEnableLight: stringToBool(statusDictionary.canEnableLight),
+    canChangeCamera: stringToBool(statusDictionary.canChangeCamera),
+    currentCamera: parseInt(statusDictionary.currentCamera)
+  };
+}
+
+// Simple utility method to ensure the background is transparent. Used by the
+// plugin to force re-rendering immediately after the native webview background
+// is made transparent.
+function clearBackground() {
+  var body = document.body;
+  if (body.style) {
+    body.style.backgroundColor = 'rgba(0,0,0,0.01)';
+    body.style.backgroundImage = '';
+    setTimeout(function() {
+      body.style.backgroundColor = 'transparent';
+    }, 1);
+    if (body.parentNode && body.parentNode.style) {
+      body.parentNode.style.backgroundColor = 'transparent';
+      body.parentNode.style.backgroundImage = '';
+    }
+  }
+}
+
+function errorCallback(callback) {
+  if (!callback) {
+    return null;
+  }
+  return function(error) {
+    var errorCode = parseInt(error);
+    var QRScannerError = {};
+    switch (errorCode) {
+      case 0:
+        QRScannerError = {
+          name: 'UNEXPECTED_ERROR',
+          code: 0,
+          _message: 'QRScanner experienced an unexpected error.'
+        };
+        break;
+      case 1:
+        QRScannerError = {
+          name: 'CAMERA_ACCESS_DENIED',
+          code: 1,
+          _message: 'The user denied camera access.'
+        };
+        break;
+      case 2:
+        QRScannerError = {
+          name: 'CAMERA_ACCESS_RESTRICTED',
+          code: 2,
+          _message: 'Camera access is restricted.'
+        };
+        break;
+      case 3:
+        QRScannerError = {
+          name: 'BACK_CAMERA_UNAVAILABLE',
+          code: 3,
+          _message: 'The back camera is unavailable.'
+        };
+        break;
+      case 4:
+        QRScannerError = {
+          name: 'FRONT_CAMERA_UNAVAILABLE',
+          code: 4,
+          _message: 'The front camera is unavailable.'
+        };
+        break;
+      case 5:
+        QRScannerError = {
+          name: 'CAMERA_UNAVAILABLE',
+          code: 5,
+          _message: 'The camera is unavailable.'
+        };
+        break;
+      case 6:
+        QRScannerError = {
+          name: 'SCAN_CANCELED',
+          code: 6,
+          _message: 'Scan was canceled.'
+        };
+        break;
+      case 7:
+        QRScannerError = {
+          name: 'LIGHT_UNAVAILABLE',
+          code: 7,
+          _message: 'The device light is unavailable.'
+        };
+        break;
+      case 8:
+        // Open settings is only available on iOS 8.0+.
+        QRScannerError = {
+          name: 'OPEN_SETTINGS_UNAVAILABLE',
+          code: 8,
+          _message: 'The device is unable to open settings.'
+        };
+        break;
+      default:
+        QRScannerError = {
+          name: 'UNEXPECTED_ERROR',
+          code: 0,
+          _message: 'QRScanner returned an invalid error code.'
+        };
+        break;
+    }
+    callback(QRScannerError);
+  };
+}
+
+function successCallback(callback) {
+  if (!callback) {
+    return null;
+  }
+  return function(statusDict) {
+    callback(null, convertStatus(statusDict));
+  };
+}
+
+function doneCallback(callback, clear) {
+  if (!callback) {
+    return null;
+  }
+  return function(statusDict) {
+    if (clear) {
+      clearBackground();
+    }
+    callback(convertStatus(statusDict));
+  };
+}
+
+return {
+  prepare: function(callback) {
+    cordova.exec(successCallback(callback), errorCallback(callback), 'QRScanner', 'prepare', []);
+  },
+  destroy: function(callback) {
+    cordova.exec(doneCallback(callback, true), null, 'QRScanner', 'destroy', []);
+  },
+  scan: function(callback) {
+    if (!callback) {
+      throw new Error('No callback provided to scan method.');
+    }
+    var success = function(result) {
+      callback(null, result);
+    };
+    cordova.exec(success, errorCallback(callback), 'QRScanner', 'scan', []);
+  },
+  cancelScan: function(callback) {
+    cordova.exec(doneCallback(callback), null, 'QRScanner', 'cancelScan', []);
+  },
+  show: function(callback) {
+    cordova.exec(doneCallback(callback, true), null, 'QRScanner', 'show', []);
+  },
+  hide: function(callback) {
+    cordova.exec(doneCallback(callback, true), null, 'QRScanner', 'hide', []);
+  },
+  pausePreview: function(callback) {
+    cordova.exec(doneCallback(callback), null, 'QRScanner', 'pausePreview', []);
+  },
+  resumePreview: function(callback) {
+    cordova.exec(doneCallback(callback), null, 'QRScanner', 'resumePreview', []);
+  },
+  enableLight: function(callback) {
+    cordova.exec(successCallback(callback), errorCallback(callback), 'QRScanner', 'enableLight', []);
+  },
+  disableLight: function(callback) {
+    cordova.exec(successCallback(callback), errorCallback(callback), 'QRScanner', 'disableLight', []);
+  },
+  useCamera: function(index, callback) {
+    cordova.exec(successCallback(callback), errorCallback(callback), 'QRScanner', 'useCamera', [index]);
+  },
+  useFrontCamera: function(callback) {
+    var frontCamera = 1;
+    if (callback) {
+      this.useCamera(frontCamera, callback);
+    } else {
+      cordova.exec(null, null, 'QRScanner', 'useCamera', [frontCamera]);
+    }
+  },
+  useBackCamera: function(callback) {
+    var backCamera = 0;
+    if (callback) {
+      this.useCamera(backCamera, callback);
+    } else {
+      cordova.exec(null, null, 'QRScanner', 'useCamera', [backCamera]);
+    }
+  },
+  openSettings: function(callback) {
+    if (callback) {
+      cordova.exec(successCallback(callback), errorCallback(callback), 'QRScanner', 'openSettings', []);
+    } else {
+      cordova.exec(null, null, 'QRScanner', 'openSettings', []);
+    }
+  },
+  getStatus: function(callback) {
+    if (!callback) {
+      throw new Error('No callback provided to getStatus method.');
+    }
+    cordova.exec(doneCallback(callback), null, 'QRScanner', 'getStatus', []);
+  }
+};
+};
+
+
+/***/ }),
+
+/***/ 4:
+/***/ (function(module, exports) {
+
+module.exports = cordova;
+
+/***/ })
+
+/******/ });
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-splashscreen/www/splashscreen.js b/platforms/android/platform_www/plugins/cordova-plugin-splashscreen/www/splashscreen.js
new file mode 100644
index 0000000..911ad50
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-splashscreen/www/splashscreen.js
@@ -0,0 +1,36 @@
+cordova.define("cordova-plugin-splashscreen.SplashScreen", function(require, exports, module) {
+/*

+ *

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ *

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ *

+*/

+

+var exec = require('cordova/exec');

+

+var splashscreen = {

+    show:function() {

+        exec(null, null, "SplashScreen", "show", []);

+    },

+    hide:function() {

+        exec(null, null, "SplashScreen", "hide", []);

+    }

+};

+

+module.exports = splashscreen;

+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-statusbar/www/statusbar.js b/platforms/android/platform_www/plugins/cordova-plugin-statusbar/www/statusbar.js
new file mode 100644
index 0000000..708186f
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-statusbar/www/statusbar.js
@@ -0,0 +1,116 @@
+cordova.define("cordova-plugin-statusbar.statusbar", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/* global cordova */
+
+var exec = require('cordova/exec');
+
+var namedColors = {
+    "black": "#000000",
+    "darkGray": "#A9A9A9",
+    "lightGray": "#D3D3D3",
+    "white": "#FFFFFF",
+    "gray": "#808080",
+    "red": "#FF0000",
+    "green": "#00FF00",
+    "blue": "#0000FF",
+    "cyan": "#00FFFF",
+    "yellow": "#FFFF00",
+    "magenta": "#FF00FF",
+    "orange": "#FFA500",
+    "purple": "#800080",
+    "brown": "#A52A2A"
+};
+
+var StatusBar = {
+
+    isVisible: true,
+
+    overlaysWebView: function (doOverlay) {
+        exec(null, null, "StatusBar", "overlaysWebView", [doOverlay]);
+    },
+
+    styleDefault: function () {
+        // dark text ( to be used on a light background )
+        exec(null, null, "StatusBar", "styleDefault", []);
+    },
+
+    styleLightContent: function () {
+        // light text ( to be used on a dark background )
+        exec(null, null, "StatusBar", "styleLightContent", []);
+    },
+
+    styleBlackTranslucent: function () {
+        // #88000000 ? Apple says to use lightContent instead
+        exec(null, null, "StatusBar", "styleBlackTranslucent", []);
+    },
+
+    styleBlackOpaque: function () {
+        // #FF000000 ? Apple says to use lightContent instead
+        exec(null, null, "StatusBar", "styleBlackOpaque", []);
+    },
+
+    backgroundColorByName: function (colorname) {
+        return StatusBar.backgroundColorByHexString(namedColors[colorname]);
+    },
+
+    backgroundColorByHexString: function (hexString) {
+        if (hexString.charAt(0) !== "#") {
+            hexString = "#" + hexString;
+        }
+
+        if (hexString.length === 4) {
+            var split = hexString.split("");
+            hexString = "#" + split[1] + split[1] + split[2] + split[2] + split[3] + split[3];
+        }
+
+        exec(null, null, "StatusBar", "backgroundColorByHexString", [hexString]);
+    },
+
+    hide: function () {
+        exec(null, null, "StatusBar", "hide", []);
+        StatusBar.isVisible = false;
+    },
+
+    show: function () {
+        exec(null, null, "StatusBar", "show", []);
+        StatusBar.isVisible = true;
+    }
+
+};
+
+// prime it. setTimeout so that proxy gets time to init
+window.setTimeout(function () {
+    exec(function (res) {
+        if (typeof res == 'object') {
+            if (res.type == 'tap') {
+                cordova.fireWindowEvent('statusTap');
+            }
+        } else {
+            StatusBar.isVisible = res;
+        }
+    }, null, "StatusBar", "_ready", []);
+}, 0);
+
+module.exports = StatusBar;
+
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-themeablebrowser/www/themeablebrowser.js b/platforms/android/platform_www/plugins/cordova-plugin-themeablebrowser/www/themeablebrowser.js
new file mode 100644
index 0000000..9c935cb
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-themeablebrowser/www/themeablebrowser.js
@@ -0,0 +1,121 @@
+cordova.define("cordova-plugin-themeablebrowser.themeablebrowser", function(require, exports, module) {
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var exec = require('cordova/exec');
+var channel = require('cordova/channel');
+var modulemapper = require('cordova/modulemapper');
+var urlutil = require('cordova/urlutil');
+
+function ThemeableBrowser() {
+   this.channels = {};
+}
+
+ThemeableBrowser.prototype = {
+    _eventHandler: function (event) {
+        if (event && (event.type in this.channels)) {
+            this.channels[event.type].fire(event);
+        }
+    },
+    close: function (eventname) {
+        exec(null, null, 'ThemeableBrowser', 'close', []);
+        return this;
+    },
+    show: function (eventname) {
+        exec(null, null, 'ThemeableBrowser', 'show', []);
+        return this;
+    },
+    reload: function (eventname) {
+        exec(null, null, 'ThemeableBrowser', 'reload', []);
+        return this;
+    },
+    addEventListener: function (eventname,f) {
+        if (!(eventname in this.channels)) {
+            this.channels[eventname] = channel.create(eventname);
+        }
+        this.channels[eventname].subscribe(f);
+        return this;
+    },
+    removeEventListener: function(eventname, f) {
+        if (eventname in this.channels) {
+            this.channels[eventname].unsubscribe(f);
+        }
+        return this;
+    },
+
+    executeScript: function(injectDetails, cb) {
+        if (injectDetails.code) {
+            exec(cb, null, 'ThemeableBrowser', 'injectScriptCode', [injectDetails.code, !!cb]);
+        } else if (injectDetails.file) {
+            exec(cb, null, 'ThemeableBrowser', 'injectScriptFile', [injectDetails.file, !!cb]);
+        } else {
+            throw new Error('executeScript requires exactly one of code or file to be specified');
+        }
+        return this;
+    },
+
+    insertCSS: function(injectDetails, cb) {
+        if (injectDetails.code) {
+            exec(cb, null, 'ThemeableBrowser', 'injectStyleCode', [injectDetails.code, !!cb]);
+        } else if (injectDetails.file) {
+            exec(cb, null, 'ThemeableBrowser', 'injectStyleFile', [injectDetails.file, !!cb]);
+        } else {
+            throw new Error('insertCSS requires exactly one of code or file to be specified');
+        }
+        return this;
+    }
+};
+
+exports.open = function(strUrl, strWindowName, strWindowFeatures, callbacks) {
+    // Don't catch calls that write to existing frames (e.g. named iframes).
+    if (window.frames && window.frames[strWindowName]) {
+        var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open');
+        return origOpenFunc.apply(window, arguments);
+    }
+
+    strUrl = urlutil.makeAbsolute(strUrl);
+    var iab = new ThemeableBrowser();
+
+    callbacks = callbacks || {};
+    for (var callbackName in callbacks) {
+        iab.addEventListener(callbackName, callbacks[callbackName]);
+    }
+
+    var cb = function(eventname) {
+       iab._eventHandler(eventname);
+    };
+
+    strWindowFeatures = strWindowFeatures && JSON.stringify(strWindowFeatures);
+    // Slightly delay the actual native call to give the user a chance to
+    // register event listeners first, otherwise some warnings or errors may be missed.
+    setTimeout(function() {
+        exec(cb, cb, 'ThemeableBrowser', 'open', [strUrl, strWindowName, strWindowFeatures || '']);
+    }, 0);
+    return iab;
+};
+
+exports.EVT_ERR = 'ThemeableBrowserError';
+exports.EVT_WRN = 'ThemeableBrowserWarning';
+exports.ERR_CRITICAL = 'critical';
+exports.ERR_LOADFAIL = 'loadfail';
+exports.WRN_UNEXPECTED = 'unexpected';
+exports.WRN_UNDEFINED = 'undefined';
+});
diff --git a/platforms/android/platform_www/plugins/cordova-plugin-touch-id/www/TouchID.js b/platforms/android/platform_www/plugins/cordova-plugin-touch-id/www/TouchID.js
new file mode 100644
index 0000000..38a3a85
--- /dev/null
+++ b/platforms/android/platform_www/plugins/cordova-plugin-touch-id/www/TouchID.js
@@ -0,0 +1,36 @@
+cordova.define("cordova-plugin-touch-id.TouchID", function(require, exports, module) {
+function TouchID() {
+}
+
+TouchID.prototype.isAvailable = function (successCallback, errorCallback) {
+  cordova.exec(successCallback, errorCallback, "TouchID", "isAvailable", []);
+};
+
+TouchID.prototype.didFingerprintDatabaseChange = function (successCallback, errorCallback) {
+  cordova.exec(successCallback, errorCallback, "TouchID", "didFingerprintDatabaseChange", []);
+};
+
+TouchID.prototype.verifyFingerprint = function (message, successCallback, errorCallback) {
+  cordova.exec(successCallback, errorCallback, "TouchID", "verifyFingerprint", [message]);
+};
+
+TouchID.prototype.verifyFingerprintWithCustomPasswordFallback = function (message, successCallback, errorCallback) {
+  cordova.exec(successCallback, errorCallback, "TouchID", "verifyFingerprintWithCustomPasswordFallback", [message]);
+};
+
+TouchID.prototype.verifyFingerprintWithCustomPasswordFallbackAndEnterPasswordLabel = function (message, enterPasswordLabel, successCallback, errorCallback) {
+  cordova.exec(successCallback, errorCallback, "TouchID", "verifyFingerprintWithCustomPasswordFallbackAndEnterPasswordLabel", [message, enterPasswordLabel]);
+};
+
+TouchID.install = function () {
+  if (!window.plugins) {
+    window.plugins = {};
+  }
+
+  window.plugins.touchid = new TouchID();
+  return window.plugins.touchid;
+};
+
+cordova.addConstructor(TouchID.install);
+
+});
diff --git a/platforms/android/project.properties b/platforms/android/project.properties
new file mode 100644
index 0000000..661238d
--- /dev/null
+++ b/platforms/android/project.properties
@@ -0,0 +1,16 @@
+# This file was originally created by the Android Tools, but is now
+# used by cordova-android to manage the state of the various third party
+# libraries used in your application
+
+# This is the Library Module that contains the Cordova Library, this is not
+# required when using an AAR
+
+# This is the application project.  This is only required for Android Studio Gradle projects
+
+# Project target.
+target=android-28
+android.library.reference.1=CordovaLib
+android.library.reference.2=app
+cordova.system.library.1=com.squareup.okhttp3:okhttp-urlconnection:3.10.0
+cordova.gradle.include.1=cordova-plugin-qrscanner/dlapp-qrscanner.gradle
+cordova.system.library.2=com.android.support:support-v4:24.1.1+
\ No newline at end of file
diff --git a/platforms/android/settings.gradle b/platforms/android/settings.gradle
new file mode 100644
index 0000000..dfb8557
--- /dev/null
+++ b/platforms/android/settings.gradle
@@ -0,0 +1,4 @@
+// GENERATED FILE - DO NOT EDIT
+include ":"
+include ":CordovaLib"
+include ":app"
diff --git a/platforms/android/wrapper.gradle b/platforms/android/wrapper.gradle
new file mode 100644
index 0000000..d7ebabd
--- /dev/null
+++ b/platforms/android/wrapper.gradle
@@ -0,0 +1 @@
+//This file is intentionally just a comment