diff --git a/build.gradle.kts b/build.gradle.kts index 0df91dee2..7816c1e66 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,23 +1,11 @@ plugins { - val kotlinVersion = "2.1.10" - id("com.android.application") version "8.8.0" apply (false) - id("org.jetbrains.kotlin.android") version kotlinVersion apply (false) - id("org.jetbrains.kotlin.kapt") version kotlinVersion apply (false) - id("org.jetbrains.kotlin.multiplatform") version kotlinVersion apply (false) - id("org.jlleitschuh.gradle.ktlint") version "11.6.1" + alias(libs.plugins.agp) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.ksp) apply false + alias(libs.plugins.ktlint.plugin) apply false + alias(libs.plugins.shadow) apply false } apply { - from("translators.gradle.kts") -} - -allprojects { - repositories { - google() - mavenCentral() - maven(url = "https://plugins.gradle.org/m2/") - maven(url = "https://oss.sonatype.org/content/repositories/snapshots/") - maven(url = "https://jitpack.io") - maven(url = "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-js-wrappers/") // Repository for kotlin-css-jvm old versions, now that the Gradle Plugin Portal no longer brings these in by mirroring JCenter - } + from("gradle/translators.gradle.kts") } diff --git a/build.sh b/build.sh index 863e8681e..a3a975716 100755 --- a/build.sh +++ b/build.sh @@ -21,7 +21,7 @@ ADB="${ANDROID_HOME}/platform-tools/adb" ANDROID_OUTPUTS_DIR="uhabits-android/build/outputs" AVDMANAGER="${ANDROID_HOME}/cmdline-tools/latest/bin/avdmanager" AVD_PREFIX="uhabitsTest" -EMULATOR="${ANDROID_HOME}/tools/emulator" +EMULATOR="${ANDROID_HOME}/emulator/emulator" GRADLE="./gradlew --stacktrace --quiet" PACKAGE_NAME=org.isoron.uhabits SDKMANAGER="${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager" @@ -38,6 +38,11 @@ if [ ! -f "${ANDROID_HOME}/platform-tools/adb" ]; then exit 1 fi +if [ ! -f "$EMULATOR" ]; then + echo "Error: Not found: $EMULATOR" + exit 1 +fi + # Logging # ----------------------------------------------------------------------------- @@ -217,6 +222,7 @@ android_test_parallel() { for API in $*; do ( LOG=build/android-test-$API.log + mkdir -p build log_info "API $API: Running tests..." android_test $API 1>$LOG 2>&1 ret_code=$? diff --git a/docs/GUIDELINES.md b/docs/GUIDELINES.md index c24b375cb..8876b0805 100644 --- a/docs/GUIDELINES.md +++ b/docs/GUIDELINES.md @@ -12,17 +12,6 @@ Please see `docs/BUILD.md` and `docs/TEST.md` -## Directory Layout - -* `docs` Documentation for developers. -* `landing` Source code for our [landing page](http://loophabits.org/). -* `uhabits-android` Android-specific code. -* `uhabits-core` Common code used by all platforms (Android, iOS). -* `uhabits-core-legacy` Proof-of-concept module, developed to evaluate the feasibility of using Kotlin multiplatform for the app; not currently used, and it will be removed soon, once all useful code is ported to the other modules. -* `uhabits-ios` Experimental iOS port of Loop. Not currently used in production. -* `uhabits-server` Source code for any server-side components the app (for example, device sync). -* `uhabits-web` Experimental web port of Loop. Not currently used in production. - ## Branching Policy This repository uses the [git-flow branching model](https://nvie.com/posts/a-successful-git-branching-model/). Basically, there are two main branches, `dev` and `master`. All the development takes place in the `dev` branch. After the new features have been implemented and tested, they are merged into the `master` branch and a new version of the app is released. Please submit your pull requests against the `dev` branch. diff --git a/gradle.properties b/gradle.properties index cfc7ec4b1..5139a4280 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,3 +6,6 @@ android.enableJetifier=true android.defaults.buildfeatures.buildconfig=true android.nonTransitiveRClass=false android.nonFinalResIds=false +org.gradle.configureondemand=true +org.gradle.warning.mode=all +org.gradle.caching=true \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 000000000..4bbc60fd5 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,102 @@ +[versions] +agp = "8.8.0" +annotation = "1.9.1" +appcompat = "1.7.0" +appintro = "6.3.1" +commonsCodec = "1.16.0" +commonsIo = "1.3.2" +commonsLang3 = "3.14.0" +dagger = "2.55" +desugar = "2.1.4" +dexmaker = "2.28.3" +espresso = "3.6.1" +guava = "33.2.1-android" +hamcrest = "2.2" +jsr250 = "1.0" +jsr305 = "3.0.2" +junit = "1.2.1" +junitJupiter = "5.10.1" +junitVersion = "4.13.2" +konfetti-xml = "2.0.2" +kotlin = "2.1.10" +kotlinxCoroutinesCoreCommon = "1.3.8" +ksp = "2.1.10-1.0.30" +ktlint-plugin = "11.6.1" +ktor = "1.6.8" +ktxCoroutine = "1.10.1" +legacy-support = "1.0.0" +material = "1.12.0" +mockito-kotlin = "5.4.0" +opencsv = "5.9" +rules = "1.6.1" +shadow = "8.1.1" +sqliteJdbc = "3.45.1.0" +uiautomator = "2.3.0" + +[libraries] +annotation = { group = "androidx.annotation", name = "annotation", version.ref = "annotation" } +appIntro = { group = "com.github.AppIntro", name = "AppIntro", version.ref = "appintro" } +appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +commons-codec = { module = "commons-codec:commons-codec", version.ref = "commonsCodec" } +commons-io = { module = "org.apache.commons:commons-io", version.ref = "commonsIo" } +commons-lang3 = { module = "org.apache.commons:commons-lang3", version.ref = "commonsLang3" } +dagger = { group = "com.google.dagger", name = "dagger", version.ref = "dagger" } +dagger-compiler = { group = "com.google.dagger", name = "dagger-compiler", version.ref = "dagger" } +desugar_jdk_libs = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "desugar" } +dexmaker-mockito = { group = "com.linkedin.dexmaker", name = "dexmaker-mockito", version.ref = "dexmaker" } +espresso-contrib = { group = "androidx.test.espresso", name = "espresso-contrib", version.ref = "espresso" } +espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso" } +guava = { group = "com.google.guava", name = "guava", version.ref = "guava" } +hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" } +jsr250-api = { group = "javax.annotation", name = "jsr250-api", version.ref = "jsr250" } +jsr305 = { group = "com.google.code.findbugs", name = "jsr305", version.ref = "jsr305" } +junit = { group = "androidx.test.ext", name = "junit", version.ref = "junit" } +junit-junit = { module = "junit:junit", version.ref = "junitVersion" } +junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junitJupiter" } +konfetti-xml = { group = "nl.dionsegijn", name = "konfetti-xml", version.ref = "konfetti-xml" } +kotlin-stdlib-jdk8 = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", version.ref = "kotlin" } +kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "ktxCoroutine" } +kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "ktxCoroutine" } +kotlinx-coroutines-core-common = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core-common", version.ref = "kotlinxCoroutinesCoreCommon" } +kotlinx-coroutines-core-jvm = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm", version.ref = "ktxCoroutine" } +ktor-client-android = { group = "io.ktor", name = "ktor-client-android", version.ref = "ktor" } +ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor" } +ktor-client-jackson = { group = "io.ktor", name = "ktor-client-jackson", version.ref = "ktor" } +ktor-client-json = { group = "io.ktor", name = "ktor-client-json", version.ref = "ktor" } +ktor-client-mock = { group = "io.ktor", name = "ktor-client-mock", version.ref = "ktor" } +ktor-jackson = { group = "io.ktor", name = "ktor-jackson", version.ref = "ktor" } +legacy-preference-v14 = { group = "androidx.legacy", name = "legacy-preference-v14", version.ref = "legacy-support" } +legacy-support-v4 = { group = "androidx.legacy", name = "legacy-support-v4", version.ref = "legacy-support" } +material = { group = "com.google.android.material", name = "material", version.ref = "material" } +mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version.ref = "mockito-kotlin" } +opencsv = { group = "com.opencsv", name = "opencsv", version.ref = "opencsv" } +rules = { group = "androidx.test", name = "rules", version.ref = "rules" } +sqlite-jdbc = { module = "org.xerial:sqlite-jdbc", version.ref = "sqliteJdbc" } +uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "uiautomator" } + +[bundles] +androidTest = [ + "annotation", + "dagger", + "dexmaker-mockito", + "espresso-contrib", + "espresso-core", + "junit", + "ktor-client-mock", + "ktor-jackson", + "mockito-kotlin", + "rules", + "uiautomator" +] +test = [ + "dagger", + "junit-junit", + "mockito-kotlin", +] + +[plugins] +agp = { id = "com.android.application", version.ref = "agp" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } +ktlint-plugin = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint-plugin" } +shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" } \ No newline at end of file diff --git a/translators.gradle.kts b/gradle/translators.gradle.kts similarity index 100% rename from translators.gradle.kts rename to gradle/translators.gradle.kts diff --git a/settings.gradle.kts b/settings.gradle.kts index 67dcdf9bd..b7b124189 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,13 +1,32 @@ pluginManagement { repositories { gradlePluginPortal() - google() + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } } - resolutionStrategy.eachPlugin { - if (requested.id.id == "com.android.application") { - useModule("com.android.tools.build:gradle:${requested.version}") +} + +include(":uhabits-android", ":uhabits-core") +dependencyResolutionManagement { + @Suppress("UnstableApiUsage") + repositories { + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } } + mavenCentral() + maven(url = "https://plugins.gradle.org/m2/") + maven(url = "https://oss.sonatype.org/content/repositories/snapshots/") + maven(url = "https://jitpack.io") } } -include(":uhabits-android", ":uhabits-core", ":uhabits-server") +include(":uhabits-android", ":uhabits-core") diff --git a/tools/androidStringsToKt.sh b/tools/androidStringsToKt.sh deleted file mode 100755 index b1ed51dcf..000000000 --- a/tools/androidStringsToKt.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -input=$1 -locale_name=$2 - -cat <\([^<]*\)<.*/ '"$prefix"'val \1 = "\2"/' - -echo "}" diff --git a/tools/convertAllStrings.sh b/tools/convertAllStrings.sh deleted file mode 100755 index fba8830b9..000000000 --- a/tools/convertAllStrings.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -INPUT_DIR=../android/uhabits-android/src/main/res/ -OUTPUT_DIR=../core/src/commonMain/kotlin/org/isoron/uhabits/i18n/ - -convert() { - ./androidStringsToKt.sh $INPUT_DIR/$1/strings.xml "$2" > $OUTPUT_DIR/Strings$2.kt -} - -#convert values "" -convert values-ar Arabic -convert values-bg Bulgarian -convert values-ca Catalan -convert values-cs Czech -convert values-da Danish -convert values-de German -convert values-el Greek -convert values-eo Esperanto -convert values-es Spanish -convert values-eu Basque -convert values-fa Persian -convert values-fi Finnish -convert values-fr French -convert values-hi Hindi -convert values-hr Croatian -convert values-hu Hungarian -convert values-in Indonesian -convert values-it Italian -convert values-iw Hebrew -convert values-ja Japanese -convert values-ko Korean -convert values-nl Dutch -convert values-no-rNO Norwegian -convert values-pl Polish -convert values-pt-rBR PortugueseBR -convert values-pt-rPT PortuguesePT -convert values-ro Romanian -convert values-ru Russian -convert values-sl Slovak -convert values-sr Serbian -convert values-sv Swedish -convert values-tr Turkish -convert values-uk Ukrainian -convert values-vi Vietnamese -convert values-zh-rCN ChineseCN -convert values-zh-rTW ChineseTW diff --git a/translators-crowdin.csv b/translators-crowdin.csv index 2ce37da5f..930671f45 100644 --- a/translators-crowdin.csv +++ b/translators-crowdin.csv @@ -1,415 +1,536 @@ Name,Languages,"Translated (Words)","Target Words","Approved (Words)",Voted,"""+"" votes received","""-"" votes received","Winning (Words)",Joined -"Alinson Xavier (iSoron)","Portuguese, Brazilian; Japanese; Chinese Simplified; Italian; Spanish; Portuguese; French; Hungarian; Chinese Traditional; Turkish; Russian; Polish; Arabic; German; Korean; Greek; Catalan; Bulgarian; Hindi; Slovenian; Ukrainian; Serbian (Cyrillic); Czech; Indonesian; Croatian; Danish; Dutch; Romanian; Swedish; Basque; Persian; Finnish; Vietnamese; Tamil; Telugu; Hebrew; Esperanto; Norwegian; Afrikaans; Slovak; Armenian; Serbian (Latin); Uyghur",15497,18825,1308,0,1896,84,4315,"2016-03-05 18:35:27" -"Slobodan Simić (Слободан Симић) (slsimic)","Serbian (Latin); Serbian (Cyrillic)",2054,1831,2114,12,33,0,1991,"2021-02-03 14:26:07" -"Oglaigh Rystard (oglaignaheireann)","Ukrainian; Portuguese; Catalan; Greek; Basque; Romanian; Italian",1103,1037,1327,1,13,6,954,"2017-03-31 09:13:19" -dukelc,Slovak,1046,993,0,0,0,0,0,"2020-08-27 14:02:41" -"David (Cliff122)",Swedish,1040,1019,725,6,0,0,700,"2020-01-21 13:56:55" -"Omer I.S. (omeritzics)",Hebrew,1040,927,1122,14,1,0,975,"2020-10-11 20:10:51" +"Alinson Xavier (iSoron)","Portuguese, Brazilian; Japanese; Chinese Simplified; Italian; Spanish; Portuguese; French; Hungarian; Chinese Traditional; Turkish; Russian; Arabic; Polish; German; Korean; Bulgarian; Catalan; Greek; Slovenian; Hindi; Serbian (Cyrillic); Ukrainian; Czech; Danish; Dutch; Indonesian; Croatian; Romanian; Swedish; Basque; Persian; Finnish; Vietnamese; Tamil; Telugu; Hebrew; Esperanto; Afrikaans; Norwegian; Armenian; Slovak; Serbian (Latin); Uyghur",15497,18825,1308,0,2094,111,4315,"2016-03-05 18:35:27" +"Slobodan Simić (Слободан Симић) (slsimic)","Serbian (Latin); Serbian (Cyrillic)",2072,1852,2139,12,30,0,2015,"2021-02-03 14:26:07" +dukelc,Slovak,1107,1052,0,0,0,0,0,"2020-08-27 14:02:41" +"Oglaigh Rystard (oglaignaheireann)","Ukrainian; Portuguese; Catalan; Greek; Basque; Romanian; Italian",1103,1037,1327,1,22,13,954,"2017-03-31 09:13:19" +Avalysion,Georgian,1057,895,0,0,0,0,0,"2023-06-30 20:05:15" +"Mathew TK (mathew2006)",Malayalam,1057,1885,0,0,0,0,0,"2023-12-16 01:57:49" +REMOVED_USER,Hebrew,1051,944,1122,14,1,0,954,"2020-10-11 20:10:51" +"David (Cliff122)",Swedish,1040,1019,725,6,37,0,700,"2020-01-21 13:56:55" "Intan Ayunda (Intan_Ayunda)",Indonesian,818,811,985,0,0,0,729,"2020-10-14 07:51:58" -"Mihail Stefanov (MStefanov)",Bulgarian,755,794,3,0,2,0,2,"2017-03-31 16:09:02" +dusanstrgar,Slovenian,770,730,0,0,0,0,0,"2017-03-31 10:30:28" +"Mihail Stefanov (MStefanov)",Bulgarian,755,794,3,0,2,4,2,"2017-03-31 16:09:02" +Osoitz,Basque,751,683,0,9,0,0,3,"2018-01-23 14:07:47" KMakoto,"Chinese Traditional",745,1146,949,0,0,0,745,"2019-10-22 04:19:52" -"Evren (evrenkiymaz)",Turkish,688,604,0,71,28,22,0,"2020-10-04 03:39:16" -andaryon,Czech,681,606,0,108,0,0,0,"2021-11-25 10:20:45" +Tomairuka,Japanese,709,1842,1033,43,12,0,585,"2020-12-12 12:14:22" +"Evren (evrenkiymaz)",Turkish,688,604,0,71,31,22,0,"2020-10-04 03:39:16" +andaryon,Czech,681,606,0,108,21,0,0,"2021-11-25 10:20:45" "Antti Kallio (antti.kallio)",Finnish,668,539,0,5,0,0,0,"2021-07-03 05:54:44" "David Nos (david.nos)","Catalan; Spanish",667,731,0,0,1,0,0,"2020-01-04 10:15:36" androide74,Italian,662,681,0,2,0,0,0,"2020-02-06 15:46:28" -Osoitz,Basque,655,595,0,9,0,0,3,"2018-01-23 14:07:47" -"Dmitriy Bogdanov (di72nn)",Russian,643,589,1197,0,36,0,515,"2017-03-31 10:00:48" -Tomairuka,Japanese,633,1636,909,43,0,0,564,"2020-12-12 12:14:22" -reyhoon,Persian,624,759,0,1,3,1,0,"2020-10-01 18:17:23" +"Dmitriy Bogdanov (di72nn)",Russian,643,589,1197,0,50,0,515,"2017-03-31 10:00:48" +reyhoon,Persian,624,759,0,1,3,2,0,"2020-10-01 18:17:23" "Saeed Esmaili (saaeed.es20)",Persian,586,795,0,5,4,0,0,"2020-11-26 15:41:15" -fabian.bouchal,German,548,527,0,6,0,3,72,"2020-01-07 06:43:37" -"Isti (eisti)",Hungarian,528,476,0,0,0,0,0,"2020-12-03 12:02:51" -boban77,Czech,509,461,0,2,29,0,0,"2020-04-30 13:18:24" +fabian.bouchal,German,548,527,0,6,4,5,72,"2020-01-07 06:43:37" +"Isti (eisti)",Hungarian,528,476,0,0,1,0,0,"2020-12-03 12:02:51" +Aravinth_Earth,Tamil,511,961,0,12,0,0,0,"2024-02-23 12:37:28" +boban77,Czech,509,461,0,2,45,0,0,"2020-04-30 13:18:24" "Martim Parente (martimparente)",Portuguese,505,542,0,38,0,0,0,"2020-08-26 10:22:11" "Yoav Argov (YoavArgov)",Hebrew,501,461,0,0,1,8,91,"2017-04-28 07:23:01" REMOVED_USER,Norwegian,501,498,501,0,148,0,501,"2017-07-05 19:02:25" "chrrris1987 (Chrrris1987)",Dutch,467,478,0,23,0,0,0,"2020-02-03 05:26:04" -"黄克 (hk13127)","Chinese Simplified",461,765,0,1,0,0,24,"2020-01-17 23:16:03" +"黄克 (hk13127)","Chinese Simplified",461,765,0,1,0,0,22,"2020-01-17 23:16:03" "Huy Ngo (huyngo)",Vietnamese,461,695,0,1,0,0,0,"2020-01-26 11:58:36" -"Arkadiusz Bubak (epitek)",Polish,458,416,52,24,9,4,0,"2020-11-05 05:11:58" +"Arkadiusz Bubak (epitek)",Polish,458,416,52,24,15,4,0,"2020-11-05 05:11:58" +"Radek Kuklík (kuklik.radek)",Czech,453,392,0,100,0,0,0,"2022-10-08 10:04:24" marco.baturan,Esperanto,452,452,0,0,0,0,0,"2020-06-23 02:49:46" -"Sief Tarek (sieftarek135)",Arabic,447,455,0,0,0,0,0,"2021-02-07 14:35:21" -"Alparslan Şakçi (sakci)",Turkish,436,372,0,118,1,0,0,"2022-01-14 12:03:11" -JY3,"Chinese Simplified",427,727,295,0,1,0,222,"2021-03-08 08:53:35" +"Sief Tarek (sieftarek135)",Arabic,447,455,0,0,1,4,0,"2021-02-07 14:35:21" +"Alparslan Şakçi (sakci)",Turkish,436,372,0,118,2,0,0,"2022-01-14 12:03:11" +JY3,"Chinese Simplified",432,741,298,0,2,0,227,"2021-03-08 08:53:35" "Samuel Guay (SamGuay)",French,426,486,0,6,0,0,0,"2020-06-25 07:14:38" "Diana Karaseva (Sun_Dianka)",Russian,399,373,0,10,1,0,209,"2020-01-30 06:40:02" -"Alexander Jansson (dalecarlian)",Swedish,396,406,507,0,0,3,399,"2017-06-21 01:37:32" +"Alexander Jansson (dalecarlian)",Swedish,396,406,507,0,29,6,399,"2017-06-21 01:37:32" luiandresgonzalez,Spanish,383,403,0,1,28,0,0,"2020-07-11 14:20:44" "Thamara Andrade (tkcandrade)","Portuguese, Brazilian",380,387,0,0,1,0,239,"2020-01-09 19:35:48" "Sølv Ræven (soelvraeven)",Danish,370,370,0,0,0,0,0,"2020-11-28 16:46:18" +strikeCunny2245,Icelandic,363,368,0,0,0,0,0,"2023-08-07 08:05:53" "Anh Quân (dangquanuet)",Vietnamese,362,530,0,42,2,0,0,"2017-10-29 12:27:44" +"Alexander Haronitakis (kanakis)",Greek,349,372,0,0,0,0,0,"2023-09-13 04:10:43" gapszi,Hungarian,348,301,0,86,0,0,0,"2019-04-08 01:35:54" "Mahdi Nasiri (mahdi.nasiri)",Persian,343,465,0,39,3,1,0,"2017-07-14 09:17:25" Seoyul,Korean,339,825,0,0,27,0,0,"2017-06-21 08:11:39" -"Magimai Prakasam (magimai)",Tamil,336,831,0,12,0,0,0,"2018-04-15 21:16:08" -"Michael Malak (MichaelKMalak)",Arabic,304,271,0,0,1,0,0,"2020-05-26 19:47:58" -Blinkin,Dutch,297,334,0,5,0,0,0,"2021-06-14 10:30:05" +"Magimai Prakasam (magimai)",Tamil,336,831,0,12,2,0,0,"2018-04-15 21:16:08" +"Star7 (Star7-crowdin)","Chinese Simplified",330,561,0,0,0,0,0,"2025-02-10 08:41:34" +Susanamesa,Spanish,306,342,0,11,0,0,0,"2023-01-01 23:56:35" +"Michael Malak (MichaelKMalak)",Arabic,304,271,0,0,4,2,0,"2020-05-26 19:47:58" "Elina Salminen (salminen.elina.m)",Finnish,297,227,0,0,0,0,0,"2021-01-06 01:28:57" -ayane.m,Japanese,292,863,0,1,5,0,22,"2019-11-20 03:28:26" -"Marius Teufelweich (teufelweich)",German,267,272,611,4,13,1,146,"2021-03-12 04:11:38" +Blinkin,Dutch,297,334,0,5,1,0,0,"2021-06-14 10:30:05" +ayane.m,Japanese,292,863,0,1,8,0,23,"2019-11-20 03:28:26" +c.m,Greek,276,293,0,124,0,0,0,"2024-07-13 14:49:43" +"Marius Teufelweich (teufelweich)",German,267,272,611,4,23,3,146,"2021-03-12 04:11:38" +"Sumin Son (todaypp)",Korean,266,221,0,7,0,0,0,"2023-06-09 05:28:30" hypnotichemionus,"Chinese Simplified",249,430,0,0,8,0,19,"2020-03-08 01:46:25" +"Israa Z (sosozozo)",Arabic,240,266,0,81,14,0,3,"2017-11-27 14:10:50" cobalt59,German,237,234,0,1,24,1,132,"2017-06-05 05:18:33" beriain,Basque,234,235,0,0,2,0,0,"2017-03-31 15:42:28" pnhpnh,Vietnamese,225,343,0,1,3,0,0,"2017-11-27 12:06:07" "Dika Fitrian Dwi Putra (OsamuDazai)",Indonesian,221,215,0,0,0,0,48,"2020-07-13 04:40:27" easyrepro,Telugu,214,297,0,0,4,0,0,"2020-06-12 12:52:10" taras-ko,Ukrainian,211,183,0,1,4,0,19,"2017-10-26 16:52:22" +"vinayak sharma (vinayak0504)",Hindi,211,456,0,0,0,0,0,"2023-05-18 18:31:51" sojusnik,German,207,200,1,0,30,0,66,"2017-04-03 17:11:56" -"Andrij Mizyk (andmizyk)",Ukrainian,204,178,0,40,0,0,53,"2021-04-01 03:56:20" +"Andrij Mizyk (andm)",Ukrainian,204,178,0,40,1,0,53,"2021-04-01 03:56:20" "Heru Yen (heruyen)",Indonesian,201,201,0,0,0,0,25,"2020-06-29 18:39:15" "Vijaykumar Borkar (vjkumar)",Hindi,200,364,0,11,0,0,0,"2021-08-06 16:12:15" _translator,French,199,227,0,11,0,0,0,"2021-07-06 07:54:12" +bearsdens,Romanian,198,210,0,0,0,0,0,"2022-08-28 17:08:33" Ishmaeel,Turkish,193,174,0,129,17,6,0,"2017-10-04 03:54:00" -oscfd,Spanish,192,201,0,2,4,0,0,"2021-05-21 17:58:22" +REMOVED_USER,Spanish,192,201,0,2,5,0,0,"2021-05-21 17:58:22" bruhwut,Vietnamese,189,292,0,1,0,0,0,"2021-05-21 07:16:30" "Aputsiak Niels Janussen (aputtu)",Danish,187,200,0,0,0,0,0,"2019-08-28 05:47:42" fbruna17,Danish,181,179,0,1,0,0,0,"2021-01-28 15:48:47" Bryanx,Dutch,179,168,0,5,2,0,0,"2019-11-21 17:08:12" -"Omry Cohen (omrycohen)",Hebrew,175,156,0,1,0,0,33,"2021-01-18 07:33:23" +"Ivan Vlahov (vlahovivan)",Croatian,179,176,0,0,0,0,0,"2024-01-25 08:12:11" +"Omry Cohen (omrycohen)",Hebrew,175,156,0,1,0,0,12,"2021-01-18 07:33:23" "Pierre GALIEGUE (pierre.galiegue)",French,171,194,0,24,4,0,0,"2020-08-16 11:41:35" -plitwin,Polish,168,151,0,2,31,0,49,"2021-01-20 06:18:37" -DionysosDV,Greek,165,153,0,0,0,0,0,"2021-02-27 19:05:25" +plitwin,Polish,168,151,0,2,55,0,49,"2021-01-20 06:18:37" +DionysosDV,Greek,165,153,0,0,27,4,0,"2021-02-27 19:05:25" "Gustavo Lima (GustavoLima)",Portuguese,158,177,0,1,4,10,0,"2020-08-26 10:35:05" +"Alex V. (elvitalex)",Romanian,154,166,0,24,0,0,0,"2022-08-03 17:40:00" "Ravi Rami (ramiravi)",Hindi,151,248,0,0,0,0,0,"2021-10-10 09:19:40" "Lương Vĩnh Khang (LuongVinhKhang)",Vietnamese,144,256,0,0,46,1,0,"2017-08-10 10:05:58" azzamsa,Indonesian,142,136,0,48,0,1,26,"2017-06-16 18:29:45" "yoding (yodingc)","Chinese Traditional; Chinese Simplified",141,271,0,10,0,0,0,"2021-07-07 01:45:45" "Neysa Nasywa (neysanasywa)",Indonesian,140,141,0,0,0,0,60,"2020-11-18 10:32:10" -mohmans,Arabic,139,141,0,12,1,0,0,"2020-11-23 02:48:00" -"Eilif Adelvice (adelvice)",Spanish,139,154,0,96,1,0,0,"2021-08-05 07:20:21" -"Mohammed Imthath (mimthath4)",Tamil,136,274,0,0,11,0,0,"2018-02-15 22:41:15" +mohmans,Arabic,139,141,0,12,7,1,0,"2020-11-23 02:48:00" +"Eilif Adelvice (adelvice)",Spanish,139,154,0,96,6,0,0,"2021-08-05 07:20:21" +"Mohammed Imthath (mimthath4)",Tamil,136,274,0,0,13,1,0,"2018-02-15 22:41:15" carllacan,Catalan,134,155,0,2,0,0,0,"2021-11-13 13:12:07" roptat,French,132,154,0,112,89,5,0,"2017-04-19 16:54:47" "Trần Thái (tranhoangthai2001)",Vietnamese,127,186,0,8,1,0,0,"2018-03-01 10:51:39" "OP Smosher (teenwolffan44)","Serbian (Cyrillic)",124,122,0,0,0,0,18,"2020-11-05 09:41:35" +"Tad Wohlrapp (TadWohlrapp)",German,124,122,0,0,2,0,0,"2022-06-28 04:55:41" 4001982248998,Esperanto,122,119,0,0,0,0,0,"2017-10-08 04:13:02" -"StoP4Me (Lcqp)",Romanian,121,119,0,0,3,0,0,"2018-05-06 18:51:59" -alalloush,Arabic,118,129,0,2,14,3,0,"2017-03-31 12:37:17" +"StoP4Me (Lcqp)",Romanian,121,119,0,0,6,0,0,"2018-05-06 18:51:59" +alalloush,Arabic,118,129,0,2,17,6,0,"2017-03-31 12:37:17" +"Brenda Correa (brenda.14)",Spanish,117,127,0,0,0,1,0,"2022-05-16 02:34:13" +Sebastian05067,Spanish,114,133,0,55,32,0,0,"2017-05-14 00:48:16" "Tanya (MagicUnderHood)",Russian,114,98,0,19,0,0,54,"2019-04-21 10:44:03" -Sebastian05067,Spanish,114,133,0,55,28,0,0,"2017-05-14 00:48:16" -REMOVED_USER,Arabic,111,106,0,22,22,2,0,"2018-01-05 07:01:45" -"Iabin Arteaga (iabin)",Spanish,108,111,0,4,21,0,0,"2017-08-26 21:08:54" +REMOVED_USER,Arabic,111,106,0,22,23,3,0,"2018-01-05 07:01:45" "Ivan Krušlin (krux3r)",Croatian,108,122,503,0,0,0,108,"2017-03-31 09:15:24" -2kaafone,Finnish,105,90,0,0,0,0,0,"2019-08-12 06:58:48" +"Iabin Arteaga (iabin)",Spanish,108,111,0,4,21,1,0,"2017-08-26 21:08:54" +REMOVED_USER,Finnish,105,90,0,0,0,0,0,"2019-08-12 06:58:48" "Adam Jurkiewicz (hasztagg)",Polish,104,105,529,0,0,0,104,"2017-03-31 09:50:51" +"PILHA PARK (pilhaha)",Korean,101,88,0,0,0,0,0,"2023-06-30 23:51:41" "just a name bro (justanamebr0)",Danish,98,109,0,0,1,0,0,"2019-06-19 11:57:55" "Nam Nguyen (namnl2706)",Vietnamese,95,137,0,0,0,0,0,"2020-08-18 23:02:33" -"손유정 (yuwon1213)",Korean,95,57,0,0,1,0,0,"2021-03-30 05:25:33" +"손유정 (yuwon1213)",Korean,95,57,0,0,1,3,0,"2021-03-30 05:25:33" ranmagen,Hebrew,91,78,0,0,0,0,0,"2021-02-16 05:44:31" LoneWanderer,"Chinese Traditional",90,137,0,4,0,0,0,"2020-09-29 05:24:48" ikkaz,Indonesian,89,84,0,5,0,0,4,"2019-09-02 19:58:54" "Vo - (voyl)","Chinese Traditional",89,126,0,0,5,0,0,"2020-09-02 23:34:42" -"Irene K (Heaun)",Korean,88,75,0,25,0,0,0,"2020-03-16 11:31:12" +"Irene K (Heaun)",Korean,88,75,0,25,2,0,0,"2020-03-16 11:31:12" Prosta4ok_ua,Ukrainian,87,84,0,1,0,0,17,"2020-01-23 19:43:41" "Kumar Anand (kumar0500)",Hindi,87,125,0,0,0,0,0,"2020-11-07 02:46:09" +G.kio,Russian,87,82,0,0,1,0,0,"2023-08-24 19:43:00" "Ohad Edri (ohadalte)",Hebrew,85,79,0,0,1,3,13,"2020-07-04 03:42:09" -helectron,Persian,84,102,0,1,0,0,0,"2021-03-02 04:10:51" -"Radu Cebotari (wildProgrammer)",Romanian,84,92,0,1,0,0,0,"2020-02-05 01:20:00" -"Bruces Lee (aplusbdesign)",Korean,82,66,0,0,0,0,0,"2021-08-23 11:27:18" -"Israa Z (sosozozo)",Arabic,79,87,0,43,14,0,3,"2017-11-27 14:10:50" -"Sofia Neves (sofiasonev)","Portuguese, Brazilian",79,84,0,1,0,0,46,"2020-03-12 18:19:46" -"Jacob Roller (jdr28070)",Korean,79,61,0,0,1,0,0,"2020-01-03 11:36:40" +"Radu Cebotari (wildProgrammer)",Romanian,84,92,0,1,1,0,0,"2020-02-05 01:20:00" +helectron,Persian,84,102,0,1,1,0,0,"2021-03-02 04:10:51" +"Bruces Lee (aplusbdesign)",Korean,82,66,0,0,2,0,0,"2021-08-23 11:27:18" Tiralka,French,79,91,0,92,1,0,0,"2018-02-09 18:39:01" +"Jacob Roller (jdr28070)",Korean,79,61,0,0,1,1,0,"2020-01-03 11:36:40" +"Sofia Neves (sofiasonev)","Portuguese, Brazilian",79,84,0,1,0,0,46,"2020-03-12 18:19:46" "Toni Mustonen (toni.mustonen)",Finnish,78,72,0,0,5,0,0,"2017-09-02 05:34:12" -"Michael (quelbs)",German,76,75,0,1,0,0,39,"2020-08-18 07:39:26" "Fauz Aladeem (topfauz)",Arabic,76,77,0,0,0,1,0,"2020-02-21 22:46:12" -"Radoslaw Biernacki (radoslaw.biernacki)",Polish,70,74,0,56,1,0,1,"2020-12-15 17:55:31" -"Oliver Gronowski (OliverGronowski)",German,70,69,0,5,2,0,0,"2021-05-14 16:37:10" +"Michael (quelbs)",German,76,75,0,1,0,0,39,"2020-08-18 07:39:26" +"Anna Maria Stålberg (stalberg.annamaria)",Swedish,76,77,0,111,4,0,0,"2023-01-16 04:08:25" +"Radoslaw Biernacki (radoslaw.biernacki)",Polish,70,74,0,56,5,0,1,"2020-12-15 17:55:31" +"Oliver Gronowski (OliverGronowski)",German,70,69,0,5,3,0,0,"2021-05-14 16:37:10" +mimizuk,Japanese,68,193,0,0,2,1,39,"2022-05-18 10:10:38" +Ryeore,Polish,68,61,0,66,0,0,0,"2022-07-27 12:22:33" RealDonald,Dutch,67,69,0,121,10,0,0,"2017-06-23 20:10:12" +"Dpd Eng (dpdeng)",Korean,67,48,0,0,1,0,0,"2022-10-15 10:56:44" sirekanyan,"Armenian; Russian",66,65,0,0,0,0,0,"2020-04-18 11:32:52" "Константин К. (kocyak1991)",Russian,64,60,0,0,1,2,0,"2018-06-10 13:39:37" +yukitsubaki,Japanese,64,185,0,32,0,0,36,"2020-01-01 13:17:44" +Suuis,Hindi,64,110,0,0,0,0,0,"2023-07-02 11:50:22" "Laura Sophie (laurasophie20)",German,62,67,0,4,0,0,0,"2018-01-06 14:21:24" raden20,Indonesian,61,62,177,0,1,0,64,"2017-04-09 22:04:23" -"Peter Williams (williamspete001)",Japanese,60,173,0,2,0,0,3,"2020-01-01 13:17:44" +"y (veggente)",Korean,61,56,0,0,0,1,0,"2022-06-28 10:41:18" "Jan Wojtecki (j4nw)",Polish,58,46,0,0,0,0,26,"2017-11-02 05:42:14" -"Deepak Bharathi (deepakbharathi1994)",Tamil,56,107,0,0,11,4,0,"2017-09-17 08:00:31" +"Deepak Bharathi (deepakbharathi1994)",Tamil,56,107,0,0,13,4,0,"2017-09-17 08:00:31" "Андрій Козицький (andriikozytskyi1108)",Ukrainian,52,52,0,0,1,0,0,"2018-10-22 01:45:08" "Nil riera (nilriera2000)",Catalan,52,61,0,1,2,0,0,"2021-06-22 16:37:44" -"Neoone (Neooneqq)",Romanian,51,54,0,0,0,0,0,"2022-05-05 20:42:11" REMOVED_USER,Italian,51,52,0,2,0,0,0,"2017-08-21 05:15:31" -govindap,"Japanese; Hindi",51,114,0,6,1,0,0,"2020-06-02 20:15:52" +govindap,"Japanese; Hindi",51,114,0,6,3,1,0,"2020-06-02 20:15:52" +"Neoone (Neooneqq)",Romanian,51,54,0,0,0,0,0,"2022-05-05 20:42:11" "Mare Geldenhuys (mare.geldenhuys)",Afrikaans,50,57,0,0,0,0,0,"2017-10-20 18:00:14" -"Mahmoud Magdy (M7moudManson)",Arabic,49,60,0,6,8,1,0,"2021-08-21 09:01:38" "Behnood HRazy (behnoodhr)",Persian,49,70,0,0,0,0,0,"2017-11-25 10:57:21" +"Mahmoud Magdy (M7moudManson)",Arabic,49,60,0,6,12,6,0,"2021-08-21 09:01:38" J3ll3nl,Dutch,48,48,0,0,17,1,3,"2017-03-31 11:56:09" "tat bz (Tat_i)",German,48,56,0,55,0,1,27,"2021-03-26 05:12:54" -vach,Armenian,47,36,0,0,0,0,0,"2020-04-18 16:53:12" "Andrew Firnes (Anechan)",Russian,47,47,0,3,0,0,29,"2019-09-18 09:51:59" -andowero,Czech,47,38,0,0,3,0,0,"2020-01-20 02:29:01" +andowero,Czech,47,38,0,0,8,0,0,"2020-01-20 02:29:01" +vach,Armenian,47,36,0,0,0,0,0,"2020-04-18 16:53:12" "Rahul Shishodia (rahul.shishodia.10)",Hindi,46,85,0,6,5,1,0,"2018-12-24 22:18:19" "Coni Ragni (coni2ragnii)",Spanish,46,46,0,0,0,0,0,"2021-02-28 20:18:37" Cp0204,"Chinese Simplified",45,72,0,0,0,0,0,"2019-08-20 11:04:27" "cc (cavaz)",Italian,44,41,0,0,0,0,0,"2017-04-01 04:21:08" -"Boban Jagertraum (boban40)",Czech,43,38,0,2,18,1,0,"2017-03-31 09:39:16" -"Kamil Dziadek (prso94)",Polish,43,39,0,0,6,0,0,"2020-04-06 17:12:06" +"Andrej Šutovský (16andrej.s)",Slovak,44,41,0,0,0,0,0,"2022-06-12 18:01:16" +"Boban Jagertraum (boban40)",Czech,43,38,0,2,31,1,0,"2017-03-31 09:39:16" +"Kamil Dziadek (prso94)",Polish,43,39,0,0,11,0,0,"2020-04-06 17:12:06" +"Balázs Keresztury (belidzs)",Hungarian,42,41,501,0,7,0,38,"2017-04-06 02:40:24" andreea.muscalagiu,Romanian,42,52,0,1,0,0,0,"2017-10-22 07:19:49" "Me Me (gentelwom)",Arabic,42,40,0,0,0,0,0,"2020-11-08 20:44:01" -"Balázs Keresztury (belidzs)",Hungarian,42,41,501,0,7,0,38,"2017-04-06 02:40:24" -"Mateusz Duda (MateuszDuda)",Polish,42,42,0,0,6,0,0,"2021-08-17 11:27:11" "Ali Elsheikh (aelsheikh1987)",Arabic,42,41,0,0,0,0,0,"2021-06-16 10:17:26" -"Ali Zali (stm19951995)",Persian,40,60,0,0,0,0,0,"2020-03-23 19:57:26" +"Mateusz Duda (MateuszDuda)",Polish,42,42,0,0,20,0,0,"2021-08-17 11:27:11" +"Mr Habti (donhabti)",Arabic,41,40,0,0,0,0,0,"2023-02-20 10:52:50" "Sofia Veijonen (Suklaa) (sofia.veijonen)",Finnish,40,33,0,0,0,0,0,"2018-03-07 09:24:22" -dusanstrgar,Slovenian,39,41,0,0,0,0,0,"2017-03-31 10:30:28" +"Neeraj Verma (verma.neeraj.in)",Hindi,40,65,0,0,1,0,0,"2018-07-23 07:16:41" +"Ali Zali (stm19951995)",Persian,40,60,0,0,0,0,0,"2020-03-23 19:57:26" "Limin Lu (liminlu)","Chinese Simplified",39,79,503,0,0,0,39,"2017-03-31 09:49:35" -Anshoe,Tamil,38,65,0,14,0,0,0,"2018-01-02 11:06:52" +Anshoe,Tamil,38,65,0,14,3,0,0,"2018-01-02 11:06:52" +"Pavel Protasov (pvphome)",Russian,38,33,0,0,0,0,0,"2024-02-09 03:40:33" anasshm,Arabic,37,36,0,9,0,0,0,"2019-01-27 04:07:22" hrexen,Armenian,37,37,0,0,0,0,0,"2020-12-09 02:30:34" -"Abdulrahman (D7M)",Arabic,36,39,0,0,0,0,0,"2020-01-29 18:55:30" -REMOVED_USER,Swedish,36,33,0,5,1,0,0,"2018-09-29 17:47:33" -xphsis,Basque,36,31,0,0,0,0,0,"2022-01-02 08:16:19" +REMOVED_USER,Swedish,36,33,0,5,2,0,0,"2018-09-29 17:47:33" +"Abdulrahman (D7M)",Arabic,36,39,0,0,4,0,0,"2020-01-29 18:55:30" "Maria Chushnyakova (maria.ch)",Russian,36,31,0,3,0,0,0,"2021-08-17 03:23:58" -"長谷川知里 (chase0213)",Japanese,34,138,0,13,0,0,24,"2018-12-14 10:52:44" -"Piotr Łuczyński (peterluczynski)",Polish,33,30,0,6,10,0,2,"2020-01-29 07:27:40" -"Luis E. Perichon (luisperichon)",Spanish,33,40,0,104,0,0,0,"2017-09-04 13:46:06" +xphsis,Basque,36,31,0,0,0,0,0,"2022-01-02 08:16:19" +"長谷川知里 (chase0213)",Japanese,34,138,0,13,0,0,32,"2018-12-14 10:52:44" "milad farahani (miladfarmahini90)",Persian,33,44,0,18,1,0,3,"2017-08-31 16:09:00" +"Luis E. Perichon (luisperichon)",Spanish,33,40,0,104,0,0,0,"2017-09-04 13:46:06" +"Piotr Łuczyński (peterluczynski)",Polish,33,30,0,6,17,0,2,"2020-01-29 07:27:40" JoeLi,"Chinese Traditional",31,70,0,12,0,0,24,"2017-06-25 05:32:48" -andriikozytskyi2625,Ukrainian,31,23,0,0,0,0,0,"2019-07-08 00:16:41" REMOVED_USER,Russian,31,30,0,2,4,0,3,"2018-12-03 23:55:47" -Moastafa,Arabic,31,25,0,0,0,0,0,"2020-07-06 11:37:53" -"hamza gamal (hamzagamal4444)",Arabic,31,28,0,0,0,0,0,"2020-08-03 15:23:34" +andriikozytskyi2625,Ukrainian,31,23,0,0,0,0,0,"2019-07-08 00:16:41" +Moastafa,Arabic,31,25,0,0,0,4,0,"2020-07-06 11:37:53" +"hamza gamal (hamzagamal4444)",Arabic,31,28,0,0,1,0,0,"2020-08-03 15:23:34" yancyn,"Chinese Simplified",30,40,0,0,0,0,1,"2020-05-18 20:06:03" +"Siniša Sabljić (ssabljic)",Croatian,30,37,0,0,0,0,0,"2023-11-13 15:51:00" "Ruud Schouten (ruudschouten)",Dutch,29,32,0,41,3,0,0,"2017-07-22 17:49:17" -"비니몬youtube (khj01025276475)",Korean,29,25,0,0,0,0,0,"2020-02-09 20:44:35" +"비니몬youtube (khj01025276475)",Korean,29,25,0,0,0,1,0,"2020-02-09 20:44:35" avelneve,Indonesian,29,28,0,0,0,0,0,"2022-04-13 13:26:10" +bzhn,Ukrainian,29,26,0,0,4,0,0,"2022-06-18 17:09:13" +"Gergő Mihály (mihalygergo97)",Hungarian,28,69,0,0,0,0,0,"2024-02-13 08:35:57" "Niraj Yadav (neverforgetniraj)",Hindi,26,48,0,0,0,0,0,"2017-04-11 02:26:50" -"Aaron Dalton (Perlkonig)",French,26,25,0,141,1,0,0,"2018-01-14 12:58:19" -"Jonny I (jonny99dj)",Italian,26,26,0,5,0,0,0,"2017-10-07 07:35:34" "Guillaume Collic (gcollic)",French,26,28,0,126,11,0,0,"2017-05-05 16:13:00" -Pan_Filuta,Czech,25,21,0,5,8,0,3,"2017-04-29 12:55:14" +"Jonny I (jonny99dj)",Italian,26,26,0,5,0,0,0,"2017-10-07 07:35:34" +"Aaron Dalton (Perlkonig)",French,26,25,0,141,1,0,0,"2018-01-14 12:58:19" +Pan_Filuta,Czech,25,21,0,5,11,0,3,"2017-04-29 12:55:14" "Eddie (eddieattaboy)","Chinese Traditional",25,34,0,1,0,0,0,"2020-11-04 21:48:05" -"eduard83 (barbany.eduard)",Catalan,24,25,0,2,0,0,0,"2019-06-26 14:59:47" -"A Aa (ylayzlmimashisafyoutub)",Arabic,23,33,0,34,1,1,0,"2021-09-27 15:34:26" +REMOVED_USER,Catalan,24,25,0,2,0,0,0,"2019-06-26 14:59:47" "Caner Başaran (basarancaner)",Turkish,23,21,0,0,26,1,0,"2017-04-09 06:34:59" "Ľuboš Čaky (lubos.caky)",Slovak,23,22,0,0,0,0,0,"2019-07-02 16:51:44" -"Neeraj Verma (verma.neeraj.in)",Hindi,22,37,0,0,1,0,0,"2018-07-23 07:16:41" -gnu-ewm,Polish,22,23,0,6,2,0,0,"2021-02-24 03:42:01" +"A Aa (ylayzlmimashisafyoutub)",Arabic,23,33,0,34,3,2,0,"2021-09-27 15:34:26" hodanli,Turkish,22,26,0,0,1,0,0,"2017-11-03 14:33:41" +REMOVED_USER,Polish,22,23,0,6,9,0,0,"2021-02-24 03:42:01" "Alcarkse (alexis.brusle)",French,21,25,0,7,11,0,0,"2017-08-06 09:32:29" +"Hugo Nogueira (hfrnogueira86)",Portuguese,21,22,0,0,0,0,0,"2023-01-09 22:51:24" "Shashwat (goforgold)",Hindi,20,33,0,0,0,0,0,"2020-05-17 10:34:42" olbotta,Italian,20,25,0,2,0,0,0,"2021-06-06 04:22:55" -can13,Turkish,19,14,0,8,0,0,0,"2021-01-03 10:39:03" -"사자솥 (toke1597)",Korean,19,19,0,0,0,0,0,"2020-02-04 13:36:11" -KenKailer,Arabic,19,25,0,0,0,0,0,"2022-05-10 06:16:54" "İsa Eş (IsaEs)",Turkish,19,17,0,0,6,2,0,"2017-06-20 07:30:22" "Magdalena Urbańczyk (madziia139)",Polish,19,19,0,0,0,0,0,"2017-10-21 03:01:04" sheeCesu,French,19,18,0,48,4,0,0,"2017-12-21 17:01:39" +"사자솥 (toke1597)",Korean,19,19,0,0,0,0,0,"2020-02-04 13:36:11" +can13,Turkish,19,14,0,8,0,0,0,"2021-01-03 10:39:03" +KenKailer,Arabic,19,25,0,0,0,0,0,"2022-05-10 06:16:54" axikman11111,Uyghur,18,19,0,0,0,0,0,"2018-10-13 12:25:31" -Adeline31,French,17,20,0,3,0,0,0,"2019-12-06 00:00:11" -"Hoon Jung (hooni100)",Korean,17,10,0,0,0,0,0,"2021-01-03 02:26:54" -takoyakibento,Korean,17,13,0,3,0,0,0,"2020-08-01 08:44:15" +"Sanjay Krishna (sjaykh)",Malayalam,18,42,0,0,0,0,0,"2024-06-01 08:57:37" +"Chuang-Chen Chiu (peterChiu9952)","Chinese Traditional",18,28,0,0,0,0,0,"2024-07-02 09:36:59" +AlexanderS,German,18,16,0,8,0,0,0,"2025-02-02 16:58:09" "Ceara Lopez (cealopez)",Spanish,17,18,0,0,5,1,0,"2017-08-22 22:56:13" -bretzel15,German,16,20,0,0,0,0,0,"2020-04-06 02:49:14" -DebatablySane,Bulgarian,16,15,0,48,0,0,0,"2017-07-10 15:13:18" +Adeline31,French,17,20,0,3,1,0,0,"2019-12-06 00:00:11" +takoyakibento,Korean,17,13,0,3,0,0,0,"2020-08-01 08:44:15" +"Hoon Jung (hooni100)",Korean,17,10,0,0,0,0,0,"2021-01-03 02:26:54" +Annelotte,Dutch,17,20,0,0,0,0,0,"2022-11-09 08:33:20" +wppoqqqi,Korean,17,18,0,4,0,0,0,"2024-11-30 04:22:21" "Şamil Ateşoğlu (m.samilatesoglu)",Turkish,16,22,0,11,6,3,0,"2017-07-05 18:37:08" +DebatablySane,Bulgarian,16,15,0,48,0,0,0,"2017-07-10 15:13:18" +bretzel15,German,16,20,0,0,1,0,0,"2020-04-06 02:49:14" engineeringforgood,Russian,16,15,0,0,0,0,16,"2021-01-22 03:32:35" +"M7md Salahaddin (m7mdsalahaddin)",Arabic,16,16,0,1,0,0,0,"2024-07-17 18:49:07" "Bhava Tharini (bhavidanush)",Tamil,15,37,0,0,0,0,0,"2019-10-09 05:43:11" -"Maro Chr (caprisunglasses)",Greek,14,17,0,0,0,0,0,"2021-08-17 06:53:33" -"Zeynep Esen (nezihaesen50)",Turkish,14,13,0,0,0,0,0,"2020-01-28 07:05:15" +"Ch. (sftblw)",Korean,15,17,0,1,0,0,0,"2023-01-25 19:22:34" iamsurajbobade,Hindi,14,30,0,0,0,0,0,"2018-05-21 11:23:27" -"Faiz Ahamed (faiznewton)",Tamil,14,31,0,0,0,0,0,"2021-05-06 23:06:46" +"Zeynep Esen (nezihaesen50)",Turkish,14,13,0,0,0,0,0,"2020-01-28 07:05:15" "Sanji Vinsmock (mukanzhanbolat4)",Russian,14,14,0,0,0,0,0,"2020-02-18 12:38:54" -"Zeeshan Rabbani (Zeera)",Hindi,14,25,0,0,0,0,0,"2020-09-15 11:32:01" -"pi hobbes (uwe_silv)",Japanese,14,46,0,0,0,0,0,"2022-01-15 02:57:14" "Anastasia Borchuk (al2.borchuk)",Russian,14,14,0,0,0,0,0,"2020-04-14 13:22:49" "Fikret Bilici (fikretbilici)",Turkish,14,13,0,0,0,0,0,"2020-06-21 17:16:11" -"EuiHo Hwang (euiho.hwang)",Korean,14,16,0,0,0,0,0,"2020-06-23 02:40:01" -"Uwe Mönks (schirinowski)",German,13,12,0,0,0,0,0,"2021-02-18 04:00:41" +"EuiHo Hwang (euiho.hwang)",Korean,14,16,0,0,1,0,0,"2020-06-23 02:40:01" +"Zeeshan Rabbani (Zeera)",Hindi,14,25,0,0,0,0,0,"2020-09-15 11:32:01" +"Faiz Ahamed (faiznewton)",Tamil,14,31,0,0,0,0,0,"2021-05-06 23:06:46" +"Maro Chr (caprisunglasses)",Greek,14,17,0,0,0,0,0,"2021-08-17 06:53:33" +"pi hobbes (uwe_silv)",Japanese,14,46,0,0,0,0,14,"2022-01-15 02:57:14" +"Mar Tous (mtousfernandez)",Catalan,14,18,0,0,0,0,0,"2022-08-16 17:55:28" +Ferhatt,Turkish,14,13,0,3,0,0,0,"2022-12-13 12:52:20" +alchemiker,German,14,13,0,0,0,0,0,"2024-09-03 10:16:04" +"Nenad Vukotic (vukotic.nenad)","Serbian (Cyrillic)",13,13,0,1,2,6,0,"2019-01-31 14:29:15" "Dave (xdave)",Hungarian,13,11,0,0,0,0,0,"2020-03-02 20:56:50" +"Uwe Mönks (schirinowski)",German,13,12,0,0,0,0,0,"2021-02-18 04:00:41" +Herbie_23,Italian,13,15,0,0,0,0,0,"2022-01-17 17:35:40" "Ana Kelly Vale (anakvale)","Portuguese, Brazilian",13,21,0,4,0,0,2,"2022-03-30 00:15:37" -GiorgioHerbie,Italian,13,15,0,0,0,0,0,"2022-01-17 17:35:40" -"Nenad Vukotic (vukotic.nenad)","Serbian (Cyrillic)",13,13,0,1,2,6,0,"2019-01-31 14:29:15" -soura2,Arabic,12,13,0,0,0,0,0,"2020-01-13 19:23:47" +"Minsu (cknblue)",Korean,13,10,0,1,0,0,0,"2022-05-18 00:26:54" "shreyas (techiespace)",Hindi,12,20,0,0,0,0,0,"2018-06-10 01:14:26" +soura2,Arabic,12,13,0,0,0,0,0,"2020-01-13 19:23:47" +"Ammar Naif (Ammar_Naif)",Arabic,12,12,0,6,0,0,0,"2022-01-15 05:16:41" "Jo Chuang (josephch405)","Chinese Traditional",11,24,0,0,0,0,11,"2017-06-16 20:21:06" Vmrc,French,11,12,0,2,0,0,0,"2020-11-02 05:35:06" -"Ammar Naif (Ammar_Naif)",Arabic,11,11,0,4,0,0,0,"2022-01-15 05:16:41" "Sonu Sharma (riteetude)",Hindi,11,23,0,0,0,0,0,"2021-05-30 19:38:00" +"Lucas Depetris (lucasdepetrisd)","Spanish; Catalan; Italian; French",11,12,0,12,0,0,0,"2023-10-24 21:16:21" +"Mihael Wagner (miha.wagner)",Slovenian,10,9,0,7,0,0,0,"2017-10-18 18:26:29" +"Anonymous edgy nerd (yamentaad)",Arabic,10,13,0,1,0,0,0,"2018-05-06 09:23:57" "Edwin van Rooij (edwinvrooij)",Dutch,10,13,0,17,0,0,0,"2018-11-05 03:59:10" "Brian Camacho (bmcamacho)",Polish,10,11,0,0,1,1,0,"2020-08-03 02:27:28" -"Mihael Wagner (miha.wagner)",Slovenian,10,9,0,7,0,0,0,"2017-10-18 18:26:29" -"Hrant Hakobian (hrastgh1)",Armenian,10,9,0,0,0,0,0,"2021-08-29 15:22:10" "sathvic k (sathvictripleseven)",Telugu,10,17,0,0,0,0,0,"2020-09-11 08:11:32" "Ahmed Mosaad (ahmed.mosaad2018)",Arabic,10,12,0,6,0,0,0,"2021-02-03 18:45:43" -"Anonymous edgy nerd (yamentaad)",Arabic,10,13,0,1,0,0,0,"2018-05-06 09:23:57" +"Hrant Hakobian (hrastgh1)",Armenian,10,9,0,0,0,0,0,"2021-08-29 15:22:10" +"Milan Siebenbürger (lennyd)",Czech,10,7,0,1,1,0,0,"2022-01-30 07:09:42" "Zesar Cebrián (Txorrota)",Spanish,10,44,0,0,0,0,0,"2022-02-09 01:34:32" -"Milan Siebenbürger (lennyd)",Czech,10,7,0,1,0,0,0,"2022-01-30 07:09:42" -"Suhaili Hassan (kucingsyg96)",Indonesian,9,10,0,0,0,0,0,"2018-06-10 11:55:09" +"Слави Велчев (BRO36S) (gg13656)",Bulgarian,10,11,0,9,0,0,0,"2025-01-09 08:47:04" "Sourire Lucide (sourire_lucide)",Russian,9,10,0,0,1,0,0,"2018-03-22 01:37:55" -"Martin Vostatek (martinvostatek)",Czech,9,8,0,32,2,0,0,"2019-01-21 13:52:36" -"Seweryn Piotrowski (Draxxsx)",Polish,9,10,0,0,19,0,0,"2020-01-02 09:55:48" -"Jakob Weickmann (jweickm)",Japanese,8,21,0,0,0,0,0,"2021-10-05 11:10:25" +"Suhaili Hassan (kucingsyg96)",Indonesian,9,10,0,0,0,0,0,"2018-06-10 11:55:09" +"Martin Vostatek (martinvostatek)",Czech,9,8,0,32,3,0,0,"2019-01-21 13:52:36" +"Seweryn Piotrowski (Draxxsx)",Polish,9,10,0,0,26,0,0,"2020-01-02 09:55:48" +omoise,French,9,11,0,1,0,0,0,"2023-12-26 14:27:17" Rex123,Persian,8,8,0,0,0,0,0,"2017-07-01 00:47:42" +"Jakob Weickmann (jweickm)",Japanese,8,21,0,0,0,0,8,"2021-10-05 11:10:25" "Andrey ZaXeLoN (waragaa)",Russian,7,7,0,8,1,0,0,"2017-09-18 21:37:42" +"Vladimir Pavlychev (vovs03)",Russian,7,9,0,0,0,0,0,"2017-12-18 02:46:56" "Konstantin (KZhidovinov)",Russian,7,7,0,0,0,0,0,"2020-01-29 13:35:12" +pkorove,Greek,7,7,0,0,1,0,0,"2020-03-07 11:36:12" ftfoi,Norwegian,7,6,0,0,0,0,0,"2020-04-11 20:42:35" -"Vladimir Pavlychev (vovs03)",Russian,7,9,0,0,0,0,0,"2017-12-18 02:46:56" -"Felipe Chagas (chagretes)","Portuguese, Brazilian",7,8,0,0,3,0,5,"2022-01-10 12:20:25" "Андрій Козицький (andriikozytskyi3807)",Ukrainian,7,12,0,2,0,0,0,"2020-09-26 20:31:56" -pkorove,Greek,7,7,0,0,0,0,0,"2020-03-07 11:36:12" -ChloeLiang,Japanese,6,22,0,0,1,0,3,"2017-08-08 05:02:59" +"Felipe Chagas (chagretes)","Portuguese, Brazilian",7,8,0,0,3,0,5,"2022-01-10 12:20:25" +"Tomáš Miklovič (zyppi)",Slovak,7,7,0,0,0,0,0,"2022-09-11 15:12:06" "Sam (SorodonSorodon)",German,6,6,0,13,0,0,0,"2017-04-14 11:09:27" +ChloeLiang,Japanese,6,22,0,0,1,0,3,"2017-08-08 05:02:59" "닉닉 (seohu9466)",Korean,6,14,0,13,0,0,0,"2017-10-09 23:08:15" -"Sarita Cajas (sarayanacajas)",Spanish,6,4,0,0,1,0,0,"2021-05-14 14:27:59" erfan2927,Persian,6,6,0,0,0,0,0,"2018-04-09 02:12:44" "Burak Ceylan (7burakceylan)",Turkish,6,6,0,0,0,0,0,"2018-05-20 17:24:19" -andriikozytskyi2018,Ukrainian,5,5,0,0,0,0,0,"2017-09-03 05:24:43" -"Vitor Henrique (vitorhcl)","Portuguese, Brazilian",5,8,0,1,0,0,0,"2022-03-08 20:00:59" +"Sarita Cajas (sarayanacajas)",Spanish,6,4,0,0,1,0,0,"2021-05-14 14:27:59" +"خالد (mkhrafi1999)",Arabic,6,3,0,6,0,0,0,"2023-06-25 00:36:13" "Matthias Joly (joly.matt12)",French,5,8,0,27,1,0,0,"2017-08-28 09:53:59" -"Tomáš Hrabáček (Hrabyyy)",Czech,5,3,0,0,1,0,0,"2021-05-27 11:58:11" -"Guerra Ivaneth (rossanaiva-04)",Spanish,5,7,0,0,0,0,0,"2019-02-03 16:48:59" +andriikozytskyi2018,Ukrainian,5,5,0,0,0,0,0,"2017-09-03 05:24:43" "Дмитрий Хапенков (d.khapenkov)",Russian,5,5,0,6,4,0,2,"2018-01-06 23:00:43" +"Guerra Ivaneth (rossanaiva-04)",Spanish,5,7,0,0,0,0,0,"2019-02-03 16:48:59" "Micaela Pighin (micaelapiighin)",Spanish,5,6,0,1,0,0,0,"2019-10-09 23:32:42" -"Manuel Tassi (Mannivu)",Italian,5,6,0,0,0,0,0,"2021-01-03 11:00:33" -"Neko123 (emandic11)","Serbian (Cyrillic)",4,4,0,57,0,0,0,"2021-04-21 15:33:29" +"Manuel (Mannivu)",Italian,5,6,0,0,0,0,0,"2021-01-03 11:00:33" +"Tomáš Hrabáček (Hrabyyy)",Czech,5,3,0,0,2,0,0,"2021-05-27 11:58:11" +"Vitor Henrique (vitorhcl)","Portuguese, Brazilian",5,8,0,1,0,0,0,"2022-03-08 20:00:59" +SubhamJena,Hindi,5,12,0,3,0,0,0,"2023-04-19 11:13:19" "Lopo Isaac Fernández (rocapata)",Spanish,4,3,0,0,0,0,0,"2018-09-20 11:46:22" "Eli Besirov (elibesirov07)",Turkish,4,4,0,0,0,0,0,"2019-03-25 07:12:34" +bziuum,Polish,4,4,0,0,6,0,0,"2020-09-01 09:08:01" marmo,German,4,4,0,0,0,0,0,"2021-01-13 01:16:35" -bziuum,Polish,4,4,0,0,3,0,0,"2020-09-01 09:08:01" -"Craig Foobar (craig.foobar)",German,3,3,0,25,0,0,0,"2022-02-20 16:55:47" -Katarin,Ukrainian,3,3,0,0,0,0,0,"2022-03-17 14:44:59" -"Sarath S (CyberShark)",Tamil,3,7,0,0,0,0,0,"2020-08-27 22:43:16" +"Neko123 (emandic11)","Serbian (Cyrillic)",4,4,0,57,0,0,1,"2021-04-21 15:33:29" +"Mo Heydari (Mrheydari)",Dutch,4,4,0,0,0,0,0,"2023-02-21 04:54:49" +"Srekaravarshan N K (srekaravarshan)",Tamil,4,4,0,0,0,0,0,"2023-04-22 06:08:57" +"Thoum Ptrgnt (thomas.petrignet)",French,3,3,0,2,0,3,0,"2017-09-23 19:25:52" +carsten_kafke,German,3,3,0,43,0,0,3,"2017-10-27 13:27:47" "Vagner Roberto (vagner.trompete)","Portuguese, Brazilian",3,3,0,0,0,0,0,"2017-12-30 17:54:26" "Igor Piskun (i_piskun)",Ukrainian,3,3,0,0,0,0,0,"2018-01-19 15:20:27" -"Cláudio Bernardo (claudiobernardo.ti)","Portuguese, Brazilian",3,4,0,1,0,0,0,"2019-01-08 14:41:10" -"Unnie Here (Carb)",Hindi,3,8,0,0,0,0,0,"2020-03-18 23:34:35" +"Andrea Bianchi (andreawhite1597)",Italian,3,1,0,1,0,0,0,"2018-01-21 17:45:48" +"Gabriel Cavalcante (gabrielc.alves14)","Portuguese, Brazilian",3,4,0,0,0,0,0,"2018-08-06 22:24:54" +"joabe gabriel (joabegabrielcma1)","Portuguese, Brazilian",3,4,0,0,0,0,0,"2018-08-21 09:08:59" +"Martin Zimdahl (zimdahlmartin)",Swedish,3,2,0,0,2,0,3,"2018-09-15 04:39:22" REMOVED_USER,"Portuguese, Brazilian",3,4,0,0,0,0,0,"2018-11-18 09:02:37" -"Thoum Ptrgnt (thomas.petrignet)",French,3,3,0,2,0,3,0,"2017-09-23 19:25:52" "Oleg Kogut (kogut_oleg)",Ukrainian,3,3,0,0,0,0,0,"2018-12-28 14:31:02" -carsten_kafke,German,3,3,0,43,0,0,3,"2017-10-27 13:27:47" -Magidxz,Arabic,3,3,0,0,0,0,0,"2021-01-05 05:02:54" -"Péter Bernát (bernatp)",Hungarian,3,2,0,0,0,0,0,"2019-11-30 15:50:33" -"joabe gabriel (joabegabrielcma1)","Portuguese, Brazilian",3,4,0,0,0,0,0,"2018-08-21 09:08:59" -"Gabriel Cavalcante (gabrielc.alves14)","Portuguese, Brazilian",3,4,0,0,0,0,0,"2018-08-06 22:24:54" -"Martin Zimdahl (zimdahlmartin)",Swedish,3,2,0,0,1,0,3,"2018-09-15 04:39:22" +"Cláudio Bernardo (claudiobernardo.ti)","Portuguese, Brazilian",3,4,0,1,0,0,0,"2019-01-08 14:41:10" atomjani,Hungarian,3,3,0,0,0,0,0,"2019-01-19 00:49:25" -"mohammadali barati (mabaraty)",Persian,3,3,0,0,0,0,0,"2021-07-10 05:54:44" "Hiohana Rilary (hiohanarilary)","Portuguese, Brazilian",3,4,0,0,0,0,0,"2019-07-31 20:42:20" +"Péter Bernát (bernatp)",Hungarian,3,2,0,0,0,0,0,"2019-11-30 15:50:33" +"Unnie Here (Carb)",Hindi,3,8,0,0,0,0,0,"2020-03-18 23:34:35" +"Sarath S (CyberShark)",Tamil,3,7,0,0,0,0,0,"2020-08-27 22:43:16" +Magidxz,Arabic,3,3,0,0,0,0,0,"2021-01-05 05:02:54" +"mohammadali barati (mabaraty)",Persian,3,3,0,0,0,0,0,"2021-07-10 05:54:44" "Tejaswini Boppana (Tejaswini)",Telugu,3,1,0,0,0,0,0,"2021-08-27 23:48:55" -"Andrea Bianchi (andreawhite1597)",Italian,3,1,0,1,0,0,0,"2018-01-21 17:45:48" -"Ño Bí Tã (pt614553)",Arabic,2,8,0,1,0,2,0,"2021-05-22 20:41:01" -"Judith Ayala (Azul1612)",Spanish,2,1,0,0,0,1,0,"2021-05-18 17:07:19" -"Valerij D (vala.dobler)",German,2,2,0,0,0,0,0,"2018-09-22 09:38:27" +"Craig Foobar (craig.foobar)",German,3,3,0,25,1,0,0,"2022-02-20 16:55:47" +Katarin,Ukrainian,3,3,0,0,0,0,0,"2022-03-17 14:44:59" +ayet,Arabic,3,3,0,0,0,0,0,"2023-08-16 20:18:12" +REMOVED_USER,Ukrainian,2,2,0,0,0,0,0,"2017-06-15 12:24:44" +"Alex Stein (diefaust1993)",Russian,2,2,0,4,4,0,2,"2017-07-13 06:56:17" +omerfarukbas,Turkish,2,3,0,19,2,0,0,"2017-08-14 16:10:35" "Balthazar Aubard (Balatzar)",French,2,5,0,0,1,0,0,"2017-09-23 01:42:57" -"Ahmed Bazazo (ahmedbazazo)",Arabic,2,2,0,0,0,0,0,"2022-02-19 20:11:09" -"Ali Zaida (alizaeda92)",Arabic,2,2,0,0,0,0,0,"2019-12-01 11:47:00" "FAy FAy (fayfayfay52)","Chinese Traditional",2,5,0,0,0,0,0,"2017-10-06 08:53:21" -Soroor_SI,Persian,2,2,0,0,0,0,0,"2018-06-10 06:28:27" -chavs1997,Russian,2,2,0,9,0,0,0,"2018-05-18 16:58:19" -"Naveen jai krishna (njsbpolymer1)",Tamil,2,5,0,0,0,0,0,"2020-01-10 14:19:41" -omerfarukbas,Turkish,2,3,0,19,2,0,0,"2017-08-14 16:10:35" "Ilyas Fekhar (il47yas)",Arabic,2,2,0,0,0,0,0,"2018-04-17 22:00:41" -"Héctor Mañas García (hectodium)",Catalan,2,3,0,0,0,0,0,"2021-10-02 20:32:09" -"Walid Baazia (walidbaazia2005)",Arabic,2,1,0,0,0,0,0,"2021-01-27 12:47:34" -"fatemeh s (fargolseifoori3)",Persian,2,2,0,0,0,0,0,"2019-01-31 12:06:57" -"hesamiranii (esam.matouri)",Persian,2,2,0,0,0,0,0,"2018-09-22 16:33:36" -REMOVED_USER,Ukrainian,2,2,0,0,0,0,0,"2017-06-15 12:24:44" -"Alex Stein (diefaust1993)",Russian,2,2,0,4,4,0,2,"2017-07-13 06:56:17" amei,"Portuguese, Brazilian",2,2,0,0,0,0,0,"2018-04-19 19:42:28" -"أم محمد تقي (souadboudia19)",Arabic,2,2,0,0,0,0,0,"2020-06-13 15:24:17" -LNDDYL,"Chinese Traditional",2,4,0,0,0,0,2,"2018-04-22 04:00:19" +"Jimmy Young (Jimmyyoung)","Chinese Traditional",2,4,0,0,0,0,2,"2018-04-22 04:00:19" +chavs1997,Russian,2,2,0,9,0,0,0,"2018-05-18 16:58:19" +Soroor_SI,Persian,2,2,0,0,0,0,0,"2018-06-10 06:28:27" +"Valerij D (vala.dobler)",German,2,2,0,0,0,0,0,"2018-09-22 09:38:27" +"hesamiranii (esam.matouri)",Persian,2,2,0,0,0,0,0,"2018-09-22 16:33:36" +"fatemeh s (fargolseifoori3)",Persian,2,2,0,0,0,0,0,"2019-01-31 12:06:57" +"Danial Agh (danialagh)",Persian,2,3,0,0,0,0,0,"2019-03-30 13:24:16" "조화정 (yunjoo337)",Korean,2,2,0,0,0,0,0,"2019-06-16 22:25:31" +"Ali Zaida (alizaeda92)",Arabic,2,2,0,0,0,0,0,"2019-12-01 11:47:00" +"Naveen jai krishna (njsbpolymer1)",Tamil,2,5,0,0,1,0,0,"2020-01-10 14:19:41" +"أم محمد تقي (souadboudia19)",Arabic,2,2,0,0,0,0,0,"2020-06-13 15:24:17" +"Walid Baazia (walidbaazia2005)",Arabic,2,1,0,0,0,0,0,"2021-01-27 12:47:34" +"Judith Ayala (Azul1612)",Spanish,2,1,0,0,0,1,0,"2021-05-18 17:07:19" +"Ño Bí Tã (pt614553)",Arabic,2,8,0,1,0,2,0,"2021-05-22 20:41:01" +"Héctor Mañas García (hectodium)",Catalan,2,3,0,0,0,0,0,"2021-10-02 20:32:09" "Sidali Aymen (sidaliaymen950)",Arabic,2,2,0,0,0,0,0,"2022-01-31 18:50:59" -"Danial Agh (danialagh)",Persian,2,3,0,0,0,0,0,"2019-03-30 13:24:16" +"Ahmed Bazazo (ahmedbazazo)",Arabic,2,2,0,0,0,0,0,"2022-02-19 20:11:09" +"HypemanKEK (rocasta.dodvi)",Russian,2,2,0,0,0,0,0,"2023-01-13 03:45:06" +"Gmas (gustmaes1)",Dutch,2,2,0,0,0,0,0,"2023-01-26 13:52:54" +"Катерина Ховалкина (katerina959)",Russian,2,2,0,1,0,0,0,"2023-05-18 14:50:30" +"Pratheba Devanathan (devprath05)",Tamil,2,2,0,0,1,0,0,"2023-06-05 12:35:45" +"Gordon James Campbell (gordonjamescampbell)",Catalan,2,2,0,0,0,0,0,"2023-06-23 23:23:46" +"Suren Airyanam (suren.airyanam)",Persian,2,2,0,0,0,0,0,"2023-10-21 18:01:41" +axq,German,2,1,0,1,0,0,0,"2024-02-29 17:14:13" +"Hades Mori (Hades_Mori)",Ukrainian,2,2,0,0,0,0,0,"2024-07-03 07:14:58" iSoron2,"Portuguese, Brazilian",1,1,0,0,0,0,0,"2017-03-18 17:56:29" "Anton (tT0NG)","Chinese Traditional",1,2,0,0,0,0,1,"2017-07-06 14:18:39" -"Luca Gori (grolcu)",Italian,1,2,0,0,0,0,0,"2020-09-26 23:26:15" -axd,Spanish,1,1,0,15,0,0,0,"2017-09-12 05:48:51" -REMOVED_USER,Russian,1,2,0,6,1,0,1,"2019-12-26 05:37:01" -jonesses,German,1,1,0,1,0,0,1,"2021-01-01 08:03:18" +axd,Spanish,1,1,0,15,1,0,0,"2017-09-12 05:48:51" +"Wibi Cahyo (wbcahyoh)",Indonesian,1,3,0,0,0,0,0,"2017-12-14 06:35:58" "Alan Jeon (skyisle)",Korean,1,2,0,8,0,0,0,"2018-01-09 10:46:00" -"Maria Fefelova (mashafefel)",Russian,1,1,0,0,0,0,0,"2019-05-18 02:03:56" -"Patrick Pimenta (trickap1)","Portuguese, Brazilian",1,1,0,0,0,0,0,"2018-12-01 14:31:21" "박찌 (perpact20)",Korean,1,1,0,0,0,0,0,"2018-02-10 10:11:44" +"Patrick Pimenta (trickap1)","Portuguese, Brazilian",1,1,0,0,0,0,0,"2018-12-01 14:31:21" "Kan Black (kanblack.va)",Vietnamese,1,2,0,0,0,1,0,"2019-01-15 03:50:10" +"Maria Fefelova (mashafefel)",Russian,1,1,0,0,0,0,0,"2019-05-18 02:03:56" "Anastasiia Bondarenko (nastasya.bondarenko.97)",Russian,1,1,0,0,0,0,0,"2019-06-07 17:43:08" -"Wibi Cahyo (wbcahyoh)",Indonesian,1,3,0,0,0,0,0,"2017-12-14 06:35:58" -sanyoniket,,0,0,0,0,0,0,0,"2019-07-23 12:58:40" -"Sri Harsha Bhogi (sriharshabhogi)",,0,0,0,0,0,0,0,"2018-09-02 05:31:53" -Irsgram,Russian,0,0,0,1,0,0,0,"2019-09-30 16:42:20" -"Baran Özavcı (n2141n)",Turkish,0,0,0,1,0,0,0,"2022-02-26 04:32:51" -"Masataka Yakura (myakura)",Japanese,0,0,0,1,0,0,0,"2021-09-03 22:10:36" -ava_rfie,Persian,0,0,0,1,0,0,0,"2019-06-09 16:19:24" +REMOVED_USER,Russian,1,2,0,6,1,0,1,"2019-12-26 05:37:01" +"Luca Gori (grolcu)",Italian,1,2,0,0,0,0,0,"2020-09-26 23:26:15" +jonesses,German,1,1,0,1,0,0,1,"2021-01-01 08:03:18" +"monir s (ms.alam)",Persian,1,1,0,1,0,0,0,"2022-05-23 06:34:00" +"Daniel Luque (LuqueDaniel)",Spanish,1,1,0,0,0,0,0,"2022-06-30 20:37:07" +Liboide,Spanish,1,1,0,0,0,0,0,"2022-11-03 23:57:45" +"K RITE (kriteshojha5)",Hindi,1,1,0,1,0,0,0,"2024-08-14 17:28:55" +"Angelos (angelos1993)",Arabic,1,1,0,0,0,0,0,"2024-11-20 07:38:18" +"Bora Atıcı (Brtc)",Turkish,1,2,0,0,0,0,0,"2025-03-07 20:33:19" +EmanAmini,,0,0,0,0,0,0,0,"2017-03-31 13:27:43" +AnggaRifandi,,0,0,0,0,0,0,0,"2017-03-31 19:28:35" +"Lori Amico (lavodkaclyde2323)",Italian,0,0,0,1,0,0,0,"2017-04-09 10:08:13" +"Florian Stuhlmann (stuhlmann)",German,0,0,0,10,0,0,0,"2017-04-15 04:04:00" +Kamalakannan,,0,0,0,0,0,0,0,"2017-05-14 11:40:23" +"Éjbãss Übbeî (littlebittlebottle)",Norwegian,0,0,0,152,0,0,0,"2017-07-05 21:12:02" +"Dagna Q (dagnaq)",,0,0,0,0,0,0,0,"2017-08-06 01:42:52" +"Petros Bleyan (coolbleyan)",Russian,0,0,0,14,0,0,0,"2017-08-18 18:37:18" +Itch,,0,0,0,0,0,0,0,"2017-10-16 09:18:42" +"Muhammet Furkan ALMACI (furkan.almaci)",Turkish,0,0,0,1,0,0,0,"2017-10-29 13:44:56" +"Balaji Jayaraman (jkbalaji1103)",,0,0,0,0,0,0,0,"2017-10-30 22:12:27" +"Wellington Ribeiro (wellington.rib)",,0,0,0,0,0,0,0,"2017-11-16 07:32:25" +"Javid IRAN (twitteriran98)",Persian,0,0,0,1,0,0,0,"2017-11-25 16:47:25" +REMOVED_USER,Czech,0,0,0,1,0,0,0,"2017-12-24 04:08:27" +AhmedDz,Arabic,0,0,0,1,0,0,0,"2017-12-31 10:12:31" +"박인호 (wphestiraid)",Korean,0,0,0,2,0,0,0,"2018-01-05 00:33:14" +REMOVED_USER,,0,0,0,0,0,0,0,"2018-01-05 16:56:12" +NairaDNV,Spanish,0,0,0,9,0,0,0,"2018-01-05 19:10:33" +Raulbertassi,,0,0,0,0,0,0,0,"2018-01-07 17:23:18" +"Katherine Alexandra Flórez Ramírez (katherine.florez12)",Spanish,0,0,0,46,0,0,0,"2018-01-20 02:18:32" +farbod66,Persian,0,0,0,1,0,0,0,"2018-01-20 11:04:23" +droidahmed,Arabic,0,0,0,7,0,0,0,"2018-01-31 02:18:49" +"Yasin Okumus (lacivert)",Turkish,0,0,0,1,0,0,0,"2018-02-07 04:13:51" +"Sarah BCNN (fsarahboucenna)",French,0,0,0,16,0,0,0,"2018-02-11 11:07:36" T-v-Gerwen,Dutch,0,0,0,47,0,0,0,"2018-03-02 10:26:33" -"George Merkulov (george142.emarket)",Russian,0,0,0,11,0,0,0,"2019-06-09 19:47:02" -philfr49,French,0,0,0,2,0,0,0,"2018-09-03 14:20:32" "عبد الناصر سعيد الثبيتي (asaeed)",,0,0,0,0,0,0,0,"2018-03-13 02:09:35" -"Thomas Orlita (Thomas995)",Czech,0,0,0,1,0,0,0,"2017-12-24 04:08:27" -"Edmunds Edmundam (edmundam)",,0,0,0,0,0,0,0,"2020-06-01 14:18:18" -"Elmo (oberknecht)",,0,0,0,0,0,0,0,"2020-04-16 08:45:50" -"Равиль Мифтахов (ravilmif47)",Russian,0,0,0,1,0,0,0,"2019-08-12 21:58:30" -"Manny Farsangy (manifarsangi)",Persian,0,0,0,12,0,0,0,"2021-08-10 05:32:28" -"Samuel Przeździęk (samek22)",Polish,0,0,0,1,0,0,0,"2021-08-01 00:49:01" -"Saiprasath B (Saiprasath)",,0,0,0,0,0,0,0,"2021-07-11 11:10:41" +REMOVED_USER,Czech,0,0,0,18,0,0,0,"2018-03-27 06:19:52" +BongTran,Vietnamese,0,0,0,2,0,0,0,"2018-04-24 05:16:07" +"Ahmed Nazir (ahmednazir333)",,0,0,0,0,0,0,0,"2018-05-06 12:10:27" +mdrobulis,,0,0,0,0,0,0,0,"2018-05-24 01:40:42" REMOVED_USER,,0,0,0,0,0,0,0,"2018-08-24 00:17:43" -REMOVED_USER,,0,0,0,0,0,0,0,"2020-02-01 03:47:48" -"Arjun K. (arjunkdot)",,0,0,0,0,0,0,0,"2020-09-20 11:16:18" -EwanB,,0,0,0,0,0,0,0,"2019-11-19 10:04:38" -shuvo786,,0,0,0,0,0,0,0,"2019-11-13 00:18:12" -"Pro AAA (pro1010)",Arabic,0,0,0,1,0,0,0,"2022-02-14 03:32:44" -"manu (manuL96)",,0,0,0,0,0,0,0,"2022-05-06 23:34:55" -"Rivo Zängov (Eraser)",,0,0,0,0,0,0,0,"2020-10-13 04:38:26" -ashik8113,,0,0,0,0,0,0,0,"2022-04-13 11:58:26" -deepbird,,0,0,0,0,0,0,0,"2022-04-11 03:21:05" -REMOVED_USER,,0,0,0,0,0,0,0,"2018-10-27 15:34:36" -Elham1361,,0,0,0,0,0,0,0,"2018-10-27 12:01:06" +"Sri Harsha Bhogi (sriharshabhogi)",,0,0,0,0,0,0,0,"2018-09-02 05:31:53" +philfr49,French,0,0,0,2,0,0,0,"2018-09-03 14:20:32" "Ahnaf Tajwar (atn4404)",,0,0,0,0,0,0,0,"2018-10-16 11:13:30" +Elham1361,,0,0,0,0,0,0,0,"2018-10-27 12:01:06" +REMOVED_USER,,0,0,0,0,0,0,0,"2018-10-27 15:34:36" +"Никита Карамов (nikita.karamoff)",Russian,0,0,0,10,0,0,0,"2018-10-29 03:57:21" martyaberger,,0,0,0,0,0,0,0,"2019-01-01 18:48:08" AsadullahIlyas,,0,0,0,0,0,0,0,"2019-01-04 06:14:15" -"akmal shafiq (mohdakmalshafiq)",,0,0,0,0,0,0,0,"2021-11-01 01:04:50" -"Sylwuskak (sylwuskak)",Polish,0,0,0,1,0,0,0,"2022-01-25 04:19:53" -"Yunsu Kim (yunsukim86)",Korean,0,0,0,2,0,0,0,"2022-01-14 06:33:43" "Pumpith Ungsupanit (pumpithu)",,0,0,0,0,0,0,0,"2019-01-19 23:47:57" "Nat Fomicheva (natac)",Russian,0,0,0,3,0,0,0,"2019-01-25 14:35:02" -HemanthMeda,Telugu,0,0,0,4,0,0,0,"2021-12-01 14:02:14" -"darkkingredian (rediancool)",,0,0,0,0,0,0,0,"2021-07-27 16:04:32" -catemlitten,Japanese,0,0,0,1,0,0,0,"2021-11-17 15:06:02" -"Said Tahsin Dane (tasomaniac)",,0,0,0,0,0,0,0,"2021-09-25 05:31:01" +ava_rfie,Persian,0,0,0,1,0,0,0,"2019-06-09 16:19:24" +"George Merkulov (george142.emarket)",Russian,0,0,0,11,0,0,0,"2019-06-09 19:47:02" +sanyoniket,,0,0,0,0,0,0,0,"2019-07-23 12:58:40" +"Arttu Ylhävuori (arttu.ylhavuori)",,0,0,0,0,0,0,0,"2019-07-24 15:03:42" +"Равиль Мифтахов (ravilmif47)",Russian,0,0,0,1,0,0,0,"2019-08-12 21:58:30" +Irsgram,Russian,0,0,0,1,0,0,0,"2019-09-30 16:42:20" "Matus Zdansky (matuszdansky)",,0,0,0,0,0,0,0,"2019-10-20 13:52:24" -mdrobulis,,0,0,0,0,0,0,0,"2018-05-24 01:40:42" -valney.faria,"Portuguese, Brazilian",0,0,0,1,0,0,0,"2020-02-02 14:45:02" -"Petros Bleyan (coolbleyan)",Russian,0,0,0,14,0,0,0,"2017-08-18 18:37:18" -"Карлен Шаухаев (KarlenShaukhaev)",,0,0,0,0,0,0,0,"2020-04-27 08:53:49" -"Shuvashish Sahoo (shuvashish76)",,0,0,0,0,0,0,0,"2020-09-17 09:10:09" -REMOVED_USER,,0,0,0,0,0,0,0,"2018-01-05 16:56:12" -"Dagna Q (dagnaq)",,0,0,0,0,0,0,0,"2017-08-06 01:42:52" -Sandhu564.,,0,0,0,0,0,0,0,"2020-12-14 01:27:45" -AhmedDz,Arabic,0,0,0,1,0,0,0,"2017-12-31 10:12:31" -"Quentin Hibon (hiq)",,0,0,0,0,0,0,0,"2021-02-07 16:39:31" -"Ahmed Nazir (ahmednazir333)",,0,0,0,0,0,0,0,"2018-05-06 12:10:27" -"박인호 (wphestiraid)",Korean,0,0,0,2,0,0,0,"2018-01-05 00:33:14" -Raulbertassi,,0,0,0,0,0,0,0,"2018-01-07 17:23:18" -"Javid IRAN (twitteriran98)",Persian,0,0,0,1,0,0,0,"2017-11-25 16:47:25" -"Wellington Ribeiro (wellington.rib)",,0,0,0,0,0,0,0,"2017-11-16 07:32:25" -dimateos,,0,0,0,0,0,0,0,"2021-01-10 06:29:52" -"Balaji Jayaraman (jkbalaji1103)",,0,0,0,0,0,0,0,"2017-10-30 22:12:27" -"reza golestanzadeh (reza.golestanzadeh)",Persian,0,0,0,1,0,0,0,"2020-10-21 12:07:20" -"Muhammet Furkan ALMACI (furkan.almaci)",Turkish,0,0,0,1,0,0,0,"2017-10-29 13:44:56" -dongchen.yue,German,0,0,0,4,0,0,0,"2020-09-12 15:05:59" -"Алтынбек Наурызғали (altinbeknaurizgali)",Russian,0,0,0,1,0,0,0,"2020-08-12 13:03:49" -rooban23,,0,0,0,0,0,0,0,"2020-09-15 11:49:14" -NairaDNV,Spanish,0,0,0,9,0,0,0,"2018-01-05 19:10:33" -"Katherine Alexandra Flórez Ramírez (katherine.florez12)",Spanish,0,0,0,46,0,0,0,"2018-01-20 02:18:32" -Itch,,0,0,0,0,0,0,0,"2017-10-16 09:18:42" -"Yasin Okumus (lacivert)",Turkish,0,0,0,1,0,0,0,"2018-02-07 04:13:51" +shuvo786,,0,0,0,0,0,0,0,"2019-11-13 00:18:12" +EwanB,,0,0,0,0,0,0,0,"2019-11-19 10:04:38" "Eduard Boboc (edi.boboc33)",Romanian,0,0,0,4,0,0,0,"2019-12-16 09:08:39" Hayder21,,0,0,0,0,0,0,0,"2019-12-31 10:56:24" "Eliška Roubalová (roubaeli)",Czech,0,0,0,6,0,0,0,"2019-12-31 12:47:29" -Fazy1380,,0,0,0,0,0,0,0,"2021-04-10 11:02:53" -"Arttu Ylhävuori (arttu.ylhavuori)",,0,0,0,0,0,0,0,"2019-07-24 15:03:42" -EmanAmini,,0,0,0,0,0,0,0,"2017-03-31 13:27:43" -AnggaRifandi,,0,0,0,0,0,0,0,"2017-03-31 19:28:35" -"Lori Amico (lavodkaclyde2323)",Italian,0,0,0,1,0,0,0,"2017-04-09 10:08:13" -"Florian Stuhlmann (stuhlmann)",German,0,0,0,10,0,0,0,"2017-04-15 04:04:00" -Kamalakannan,,0,0,0,0,0,0,0,"2017-05-14 11:40:23" -farbod66,Persian,0,0,0,1,0,0,0,"2018-01-20 11:04:23" -"vi ve (VimalV)",,0,0,0,0,0,0,0,"2021-02-08 02:35:45" -"Éjbãss Übbeî (littlebittlebottle)",Norwegian,0,0,0,152,0,0,0,"2017-07-05 21:12:02" -"LeMeD (LeMeS)",French,0,0,0,2,0,0,0,"2021-02-06 15:35:00" -BongTran,Vietnamese,0,0,0,2,0,0,0,"2018-04-24 05:16:07" -REMOVED_USER,Czech,0,0,0,18,0,0,0,"2018-03-27 06:19:52" +REMOVED_USER,,0,0,0,0,0,0,0,"2020-02-01 03:47:48" mushin,,0,0,0,0,0,0,0,"2020-02-02 04:08:05" +valney.faria,"Portuguese, Brazilian",0,0,0,1,0,0,0,"2020-02-02 14:45:02" +"Elmo (oberknecht)",,0,0,0,0,0,0,0,"2020-04-16 08:45:50" +"Карлен Шаухаев (KarlenShaukhaev)",,0,0,0,0,0,0,0,"2020-04-27 08:53:49" +"Edmunds Edmundam (edmundam)",,0,0,0,0,0,0,0,"2020-06-01 14:18:18" +"Алтынбек Наурызғали (altinbeknaurizgali)",Russian,0,0,0,1,0,0,0,"2020-08-12 13:03:49" +dongchen.yue,German,0,0,0,4,0,0,0,"2020-09-12 15:05:59" +rooban23,,0,0,0,0,0,0,0,"2020-09-15 11:49:14" +REMOVED_USER,,0,0,0,0,0,0,0,"2020-09-17 09:10:09" +"Arjun K. (arjunkdot)",,0,0,0,0,0,0,0,"2020-09-20 11:16:18" +"Rivo Zängov (Eraser)",,0,0,0,0,0,0,0,"2020-10-13 04:38:26" +"reza golestanzadeh (reza.golestanzadeh)",Persian,0,0,0,1,0,0,0,"2020-10-21 12:07:20" +Sandhu564.,,0,0,0,0,0,0,0,"2020-12-14 01:27:45" +dimateos,,0,0,0,0,0,0,0,"2021-01-10 06:29:52" "Mateusz Teteruk (mttet)",Polish,0,0,0,1,0,0,0,"2021-01-23 13:09:59" -"Sarah BCNN (fsarahboucenna)",French,0,0,0,16,0,0,0,"2018-02-11 11:07:36" -droidahmed,Arabic,0,0,0,7,0,0,0,"2018-01-31 02:18:49" -"Никита Карамов (nikita.karamoff)",Russian,0,0,0,10,0,0,0,"2018-10-29 03:57:21" +"LeMeD (LeMeS)",French,0,0,0,2,0,0,0,"2021-02-06 15:35:00" +"Quentin Hibon (hiq)",,0,0,0,0,0,0,0,"2021-02-07 16:39:31" +"vi ve (VimalV)",,0,0,0,0,0,0,0,"2021-02-08 02:35:45" +Fazy1380,,0,0,0,0,0,0,0,"2021-04-10 11:02:53" +"Saiprasath B (Saiprasath)",,0,0,0,0,0,0,0,"2021-07-11 11:10:41" +"darkkingredian (rediancool)",,0,0,0,0,0,0,0,"2021-07-27 16:04:32" +"Samuel Przeździęk (samek22)",Polish,0,0,0,1,0,0,0,"2021-08-01 00:49:01" +"Manny Farsangy (manifarsangi)",Persian,0,0,0,12,0,0,0,"2021-08-10 05:32:28" +"Masataka Yakura (myakura)",Japanese,0,0,0,1,0,0,0,"2021-09-03 22:10:36" +"Said Tahsin Dane (tasomaniac)",,0,0,0,0,0,0,0,"2021-09-25 05:31:01" +"akmal shafiq (mohdakmalshafiq)",,0,0,0,0,0,0,0,"2021-11-01 01:04:50" +catemlitten,Japanese,0,0,0,1,0,0,0,"2021-11-17 15:06:02" +HemanthMeda,Telugu,0,0,0,4,0,0,0,"2021-12-01 14:02:14" +"Yunsu Kim (yunsukim86)",Korean,0,0,0,2,0,0,0,"2022-01-14 06:33:43" +"Sylwuskak (sylwuskak)",Polish,0,0,0,1,0,0,0,"2022-01-25 04:19:53" +"Pro AAA (pro1010)",Arabic,0,0,0,1,0,0,0,"2022-02-14 03:32:44" +"Baran Özavcı (n2141n)",Turkish,0,0,0,1,0,0,0,"2022-02-26 04:32:51" +deepbird,,0,0,0,0,0,0,0,"2022-04-11 03:21:05" +ashik8113,,0,0,0,0,0,0,0,"2022-04-13 11:58:26" +"manu (manuL96)",,0,0,0,0,0,0,0,"2022-05-06 23:34:55" +"Agnel (agnelwaghela)",,0,0,0,0,0,0,0,"2022-06-19 10:32:33" +"Ruslan Zaynetdinov (theRuslan)",Russian,0,0,0,6,0,0,0,"2022-07-06 10:48:31" +"Marcel (flaced)",German,0,0,0,1,0,0,0,"2022-08-19 15:19:26" +pixx1,German,0,0,0,6,0,0,0,"2022-08-22 00:38:13" +"Onder Nuray (ondernuray)",,0,0,0,0,0,0,0,"2022-08-30 08:16:27" +"Md Faridul Islam (mdfaridulislam509)",,0,0,0,0,0,0,0,"2022-09-04 06:25:20" +Felone,,0,0,0,0,0,0,0,"2022-09-10 08:04:02" +Sawwwwwplan,,0,0,0,0,0,0,0,"2022-09-10 11:35:14" +"Fatima (fatima.a)",Arabic,0,0,0,1,0,0,0,"2022-09-20 09:48:25" +DomiAlt,,0,0,0,0,0,0,0,"2022-10-02 15:44:26" +Erwindly,Polish,0,0,0,1,0,0,0,"2022-11-01 04:12:58" +"Deniz Çelik (DenizCelik)",,0,0,0,0,0,0,0,"2022-11-09 02:13:11" +Watashiwanilli,,0,0,0,0,0,0,0,"2022-11-14 10:12:21" +"Maxence LIGAN (Daddy_Caramel)",,0,0,0,0,0,0,0,"2022-12-23 04:43:30" +wstroobandt,Dutch,0,0,0,1,0,0,0,"2023-01-03 17:52:42" +"ニキホロブ蒼井 (abhigyahazra)",,0,0,0,0,0,0,0,"2023-01-08 21:37:53" +"Afrim Kamberi (afrimkamberi)",,0,0,0,0,0,0,0,"2023-01-17 05:20:06" +ViacheslavLabs,Ukrainian,0,0,0,5,0,0,0,"2023-01-21 15:34:40" +Basta,,0,0,0,0,0,0,0,"2023-03-04 16:13:57" +raselh,,0,0,0,0,0,0,0,"2023-03-15 03:33:21" +"Adrian Miozga (AdrianMiozga)",Polish,0,0,0,13,0,0,0,"2023-03-25 17:00:53" +"Atlas Steel (atlas.steel.erbil)",,0,0,0,0,0,0,0,"2023-05-16 05:23:32" +"Sathyakumar Ps (sathyakumar63)",,0,0,0,0,0,0,0,"2023-05-24 11:44:23" +"Abdul nafih (nafih_zain_)",,0,0,0,0,0,0,0,"2023-05-25 06:24:31" +"Bernhard (bernikr)",German,0,0,0,1,0,0,0,"2023-06-12 11:18:18" +"Anna Boda (annaboda08)",Hungarian,0,0,0,1,0,0,0,"2023-07-03 13:28:12" +"Rubén CH (chruben45)",Spanish,0,0,0,1,0,0,0,"2023-07-24 12:39:51" +"Vinicius (exteraDev)",,0,0,0,0,0,0,0,"2023-08-08 15:47:45" +"mugdad alhammad (alhammad5057)",,0,0,0,0,0,0,0,"2023-08-13 22:36:01" +"Arthur Waldes (arthurwaldes)",,0,0,0,0,0,0,0,"2023-08-22 15:38:12" +"Mahmoud Hatem (mahmoudhatem)",Arabic,0,0,0,1,0,0,0,"2023-09-12 05:12:34" +"Jacques Francky Salomon (jacquesfranckysalomon)",,0,0,0,0,0,0,0,"2023-10-14 20:55:30" +"Mohammad Hashem (hashemchattogram)",,0,0,0,0,0,0,0,"2023-10-27 02:15:39" +Aylinddd,Persian,0,0,0,1,0,0,0,"2023-11-07 22:50:37" +Dinock,German,0,0,0,1,0,0,0,"2023-11-10 07:08:23" +zelfoxx,German,0,0,0,12,0,0,0,"2023-11-22 11:11:44" +REMOVED_USER,,0,0,0,0,0,0,0,"2023-11-28 17:42:55" +"Dennis Li (Dennis_Li)","Chinese Simplified",0,0,0,1,0,0,0,"2023-12-24 21:12:43" +REMOVED_USER,Russian,0,0,0,5,0,0,0,"2024-01-01 17:15:06" +"Daniill l (daniill)",,0,0,0,0,0,0,0,"2024-01-12 02:42:52" +"NONE NAME (RagnarGraves)",Spanish,0,0,0,1,0,0,0,"2024-02-18 01:39:39" +lu21232512,,0,0,0,0,0,0,0,"2024-04-15 12:40:05" +"Oscariño (oscarinhooo)",,0,0,0,0,0,0,0,"2024-07-07 08:47:25" +"Vladimir Sveshnikov (proloxy)",Russian,0,0,0,6,0,0,0,"2024-07-12 03:27:39" +L0f3n,Swedish,0,0,0,2,0,0,0,"2024-08-06 17:13:50" +"Christer Fletcher (chrfle)",Swedish,0,0,0,2,0,0,0,"2024-08-15 04:15:49" +"Moaid alzawy (dodoalzawy200)",Arabic,0,0,0,1,0,0,0,"2024-09-18 12:17:31" +"Eduardo Ferreira (eduu)",,0,0,0,0,0,0,0,"2024-10-27 19:09:20" +"عبد الملك بلكم (aboodpvp555)",Arabic,0,0,0,1,0,0,0,"2024-12-12 02:42:14" +4Kio,Russian,0,0,0,1,0,0,0,"2024-12-12 12:31:25" +"رودينه (rwdynh874)",Arabic,0,0,0,1,0,0,0,"2024-12-24 18:31:33" +"zahra ghasemi (z.ghasemizahra)",Persian,0,0,0,1,0,0,0,"2024-12-29 04:36:27" +"Mustafa Işıksız (mustafalordon27)",Turkish,0,0,0,1,0,0,0,"2025-01-15 13:52:32" +"Ahlem Ben (ahlemben1513)",Arabic,0,0,0,1,0,0,0,"2025-02-12 11:09:57" +"Francisco Parra (Frn_7)",Spanish,0,0,0,1,0,0,0,"2025-02-18 22:57:05" +"mizumoto (yuta-mizumoto)",Japanese,0,0,0,2,0,0,0,"2025-03-03 18:35:56" diff --git a/uhabits-android/build.gradle.kts b/uhabits-android/build.gradle.kts index c599664c1..e17232c3d 100644 --- a/uhabits-android/build.gradle.kts +++ b/uhabits-android/build.gradle.kts @@ -18,10 +18,10 @@ */ plugins { - id("com.android.application") version "8.8.0" - id("org.jetbrains.kotlin.android") - id("org.jetbrains.kotlin.kapt") - id("org.jlleitschuh.gradle.ktlint") + alias(libs.plugins.agp) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.ksp) + alias(libs.plugins.ktlint.plugin) } tasks.compileLint { @@ -40,16 +40,14 @@ kotlin { } android { - namespace = "org.isoron.uhabits" - compileSdk = 35 - // compileSdkPreview = "VanillaIceCream" + compileSdk = 36 defaultConfig { versionCode = 20200 versionName = "2.2.0" minSdk = 28 - targetSdk = 35 + targetSdk = 36 applicationId = "org.isoron.uhabits" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } @@ -66,7 +64,7 @@ android { } buildTypes { - getByName("release") { + release { isMinifyEnabled = true proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.txt") if (signingConfigs.findByName("release") != null) { @@ -74,8 +72,8 @@ android { } } - getByName("debug") { - isTestCoverageEnabled = true + debug { + enableUnitTestCoverage = true } } @@ -84,64 +82,35 @@ android { targetCompatibility(JavaVersion.VERSION_11) sourceCompatibility(JavaVersion.VERSION_11) } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_11.toString() - } - - buildFeatures { - viewBinding = true - } - lint { - abortOnError = false - } + kotlinOptions.jvmTarget = JavaVersion.VERSION_11.toString() + buildFeatures.viewBinding = true + lint.abortOnError = false } dependencies { - val daggerVersion = "2.51.1" - val kotlinVersion = "2.1.10" - val kxCoroutinesVersion = "1.10.1" - val ktorVersion = "1.6.8" - val espressoVersion = "3.6.1" - - androidTestImplementation("androidx.test.espresso:espresso-contrib:$espressoVersion") - androidTestImplementation("androidx.test.espresso:espresso-core:$espressoVersion") - androidTestImplementation("com.google.dagger:dagger:$daggerVersion") - androidTestImplementation("com.linkedin.dexmaker:dexmaker-mockito:2.28.3") - androidTestImplementation("io.ktor:ktor-client-mock:$ktorVersion") - androidTestImplementation("io.ktor:ktor-jackson:$ktorVersion") - androidTestImplementation("androidx.annotation:annotation:1.7.1") - androidTestImplementation("androidx.test.ext:junit:1.2.1") - androidTestImplementation("androidx.test.uiautomator:uiautomator:2.3.0") - androidTestImplementation("androidx.test:rules:1.6.1") - androidTestImplementation("org.mockito.kotlin:mockito-kotlin:5.4.0") - compileOnly("javax.annotation:jsr250-api:1.0") - coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4") - implementation("com.github.AppIntro:AppIntro:6.3.1") - implementation("com.google.code.findbugs:jsr305:3.0.2") - implementation("com.google.dagger:dagger:$daggerVersion") - implementation("com.google.guava:guava:33.1.0-android") - implementation("io.ktor:ktor-client-android:$ktorVersion") - implementation("io.ktor:ktor-client-core:$ktorVersion") - implementation("io.ktor:ktor-client-jackson:$ktorVersion") - implementation("io.ktor:ktor-client-json:$ktorVersion") - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$kxCoroutinesVersion") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kxCoroutinesVersion") - implementation("androidx.appcompat:appcompat:1.7.0") - implementation("androidx.legacy:legacy-preference-v14:1.0.0") - implementation("androidx.legacy:legacy-support-v4:1.0.0") - implementation("com.google.android.material:material:1.12.0") - implementation("com.opencsv:opencsv:5.9") - implementation("nl.dionsegijn:konfetti-xml:2.0.2") + compileOnly(libs.jsr250.api) + coreLibraryDesugaring(libs.desugar.jdk.libs) + implementation(libs.appIntro) + implementation(libs.jsr305) + implementation(libs.dagger) + implementation(libs.guava) + implementation(libs.ktor.client.android) + implementation(libs.ktor.client.core) + implementation(libs.ktor.client.jackson) + implementation(libs.ktor.client.json) + implementation(libs.kotlin.stdlib.jdk8) + implementation(libs.kotlinx.coroutines.android) + implementation(libs.kotlinx.coroutines.core) + implementation(libs.appcompat) + implementation(libs.legacy.preference.v14) + implementation(libs.legacy.support.v4) + implementation(libs.material) + implementation(libs.opencsv) + implementation(libs.konfetti.xml) implementation(project(":uhabits-core")) - kapt("com.google.dagger:dagger-compiler:$daggerVersion") - kaptAndroidTest("com.google.dagger:dagger-compiler:$daggerVersion") - testImplementation("com.google.dagger:dagger:$daggerVersion") - testImplementation("junit:junit:4.13.2") - testImplementation("org.mockito.kotlin:mockito-kotlin:5.4.0") -} + ksp(libs.dagger.compiler) -kapt { - correctErrorTypes = true + androidTestImplementation(libs.bundles.androidTest) + testImplementation(libs.bundles.test) } diff --git a/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidget/render.png b/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidget/render.png index 2ffbb10ac..124fd3283 100644 Binary files a/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidget/render.png and b/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidget/render.png differ diff --git a/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/checked.png b/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/checked.png index a8bf398a3..0d12554f6 100644 Binary files a/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/checked.png and b/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/checked.png differ diff --git a/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/implicitly_checked.png b/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/implicitly_checked.png deleted file mode 100644 index 1f5aed305..000000000 Binary files a/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/implicitly_checked.png and /dev/null differ diff --git a/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/large_size.png b/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/large_size.png index bc7e34f20..1a15a2a80 100644 Binary files a/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/large_size.png and b/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/large_size.png differ diff --git a/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/unchecked.png b/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/unchecked.png deleted file mode 100644 index 28d40d4b3..000000000 Binary files a/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/unchecked.png and /dev/null differ diff --git a/uhabits-android/src/androidTest/assets/views/widgets/FrequencyWidget/render.png b/uhabits-android/src/androidTest/assets/views/widgets/FrequencyWidget/render.png index e72c6bedf..8efdcf216 100644 Binary files a/uhabits-android/src/androidTest/assets/views/widgets/FrequencyWidget/render.png and b/uhabits-android/src/androidTest/assets/views/widgets/FrequencyWidget/render.png differ diff --git a/uhabits-android/src/androidTest/assets/views/widgets/HistoryWidget/render.png b/uhabits-android/src/androidTest/assets/views/widgets/HistoryWidget/render.png index 23e3c979e..751c7f6ad 100644 Binary files a/uhabits-android/src/androidTest/assets/views/widgets/HistoryWidget/render.png and b/uhabits-android/src/androidTest/assets/views/widgets/HistoryWidget/render.png differ diff --git a/uhabits-android/src/androidTest/assets/views/widgets/ScoreWidget/render.png b/uhabits-android/src/androidTest/assets/views/widgets/ScoreWidget/render.png index 4f50ce820..078214a36 100644 Binary files a/uhabits-android/src/androidTest/assets/views/widgets/ScoreWidget/render.png and b/uhabits-android/src/androidTest/assets/views/widgets/ScoreWidget/render.png differ diff --git a/uhabits-android/src/androidTest/assets/views/widgets/StreakWidget/render.png b/uhabits-android/src/androidTest/assets/views/widgets/StreakWidget/render.png index 999af4424..ea183d3f8 100644 Binary files a/uhabits-android/src/androidTest/assets/views/widgets/StreakWidget/render.png and b/uhabits-android/src/androidTest/assets/views/widgets/StreakWidget/render.png differ diff --git a/uhabits-android/src/androidTest/assets/views/widgets/TargetWidget/render.png b/uhabits-android/src/androidTest/assets/views/widgets/TargetWidget/render.png index 5b3270649..bdfff3c09 100644 Binary files a/uhabits-android/src/androidTest/assets/views/widgets/TargetWidget/render.png and b/uhabits-android/src/androidTest/assets/views/widgets/TargetWidget/render.png differ diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt index 13e5f55f6..5bebfb08d 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt @@ -33,11 +33,10 @@ import org.isoron.uhabits.core.models.Entry.Companion.UNKNOWN import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL import org.isoron.uhabits.databinding.CheckmarkPopupBinding import org.isoron.uhabits.utils.InterfaceUtils.getFontAwesome -import org.isoron.uhabits.utils.getCenter import org.isoron.uhabits.utils.sres class CheckmarkDialog : AppCompatDialogFragment() { - var onToggle: (Int, String, Float, Float) -> Unit = { _, _, _, _ -> } + var onToggle: (Int, String) -> Unit = { _, _ -> } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val appComponent = (requireActivity().application as HabitsApplication).component @@ -64,8 +63,7 @@ class CheckmarkDialog : AppCompatDialogFragment() { } fun onClick(v: Int) { val notes = view.notes.text.toString().trim() - val location = view.yesBtn.getCenter() - onToggle(v, notes, location.x, location.y) + onToggle(v, notes) requireDialog().dismiss() } view.yesBtn.setOnClickListener { onClick(YES_MANUAL) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberDialog.kt index d8ba1ed59..4025bc2e6 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberDialog.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberDialog.kt @@ -25,7 +25,7 @@ import java.text.ParseException class NumberDialog : AppCompatDialogFragment() { - var onToggle: (Double, String, Float, Float) -> Unit = { _, _, _, _ -> } + var onToggle: (Double, String) -> Unit = { _, _ -> } var onDismiss: () -> Unit = {} private var originalNotes: String = "" @@ -36,16 +36,17 @@ class NumberDialog : AppCompatDialogFragment() { val appComponent = (requireActivity().application as HabitsApplication).component val prefs = appComponent.preferences view = CheckmarkPopupBinding.inflate(LayoutInflater.from(context)) - arrayOf(view.yesBtn, view.skipBtn).forEach { + arrayOf(view.yesBtn).forEach { it.setTextColor(requireArguments().getInt("color")) } - arrayOf(view.noBtn, view.unknownBtn).forEach { + arrayOf(view.noBtn, view.unknownBtnNumber).forEach { it.setTextColor(view.root.sres.getColor(R.attr.contrast60)) } - arrayOf(view.yesBtn, view.noBtn, view.skipBtn, view.unknownBtn).forEach { + arrayOf(view.yesBtn, view.noBtn, view.unknownBtnNumber).forEach { it.typeface = InterfaceUtils.getFontAwesome(requireContext()) } if (!prefs.isSkipEnabled) view.skipBtnNumber.visibility = View.GONE + if (!prefs.areQuestionMarksEnabled) view.unknownBtnNumber.visibility = View.GONE view.numberButtons.visibility = View.VISIBLE fixDecimalSeparator(view) originalNotes = requireArguments().getString("notes")!! @@ -71,6 +72,12 @@ class NumberDialog : AppCompatDialogFragment() { view.value.setText(DecimalFormat("#.###").format((Entry.SKIP.toDouble() / 1000))) save() } + + view.unknownBtnNumber.setOnClickListener { + view.value.setText(DecimalFormat("#.###").format((Entry.UNKNOWN.toDouble() / 1000))) + save() + } + view.notes.setOnEditorActionListener { v, actionId, event -> save() true @@ -115,7 +122,7 @@ class NumberDialog : AppCompatDialogFragment() { } val notes = view.notes.text.toString() val location = view.saveBtn.getCenter() - onToggle(value, notes, location.x, location.y) + onToggle(value, notes) requireDialog().dismiss() } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.kt index d16f7d702..d4e2ffa69 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.kt @@ -180,7 +180,7 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener { val timestamp = intent.extras?.getLong("timestamp") if (habitId != null && timestamp != null) { val habit = appComponent.habitList.getById(habitId)!! - component.listHabitsBehavior.onEdit(habit, Timestamp(timestamp)) + component.listHabitsBehavior.onEdit(habit, Timestamp(timestamp), 0f, 0f) } } intent = null diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt index e1f0418a3..074f22f75 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt @@ -224,6 +224,8 @@ class ListHabitsScreen } override fun showConfetti(color: PaletteColor, x: Float, y: Float) { + if (x == 0f && y == 0f) return + if (preferences.isConfettiAnimationDisabled) return val baseColor = themeSwitcher.currentTheme!!.color(color).toInt() rootView.get().konfettiView.start( Party( @@ -267,7 +269,7 @@ class ListHabitsScreen putDouble("value", value) putString("notes", notes) } - dialog.onToggle = { v, n, x, y -> callback.onNumberPicked(v, n, x, y) } + dialog.onToggle = { v, n -> callback.onNumberPicked(v, n) } dialog.dismissCurrentAndShow(fm, "numberDialog") } @@ -285,7 +287,7 @@ class ListHabitsScreen putInt("value", selectedValue) putString("notes", notes) } - dialog.onToggle = { v, n, x, y -> callback.onNotesSaved(v, n, x, y) } + dialog.onToggle = { v, n -> callback.onNotesSaved(v, n) } dialog.dismissCurrentAndShow(fm, "checkmarkDialog") } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt index 84bd001fc..eea1244eb 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt @@ -169,7 +169,8 @@ class HabitCardView( } onEdit = { timestamp -> triggerRipple(timestamp) - habit?.let { behavior.onEdit(it, timestamp) } + val location = getAbsoluteButtonLocation(timestamp) + habit?.let { behavior.onEdit(it, timestamp, location.x, location.y) } } } @@ -177,7 +178,8 @@ class HabitCardView( visibility = GONE onEdit = { timestamp -> triggerRipple(timestamp) - habit?.let { behavior.onEdit(it, timestamp) } + val location = getAbsoluteButtonLocation(timestamp) + habit?.let { behavior.onEdit(it, timestamp, location.x, location.y) } } } @@ -224,9 +226,13 @@ class HabitCardView( private fun getRelativeButtonLocation(timestamp: Timestamp): PointF { val today = DateUtils.getTodayWithOffset() val offset = timestamp.daysUntil(today) - dataOffset - val button = checkmarkPanel.buttons[offset] + val panel = when (habit!!.isNumerical) { + true -> numberPanel + false -> checkmarkPanel + } + val button = panel.buttons[offset] val y = button.height / 2.0f - val x = checkmarkPanel.x + button.x + (button.width / 2).toFloat() + val x = panel.x + button.x + (button.width / 2).toFloat() return PointF(x, y) } @@ -234,9 +240,15 @@ class HabitCardView( val containerLocation = IntArray(2) this.getLocationOnScreen(containerLocation) val relButtonLocation = getRelativeButtonLocation(timestamp) + val windowInsets = rootWindowInsets + val statusBarHeight = if (SDK_INT <= Build.VERSION_CODES.VANILLA_ICE_CREAM) { + windowInsets?.systemWindowInsetTop ?: 0 + } else { + 0 + } return PointF( containerLocation[0].toFloat() + relButtonLocation.x, - containerLocation[1].toFloat() - relButtonLocation.y + containerLocation[1].toFloat() + relButtonLocation.y - statusBarHeight ) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt index a7d07db53..fb7e3382c 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt @@ -181,7 +181,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { putDouble("value", value) putString("notes", notes) } - dialog.onToggle = { v, n, x, y -> callback.onNumberPicked(v, n, x, y) } + dialog.onToggle = { v, n -> callback.onNumberPicked(v, n) } dialog.dismissCurrentAndShow(supportFragmentManager, "numberDialog") } @@ -198,7 +198,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { putInt("value", selectedValue) putString("notes", notes) } - dialog.onToggle = { v, n, x, y -> callback.onNotesSaved(v, n, x, y) } + dialog.onToggle = { v, n -> callback.onNotesSaved(v, n) } dialog.dismissCurrentAndShow(supportFragmentManager, "checkmarkDialog") } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.kt index 6756b8acd..f5214b749 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.kt @@ -69,7 +69,7 @@ abstract class HabitWidgetView : FrameLayout { val shadowRadius = dpToPixels(context, 2f).toInt() val shadowOffset = dpToPixels(context, 1f).toInt() val shadowColor = Color.argb(shadowAlpha, 0, 0, 0) - val cornerRadius = dpToPixels(context, 12f) + val cornerRadius = dpToPixels(context, 18f) val radii = FloatArray(8) Arrays.fill(radii, cornerRadius) val shape = RoundRectShape(radii, null, null) diff --git a/uhabits-android/src/main/play/listings/ar-rSA/full-description.txt b/uhabits-android/src/main/play/listings/ar-rSA/full-description.txt index 7b10b101c..9600ad2ed 100644 --- a/uhabits-android/src/main/play/listings/ar-rSA/full-description.txt +++ b/uhabits-android/src/main/play/listings/ar-rSA/full-description.txt @@ -1,4 +1,4 @@ -يساعدك Loop Habit Tracker على إنشاء عادات إيجابية طويلة المدى والحفاظ عليها في حياتك. تعطيكم الرسوم البيانية والإحصاءات التفصيلية صورة واضحة للكيفية التي تحسنت بها عاداتك مع مرور الوقت. التطبيق خالٍ تمامًا من الإعلانات ومفتوح المصدر ويحترم خصوصيتك. +يساعدك Loop Habit Tracker على إنشاء عادات إيجابية طويلة المدى والحفاظ عليها في حياتك. تمنحك المخططات والإحصاءات التفصيلية صورة واضحة عن مدى تحسن عاداتك بمرور الوقت. التطبيق خالٍ تمامًا من الإعلانات ومفتوح المصدر ويحترم خصوصيتك. واجهة جميلة وبسيطة يحتوي Loop على واجهة أنيقة وبسيطة وسهلة الاستخدام للغاية ، حتى للمستخدمين لأول مرة. تم تحسين التطبيق ليكون ذي سرعة عالية ، ويعمل التطبيق بشكل جيد حتى على الهواتف القديمة. @@ -19,11 +19,11 @@ إذا كنت تريد إجراء مزيد من التحليل لبياناتك ، أو نقلها إلى خدمة أخرى ، فإن Loop تسمح لك بتصديرها إلى جداول البيانات (CSV) أو إلى ملف قاعدة بيانات (SQLite). بالنسبة للمستخدمين المحترفين، يمكن إضافة علامات الاختيار من خلال تطبيقات أخرى ، مثل تاسكر. لا قيود -تتبع العديد من العادات كما يحلو لك. Loop imposes no artificial limits on how many habits you can have. All features are available to all users. There are no in-app purchases. +تتبع العديد من العادات كما يحلو لك. لا تفرض Loop قيودًا مصطنعة على عدد العادات التي يمكنك ممارستها. جميع الميزات متاحة لجميع المستخدمين. لا توجد عمليات شراء داخل التطبيق. -Arabic +خالي تماما من الإعلانات ومفتوح المصدر لا توجد إعلانات أو إشعارات مزعجة أو أذونات تدخلية في هذا التطبيق ، ولن تكون هناك أبدًا. التطبيق مفتوح المصدر بالكامل (GPLv3). يعمل دون اتصال ويحترم خصوصيتك -Loop لا يتطلب اتصالاً بالإنترنت أو تسجيل حساب عبر الإنترنت. لا يتم إرسال البيانات السرية الخاصة بك إلى أي شخص. لا يتمكن المطورين ولا أي طرف ثالث من الوصول إليها. +لا يتطلب Loop اتصالاً بالإنترنت أو تسجيل حساب عبر الإنترنت. لا يتم إرسال البيانات السرية الخاصة بك إلى أي شخص. لا يتمكن المطورين ولا أي طرف ثالث من الوصول إليها. diff --git a/uhabits-android/src/main/play/listings/ar-rSA/short-description.txt b/uhabits-android/src/main/play/listings/ar-rSA/short-description.txt index 299961bd3..7b24c0765 100644 --- a/uhabits-android/src/main/play/listings/ar-rSA/short-description.txt +++ b/uhabits-android/src/main/play/listings/ar-rSA/short-description.txt @@ -1,2 +1 @@ -اخلق عادات جيدة وتابع تطورها مع مرور الوقت -(خالية من الإعلانات) +ربي عادات جيدة وتتبع تقدمها مع مرور الوقت (دون إعلانات) diff --git a/uhabits-android/src/main/play/listings/bg-rBG/full-description.txt b/uhabits-android/src/main/play/listings/bg-rBG/full-description.txt new file mode 100644 index 000000000..5f1e298b2 --- /dev/null +++ b/uhabits-android/src/main/play/listings/bg-rBG/full-description.txt @@ -0,0 +1,29 @@ +Loop Следене на навици ви помага да създавате и поддържате дългосрочни положителни навици във вашия живот. Подробни диаграми и статистики ви дават ясна картина как вашите навици са се подобрили във времето. Приложението е изцяло без реклами, с отворен код и зачита вашата поверителност. + +Красив, минималистичен и лек интерфейс +Loop има елегантен и минималистичен интерфейс, който е много лесен за използване, дори за нови потребители. Силно оптимизирано за скорост, приложението работи добре дори и на по-стари телефони. + +Сила на навиците +Loop има усъвършенствана формула за изчисляване на силата на вашите навици. Всяко повторение прави навика ви по-силен, а всеки пропуснат ден го прави по-слаб. Въпреки това, няколко пропуснати дни след продължителна поредица няма напълно да унищожат вашия напредък, за разлика от много други приложения, които следят поредици. + +Гъвкави графици +В допълнение на ежедневни навици, Loop поддържа навици с по-сложни графици, като 3 пъти седмично или през ден. + +Напомняния +Планирайте напомняния за да ви подсещат за вашите навици. Всеки навик може да си има собствено напомняне в избрано време от деня. Лесно потвърдете или отхвърлете вашия навик директно от известието. + +Приспособления +Напомняйте си за вашите навици винаги когато си отключите телефона. Цветни приспособления ви позволяват да следите навиците си директно от вашия начален екран без дори да отваряте приложението. + +Поемете контрол над вашите данни +Ако искате допълнително да анализирате вашите данни или да ги прехвърлите към друга услуга, Loop ви позволява да ги експортирате като електронни таблици (CSV) или като файл за база данни (SQLite). Напреднали потребители могат да добавят отметки от други приложения, като Tasker. + +Без ограничения +Следете толкова навика, колкото пожелаете. Loop не налага изкуствени ограничения на бройката навици, които може да имате. Всички функции са достъпни за всички потребители. Няма покупки в приложението. + +Изцяло без реклами и с отворен код +В това приложение няма реклами, досадни известия или натрапчиви разрешения, и никога няма да има. Приложението е изцяло с отворен код (GPLv3). + +Работи офлайн и уважава вашата поверителност +Loop не изисква интернет връзка или регистрация на онлайн акаунт Вашите поверителни данни никога не се изпращат на никого. Нито разработчиците, нито трети лица имат достъп до тях. + diff --git a/uhabits-android/src/main/play/listings/bg-rBG/short-description.txt b/uhabits-android/src/main/play/listings/bg-rBG/short-description.txt new file mode 100644 index 000000000..619226f67 --- /dev/null +++ b/uhabits-android/src/main/play/listings/bg-rBG/short-description.txt @@ -0,0 +1 @@ +Създайте добри навици и следете напредъка им във времето (без реклами) diff --git a/uhabits-android/src/main/play/listings/de-rDE/full-description.txt b/uhabits-android/src/main/play/listings/de-rDE/full-description.txt index d3705a7a8..4cc3cbcc8 100644 --- a/uhabits-android/src/main/play/listings/de-rDE/full-description.txt +++ b/uhabits-android/src/main/play/listings/de-rDE/full-description.txt @@ -1,6 +1,6 @@ -Loop Habit Tracker hilft dir dabei gute Gewohnheiten zu erlangen und sie ein Leben lang zu pflegen. Detaillierte Diagramme und Statistiken geben Aufschluss darüber, wie sich die Gewohnheiten über die Zeit verändern und verbessern. Die App ist werbefrei, open source und respektiert die Privatsphäre. +Loop Habit Tracker hilft dir dabei, positive Gewohnheiten in dein Leben zu integrieren und sie dauerhaft zu verfolgen. Detaillierte Diagramme und Statistiken geben Aufschluss darüber, wie sich die Gewohnheiten über die Zeit verändern und verbessern. Die App ist werbefrei, open source und respektiert die Privatsphäre. -Schöne, minimalistisch und übersichtliche Benutzeroberfläche +Schöne, minimalistische und übersichtliche Benutzeroberfläche Loop hat eine elegante und minimalistische Benutzeroberfläche, die selbst für Erstnutzer eine einfache Verwendung möglich macht. Dank vieler Geschwindigkeitsoptimierungen funktioniert die App auch auf älteren Geräten einwandfrei. Gewohnheitserfolge @@ -10,20 +10,20 @@ Loop berechnet mit einer ausgereiften Berechnungsart die Stärke der Gewohnheite Zusätzlich zu täglichen Gewohnheiten bietet Loop auch eine komplexere Zeitplanung an, wie zum Beispiel drei mal pro Woche oder jeden zweiten Tag. Erinnerungen -Benachrichtigungen können zeitlich konfiguriert und als Erinnerung verwendet werden. Für jede Gewohnheit kann eine individuelle Erinnerungen zu einer einstellbaren Tageszeit aktiviert werden. Die Gewohnheiten können dann einfach über die Benachrichtigung überprüft oder verworfen werden. +Benachrichtigungen können zeitlich konfiguriert und als Erinnerung verwendet werden. Für jede Gewohnheit kann eine individuelle Erinnerung zu einer einstellbaren Tageszeit aktiviert werden. Die Gewohnheit kann dann einfach über die Benachrichtigung abgehakt oder verworfen werden. Widgets -Denken Sie immer an Erinnerungen, Sie ihr Telefon entsperren. Mit farbenfrohen Widgets behalten Sie Ihre Gewohnheiten immer im Überblick, direkt auf dem Homescreen ihn die App zu öffnen. +Lassen Sie sich an Ihre Gewohnheiten erinnern, wenn Sie Ihr Telefon entsperren. Farbenfrohe Widgets ermöglichen es Ihnen, Ihre Gewohnheiten direkt von Ihrem Startbildschirm aus zu verfolgen, ohne die App zu öffnen. Behalten Sie die Kontrolle über Ihre Daten -Daten können zur weiteren Analyse, oder auch zum Verschieben zu einem weiteren Anbieter, als Tabelle (CSV) oder Datenbank (SQLite) exportiert werden. Power User können Häkchen durch andere Apps hinzufügen, wie zum Beispiel Tasker. +Wenn Sie Ihre Daten weiter analysieren oder zu einem anderen Dienst verschieben möchten, können Sie sie mit Loop als Tabelle (CSV) oder Datenbankdatei (SQLite) exportieren. Power-User können Häkchen durch andere Apps hinzufügen, wie zum Beispiel Tasker. Keine Einschränkungen Erstellen Sie so viele Gewohnheiten, wie Sie möchten. Loop setzt keinerlei Einschränkungen was die Anzahl der erstellbaren Gewohnheiten betrifft. Alle Funktionen sind für alle User verfügbar. Es gibt keine In-App-Käufe. Komplett werbefrei und open source -Loop beinhaltet keine Werbung, lästige Benachrichtigungen oder unnötige Berechtigungen - und wir so wird es auch immer bleiben. Die App ist komplett open source (GPLv3). +Es gibt keinerlei Werbung, lästige Benachrichtigungen oder aufdringliche Berechtigungen in dieser App – und das wird auch immer so bleiben. Die App ist komplett open source (GPLv3). Funktioniert offline und respektiert Ihre Privatsphäre -Loop benötigt keine Internetverbindung oder Online-Registrierung. Ihre privaten Daten werden nie an Dritte weitergegeben. Weder die Entwickler, noch Dritte haben Zugriff darauf. +Loop benötigt keine Internetverbindung oder Online-Registrierung. Ihre privaten Daten werden nie an Dritte weitergegeben. Weder die Entwickler noch Dritte haben darauf Zugriff. diff --git a/uhabits-android/src/main/play/listings/de-rDE/short-description.txt b/uhabits-android/src/main/play/listings/de-rDE/short-description.txt index 229fed76b..aee02875c 100644 --- a/uhabits-android/src/main/play/listings/de-rDE/short-description.txt +++ b/uhabits-android/src/main/play/listings/de-rDE/short-description.txt @@ -1 +1 @@ -Erlange gute Gewohnheiten und verfolge dessen Fortschritte (ohne Werbung) +Schaffe gute Gewohnheiten und verfolge ihre Fortschritte (ohne Werbung) diff --git a/uhabits-android/src/main/play/listings/el-rGR/full-description.txt b/uhabits-android/src/main/play/listings/el-rGR/full-description.txt new file mode 100644 index 000000000..76166d81b --- /dev/null +++ b/uhabits-android/src/main/play/listings/el-rGR/full-description.txt @@ -0,0 +1,29 @@ +Το Loop Habit Tracker σας βοηθά να δημιουργήσετε και να διατηρήσετε μακροπρόθεσμες θετικές συνήθειες στη ζωή σας. Λεπτομερή διαγράμματα και στατιστικά στοιχεία σας δίνουν μια σαφή εικόνα του πώς οι συνήθειές σας έχουν βελτιωθεί με την πάροδο του χρόνου. Η εφαρμογή είναι εντελώς χωρίς διαφημίσεις, ανοιχτού κώδικα και σέβεται το απόρρητό σας. + +Όμορφη, μινιμαλιστική και ελαφριά διεπαφή +Η εφαρμογή έχει ένα κομψό και μινιμαλιστικό περιβάλλον που είναι πολύ εύκολο στη χρήση, ακόμη και για τους χρήστες πρώτης φοράς. + +Σκόρ Συνηθειών +Η εφαρμογή έχει μια προηγμένη φόρμουλα για τον υπολογισμό της δύναμης των συνηθειών σας. Κάθε επανάληψη καθιστά τη συνήθειά σας ισχυρότερη και κάθε χαμένη μέρα καθιστά ασθενέστερη. Λίγες χαμένες ημέρες μετά από μια μεγάλη περίοδο, ωστόσο, δεν θα καταστρέψουν εντελώς την πρόοδό σας, σε αντίθεση με πολλές άλλες εφαρμογές τύπου don't-break-the-chain. + +Εύελικτα Προγράμματα +Εκτός από τις καθημερινές συνήθειες, το Loop υποστηρίζει συνήθειες με πιο σύνθετα προγράμματα, όπως 3 φορές την εβδομάδα ή κάθε δεύτερη μέρα. + +Υπενθυμίσεις +Προγραμματισμός ειδοποιήσεων για να σας υπενθυμίσουν τις συνήθειές σας. Κάθε συνήθεια μπορεί να έχει τη δική της υπενθύμιση, σε μια επιλεγμένη ώρα της ημέρας. Ελέγξτε εύκολα ή απορρίψτε τη συνήθειά σας απευθείας από την ειδοποίηση. + +Widget +Υπενθύμιση των συνηθειών σας κάθε φορά που ξεκλειδώνετε το τηλέφωνό σας. Πολύχρωμα widgets σας επιτρέπουν να παρακολουθείτε τις συνήθειές σας απευθείας από την αρχική οθόνη σας, χωρίς καν να ανοίξετε την εφαρμογή. + +Παρτε τον έλεγχο των δεδομένων σας +Αν θέλετε να αναλύσετε περαιτέρω τα δεδομένα σας, ή να τα μετακινήσετε σε άλλη υπηρεσία, Το Loop σας επιτρέπει να το εξάγετε σε υπολογιστικά φύλλα (CSV) ή σε αρχείο βάσης δεδομένων (SQLite). Για τους προχωρημένους χρήστες , τα checkmark ελέγχου μπορούν να προστεθούν και μέσω άλλων εφαρμογών, όπως το Tasker. + +Χωρίς περιορισμούς +Παρακολουθήστε όσες συνήθειες επιθυμείτε. Το Loop δεν επιβάλλει τεχνητά όρια στο πόσες συνήθειες μπορείτε να έχετε. Όλες οι δυνατότητες είναι διαθέσιμες σε όλους τους χρήστες. Δεν υπάρχουν αγορές εντός της εφαρμογής. + +Πλήρως χωρίς διαφημίσεις και ανοικτού κώδικα +Δεν υπάρχουν διαφημίσεις, ενοχλητικές ειδοποιήσεις ή παρεμβατικά δικαιώματα σε αυτήν την εφαρμογή, και δεν θα υπάρξουν ποτέ. Η εφαρμογή είναι εντελώς ανοιχτού κώδικα (GPLv3). + +Δουλέυει και χωρίς σύνδεση και σέβεται την ιδιωτικότητα σας +Η εφαρμογή δεν απαιτεί σύνδεση στο διαδίκτυο ή εγγραφή online λογαριασμού. Τα εμπιστευτικά δεδομένα σας δεν αποστέλλονται ποτέ σε κανέναν. Ούτε οι προγραμματιστές ούτε τρίτοι έχουν πρόσβαση σε αυτό. + diff --git a/uhabits-android/src/main/play/listings/eo-rUY/full-description.txt b/uhabits-android/src/main/play/listings/eo-rUY/full-description.txt new file mode 100644 index 000000000..603cc7ca5 --- /dev/null +++ b/uhabits-android/src/main/play/listings/eo-rUY/full-description.txt @@ -0,0 +1,29 @@ +Loop Habit Tracker helps you create and maintain long-term positive habits in your life. Detailed charts and statistics give you a clear picture of how your habits have improved over time. The app is completely ad-free, open source and it respects your privacy. + +Beautiful, minimalistic and lightweight interface +Loop has an elegant and minimalistic interface that is very easy to use, even for first-time users. Highly optimized for speed, the app works well even on older phones. + +Habit score +Loop has an advanced formula for calculating the strength of your habits. Every repetition makes your habit stronger and every missed day makes it weaker. A few missed days after a long streak, however, will not completely destroy your progress, unlike many other don't-break-the-chain apps. + +Flexible schedules +In addition to daily habits, Loop supports habits with more complex schedules, such as 3 times per week or every other day. + +Reminders +Schedule notifications to remind you of your habits. Each habit can have its own reminder, at a chosen time of the day. Easily check or dismiss your habit directly from the notification. + +Widgets +Be reminded of your habits whenever you unlock your phone. Colorful widgets allow you to track your habits directly from your home screen, without even opening the app. + +Take control of your data +If you want to further analyze your data, or move it to another service, Loop allows you to export it to spreadsheets (CSV) or to a database file (SQLite). For power users, checkmarks can be added through other apps, such as Tasker. + +No limitations +Track as many habits as you wish. Loop imposes no artificial limits on how many habits you can have. All features are available to all users. There are no in-app purchases. + +Completely ad-free and open source +There are no advertisements, annoying notifications or intrusive permissions in this app, and there will never be. The app is completely open-source (GPLv3). + +Works offline and respects your privacy +Loop doesn't require an Internet connection or online account registration. Your confidential data is never sent to anyone. Neither the developers nor any third-parties have access to it. + diff --git a/uhabits-android/src/main/play/listings/es-rES/full-description.txt b/uhabits-android/src/main/play/listings/es-rES/full-description.txt index 66c6cd7ba..ddd9e9f02 100644 --- a/uhabits-android/src/main/play/listings/es-rES/full-description.txt +++ b/uhabits-android/src/main/play/listings/es-rES/full-description.txt @@ -16,7 +16,7 @@ Programa notificaciones para recordarte tus hábitos. Cada hábito puede tener s Recuerde sus hábitos cada vez que desbloquee su teléfono. Los widgets de colores te permiten rastrear tus hábitos directamente desde tu pantalla de inicio, sin siquiera abrir la aplicación. Toma el control de tus datos -Si deseas analizar más sus datos o moverlos a otro servicio, Loop te permite exportarlos a hojas de cálculo (CSV) o a un archivo de base de datos (SQLite). Para usuarios avanzados, se pueden marcar hábitos a través de otras aplicaciones, como Tasker. +Si quieres analizar más a fondo tus datos o moverlos a otro servicio, Loop te permite exportarlos a hojas de cálculo (CSV) o a un archivo de base de datos (SQLite). Para usuarios avanzados, se pueden marcar hábitos a través de otras aplicaciones, como Tasker. Sin limitaciones Rastrea tantos hábitos como desees. Loop no impone límites artificiales sobre cuántos hábitos puedes tener. Todas las características están disponibles para todos los usuarios. No hay compras dentro de la aplicación. diff --git a/uhabits-android/src/main/play/listings/fi-rFI/full-description.txt b/uhabits-android/src/main/play/listings/fi-rFI/full-description.txt new file mode 100644 index 000000000..7309c5eee --- /dev/null +++ b/uhabits-android/src/main/play/listings/fi-rFI/full-description.txt @@ -0,0 +1,29 @@ +Loop Habit Tracker auttaa kehittämään ja ylläpitämään pitkäkestoisia hyviä rutiineja. Yksityiskohtaiset kaaviot ja tilastot antavat selkeän kuvan siitä, miten rutiinisi ovat parantuneet ajan kuluessa. Sovellus on mainokseton, sen lähdekoodi on avoin, ja sovellus kunnioittaa yksityisyyttäsi. + +Kaunis, minimalistinen ja kevyt käyttöliittymä +Loopin käyttöliittymä on tyylikäs ja minimalistinen. Se on helppokäyttöinen jopa uusille käyttäjille. Sovellus on optimoitu nopeaksi ja toimii hyvin myös vanhoissa puhelimissa. + +Rutiinipisteet +Loopilla on kehittynyt laskentakaava joka mittaa rutiiniesi vahvuutta. Jokainen toisto tekee rutiinistasi vahvemman ja jokainen ohitettu päivä tekee siitä heikomman. Muutama ohitettu päivä pitkän putken jälkeen ei kuitenkaan täysin tuhoa edistystäsi, toisin kuin monissa muissa älä-riko-putkea-sovelluksissa. + +Joustavat aikataulut +Päivittäisten rutiinien lisäksi Loop tukee rutiineja joilla on monimutkaisempi aikataulu, esimerkiksi kolmesti viikossa tai joka toinen päivä. + +Muistutukset +Ajasta ilmoituksia muistuttamaan sinua rutiineistasi. Jokaisella rutiinilla on oma muistutuksensa, valittuna päivän hetkenä. Kuittaa rutiinisi tehdyksi tai merkitse se hylätyksi helposti ilmoituksesta. + +Widgetit +Näe muistutuksia rutiineistasi aina kun avaat puhelimesi. Värikkäät widgetit auttavat sinua seuraamaan rutiinejasi suoraan kotinäkymästäsi, ilman että avaat sovellusta. + +Hallitse tietojasi +Jos haluat analysoida tietojasi, tai siirtää ne toiseen palveluun, Loop antaa sinun viedä ne laskentataulukoihin (CSV) tai tietokantatiedostoon (SQLite). Tehokäyttäjät voivat lisätä merkintöjä muiden sovellusten, kuten Taskerin, kautta. + +Ei rajoituksia +Seuraa niin montaa rutiinia kuin haluat. Loop ei aseta keinotekoisia rajoituksia rutiiniesi määrälle. Kaikki toiminnot ovat kaikkien käytettävissä. Sovelluksen sisäisiä ostoja ei ole. + +Täysin mainokseton ja avointa lähdekoodia +Sovelluksessa ei ole mainoksia, häiritseviä ilmoituksia tai turhia käyttöoikeusvaatimuksia, eikä tule koskaan olemaan. Sovellus on täysin avointa lähdekoodia (GPLv3). + +Toimii offline-tilassa ja kunnioittaa yksityisyyttäsi +Loop ei vaadi Internet-yhteyttä tai online-tilin rekisteröintiä. Luottamuksellisia tietojasi ei koskaan lähetetä kenellekään. Kehittäjillä ja kolmansilla osapuolilla ei ole pääsyä niihin. + diff --git a/uhabits-android/src/main/play/listings/gu-rIN/full-description.txt b/uhabits-android/src/main/play/listings/gu-rIN/full-description.txt new file mode 100644 index 000000000..603cc7ca5 --- /dev/null +++ b/uhabits-android/src/main/play/listings/gu-rIN/full-description.txt @@ -0,0 +1,29 @@ +Loop Habit Tracker helps you create and maintain long-term positive habits in your life. Detailed charts and statistics give you a clear picture of how your habits have improved over time. The app is completely ad-free, open source and it respects your privacy. + +Beautiful, minimalistic and lightweight interface +Loop has an elegant and minimalistic interface that is very easy to use, even for first-time users. Highly optimized for speed, the app works well even on older phones. + +Habit score +Loop has an advanced formula for calculating the strength of your habits. Every repetition makes your habit stronger and every missed day makes it weaker. A few missed days after a long streak, however, will not completely destroy your progress, unlike many other don't-break-the-chain apps. + +Flexible schedules +In addition to daily habits, Loop supports habits with more complex schedules, such as 3 times per week or every other day. + +Reminders +Schedule notifications to remind you of your habits. Each habit can have its own reminder, at a chosen time of the day. Easily check or dismiss your habit directly from the notification. + +Widgets +Be reminded of your habits whenever you unlock your phone. Colorful widgets allow you to track your habits directly from your home screen, without even opening the app. + +Take control of your data +If you want to further analyze your data, or move it to another service, Loop allows you to export it to spreadsheets (CSV) or to a database file (SQLite). For power users, checkmarks can be added through other apps, such as Tasker. + +No limitations +Track as many habits as you wish. Loop imposes no artificial limits on how many habits you can have. All features are available to all users. There are no in-app purchases. + +Completely ad-free and open source +There are no advertisements, annoying notifications or intrusive permissions in this app, and there will never be. The app is completely open-source (GPLv3). + +Works offline and respects your privacy +Loop doesn't require an Internet connection or online account registration. Your confidential data is never sent to anyone. Neither the developers nor any third-parties have access to it. + diff --git a/uhabits-android/src/main/play/listings/gu-rIN/short-description.txt b/uhabits-android/src/main/play/listings/gu-rIN/short-description.txt new file mode 100644 index 000000000..d19b7d128 --- /dev/null +++ b/uhabits-android/src/main/play/listings/gu-rIN/short-description.txt @@ -0,0 +1 @@ +Create good habits and track their progress over time (ad-free) diff --git a/uhabits-android/src/main/play/listings/gu-rIN/title.txt b/uhabits-android/src/main/play/listings/gu-rIN/title.txt new file mode 100644 index 000000000..027232a12 --- /dev/null +++ b/uhabits-android/src/main/play/listings/gu-rIN/title.txt @@ -0,0 +1 @@ +Loop Habit Tracker diff --git a/uhabits-android/src/main/play/listings/hi-rIN/full-description.txt b/uhabits-android/src/main/play/listings/hi-rIN/full-description.txt new file mode 100644 index 000000000..d918c24ae --- /dev/null +++ b/uhabits-android/src/main/play/listings/hi-rIN/full-description.txt @@ -0,0 +1,29 @@ +लूप हैबिट ट्रैकर आपको अपने जीवन में सकारात्मक आदतों को बनाने और बनाए रखने में मदद करता है। विस्तृत चार्ट और आंकड़े आपको एक स्पष्ट तस्वीर देते हैं कि समय के साथ आपकी आदतों में कैसे सुधार हुआ है। ब्लोकडा नि: शुल्क और खुला स्रोत है और यह आपकी गोपनीयता का सम्मान करता है + +सुंदर, न्यूनतर और हल्का इंटरफ़ेस +लूप में एक सुरुचिपूर्ण और न्यूनतर इंटरफ़ेस है जिसका उपयोग करना बहुत आसान है, यहां तक कि पहली बार उपयोगकर्ताओं के लिए भी। गति के लिए अत्यधिक अनुकूलित, ऐप पुराने फोन पर भी अच्छा काम करता है। + +आदत स्कोर +लूप में आपकी आदतों की ताकत की गणना के लिए एक उन्नत सूत्र है। हर दोहराव आपकी आदत को मजबूत बनाता है और हर छूटा हुआ दिन इसे कमजोर बनाता है। हालांकि, एक लंबी स्ट्रीक के बाद कुछ छूटे हुए दिन आपकी प्रगति को पूरी तरह से नष्ट नहीं करेंगे, कई अन्य नॉट-ब्रेक-द-चेन ऐप्स के विपरीत। + +लचीली अनुसूचियां +दैनिक आदतों के अलावा, लूप अधिक जटिल शेड्यूल वाली आदतों का समर्थन करता है, जैसे प्रति सप्ताह 3 बार या हर दूसरे दिन। + +अनुस्मारक +आपको अपनी आदतों की याद दिलाने के लिए नोटिफिकेशन शेड्यूल करें। हर आदत का अपना रिमाइंडर सेट किया जा सकता है, वह भी अपने चाहे किसी भी दिन के किसी भी समय पर। अधिसूचना पट्टी यानी "नोटिफिकेशन बार" से आप "हैबिट" (आदत/व्यवहार) की पूर्वनियोजित कार्यप्रणाली को "खारिज" (डिसमिस/dismiss) या "हां हो गया है" (चैक/check) बड़ी आसानी से कर सकते है। + +विजेट +क्या आप जब भी अपने फोन को खोले, तब आपको अपनी पूर्वनिर्धारित आदतों/व्यवहारों को आसानी से याद दिलाया जाए? रंग बिरंगे वी आकर्षक "विजेट" प्रणाली की सुविधा से आप बड़ी आसानी से अपने मोबाइल के होम स्क्रीन से अपनी आदतों वी व्यावहार संबंधित जानकारी ले सके है, वह भी ऐप को खोले बिना। + +अपनी डाटा के बारे में नियंत्रण संबंधित जानकारी वी सुविधाएं। +यदि आप अपने डेटा का और विश्लेषण करना चाहते हैं, या इसे किसी अन्य सेवा में ले जाना चाहते हैं, तो लूप आपको इसे स्प्रेडशीट (CSV) या डेटाबेस फ़ाइल (SQLite) में निर्यात करने की अनुमति देता है। "पावर" उपयोगकर्ताओं के लिए, अन्य ऐप्स जैसे "टास्कर ऐप" के माध्यम से चेकमार्क जोड़े जा सकते हैं। + +सीमाहीन +जितनी चाहें उतनी आदतों वी व्यवहारों को ट्रैक करें। यह "लूप ऐप" आपकी कितनी आदतें हो सकती हैं, इस पर कोई कृत्रिम सीमा नहीं लगाता है। इसलिए जितनी चाहे, उतनी आदतों को बनाएं और ट्रैक करें। सभी सुविधाएँ सभी उपयोगकर्ताओं के लिए उपलब्ध हैं। इन-ऐप खरीदारी नहीं है। + +पूरी तरह से विज्ञापन-मुक्त और खुला स्रोत +इस ऐप में कोई विज्ञापन, कष्टप्रद सूचनाएं या घुसपैठ की अनुमति नहीं है, और कभी नहीं होगी। ऐप पूरी तरह से ओपन-सोर्स (GPLv3) है। + +ऑफ़लाइन काम करता है और आपकी गोपनीयता का सम्मान करता है +लूप को इंटरनेट कनेक्शन या ऑनलाइन खाता पंजीकरण की आवश्यकता नहीं है। आपका गोपनीय डेटा कभी किसी को नहीं भेजा जाता है। न तो डेवलपर्स और न ही किसी तीसरे पक्ष के पास इसकी डाटा की पहुंच है। + diff --git a/uhabits-android/src/main/play/listings/hi-rIN/short-description.txt b/uhabits-android/src/main/play/listings/hi-rIN/short-description.txt new file mode 100644 index 000000000..086e9a338 --- /dev/null +++ b/uhabits-android/src/main/play/listings/hi-rIN/short-description.txt @@ -0,0 +1 @@ +अच्छी आदतें बनाएं और समय के साथ उनकी प्रगति को ट्रैक करें (विज्ञापन-मुक्त) diff --git a/uhabits-android/src/main/play/listings/hr-rHR/full-description.txt b/uhabits-android/src/main/play/listings/hr-rHR/full-description.txt new file mode 100644 index 000000000..603cc7ca5 --- /dev/null +++ b/uhabits-android/src/main/play/listings/hr-rHR/full-description.txt @@ -0,0 +1,29 @@ +Loop Habit Tracker helps you create and maintain long-term positive habits in your life. Detailed charts and statistics give you a clear picture of how your habits have improved over time. The app is completely ad-free, open source and it respects your privacy. + +Beautiful, minimalistic and lightweight interface +Loop has an elegant and minimalistic interface that is very easy to use, even for first-time users. Highly optimized for speed, the app works well even on older phones. + +Habit score +Loop has an advanced formula for calculating the strength of your habits. Every repetition makes your habit stronger and every missed day makes it weaker. A few missed days after a long streak, however, will not completely destroy your progress, unlike many other don't-break-the-chain apps. + +Flexible schedules +In addition to daily habits, Loop supports habits with more complex schedules, such as 3 times per week or every other day. + +Reminders +Schedule notifications to remind you of your habits. Each habit can have its own reminder, at a chosen time of the day. Easily check or dismiss your habit directly from the notification. + +Widgets +Be reminded of your habits whenever you unlock your phone. Colorful widgets allow you to track your habits directly from your home screen, without even opening the app. + +Take control of your data +If you want to further analyze your data, or move it to another service, Loop allows you to export it to spreadsheets (CSV) or to a database file (SQLite). For power users, checkmarks can be added through other apps, such as Tasker. + +No limitations +Track as many habits as you wish. Loop imposes no artificial limits on how many habits you can have. All features are available to all users. There are no in-app purchases. + +Completely ad-free and open source +There are no advertisements, annoying notifications or intrusive permissions in this app, and there will never be. The app is completely open-source (GPLv3). + +Works offline and respects your privacy +Loop doesn't require an Internet connection or online account registration. Your confidential data is never sent to anyone. Neither the developers nor any third-parties have access to it. + diff --git a/uhabits-android/src/main/play/listings/hr-rHR/short-description.txt b/uhabits-android/src/main/play/listings/hr-rHR/short-description.txt new file mode 100644 index 000000000..d19b7d128 --- /dev/null +++ b/uhabits-android/src/main/play/listings/hr-rHR/short-description.txt @@ -0,0 +1 @@ +Create good habits and track their progress over time (ad-free) diff --git a/uhabits-android/src/main/play/listings/is-rIS/full-description.txt b/uhabits-android/src/main/play/listings/is-rIS/full-description.txt new file mode 100644 index 000000000..603cc7ca5 --- /dev/null +++ b/uhabits-android/src/main/play/listings/is-rIS/full-description.txt @@ -0,0 +1,29 @@ +Loop Habit Tracker helps you create and maintain long-term positive habits in your life. Detailed charts and statistics give you a clear picture of how your habits have improved over time. The app is completely ad-free, open source and it respects your privacy. + +Beautiful, minimalistic and lightweight interface +Loop has an elegant and minimalistic interface that is very easy to use, even for first-time users. Highly optimized for speed, the app works well even on older phones. + +Habit score +Loop has an advanced formula for calculating the strength of your habits. Every repetition makes your habit stronger and every missed day makes it weaker. A few missed days after a long streak, however, will not completely destroy your progress, unlike many other don't-break-the-chain apps. + +Flexible schedules +In addition to daily habits, Loop supports habits with more complex schedules, such as 3 times per week or every other day. + +Reminders +Schedule notifications to remind you of your habits. Each habit can have its own reminder, at a chosen time of the day. Easily check or dismiss your habit directly from the notification. + +Widgets +Be reminded of your habits whenever you unlock your phone. Colorful widgets allow you to track your habits directly from your home screen, without even opening the app. + +Take control of your data +If you want to further analyze your data, or move it to another service, Loop allows you to export it to spreadsheets (CSV) or to a database file (SQLite). For power users, checkmarks can be added through other apps, such as Tasker. + +No limitations +Track as many habits as you wish. Loop imposes no artificial limits on how many habits you can have. All features are available to all users. There are no in-app purchases. + +Completely ad-free and open source +There are no advertisements, annoying notifications or intrusive permissions in this app, and there will never be. The app is completely open-source (GPLv3). + +Works offline and respects your privacy +Loop doesn't require an Internet connection or online account registration. Your confidential data is never sent to anyone. Neither the developers nor any third-parties have access to it. + diff --git a/uhabits-android/src/main/play/listings/is-rIS/short-description.txt b/uhabits-android/src/main/play/listings/is-rIS/short-description.txt new file mode 100644 index 000000000..d19b7d128 --- /dev/null +++ b/uhabits-android/src/main/play/listings/is-rIS/short-description.txt @@ -0,0 +1 @@ +Create good habits and track their progress over time (ad-free) diff --git a/uhabits-android/src/main/play/listings/is-rIS/title.txt b/uhabits-android/src/main/play/listings/is-rIS/title.txt new file mode 100644 index 000000000..027232a12 --- /dev/null +++ b/uhabits-android/src/main/play/listings/is-rIS/title.txt @@ -0,0 +1 @@ +Loop Habit Tracker diff --git a/uhabits-android/src/main/play/listings/iw-rIL/full-description.txt b/uhabits-android/src/main/play/listings/iw-rIL/full-description.txt index 287aa81e9..154df190e 100644 --- a/uhabits-android/src/main/play/listings/iw-rIL/full-description.txt +++ b/uhabits-android/src/main/play/listings/iw-rIL/full-description.txt @@ -1,29 +1,29 @@ -יישום ”Loop לניהול הרגלים“ מסייע לך ביצירה ובשימור הרגלים טובים וארוכי טווח. תרשימים וסטטיסטיקה מפורטים נותנים לך תמונה ברורה כיצד ההרגלים שלך השתפרו לאורך זמן. היישום נטול פרסומות לחלוטין, קוד המקור שלו פתוח והוא מכבד את הפרטיות שלך. +יישום ”Loop לניהול הרגלים“ מסייע לך להתחיל ולשמר הרגלים טובים לאורך זמן. תרשימים וסטטיסטיקה מפורטים מראים לך בדיוק כיצד ההרגלים שלך משתפרים לאורך הזמן. היישום כולו נטול פרסומות, קוד המקור שלו פתוח והוא מכבד את הפרטיות שלך. ממשק יפה, חסכוני וקליל -הממשק של Loop אלגנטי, חסכוני וקל לשימוש אפילו בפעם הראשונה. היישום מותאם במיוחד למהירות, ועובד היטב גם בטלפונים ישנים. +הממשק של Loop אלגנטי, חסכוני וקל לשימוש אפילו בפעם הראשונה. היישום מותאם לפעול במהירות, ועובד היטב גם בטלפונים ישנים. -ציון הרגל -ל־Loop יש נוסחה מתקדמת לחישוב חוזק ההרגלים שלך. כל חזרה על ההרגל מחזקת אותו, וכל יום שהוחמץ מחליש אותו. כמה ימים שהוחמצו לאחר רצף ארוך, לעומת זאת, לא יהרסו לחלוטין את ההתקדמות, בניגוד ליישומים רבים אחרים מסוג ”לא לשבור את השרשרת“. +ציונים של הרגלים +יש ל־Loop נוסחה מתקדמת לחישוב חוזק ההרגלים שלך. כל חזרה על ההרגל מחזקת אותו, וכל יום שהוחמץ מחליש אותו. למרות זאת, כמה ימים שהוחמצו לאחר רצף ארוך לא יהרסו לחלוטין את ההתקדמות, בניגוד ליישומים רבים אחרים מסוג ”לא לשבור את השרשרת“. לוחות זמנים גמישים בנוסף להרגלים יומיומיים, Loop תומך בהרגלים עם לוחות זמנים מורכבים יותר, כמו 3 פעמים בשבוע או ”יום כן ויום לא“. תזכורות -אפשר לתזמן התראות קבועות עם תזכורות לגבי ההרגלים שלך. לכל הרגל יכולה להיות תזכורת משלו, בשעה שנבחרה ביום. אפשר לסמן או לדחות את עשיית ההרגל ישירות מההתראה בקלות. +אפשר לתזמן התראות קבועות עם תזכורות לגבי ההרגלים שלך. לכל הרגל אפשר להגדיר תזכורת, ואפשר לבחור כל שעה ביום. אפשר לסמן או לדחות את הרגלים בקלות וישירות מתוך ההתראה. יישומונים -להיזכר בהרגלים בכל שחרור נעילת הטלפון. יישומונים צבעוניים שמאפשרים לך לעקוב אחר ההרגלים ישירות ממסך הבית, מבלי לפתוח אפילו את היישום. +אפשר לקבל תזכורות לגבי ההרגלים בכל פתיחה של נעילת הטלפון. עם היישומונים הצבעוניים של Loop אפשר לעקוב אחר ההרגלים ישירות ממסך הבית, ומבלי לפתוח את היישום. -השליטה בנתונים היא בידיים שלך -אם ברצונך לנתח יותר לעומק את הנתונים שלך, או להעבירם לשירות אחר, Loop מאפשרת לך לייצא אותם לגיליונות אלקטרוניים (CSV) או לקובץ מסד נתונים (SQLite). למשתמשים מתקדמים, אפשר לסמן הרגלים דרך יישומים אחרים, כגון Tasker. +שליטה בנתונים שלך +אם ברצונך לחקור את הנתונים שלך לעומק, או להעביר אותם לשירות אחר, Loop מאפשר לך לייצא אותם לגיליונות אלקטרוניים (CSV) או לקובץ מסד נתונים (SQLite). משתמשים מתקדמים יכולים לסמן הרגלים אפילו דרך יישומים אחרים, כמו Tasker. בלי הגבלות -אפשר לעקוב אחר כמה הרגלים שרוצים. Loop לא מגבילה את כמות ההרגלים שאפשר להוסיף. כל התכונות זמינות לכל המשתמשים. אין רכישות מתוך היישום. +אפשר לעקוב אחר כמה הרגלים שרוצים. ב־Loop אפשר ליצור כמה הרגלים שרוצים, ללא הגבלה. כל התכונות זמינות לכל המשתמשים. אין רכישות מתוך היישום. -היישום נטול פרסומות במלואו וקוד המקור שלו פתוח -אין שום פרסומות, התראות מעצבנות או הרשאות פולשניות ביישום הזה, ולעולם לא יהיו. קוד היישום הזה פתוח לחלוטין (GPLv3). +היישום כולו נטול פרסומות וקוד המקור שלו פתוח +אין שום פרסומות, התראות מעצבנות או הרשאות פולשניות ביישום הזה, ולעולם לא יהיו. קוד המקור של היישום הזה פתוח לחלוטין (GPLv3). עובד במצב לא מקוון ומכבד את פרטיותך -ל־Loop לא נחוצים חיבור לאינטרנט או הרשמה לחשבון מקוון. הנתונים הסודיים שלך לא נשלחים לאחרים כלל. גם למפתחים וגם לגורמי צד שלישי כלשהם אין גישה אליהם. +לא צריך חיבור לאינטרנט או חשבון מקוון כדי להשתמש ב־Loop. הנתונים הפרטיים שלך לא נשלחים לאף אחד. גם למפתחים ולכל מיני גורמי צד שלישי אין גישה אליהם. diff --git a/uhabits-android/src/main/play/listings/ja-rJP/short-description.txt b/uhabits-android/src/main/play/listings/ja-rJP/short-description.txt index 16a88bc2a..3abde4c92 100644 --- a/uhabits-android/src/main/play/listings/ja-rJP/short-description.txt +++ b/uhabits-android/src/main/play/listings/ja-rJP/short-description.txt @@ -1 +1 @@ -良い習慣を作り、その進捗を長期にわたって追跡できる便利なツール(広告なし) +よい習慣を身につけ、その進捗を記録しましょう (広告なし) diff --git a/uhabits-android/src/main/play/listings/ka-rGE/full-description.txt b/uhabits-android/src/main/play/listings/ka-rGE/full-description.txt new file mode 100644 index 000000000..bb028bb88 --- /dev/null +++ b/uhabits-android/src/main/play/listings/ka-rGE/full-description.txt @@ -0,0 +1,29 @@ +Loop ჩვევების ტრეკერია, რომელიც გეხმარება ყოველდღიურობისთვის სასარგებლო ჩვევები გამოიმუშავო და ხანგრძლივად შეინარჩუნო. დეტალური დიაგრამებითა და სტატისტიკით წარმოდგენა გექმნება, თუ როგორ ვითარდება და მყარდება შენი ჩვევები. აპლიკაცია ურეკლამო და ღია კოდის მქონეა და ის იცავს შენს კონფიდენციალურობას. + +ლამაზი, მინიმალისტური და მსუბუქი ინტერფეისი +Loop-ს ელეგანტური და მინიმალისტური ინტერფეისი აქვს, რომელიც დამწყები მომხმარებლებისთვისაც კი ადვილად მოსახმარია. აპლიკაცია დახვეწილია სიჩქარისთვის, ამიტომ ძველ მოწყობილობებზეც კარგად მუშაობს. + +ჩვევების შეფასება +Loop დახვეწილი ფორმულის მეშვეობით ითვლის ჩვევების გაჯდომის დონეს. ყოველი გამეორებით იზრდება ჩვევის გაჯდომის დონე, გაცდენილი დღეების შემთხვევაში კი მცირდება. თუმცა ხანგრძლივი სერიის შემდეგ რამდენიმე დღის გაცდენით არ მოიშლება შენი მთლიანი პროგრესი, ბევრი სხვა „შეინარჩუნე-სერია“ სახის აპლიკაციისგან განსხვავებით. + +მორგებადი განრიგი +ყოველდღიური ჩვევების გარდა Loop-ში ასევე ისეთი ჩვევების შექმნა შეიძლება, რომლებსაც უფრო რთული განრიგი აქვთ. მაგალითად: „კვირაში 3-ჯერ“ ან „ყოველ მე-2 დღეს“. + +შემახსენებელი შეტყობინებები +დააყენე შეტყობინებები, რათა ჩვევები გაგახსენდეს. ყველა ჩვევას შეუძლია საკუთარი შემახსენებელი შეტყობინება ჰქონდეს დღის სასურველ დროს. ჩვევასთან თოლიის (✓) ჩანიშვნა შეტყობინებიდანვე შეგიძლია. + +ვიჯეტები +გაიხსენე ჩვევები ტელეფონის ყოველ განბლოკვაზე. ფერადი ვიჯეტებით გეძლევა იმის საშუალება, რომ ჩვევები საწყისი ეკრანიდანვე, აპლიკაციის გახსნის გარეშე, მართო. + +უხელმძღვანელე შენს მონაცემებს +მონაცემთა უფრო დეტალური ანალიზის გაკეთების ან სხვა სერვისზე გადატანის სურვილის არსებობის შემთხვევაში Loop საშუალებას გაძლევს, ისინი ელექტრონული ცხრილის (CSV) ან მონაცემთა ბაზის ფაილად (SQLite) დააექსპორტო. გამოცდილ მომხმარებლებს შეუძლიათ თოლიები (✓) ჩაამატონ სხვა აპლიკაციებით, როგორიცაა, მაგალითად, Tasker. + +შეუზღუდავი +იმდენ ჩვევას ადევნე თვალი, რამდენსაც ისურვებ. Loop არ ზღუდავს ჩვევების შესაძლო რაოდენობას. ყველა ფუნქცია ხელმისაწვდომია ნებისმიერი მომხმარებელისთვის. არ აქვს აპლიკაციის შიდა შენაძენები. + +ურეკლამო და ღია კოდით +აპლიკაციას არ აქვს და არც არასდროს ექნება რეკლამები, შემაწუხებელი შეტყობინებები, ან მოთხოვნა ზედმეტ ნებართვაზე. აპლიკაციის საწყისი კოდი მთლიანად ღიაა. (GPLv3) + +მუშაობს ხაზგარეშე რეჟიმში და პატივს სცემს შენს კონფიდენციალურობას +Loop არ საჭიროებს ინტერნეტკავშირს ან ონლაინ ანგარიშის რეგისტრაციას. შენი პირადი მონაცემები არასდროს გაზიარდება მესამე პირებთან. მონაცემებზე წვდომა არც დეველოპერს და არც მესამე პირებს გააჩნიათ. + diff --git a/uhabits-android/src/main/play/listings/ka-rGE/short-description.txt b/uhabits-android/src/main/play/listings/ka-rGE/short-description.txt new file mode 100644 index 000000000..5c9ed523a --- /dev/null +++ b/uhabits-android/src/main/play/listings/ka-rGE/short-description.txt @@ -0,0 +1 @@ +გამოიმუშავე კარგი ჩვევები და თან ადევნე თვალი შენს პროგრესს (ურეკლამო) diff --git a/uhabits-android/src/main/play/listings/ka-rGE/title.txt b/uhabits-android/src/main/play/listings/ka-rGE/title.txt new file mode 100644 index 000000000..d714a0c39 --- /dev/null +++ b/uhabits-android/src/main/play/listings/ka-rGE/title.txt @@ -0,0 +1 @@ +Loop — ჩვევების ტრეკერი diff --git a/uhabits-android/src/main/play/listings/ko-rKR/full-description.txt b/uhabits-android/src/main/play/listings/ko-rKR/full-description.txt new file mode 100644 index 000000000..abe5293d3 --- /dev/null +++ b/uhabits-android/src/main/play/listings/ko-rKR/full-description.txt @@ -0,0 +1,29 @@ +Loop Habit Tracker는 여러분의 인생에 있어 좋은 습관을 만들고 이를 장기적으로 유지하는 데 도움을 주는 앱입니다. 좋은 습관들이 나날이 늘어가는 모습을 자세한 차트와 통계를 통해 확인할 수 있습니다. Loop Habit Tracker는 오픈소스 프로젝트로 광고가 없으며 사용자의 개인정보를 수집하지 않습니다. + +아름답고 미니멀하며 가벼운 인터페이스 +Loop는 누구나 간편하게 사용하기 쉽도록 세련되고 미니멀한 인터페이스를 제공합니다. 또한 최적화가 잘 되어있어 최신형 휴대폰이 아니더라도 끊김없이 부드럽게 작동합니다. + +습관 점수 +Loop는 특수한 공식을 이용하여 사용자의 습관화가 얼마나 진척되었는지 계산합니다. 습관화의 정도는 반복되면 될수록 강해지지만 놓치는 날이 많아진다면 점차 약해집니다. 하지만 한 번 습관이 잘 형성되었다면 며칠 정도 놓치더라도 전반적인 흐름에 큰 영향을 주지 않습니다. 다른 앱에서 반복을 놓치지 말라고 강조하는 것과 차별화되는 점이죠. + +유연한 일정관리 +Loop는 매일 반복되는 일정 외에도 일주일에 3번 또는 격일로 반복하는 것처럼 더 복잡한 일정도 유연하게 관리할 수 있습니다. + +알림 +하루의 일정을 잊지 않도록 알림을 설정해보세요. 각각의 습관 일정에 맞추어 알림을 별도로 설정할 수 있습니다. 또한 상단메뉴바에서 손쉽게 일정을 확인하고 해제할 수 있습니다. + +위젯 +휴대폰을 잠금 해제할 때마다 하루의 일정을 떠올려 보세요. 다양한 위젯을 통해 앱을 열지 않고도 홈 화면에서 직접 습관목록을 관리할 수 있습니다. + +통계데이터 관리 +그동안 모은 통계데이터를 별도로 분석하거나 다른 서비스로 옮길 수 있도록 스프레드시트(CSV), 데이터베이스 파일(SQLite)의 형식으로 내보낼 수 있습니다. 고급 사용자의 경우 Tasker와 같은 다른 앱을 통해 자동으로 일정에 완료 표시하는 등 범용적으로 활용할 수도 있습니다. + +제한없이 사용하기 +원하는 만큼 습관을 추적해 보세요. Loop는 설정 할 수 있는 습관의 수를 제한하고 있지 않습니다. 유저들은 모든 기능을 이용할 수 있습니다. 인앱 구매가 필요하지 않습니다. + +완벽하게 광고가 없는 오픈소스 앱입니다. +Loop Habit Tracker에는 광고, 귀찮은 알림, 혹은 권한 설정이 필요 없으며, 앞으로 또한 그럴 것입니다. 이 앱은 완벽한 오픈소스입니다. (GPLv3) + +오프라인 환경에서도 작동하며 개인 정보를 존중합니다. +Loop Habit Tracker는 인터넷 연결이나 온라인 계정 등록을 필요로 하지 않습니다. 이용자의 소중한 데이터는 그 누구에게도 제공되지 않습니다. 개발자나 제3자 모두 접근할 수 없습니다. + diff --git a/uhabits-android/src/main/play/listings/ko-rKR/short-description.txt b/uhabits-android/src/main/play/listings/ko-rKR/short-description.txt index 22cdf6e96..062a49348 100644 --- a/uhabits-android/src/main/play/listings/ko-rKR/short-description.txt +++ b/uhabits-android/src/main/play/listings/ko-rKR/short-description.txt @@ -1 +1 @@ -좋은 습관을 만들고, 시간이 지나면서 습관이 어떻게 발전하는지 지켜보세요. +좋은 습관을 만들고, 시간이 지나면서 습관이 어떻게 발전하는지 지켜보세요. (광고 없음) diff --git a/uhabits-android/src/main/play/listings/ml-rIN/full-description.txt b/uhabits-android/src/main/play/listings/ml-rIN/full-description.txt new file mode 100644 index 000000000..da9e99fa8 --- /dev/null +++ b/uhabits-android/src/main/play/listings/ml-rIN/full-description.txt @@ -0,0 +1,29 @@ +നിങ്ങളുടെ ജീവിതത്തിൽ ദീർഘകാല പോസിറ്റീവ് ശീലങ്ങൾ സൃഷ്ടിക്കാനും നിലനിർത്താനും ലൂപ്പ് ഹാബിറ്റ് ട്രാക്കർ നിങ്ങളെ സഹായിക്കുന്നു. വിശദമായ ചാർട്ടുകളും സ്ഥിതിവിവരക്കണക്കുകളും നിങ്ങളുടെ ശീലങ്ങൾ കാലക്രമേണ എങ്ങനെ മെച്ചപ്പെട്ടുവെന്നതിന്റെ വ്യക്തമായ ചിത്രം നൽകുന്നു. ആപ്പ് പൂർണ്ണമായും പരസ്യരഹിതമാണ്, ഓപ്പൺ സോഴ്‌സ് ആണ്, ഇത് നിങ്ങളുടെ സ്വകാര്യതയെ മാനിക്കുന്നു. + +മനോഹരവും ചുരുങ്ങിയതും ഭാരം കുറഞ്ഞതുമായ ഇന്റർഫേസ് +ലൂപ്പിന് ഗംഭീരവും ചുരുങ്ങിയതുമായ ഒരു ഇന്റർഫേസ് ഉണ്ട്, അത് ആദ്യമായി ഉപയോഗിക്കുന്നവർക്ക് പോലും ഉപയോഗിക്കാൻ വളരെ എളുപ്പമാണ്. വേഗതയ്‌ക്കായി വളരെ ഒപ്റ്റിമൈസ് ചെയ്‌തിരിക്കുന്ന ആപ്പ് പഴയ ഫോണുകളിൽ പോലും നന്നായി പ്രവർത്തിക്കുന്നു. + +ശീല സ്കോർ +നിങ്ങളുടെ ശീലങ്ങളുടെ ശക്തി കണക്കാക്കുന്നതിനുള്ള വിപുലമായ ഫോർമുല ലൂപ്പിനുണ്ട്. ഓരോ ആവർത്തനവും നിങ്ങളുടെ ശീലത്തെ കൂടുതൽ ശക്തമാക്കുന്നു, കൂടാതെ നഷ്ടപ്പെട്ട ഓരോ ദിവസവും അതിനെ ദുർബലമാക്കുന്നു. എന്നിരുന്നാലും, നീണ്ട ഇടവേളയ്ക്ക് ശേഷം നഷ്‌ടമായ കുറച്ച് ദിവസങ്ങൾ, മറ്റ് പല ഡോൺ-ബ്രേക്ക്-ദി-ചെയിൻ ആപ്പുകളിൽ നിന്ന് വ്യത്യസ്തമായി നിങ്ങളുടെ പുരോഗതിയെ പൂർണ്ണമായും നശിപ്പിക്കില്ല. + +ഫ്ലെക്‌സിബിൾ ഷെഡ്യൂളുകൾ +ദൈനംദിന ശീലങ്ങൾക്ക് പുറമേ, ആഴ്ചയിൽ 3 തവണ അല്ലെങ്കിൽ മറ്റെല്ലാ ദിവസവും പോലെ കൂടുതൽ സങ്കീർണ്ണമായ ഷെഡ്യൂളുകളുള്ള ശീലങ്ങളെ ലൂപ്പ് പിന്തുണയ്ക്കുന്നു. + +ഓർമ്മപ്പെടുത്തലുകൾ +നിങ്ങളുടെ ശീലങ്ങളെക്കുറിച്ച് ഓർമ്മപ്പെടുത്തുന്നതിന് അറിയിപ്പുകൾ ഷെഡ്യൂൾ ചെയ്യുക. ഓരോ ശീലത്തിനും അതിന്റേതായ ഓർമ്മപ്പെടുത്തൽ ഉണ്ടായിരിക്കാം, ദിവസത്തിലെ തിരഞ്ഞെടുത്ത സമയത്ത്. അറിയിപ്പിൽ നിന്ന് നേരിട്ട് നിങ്ങളുടെ ശീലം എളുപ്പത്തിൽ പരിശോധിക്കുക അല്ലെങ്കിൽ നിരസിക്കുക. + +വിജറ്റുകൾ +നിങ്ങളുടെ ഫോൺ അൺലോക്ക് ചെയ്യുമ്പോഴെല്ലാം നിങ്ങളുടെ ശീലങ്ങൾ ഓർമ്മിപ്പിക്കുക. ആപ്പ് തുറക്കാതെ തന്നെ ഹോം സ്‌ക്രീനിൽ നിന്ന് നേരിട്ട് നിങ്ങളുടെ ശീലങ്ങൾ ട്രാക്ക് ചെയ്യാൻ വർണ്ണാഭമായ വിജറ്റുകൾ നിങ്ങളെ അനുവദിക്കുന്നു. + +നിങ്ങളുടെ ഡാറ്റയുടെ നിയന്ത്രണം ഏറ്റെടുക്കുക +നിങ്ങളുടെ ഡാറ്റ കൂടുതൽ വിശകലനം ചെയ്യാനോ മറ്റൊരു സേവനത്തിലേക്ക് നീക്കാനോ നിങ്ങൾ ആഗ്രഹിക്കുന്നുവെങ്കിൽ, അത് സ്പ്രെഡ്‌ഷീറ്റുകളിലേക്കോ (CSV) അല്ലെങ്കിൽ ഒരു ഡാറ്റാബേസ് ഫയലിലേക്കോ (SQLite) കയറ്റുമതി ചെയ്യാൻ ലൂപ്പ് നിങ്ങളെ അനുവദിക്കുന്നു. പവർ ഉപയോക്താക്കൾക്ക്, ടാസ്‌കർ പോലുള്ള മറ്റ് ആപ്പുകൾ വഴി ചെക്ക്‌മാർക്കുകൾ ചേർക്കാവുന്നതാണ്. + +പരിമിതികളില്ല +നിങ്ങൾ ആഗ്രഹിക്കുന്നത്രയും ശീലങ്ങൾ ട്രാക്ക് ചെയ്യുക. നിങ്ങൾക്ക് എത്ര ശീലങ്ങൾ ഉണ്ടായിരിക്കാം എന്നതിന് ലൂപ്പ് കൃത്രിമ പരിധികളൊന്നും ഏർപ്പെടുത്തുന്നില്ല. എല്ലാ ഫീച്ചറുകളും എല്ലാ ഉപയോക്താക്കൾക്കും ലഭ്യമാണ്. ഇൻ-ആപ്പ് വാങ്ങലുകളൊന്നുമില്ല. + +പൂർണ്ണമായും പരസ്യരഹിതവും ഓപ്പൺ സോഴ്‌സും +ഈ ആപ്പിൽ പരസ്യങ്ങളോ ശല്യപ്പെടുത്തുന്ന അറിയിപ്പുകളോ നുഴഞ്ഞുകയറ്റ അനുമതികളോ ഇല്ല, ഒരിക്കലും ഉണ്ടാകില്ല. ആപ്പ് പൂർണ്ണമായും ഓപ്പൺ സോഴ്സ് ആണ് (GPLv3). + +ഓഫ്‌ലൈനായി പ്രവർത്തിക്കുകയും നിങ്ങളുടെ സ്വകാര്യതയെ മാനിക്കുകയും ചെയ്യുന്നു +ലൂപ്പിന് ഇന്റർനെറ്റ് കണക്ഷനോ ഓൺലൈൻ അക്കൗണ്ട് രജിസ്ട്രേഷനോ ആവശ്യമില്ല. നിങ്ങളുടെ രഹസ്യസ്വഭാവമുള്ള ഡാറ്റ ഒരിക്കലും ആർക്കും അയയ്ക്കില്ല. ഡവലപ്പർമാർക്കോ ഏതെങ്കിലും മൂന്നാം കക്ഷിക്കോ ഇതിലേക്ക് ആക്‌സസ് ഇല്ല. + diff --git a/uhabits-android/src/main/play/listings/ml-rIN/short-description.txt b/uhabits-android/src/main/play/listings/ml-rIN/short-description.txt new file mode 100644 index 000000000..6eb3cc6b0 --- /dev/null +++ b/uhabits-android/src/main/play/listings/ml-rIN/short-description.txt @@ -0,0 +1 @@ +നല്ല ശീലങ്ങൾ സൃഷ്ടിക്കുകയും കാലക്രമേണ അവരുടെ പുരോഗതി ട്രാക്ക് ചെയ്യുകയും ചെയ്യുക (പരസ്യരഹിതം) diff --git a/uhabits-android/src/main/play/listings/ml-rIN/title.txt b/uhabits-android/src/main/play/listings/ml-rIN/title.txt new file mode 100644 index 000000000..799b947be --- /dev/null +++ b/uhabits-android/src/main/play/listings/ml-rIN/title.txt @@ -0,0 +1 @@ +ലൂപ്പ് ഹാബിറ്റ് ട്രാക്കർ diff --git a/uhabits-android/src/main/play/listings/no-rNO/full-description.txt b/uhabits-android/src/main/play/listings/no-rNO/full-description.txt new file mode 100644 index 000000000..603cc7ca5 --- /dev/null +++ b/uhabits-android/src/main/play/listings/no-rNO/full-description.txt @@ -0,0 +1,29 @@ +Loop Habit Tracker helps you create and maintain long-term positive habits in your life. Detailed charts and statistics give you a clear picture of how your habits have improved over time. The app is completely ad-free, open source and it respects your privacy. + +Beautiful, minimalistic and lightweight interface +Loop has an elegant and minimalistic interface that is very easy to use, even for first-time users. Highly optimized for speed, the app works well even on older phones. + +Habit score +Loop has an advanced formula for calculating the strength of your habits. Every repetition makes your habit stronger and every missed day makes it weaker. A few missed days after a long streak, however, will not completely destroy your progress, unlike many other don't-break-the-chain apps. + +Flexible schedules +In addition to daily habits, Loop supports habits with more complex schedules, such as 3 times per week or every other day. + +Reminders +Schedule notifications to remind you of your habits. Each habit can have its own reminder, at a chosen time of the day. Easily check or dismiss your habit directly from the notification. + +Widgets +Be reminded of your habits whenever you unlock your phone. Colorful widgets allow you to track your habits directly from your home screen, without even opening the app. + +Take control of your data +If you want to further analyze your data, or move it to another service, Loop allows you to export it to spreadsheets (CSV) or to a database file (SQLite). For power users, checkmarks can be added through other apps, such as Tasker. + +No limitations +Track as many habits as you wish. Loop imposes no artificial limits on how many habits you can have. All features are available to all users. There are no in-app purchases. + +Completely ad-free and open source +There are no advertisements, annoying notifications or intrusive permissions in this app, and there will never be. The app is completely open-source (GPLv3). + +Works offline and respects your privacy +Loop doesn't require an Internet connection or online account registration. Your confidential data is never sent to anyone. Neither the developers nor any third-parties have access to it. + diff --git a/uhabits-android/src/main/play/listings/no-rNO/short-description.txt b/uhabits-android/src/main/play/listings/no-rNO/short-description.txt new file mode 100644 index 000000000..d19b7d128 --- /dev/null +++ b/uhabits-android/src/main/play/listings/no-rNO/short-description.txt @@ -0,0 +1 @@ +Create good habits and track their progress over time (ad-free) diff --git a/uhabits-android/src/main/play/listings/ro-rRO/full-description.txt b/uhabits-android/src/main/play/listings/ro-rRO/full-description.txt new file mode 100644 index 000000000..28e975001 --- /dev/null +++ b/uhabits-android/src/main/play/listings/ro-rRO/full-description.txt @@ -0,0 +1,29 @@ +Loop Habit Tracker te ajută să creezi și să menții obiceiuri pozitive pe termen lung în viața ta. Detailed charts and statistics give you a clear picture of how your habits have improved over time. The app is completely ad-free, open source and it respects your privacy. + +Beautiful, minimalistic and lightweight interface +Loop are o interfață elegantă și minimalistă, care este foarte ușor de utilizat, chiar și pentru utilizatorii începători. Foarte optimizată pentru viteză, aplicația funcționează bine chiar și pe telefoanele mai vechi. + +Scorul obiceiului +Loop has an advanced formula for calculating the strength of your habits. Every repetition makes your habit stronger and every missed day makes it weaker. A few missed days after a long streak, however, will not completely destroy your progress, unlike many other don't-break-the-chain apps. + +Flexible schedules +Pe lângă obiceiurile zilnice, Loop susține obiceiuri cu programe mai complexe, cum ar fi, de 3 ori pe săptămână sau din două în două zile. + +Reminders +Programează notificări pentru a-ți aminti de obiceiurile tale. Each habit can have its own reminder, at a chosen time of the day. Easily check or dismiss your habit directly from the notification. + +Widgets +Be reminded of your habits whenever you unlock your phone. Colorful widgets allow you to track your habits directly from your home screen, without even opening the app. + +Preia controlul asupra datelor tale +If you want to further analyze your data, or move it to another service, Loop allows you to export it to spreadsheets (CSV) or to a database file (SQLite). For power users, checkmarks can be added through other apps, such as Tasker. + +Fără limitări +Track as many habits as you wish. Loop nu impune limite artificiale asupra numărului de obiceiuri pe care le poți avea. Toate funcțiile sunt disponibile pentru toți utilizatorii. There are no in-app purchases. + +Complet fără reclame și open-source +Nu există reclame, notificări enervante sau permisiuni intruzive în această aplicație și nu vor exista niciodată. Aplicația este complet open-source (GPLv3). + +Funcționează offline și respectă confidențialitatea ta +Loop nu necesită o conexiune la internet sau înregistrarea unui cont online. Datele tale confidențiale nu au fost trimise nimănui. Neither the developers nor any third-parties have access to it. + diff --git a/uhabits-android/src/main/play/listings/ro-rRO/short-description.txt b/uhabits-android/src/main/play/listings/ro-rRO/short-description.txt new file mode 100644 index 000000000..32eb53451 --- /dev/null +++ b/uhabits-android/src/main/play/listings/ro-rRO/short-description.txt @@ -0,0 +1 @@ +Creați obiceiuri bune și urmăriți progresul lor în timp (fără reclame) diff --git a/uhabits-android/src/main/play/listings/sl-rSI/full-description.txt b/uhabits-android/src/main/play/listings/sl-rSI/full-description.txt new file mode 100644 index 000000000..b8aecee93 --- /dev/null +++ b/uhabits-android/src/main/play/listings/sl-rSI/full-description.txt @@ -0,0 +1,29 @@ +Loop Habit Tracker vam pomaga ustvariti in ohraniti dolgoročne pozitivne navade v vašem življenju. Podrobni grafikoni in statistični podatki vam dajejo jasno sliko o tem, kako so se vaše navade sčasoma izboljšale. Aplikacija je popolnoma brez oglasov, odprtokodna in spoštuje vašo zasebnost. + +Lep, minimalističen in lahek vmesnik +Loop ima eleganten in minimalističen vmesnik, ki je zelo enostaven za uporabo, tudi za začetnike. Aplikacija je zelo optimizirana za hitrost, dobro deluje tudi na starejših telefonih. + +Ocena navade +Loop ima napredno formulo za izračun moči vaših navad. Vsako ponavljanje naredi vašo navado močnejšo in vsak zamujeni dan jo oslabi. Nekaj zamujenih dni po dolgem nizu pa ne bo popolnoma uničilo vašega napredka, za razliko od mnogih drugih aplikacij, ki ne prekinjajo verige. + +Prilagodljivi urniki +Poleg dnevnih navad Loop podpira navade z bolj zapletenimi urniki, na primer 3-krat na teden ali vsak drugi dan. + +Opomniki +Načrtujte obvestila, ki vas bodo spomnila na vaše navade. Vsaka navada ima lahko svoj opomnik, ob izbrani uri dneva. Preprosto preverite ali opustite svojo navado neposredno iz obvestila. + +Pripomočki +Ko odklenete telefon, se opomnite na svoje navade. Pisani pripomočki vam omogočajo, da spremljate svoje navade neposredno z začetnega zaslona, ne da bi sploh odprli aplikacijo. + +Prevzemite nadzor nad svojimi podatki +Če želite svoje podatke dodatno analizirati ali jih premakniti v drugo storitev, vam Loop omogoča, da jih izvozite v preglednice (CSV) ali v datoteko zbirke podatkov (SQLite). Za napredne uporabnike lahko kljukice dodate prek drugih aplikacij, kot je Tasker. + +Brez omejitev +Spremljajte toliko navad, kot želite. Loop ne postavlja nobenih umetnih omejitev glede števila navad, ki jih lahko imate. Vse funkcije so na voljo vsem uporabnikom. Nakupov v aplikaciji ni. + +Popolnoma brez oglasov in odprtokoden +V tej aplikaciji ni oglasov, nadležnih obvestil ali vsiljivih dovoljenj in jih nikoli ne bo. Aplikacija je popolnoma odprtokodna (GPLv3). + +Deluje brez povezave in spoštuje vašo zasebnost +Loop ne zahteva internetne povezave ali spletne registracije računa. Vaši zaupni podatki niso nikoli nikomur poslani. Niti razvijalci niti katere koli tretje osebe nimajo dostopa do njega. + diff --git a/uhabits-android/src/main/play/listings/sl-rSI/short-description.txt b/uhabits-android/src/main/play/listings/sl-rSI/short-description.txt new file mode 100644 index 000000000..752aa9274 --- /dev/null +++ b/uhabits-android/src/main/play/listings/sl-rSI/short-description.txt @@ -0,0 +1 @@ +Ustvarite dobre navade in spremljajte njihov napredek skozi čas (brez oglasov) diff --git a/uhabits-android/src/main/play/listings/ta-rIN/full-description.txt b/uhabits-android/src/main/play/listings/ta-rIN/full-description.txt new file mode 100644 index 000000000..80fd2925c --- /dev/null +++ b/uhabits-android/src/main/play/listings/ta-rIN/full-description.txt @@ -0,0 +1,29 @@ +உங்கள் வாழ்க்கையில் நீண்டகால நேர்மறையான பழக்கங்களை உருவாக்கவும் பராமரிக்கவும் லூப் ஹாபிட் டிராக்கர் உதவுகிறது. உங்களின் பழக்கவழக்கங்கள், காலப்போக்கில் எவ்வாறு முன்னேறியுள்ளன என்பதை விரிவான அட்டவணைகளும் புள்ளிவிவரங்களும் தெளிவாக காண்பிக்கும் இந்தப் பயன்பாடானது முற்றிலும் விளம்பரங்களற்றது, திறந்த மூலம் மற்றும் உங்களின் தனியுரிமையை மதிக்கும். + +அழகான, குறைந்தபட்சமான மற்றும் இலகுரக இடைமுகம் +Loop இலகுவாகப் பயன்படுத்தக்கூடிய, முதல் முறையிலேயே பயன்படுத்துவோருக்கும் எளிதான, நேர்த்தியான மற்றும் குறைந்தபட்சமான இடைமுகத்தைக் கொண்டுள்ளது. வேகத்திற்காக மிகவும் திறமையாகக் கட்டமைக்கப்பட்ட, இந்தப் பயன்பாடு பழைய தொலைபேசிகளில் கூட நன்கு செயல்படுகிறது. + +பழக்க மதிப்பெண் +Loop உங்களின் பழக்கங்களின் வலிமையை கணக்கிடுவதற்கு மேம்பட்ட சூத்திரத்தைக் கொண்டுள்ளது. ஒவ்வொரு மீளுருவாக்கமும் உங்கள் பழக்கத்தை வலுவாக்குகிறது, மேலும் ஒவ்வொரு தவறிய நாளும் அதைப் பலவீனப்படுத்துகிறது. A few missed days after a long streak, however, will not completely destroy your progress, unlike many other don't-break-the-chain apps. + +மாற்றியமைக்கக்கூடிய நாள்காட்டி +In addition to daily habits, Loop supports habits with more complex schedules, such as 3 times per week or every other day. + +நினைவூட்டல்கள் +உங்கள் பழக்கங்களை நினைவூட்ட உதவிக்கான அறிவிப்புகளைத் திட்டமிடவும் ஒவ்வொரு பழக்கத்திற்கும், நாளில் தேர்ந்தெடுக்கப்பட்ட நேரத்தில் தனித்துவமான நினைவூட்டலைக் கொடுக்கலாம் அறிவிப்பிலிருந்து உங்கள் பழக்கத்தை எளிதாக முடிக்கவும் அல்லது மறுக்கவும். + +Widgets +Be reminded of your habits whenever you unlock your phone. Colorful widgets allow you to track your habits directly from your home screen, without even opening the app. + +உங்கள் தரவு உங்கள் கட்டுப்பாட்டில் +If you want to further analyze your data, or move it to another service, Loop allows you to export it to spreadsheets (CSV) or to a database file (SQLite). For power users, checkmarks can be added through other apps, such as Tasker. + +எந்த வரம்புகளும் இல்லை +Track as many habits as you wish. Loop imposes no artificial limits on how many habits you can have. All features are available to all users. There are no in-app purchases. + +Completely ad-free and open source +இந்தச் செயலியில் விளம்பரங்கள், சிரமமான அறிவிப்புகள் அல்லது அடி முறைகளைப் பொருந்தும் அனுமதிகள் எதுவும் இல்லை, மற்றும் எப்போது இல்லை. இந்தச் செயலி முழுமையாகத் திறந்த மூல குறியீட்டுடன் (GPLv3) உள்ளது. + +Works offline and respects your privacy +Loop doesn't require an Internet connection or online account registration. Your confidential data is never sent to anyone. Neither the developers nor any third-parties have access to it. + diff --git a/uhabits-android/src/main/play/listings/ta-rIN/short-description.txt b/uhabits-android/src/main/play/listings/ta-rIN/short-description.txt new file mode 100644 index 000000000..8dd23fa53 --- /dev/null +++ b/uhabits-android/src/main/play/listings/ta-rIN/short-description.txt @@ -0,0 +1 @@ +நல்ல பழக்கங்களை உருவாக்க, அவற்றின் முன்னேற்றங்களைக் கண்காணிக்க (விளம்பரம் அற்றது) diff --git a/uhabits-android/src/main/play/listings/tr-rTR/full-description.txt b/uhabits-android/src/main/play/listings/tr-rTR/full-description.txt index 63130e9ad..b71b8697a 100644 --- a/uhabits-android/src/main/play/listings/tr-rTR/full-description.txt +++ b/uhabits-android/src/main/play/listings/tr-rTR/full-description.txt @@ -10,7 +10,7 @@ Loop, alışkanlıklarınızın kalıcılığını hesaplamak için gelişmiş b Loop, günlük alışkanlıkların yanında, daha karmaşık programları da (örneğin haftada 3 kez veya gün aşırı gibi) destekler. Hatırlatmalar -Alışkanlıklarınızı size hatırlatması için bildirimler ayarlayabilirsiniz. Her alışkanlık için özel bir bildirim ayarlayabilirsiniz, belirlediğiniz zamanda hatırlatmak üzere. Alışkanlığınızı doğrudan bildirimlerden kolayca işaretleyin veya erteleyin. +Alışkanlıklarınızı size hatırlatması için bildirimler ayarlayabilirsiniz. Her bir alışkanlık için gün içinde seçilecek bir zamanda ayrı ayrı bildirim ayarlayabilirsiniz, Alışkanlığınızı doğrudan bildirimlerden kolayca işaretleyin veya erteleyin. Widget'lar Telefonunuzun kilidini her açtığınızda alışkanlıklarınız size hatırlatılır. Renkli widget'lar, uygulamayı açmadan bile alışkanlıklarınızı doğrudan ana ekranınızdan izlemenizi sağlar. diff --git a/uhabits-android/src/main/play/listings/zh-rCN/full-description.txt b/uhabits-android/src/main/play/listings/zh-rCN/full-description.txt index 829db6db2..9ca7400c3 100644 --- a/uhabits-android/src/main/play/listings/zh-rCN/full-description.txt +++ b/uhabits-android/src/main/play/listings/zh-rCN/full-description.txt @@ -1,22 +1,22 @@ -Loop 习惯记录(以下简称“Loop”)能帮你养成和长期保持好习惯。 详细的图表和统计数据能让您更清楚地看到自己的进步。 这是一个完全无广告的开源应用,它尊重您的隐私。 +Loop 习惯记录(以下简称“Loop”)能帮你养成和长期保持好习惯。 通过详细的图表和统计数据,你可以清晰地看到自己的习惯是如何随着时间的推移而逐步改善的。 这是一个完全无广告的开源应用,它尊重您的隐私。 优雅、简约、轻巧 -Loop 具有优雅而简约的界面,即使对于初次使用的用户,也非常易于使用。 该应用针对速度进行了高度优化,即使在较旧的手机上也可以正常运行。 +Loop 的界面优雅而简约,即便初次使用,也能轻松上手。 该应用针对运行速度进行了高度优化,在旧手机上也表现良好。 -习惯强度 -Loop 有高级的公式来计算您习惯的强度。 多多重复会使你的习惯更牢固, 但是,与其他记录的应用不同,即便您有几天没有记录习惯,依然不会破坏您的进度。 +习惯分 +Loop 有高级的公式来计算您习惯的养成程度。 每次重复打卡都会让习惯更牢固,而每一次错过都会削弱。 不过与其他打卡的APP不同,即便您有几天没有记录习惯,依然不会破坏您的进度。 弹性计划 -除了每天习惯之外,Loop 还支持更加复杂的时间安排,例如每周三次或每天三次。 +除了每日打卡之外,Loop 还支持更加复杂的时间安排,例如每周3次或每天3次。 提醒 -设定通知以提醒您完成习惯。 您可以为每个习惯单独设置提醒,选定当天的某个时间提醒该习惯。 同时从通知中轻松地检查或取消您的习惯。 +您可以设定通知以提醒您完成习惯, 也可以为每个习惯单独设置提醒,并选定每日的提醒时间。 同时可以从通知中轻松地记录或取消打卡。 微件 -当您解锁手机时, 多彩的小部件可让您直接从主屏幕记录自己的习惯,而无需打开应用程序。 +当您解锁手机时, 缤纷的小部件可让您直接从桌面记录自己的习惯,而无需打开应用程序。 掌控您的数据 -如果您想进一步分析数据或将数据备份,则可以使用 Loop 将其导出为电子表格(CSV)或数据库文件(SQLite)。 对于高级用户,可以通过其他应用如 Tasker 实现自动化添加标记。 +如果您想进一步分析数据或将数据备份,则可以使用 Loop 将其导出为电子表格(CSV)或数据库文件(SQLite)。 对于高级用户,可以通过其他应用如 Tasker 实现自动化打卡。 无限制 想记录多少习惯都没问题! Loop 对您的习惯没有任何限制, 所有用户均可使用所有功能, 并且没有应用内购买。 @@ -24,6 +24,6 @@ Loop 有高级的公式来计算您习惯的强度。 多多重复会使你的 完全无广告的开源软件 本应用永远都不会有广告和烦人的通知,也不会索取侵入性权限。 本应用是完全开源的(GPLv3)。 -脱机工作并尊重您的隐私 -Loop 不需要网络连接或在线帐户注册。 您的用户数据永远不会发送给任何人, 包括开发人员和任何第三方都无法访问它。 +离线运行,尊重隐私 +Loop 不需要联网运行或注册在线帐号。 您的用户数据永远不会发送给任何人, 包括开发人员和任何第三方都无法访问它。 diff --git a/uhabits-android/src/main/res/drawable/widget_button_background.xml b/uhabits-android/src/main/res/drawable/widget_button_background.xml index a5d8b5fbf..2ea56e4e9 100644 --- a/uhabits-android/src/main/res/drawable/widget_button_background.xml +++ b/uhabits-android/src/main/res/drawable/widget_button_background.xml @@ -28,7 +28,7 @@ - + diff --git a/uhabits-android/src/main/res/layout/about_translators.xml b/uhabits-android/src/main/res/layout/about_translators.xml index 52c80303c..61bb51efc 100644 --- a/uhabits-android/src/main/res/layout/about_translators.xml +++ b/uhabits-android/src/main/res/layout/about_translators.xml @@ -25,17 +25,19 @@ + + + - @@ -57,11 +59,17 @@ + + + + + + @@ -69,6 +77,8 @@ + + @@ -90,15 +100,18 @@ + + + + - @@ -122,12 +135,15 @@ + + + @@ -149,7 +165,6 @@ - @@ -170,6 +185,7 @@ + @@ -182,6 +198,7 @@ + @@ -191,8 +208,13 @@ + + + + + \ No newline at end of file diff --git a/uhabits-android/src/main/res/layout/checkmark_popup.xml b/uhabits-android/src/main/res/layout/checkmark_popup.xml index 59f5c81a1..7661735f4 100644 --- a/uhabits-android/src/main/res/layout/checkmark_popup.xml +++ b/uhabits-android/src/main/res/layout/checkmark_popup.xml @@ -23,32 +23,32 @@ android:id="@+id/container" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:minHeight="128dp" + android:background="@drawable/checkmark_dialog_bg" android:minWidth="208dp" - app:divider="@drawable/checkmark_dialog_divider" - app:showDividers="middle" + android:minHeight="128dp" android:orientation="vertical" - android:background="@drawable/checkmark_dialog_bg"> + app:divider="@drawable/checkmark_dialog_divider" + app:showDividers="middle"> + android:text="" + android:textSize="@dimen/smallTextSize" /> @@ -75,10 +75,10 @@ @@ -86,21 +86,26 @@ android:id="@+id/value" android:layout_width="0dp" android:layout_height="match_parent" - android:layout_weight="1" + android:layout_weight="2" android:background="@color/transparent" - android:textAlignment="center" android:inputType="numberDecimal" android:selectAllOnFocus="true" + android:textAlignment="center" android:textSize="@dimen/smallTextSize" /> + + + android:id="@+id/unknownBtnNumber" + style="@style/CheckmarkPopupBtn" + android:text="@string/fa_question" /> \ No newline at end of file diff --git a/uhabits-android/src/main/res/values-ar-rSA/strings.xml b/uhabits-android/src/main/res/values-ar-rSA/strings.xml index ca1c23f92..33ce2d62a 100644 --- a/uhabits-android/src/main/res/values-ar-rSA/strings.xml +++ b/uhabits-android/src/main/res/values-ar-rSA/strings.xml @@ -28,6 +28,38 @@ إضافة عادة تغيير اللون تم إنشاء عادة + + تم تغيير العادة + تم تغيير العادة + تم تغيير العادتين + تم تغيير العادات + تم تغيير العادات + تم تغيير العادات + + + تم حذف العادة + تم حذف العادة + تم حذف العادتين + تم حذف العادات + تم حذف العادات + تم حذف العادات + + + تمت أرشفة العادة + تم أرشفه العادة + تمت أرشفة العادتين + تمت أرشفة العادات + تمت أرشفة العادات + تمت أرشفة العادات + + + تم الغاء ارشفه العادة + تم الغاء ارشفه العادة + تم إلغاء أرشفة العادتين + تم إلغاء أرشفة العادات + تم إلغاء أرشفة العادات + تم إلغاء أرشفة العادة + نظرة عامة قوة العادة السجل @@ -37,14 +69,14 @@ الإنجازات لا يوجد لديك عادات مفعله لقد أنهيت ألعمل لليوم - إلمس و إستمر لتحقق أو ازل. + اضغط باستمرار للتأكيد أو الإزالة. إيقاف انشاء العادة تعديل العادة - حقق + سجل لاحقاً أهلا بك - Loop Habit Tracker يساعدك في بدء عادات جيدة والحفاظ عليها. + يساعدك متتبع العادات loop في بَدْء عادات جيدة والحفاظ عليها. إنشاء بعض عادات جديدة كل يوم، بعد أداء عادتك، ضع علامة عليها في التطبيق. تتبع تقدمك @@ -53,9 +85,9 @@ 30 دقيقة ساعة واحدة ساعتان - أربع ساعات - 8 ساعات - 24 ساعة + ٤ ساعات + ٨ ساعات + ٢٤ ساعة اسأل دائماً مخصص... تبديل وضعية العادة بضغطة قصيرة @@ -64,19 +96,35 @@ أرسل الملاحظات إلى المطور إفحص التعليمات البرمجية على GitHub روابط - اسم + الاسم إعدادات حدد تأخير الغفوة هل كنت تعلم؟ لإعادة ترتيب القوائم، أضغط اسم من هذه العادة، ثم اسحبه إلى المكان الصحيح. يمكنك ان ترى المزيد أيام عن طريق وضع الهاتف في وضع أفقي. + + حذف العادة؟ + حذف العادة؟ + حذف العادتين؟ + حذف العادات؟ + حذف العادات؟ + حذف العادات؟ + + + سيتم حذف العادة بشكل دائم. لا يمكن التراجع عن هذه الخطوة. + سيتم حذف العادة بشكل دائم. لا يمكن التراجع عن هذه الخطوة. + سيتم حذف العادتين بشكل دائم. لا يمكن التراجع عن هذه الخطوة. + سيتم حذف العادات بشكل دائم. لا يمكن التراجع عن هذه الخطوة. + سيتم حذف العادات بشكل دائم. لا يمكن التراجع عن هذه الخطوة. + سيتم حذف العادات بشكل دائم. لا يمكن التراجع عن هذه الخطوة. + العادة حذفت/لم يتم العثور عليها عطلة نهاية الأسبوع أيام الأسبوع. أي يوم. إختار أيام تصدير البيانات (CSV) - منجز + إنهاء نظف تحديد ساعات تحديد دقائق @@ -103,13 +151,13 @@ توليد تقرير الاعطال. استكشاف الأخطاء وإصلاحها. المساعدة في ترجمة هذا البرنامج. - الوضع الليلي. + الوضع الليلي استخدام أسود نقي في الوضع الليلي. يستبدل خلفيات رمادية مع أسود نقي في الوضع الليلي. يقلل من استهلاك البطارية في الهواتف مع شاشة AMOLED. . السطح البيني. ترتيب عكسي أيام. عرض أيام في ترتيب عكسي على الشاشة الرئيسية. - يوم. + يوم أسبوع. شهر. ربع سنه. @@ -150,10 +198,10 @@ على الأقل على الأكثر على سبيل المثال هل تمرنت اليوم؟ - السؤال - الهدف - نعم - لا + السؤال + الهدف + نعم + لا Change sound, vibration, light and other notification settings Customize notifications عرض نهج الخصوصية @@ -175,7 +223,7 @@ اللون مثال: 15 مثلا: الجري - مثلا: كم كيلومترًا جريته اليوم؟ + مثلا، كم ميلا ركضت اليوم؟ مثلا: كيلومترات كل شهر لا يمكن أن يكون الإسم فارغًا diff --git a/uhabits-android/src/main/res/values-ca-rES/strings.xml b/uhabits-android/src/main/res/values-ca-rES/strings.xml index ec2979478..85af18328 100644 --- a/uhabits-android/src/main/res/values-ca-rES/strings.xml +++ b/uhabits-android/src/main/res/values-ca-rES/strings.xml @@ -67,6 +67,7 @@ Pregunta sempre Personalitza... Activar/desactivar repeticions prement curt + Posa les marques de verificació amb un sol toc en lloc de prémer Valora aquesta app a Google Play Enviar resposta al desenvolupador Veure codi font a Github @@ -127,7 +128,7 @@ Dia Setmana Mes - Quatrimestre + Trimestre Any Total Sí o No @@ -138,6 +139,7 @@ Cap Filtre Amaga completat + Amagar introduït Amaga arxivades Fer les notificacions enganxós Evita les notificacions de ser pispat lluny. @@ -157,8 +159,11 @@ Per estat Exportar Prémer i mantenir per a canviar el valor + Valor Calendari Unitat + Tipus objectiu + Al menys p.e. Has fet exercici avui? Pregunta Objectiu diff --git a/uhabits-android/src/main/res/values-cs-rCZ/strings.xml b/uhabits-android/src/main/res/values-cs-rCZ/strings.xml index 1680ac9d6..2f1ced2a1 100644 --- a/uhabits-android/src/main/res/values-cs-rCZ/strings.xml +++ b/uhabits-android/src/main/res/values-cs-rCZ/strings.xml @@ -28,6 +28,30 @@ Přidat zvyk Změnit barvu Zvyk vytvořen. + + Návyk upraven + Návyky upraveny + Návyky upraveny + Návyky upraveny + + + Návyk odstraněn + Návyky odstraněny + Návyky odstraněny + Návyky odstraněny + + + Návyk archivován + Návyky archivovány + Návyky archivovány + Návyky archivovány + + + Návyk obnoven + Návyky obnoveny + Návyky obnoveny + Návyky obnoveny + Přehled Síla zvyku Historie @@ -35,8 +59,8 @@ Připomenutí Uložit Série - Nemáte zapsané žádné zvyky - Splnili jste vše pro dnešní den! + Nemáte žádné aktivní návyky + Dnes máte hotovo! Stiskni a drž pro označení Vyp. Vytvořit zvyk @@ -44,32 +68,44 @@ Hotovo Odložit Vítejte - Sledování zvyků Vám pomůže vytvořit a dosáhnout dobrých návyků. + Loop Habit Tracker vám pomůže vytvořit a udržet dobré návyky. Vytvoř si nové zvyky Každý den po splnění zvyku si ho v aplikaci zaškrtněte. - Sledujte svůj pokrok - Detailní grafy Vám ukážou, jak se Vaše zvyky v průběhu času zlepšily. + Sleduj svůj postup + Detailní grafy ukazují zlepšení vašich návyků v průběhu času. 15 minut 30 minut - Hodina + 1 hodina 2 hodiny 4 hodiny 8 hodin 24 hodin - Vždy se ptát + Vždy se dotázat Vlastní... - Označte opakování krátkým stisknutím - Zaškrtněte jediným klepnutím místo dlouhého podržení. - Ohodnoťte nás v Google Play - Zpětná vazba vývojáři - Zobrazit zdroj. kód na GitHub + Označte krátkým stisknutím + Zaškrtněte jediným klepnutím namísto dlouhého podržení. + Ohodnotit aplikaci v Google Play + Odeslat zpětnou vazbu vývojáři + Zobrazit zdrojový kód na GitHub Odkazy - Jméno + Název Nastavení Nastavit délku odložení Věděli jste? - Přeřazení záznamů proveďte stisknutím a podržením názvu zvyku a poté přesunutím na správné místo. + Pro přeřazení položek stiskněte a podržte název zvyku a přesuňte ho na správné místo. Můžete vidět více dnů otočením telefonu na šířku. + + Odstranit návyk? + Odstranit návyky? + Odstranit návyky? + Odstranit návyky? + + + Návyk bude trvale odstraněn. Tento krok je nevratný. + Návyky budou trvale odstraněny. Tento krok je nevratný. + Návyky budou trvale odstraněny. Tento krok je nevratný. + Návyky budou trvale odstraněny. Tento krok je nevratný. + Zvyk smazán / nenalezen Víkendy Pondělí až pátek @@ -85,7 +121,7 @@ Vývojáři Verze %s Frekvence - Fajfka + Zaškrtnutí Nejlepší série Každý den Každý týden @@ -96,9 +132,9 @@ Zvyky úspěšně importovány. Importovat Kompletní export - Podporuje exporty z této aplikace, ale také soubory vygenerované aplikacemi od Tickmate, HabitBull nebo Rewire. Pro více informací si prečtěte FAQ. - Generuje soubory, které mohou být otevřeny v tabulkových editorech jako jsou Microsoft Excel nebo OpenOffice Calc. Tyto soubory nelze importovat zpět. - Generuje soubor, který obsahuje všechna Vaše data. Tento soubor může být importován zpět. + Podporuje plné zálohy z této aplikace, stejně jako soubory vygenerované aplikacemi od Tickmate, HabitBull nebo Rewire. Pro více informací konzultujte FAQ. + Generuje soubory, které mohou být otevřeny v tabulkových editorech jako jsou Microsoft Excel nebo OpenOffice Calc. Tento soubor nelze importovat zpět. + Generuje soubor, který obsahuje veškerá vaše data. Tento soubor může být importován zpět. Generace výpisu chyb selhala. Generovat výpis chyb Řešení problémů @@ -119,15 +155,16 @@ Každých %d dní Každých %d týdnů Skóre - Zvuk připomínky + Zvuk upozornění Žádný Filtr Skrýt dokončené + Skrýt vyplněné Skrýt archivované Připnout upozornění Zabraňuje odstranění upozornění přejetím. Světelné upozornění - Blikání diody při upozornění. Funkční pouze na telefonech s notifikační LED diodou. + Bliká při upozornění. Pouze pro telefony s LED notifikačními světly. Opravit databázi Databáze opravena. Odznačit @@ -139,12 +176,16 @@ Abecedně Podle barvy Podle skóre - Podle statusu + Podle stavu Export Stiskněte a držte pro změnu hodnoty + Hodnota Kalendář Jednotka - Např. Cvičil jsi dnes? + Typ Cíle + Minimálně + Maximálně + např. Cvičil jsi dnes? Otázka Cíl Ano @@ -157,36 +198,36 @@ Průhlednost widgetu Upravuje průhlednost pozadí widgetu na domovské obrazovce. První den v týdnu - Dokončili jste dnes tento zvyk? + Dokončili jste dnes tento návyk? Poznámky (nepovinné) - Např. Vzbudil ses dnes brzy? Cvičil jsi dnes? Hrál jsi šachy? + např. Vzbudil ses dnes brzy? Cvičil jsi dnes? Hrál jsi šachy? Měřitelný - Např. Kolik kilometrů jsi dnes uběhl? Kolik stránek jsi dnes přečetl? + např. Kolik kilometrů jsi dnes uběhl? Kolik stránek jsi dnes přečetl? %d krát týdně %d krát za měsíc %d krát za %d dní - Např. Cvičení + např. Cvičení Barva - Např. 15 - Např. Běh - Např. Kolik kilometrů jste dnes uběhl? - Např. Kilometry + např. 15 + např. Běh + např. Kolik kilometrů jsi dnes uběhl? + např. Kilometry Každý měsíc Musíte vyplnit Dnes Vyplnit - Nenalezeny žádné zvyky - Nenalezeny žádné měřitelné zvyky - Nenalezeny žádné \"ano/ne\" zvyky - Zvětšit - Zmenšit - Povolit přeskakování dnů - Klikněte dvakrát pro přidání pomlčky (přeskočení dne) místo fajfky. Pomlčka nezmění Vaše skóre, ani nepřeruší Vaši výzvu. - Při chybějícím údaji zobrazit otazník - Odlište dny bez údajů od nesplněného zvyku. Pro zadání \"nesplněno\" klikněte dvakrát. + Žádné návyky nenalezeny + Žádné měřitelné návyky nenalezeny + Nenalezeny žádné \"ano/ne\" návyky + Zvýšit + Snížit + Umožnit přeskakování dnů + Klikněte dvakrát pro přeskočení namísto zaškrtnutí. Pomlčka nezmění vaše skóre, ani nepřeruší vaši sérii. + Zobrazit otazník pro chybějící data + Odlište dny bez údajů od nesplněného návyku. Pro zadání \"nesplněno\", klikněte dvakrát. Nyní jste vývojář - Pro daný krok nebyla nalezena aplikace - Po půlnoci prodloužit den o několik hodin - Počkat do 3:00 ráno pro zobrazení nového dne. Užitečné, pokud chodíte spát po půlnoci. Vyžaduje restartování aplikace. + Nenalezen program podporující tento krok + Prodloužit den o pár hodin po půlnoci + Počkat do tří ráno pro zobrazení nového dne. Užitečné, pokud chodíte spát po půlnoci. Vyžaduje restartování aplikace. diff --git a/uhabits-android/src/main/res/values-de-rDE/strings.xml b/uhabits-android/src/main/res/values-de-rDE/strings.xml index ca119039f..90959fbb9 100644 --- a/uhabits-android/src/main/res/values-de-rDE/strings.xml +++ b/uhabits-android/src/main/res/values-de-rDE/strings.xml @@ -105,8 +105,8 @@ Stunden auswählen Minuten auswählen Über Loop - Übersetzer und Übersetzerinnen - Entwickler und Entwicklerinnen + Übersetzer + Entwickler Version %s Häufigkeit Häkchen @@ -120,7 +120,7 @@ Gewohnheiten erfolgreich importiert. Daten importieren Vollständige Sicherung exportieren - Unterstützt vollständige Sicherungen dieser App, als auch von Tickmate, HabitBull und Rewire. Siehe FAQ für weitere Informationen. + Unterstützt vollständige Sicherungen dieser App, sowie von Tickmate, HabitBull und Rewire erzeugte Sicherungen. Siehe FAQ für weitere Informationen. Erstellt Dateien, die von Tabellenkalkulationsprogrammen wie Microsoft Excel oder LibreOffice Calc geöffnet werden können. Diese Dateien können nicht wieder importiert werden. Erstellt eine Datei, die alle deine Daten enthält. Diese Datei kann wieder importiert werden. Fehler beim Erstellen eines Fehlerberichts. @@ -172,7 +172,7 @@ Einheit Zieltyp Mindestens - Höchtens + Höchstens z.B. Hast du heute trainiert? Frage Ziel diff --git a/uhabits-android/src/main/res/values-el-rGR/strings.xml b/uhabits-android/src/main/res/values-el-rGR/strings.xml index 3457ddac7..bf322f489 100644 --- a/uhabits-android/src/main/res/values-el-rGR/strings.xml +++ b/uhabits-android/src/main/res/values-el-rGR/strings.xml @@ -28,6 +28,22 @@ Νέα συνήθεια Αλλαγή χρώματος Η συνήθεια δημιουργήθηκε + + Η συνήθεια άλλαξε + Οι συνήθειες άλλαξαν + + + Η συνήθεια διαγράφηκε + Οι συνήθειες διαγράφηκαν + + + Η συνήθεια αρχειοθετήθηκε + Οι συνήθειες αρχειοθετήθηκαν + + + Έγινε αφαίρεση αρχειοθέτησης συνήθειας + Έγινε αφαίρεση αρχειοθέτησης συνηθειών + Επισκόπηση Δύναμη συνήθειας Ιστορικό @@ -36,8 +52,9 @@ Αποθήκευση Σερί Δεν έχετε ενεργές συνήθειες + Είστε πανέτοιμοι για σήμερα! Πατήστε παρατεταμένα για επιλογή η αποεπιλογή - Χωρίς + Ανενεργό Δημιουργία συνήθειας Επεξεργασία συνήθειας Επιλογή @@ -46,34 +63,43 @@ Το Loop - Καταγραφή Συνηθειών σας βοηθάει να δημιουργήσετε και να διατηρήσετε καλές συνήθειες. Δημιουργήστε μερικές νέες συνήθειες Κάθε μέρα, με το πέρας της συνήθειας, βάλτε ένα τικ στην εφαρμογή. - Κατέγραψε την πρόοδο σου - Λεπτομερή διαγράμματα σας δείχνουν την πρόοδο των συνηθειών. + Καταγράψτε την πρόοδό σας + Λεπτομερή διαγράμματα σας δείχνουν την πρόοδο των συνηθειών σας. 15 λεπτά 30 λεπτά 1 ώρα 2 ώρες 4 ώρες 8 ώρες - 24 Ωρο + 24 ώρες Να ερωτούμαι πάντα - Προσαρμογή + Προσαρμογή... Κάντε εναλλαγή των επαναλήψεων με σύντομο πάτημα + Τοποθέτηση σημείων ελέγχου με ένα μόνο πάτημα αντί για πάτημα και αναμονή. Βαθμολογήστε αυτή την εφαρμογή στο Google Play - Στείλετε σχόλια + Αποστολή σχολίων στον προγραμματιστή Δείτε τον πηγαίο κώδικα στο GitHub Σύνδεσμοι Όνομα Ρυθμίσεις Επιλογή καθυστέρησης αναβολής - Γνωρίζατε; + Το γνωρίζατε; Αναδιατάξετε τις συνήθειες πατώντας παρατεταμένα στο όνομα και σύροντας στην σωστή θέση. Μπορείτε να δείτε περισσότερες ημέρες στην οριζόντια προβολή. - Η συνήθεια διαγράφηκε / δεν βρέθηκε + + Διαγραφή συνήθειας; + Διαγραφή συνηθειών; + + + Η συνήθεια θα διαγραφεί οριστικά. Αυτή η ενέργεια δεν μπορεί να αναιρεθεί. + Οι συνήθειες θα διαγραφούν οριστικά. Αυτή η ενέργεια δεν μπορεί να αναιρεθεί. + + Η συνήθεια διαγράφηκε / δε βρέθηκε Σαββατοκύριακα Δευτέρα μέχρι Παρασκευή Οποιαδήποτε μέρα της εβδομάδας Επιλογή ημερών - Εξαγωγή σαν CSV + Εξαγωγή ως CSV Έγινε Εκκαθάριση Επιλογή ωρών @@ -84,12 +110,12 @@ Έκδοση %s Συχνότητα Σημάδι επιλογής - Καλύτερα σερί + Τα καλύτερα σερί Κάθε μέρα Κάθε εβδομάδα - Βοήθεια & FAQ - Αποτυχία εξαγωγής. - Αποτυχία εισαγωγής. + Βοήθεια & Συχνές Ερωτήσεις + Αποτυχία εξαγωγής δεδομένων. + Αποτυχία εισαγωγής δεδομένων. Άγνωστο αρχείο. Οι συνήθειες εισάχθηκαν επιτυχώς. Εισαγωγή δεδομένων @@ -100,20 +126,20 @@ Απέτυχε ή παραγωγή αναφοράς bug. Παραγωγή αναφοράς bug. Αντιμετ.Προβλημάτων - Βοηθήστε στην μετάφραση - Νυχτ.Λειτ. + Βοηθήστε στη μετάφραση της εφαρμογής + Σκοτεινό θέμα Χρήση απόλυτου μαύρου στη νυχτ.λειτουργία Αντικαθιστά τα γκρί υπόβαθρα με απόλυτα μαύρα σε νυχτ.λειτουργία. Μειώνει την κατανάλωση μπαταρίας σε συσκευές με οθόνη AMOLED. - Διεπιφάνεια - Αναστροφή σειράς των ημερών. + Διεπαφή + Αντίστροφη σειρά ημερών Προβολή των ημερών σε αντίστροφη σειρά στην κυρία οθόνη. Ημέρα Εβδομάδα Μήνας Τρίμηνο - Χρόνος + Έτος Σύνολο - Ναι / Όχι + Ναι ή Όχι Κάθε %d ημέρες Κάθε %d εβδομάδες Σκόρ @@ -121,26 +147,32 @@ Σιωπηλό Φίλτρο Απόκρυψη ολοκληρωμένων - Απόκρυψη των αρχειοθετημένων + Απόκρυψη εισαγμένων + Απόκρυψη αρχειοθετημένων Κάντε τις ειδοποιήσεις κολλώδεις Αποτρέπει την απομάκρυνση των ειδοποιήσεων. - Ένδειξη LED ειδοποίησης + Φως ειδοποιήσεων Αναβοσβήνει μια φωτεινή ένδειξη για υπενθυμίσεις. Διαθέσιμο μόνο σε τηλέφωνα με φωτεινές ενδείξεις LED. Επισκευή βάσης δεδομένων Η βάση δεδομένων επισκευάστηκε. Ξεμαρκάρισμα Εναλλαγή - Δράση - Συνήθειες + Ενέργεια + Συνήθεια Ταξινόμηση Χειροκίνητα - Κατά όνομα - Με χρώμα + Ανά όνομα + Ανά χρώμα Με σκορ + Κατά κατάσταση Εξαγωγή Πατήστε και κρατήστε πατημένο για να αλλάξετε την τιμή + Τιμή Ημερολόγιο Μονάδα + Τύπος Στόχου + Τουλάχιστον + Το πολύ π.χ. Ασκήθηκες σήμερα; Ερώτηση Στόχος @@ -148,7 +180,7 @@ Όχι Αλλαγή ρυθμίσεων ήχου, δόνησης, φωτισμού και άλλων ειδοποιήσεων Προσαρμογή ειδοποιήσεων - Προβολή πολιτικής προστασίας προσωπικών δεδομένων + Προβολή πολιτικής απορρήτου Προβολή όλων των συντελεστών… Βάση δεδομένων Διαφάνεια widget @@ -159,16 +191,31 @@ (Προαιρετικό) π.χ. Ξύπνησες νωρίς σήμερα; Ασκήθηκες; Έπαιξες σκάκι; Μετρήσιμο + π.χ. Πόσα χιλιόμετρα τρέξατε σήμερα; Πόσες σελίδες διαβάσατε; %d φορές την εβδομάδα %d φορές το μήνα - %d φορές την %d ημέρες + %d φορές σε %d ημέρες π.χ. Σωματική άσκηση Χρώμα π.χ. 15 π.χ. Τρέξιμο - π.χ. Πόσα χιλιόμετρα έτρεξες σήμερα? + π.χ. Πόσα χιλιόμετρα τρέξατε σήμερα; π.χ. χιλιόμετρα Κάθε μήνα Δεν μπορεί να είναι κενό Σήμερα + Εισαγωγή + Δεν βρέθηκαν συνήθειες + Δεν βρέθηκαν μετρήσιμες συνήθειες + Δεν βρέθηκαν συνήθειες ναι-ή-όχι + Αύξηση + Μείωση + Ενεργοποίηση παράλειψης ημερών + Εναλλαγή δύο φορές για να προσθέσετε μια παράκαμψη αντί για ένα σημάδι ελέγχου. Οι παραλείψεις κρατούν το σκορ σας αμετάβλητο και να δε σπάνε το σερί σας. + Εμφάνιση ερωτηματικών για τα δεδομένα που λείπουν + Διαφορικές ημέρες χωρίς δεδομένα από πραγματικές παραλήψεις. Για να εισάγετε μια παράληψη, κάντε εναλλαγή δύο φορές. + Είστε πλέον προγραμματιστής + Δεν βρέθηκε εφαρμογή για την υποστήριξη αυτής της ενέργειας + Επεκτείνετε την ημέρα λίγες ώρες μετά τα μεσάνυχτα + Περιμένετε μέχρι τις 3:00 πμ για να εμφανιστεί μια νέα μέρα. Χρήσιμο αν συνήθως πάτε για ύπνο μετά τα μεσάνυχτα. Απαιτεί επανεκκίνηση της εφαρμογής. diff --git a/uhabits-android/src/main/res/values-es-rES/strings.xml b/uhabits-android/src/main/res/values-es-rES/strings.xml index 44bcdec51..28d1fae9b 100644 --- a/uhabits-android/src/main/res/values-es-rES/strings.xml +++ b/uhabits-android/src/main/res/values-es-rES/strings.xml @@ -64,7 +64,7 @@ Crea algunos hábitos nuevos Cada día, después de realizar tu hábito, pon una marca en la aplicación. Haz un seguimiento de tu progreso - Gráficos detallados muestran cómo mejoraron sus hábitos con el tiempo. + Gráficos detallados te muestran cómo mejoraron tus hábitos con el tiempo. 15 minutos 30 minutos 1 hora @@ -76,7 +76,7 @@ Personalizar... Marca las repeticiones con una pulsación corta Ponga marcas de verificación con un solo toque en lugar de mantener presionado. - Valora esta aplicación en Google Play + Califica esta aplicación en Google Play Enviar sugerencias al desarrollador Ver código fuente en GitHub Enlaces @@ -84,7 +84,7 @@ Configuración Seleccione el retardo de la interrupción ¿Sabías qué? - Para reordenar las entradas, mantén pulsado el nombre del hábito, después arrástralo a su posición correcta. + Para reorganizar las entradas, mantén presionado el nombre del hábito y luego arrástralo al lugar correcto. Puedes ver más días al poner tu teléfono en modo horizontal. ¿Eliminar hábito? @@ -113,30 +113,30 @@ Mejores rachas Diariamente Semanalmente - Ayuda & FAQ + Ayuda & Preguntas frecuentes Error al exportar datos. Error al importar datos. Archivo no reconocido. Hábitos importados exitosamente. Importar datos Exportar copia de seguridad - Soporta exportar copias de seguridad completas, así como archivos generados por Tickmate, HabitBull o Rewire. Mira el FAQ para más información. - Genera archivos que pueden ser abiertos por programas de hojas de cálculo como Microsoft Excel o OpenOffice Calc. Este archivo no puede volver a importarse. - Genera un archivo que contiene todos tus datos. Este archivo puede volver a importarse. + Es compatible con exportar copias de seguridad completas, así como archivos generados por Tickmate, HabitBull o Rewire. Mira el FAQ para más información. + Genera archivos que pueden ser abiertos por programas de hojas de cálculo como Microsoft Excel o OpenOffice Calc. Este archivo no puede volver a importarse de vuelta. + Genera un archivo que contiene todos tus datos. Este archivo puede volver a importarse de vuelta. Error al generar el reporte de error. - Generar reporte de errores + Generar informe de bug Solución de problemas - Ayuda a traducir esta app + Ayuda a traducir esta aplicación Modo nocturno Utilizar color negro en modo nocturno Reemplaza fondos grises por color negro en modo nocturno. Reduce el consumo de batería en teléfonos con pantalla AMOLED. Interfaz - Orden inverso de días - Mostrar días en orden inverso en la pantalla principal + Invertir el orden de los días + Mostrar días en orden inverso en la pantalla principal. Día Semana Mes - Cuatrimestre + Trimestre Año Total Sí / No @@ -149,9 +149,9 @@ Ocultar completos Ocultar ingresado Ocultar archivados - Hacer notificaciones fijas + Hacer que las notificaciones sean fijas Evita que las notificaciones sean descartadas. - Luz de notificaciones + Luz de notificación Muestra una luz intermitente para recordatorios. Solo disponible en teléfonos con luces de notificación LED. Reparar base de datos Base de datos reparada. @@ -176,9 +176,9 @@ ej. ¿Has ejercitado hoy? Pregunta Objetivo - Si + No - Cambiar el sonido, la vibración, la luz y otras configuraciones de notificación + Cambiar sonido, vibración, luz y otros ajustes de notificación Personalizar las notificaciones Ver política de privacidad Ver todos los colaboradores… @@ -189,16 +189,16 @@ ¿Has completado este hábito hoy? Notas (Opcional) - por ejemplo, ¿te despertaste temprano hoy? ¿Hiciste ejercicio? ¿Jugaste al ajedrez? + ej. ¿Te levantaste temprano hoy? ¿Hiciste ejercicio? ¿Jugaste al ajedrez? Medible - ej. ¿Cuántas millas ha corrido hoy? ¿Cuántas páginas ha leído? + ej. ¿Cuántas millas has corrido hoy? ¿Cuántas páginas has leído? %d veces por semana %d veces al mes %d veces en %d días ej. Ejercicio Color ej. 15 - por ejemplo, correr + ej. Correr ej. ¿Cuántos kilómetros has corrido hoy? ej. kilómetros Cada mes @@ -209,11 +209,11 @@ No se encontraron hábitos medibles No se encontraron hábitos de sí o no Incrementar - Decrementar + Disminuir Habilitar días libres - Alternar dos veces para agregar un salto en lugar de una marca de verificación. Los saltos mantienen su puntaje sin cambios y no rompen su racha. - Mostrar interrogantes para datos faltantes - Diferenciar los días sin datos de los lapsos reales. Para ingresar un lapso, alternar dos veces. + Presionar dos veces para agregar un salto en lugar de una marca de verificación. Los saltos mantienen tu puntaje sin cambios y no rompen tu racha. + Mostrar signos de interrogación para datos faltantes + Diferenciar los días sin datos de los lapsos reales. Para ingresar un lapso, presionar dos veces. Ahora eres desarrollador No se encontró ninguna aplicación que admita esta acción Ampliar día unas horas después de medianoche diff --git a/uhabits-android/src/main/res/values-eu-rES/strings.xml b/uhabits-android/src/main/res/values-eu-rES/strings.xml index e651b5ad5..f40266ce6 100644 --- a/uhabits-android/src/main/res/values-eu-rES/strings.xml +++ b/uhabits-android/src/main/res/values-eu-rES/strings.xml @@ -40,6 +40,10 @@ Ohitura artxibatu da Ohiturak artxibatu dira + + Ohitura desartxibatu da + Ohiturak desartxibatu dira + Ikuspegi orokorra Ohituraren indarra Historia @@ -71,6 +75,7 @@ Galdetu beti Pertsonalizatua... Ukitze laburrarekin markatu + Jarri kontrol-markak ukitu bakar batekin sakatu eta eutsi beharrean. Aplikazio hau Google Playen puntuatu Zure iritzia garatzaileari bidali Iturburu kodea GitHuben ikusi @@ -85,6 +90,10 @@ Ohiturak ezabatu Ohiturak ezabatu + + Ohitura betirako ezabatuko da. Ekintza hau ezin da desegin. + Ohiturak betirako ezabatuko dira. Ekintza hau ezin da desegin. + Ohitura ezabatua / ez aurkitua Asteburuak Astelehenetik ostiralera @@ -138,6 +147,7 @@ Bat ere ez Iragazkia Ezkutatu lortutakoak + Ezkutatu betetakoak Ezkutatu artxibatutakoak Jakinarazpenak itsaskorrak bihurtu Jakinarazpenak keinu batez ezabatzea sahiesten du. @@ -160,6 +170,7 @@ Balioa Egutegia Unitatea + Helburu mota Gutxienez Gehienez adib. ariketa egin al duzu gaur? @@ -180,6 +191,7 @@ (Aukerazkoa) adib. Gaur goiz esnatu zara? Ariketa fisikoa egin al duzu? Xakean jolastu al duzu? Neurgarria + Adib. Zenbat kilometro egin dituzu gaur? Zenbat orrialde irakurri dituzu? Astean %d aldiz Hilean %d aldiz %d aldiz %d egunetan @@ -196,8 +208,12 @@ Ez da ohiturarik aurkitu Ez da aurkitu ohitura neurgarririk Ez da bai-ala-ez ohiturarik aurkitu + Gaitu atseden egunak + Sakatu bi aldiz kontrol-markaren ordez atseden bat gehitzeko. Atsedenek zure puntuazioa aldatu gabe mantentzen dute eta ez dute segida hausten. Adierazi galdera ikurra falta diren datuetan + Bereizi daturik gabeko egunak benetako hutsegiteetatik. Hutsegite bat sartzeko, sakatu bi aldiz. Garatzailea zara! Ez da aurkitu akzio hau gauzatu dezakeen aplikaziorik + Luzatu eguna gauerdia osteko ordu batzuetara Itxaron goizeko 3:00ak arte egun berri bat erakusteko. Erabilgarria normalean gauerdia pasata lotara joaten bazara. Aplikazioa berrabiarazi behar da. diff --git a/uhabits-android/src/main/res/values-fa-rIR/strings.xml b/uhabits-android/src/main/res/values-fa-rIR/strings.xml index ae6c915cf..391e558d4 100644 --- a/uhabits-android/src/main/res/values-fa-rIR/strings.xml +++ b/uhabits-android/src/main/res/values-fa-rIR/strings.xml @@ -147,7 +147,7 @@ هیچ‌کدام فیلتر مخفی کردن کامل‌شده‌ها - پنهان کردن مقادیر + پنهان کردن مقادیر مخفی کردن بایگانی‌شده‌ها چسبناک کردن اعلان‌ها از رد کردن اعلان با کشیدن جلوگیری می‌کند. diff --git a/uhabits-android/src/main/res/values-fi-rFI/strings.xml b/uhabits-android/src/main/res/values-fi-rFI/strings.xml index 867aec122..5dbc61f06 100644 --- a/uhabits-android/src/main/res/values-fi-rFI/strings.xml +++ b/uhabits-android/src/main/res/values-fi-rFI/strings.xml @@ -147,7 +147,7 @@ Ei mitään Suodata Piilota suoritetut - Piilota syötetty + Piilota syötetty Piilota arkistoidut Tee ilmoituksesta kiinnitettyjä Estää ilmoitusten pois pyyhkäisemisen. diff --git a/uhabits-android/src/main/res/values-fr-rFR/strings.xml b/uhabits-android/src/main/res/values-fr-rFR/strings.xml index 69672682b..1132dd261 100644 --- a/uhabits-android/src/main/res/values-fr-rFR/strings.xml +++ b/uhabits-android/src/main/res/values-fr-rFR/strings.xml @@ -75,7 +75,7 @@ Toujours demander Personnaliser... Valider l\'habitude avec un appui court - Cochez les cases d\'un simple appuie au lieu de les maintenir + Cochez les cases d\'un simple appui au lieu de les maintenir Notez cette app sur le Google Play Store Envoyez un avis au développeur Voir le code source sur GitHub @@ -147,7 +147,7 @@ Aucun Filtre Cacher les habitudes complétées - Cacher les entrées + Cacher les entrées Cacher les habitudes archivées Rendre les notifications persistantes Évite que les notifications ne soient enlevées. diff --git a/uhabits-server/src/main/resources/logback.xml b/uhabits-android/src/main/res/values-gu-rIN/strings.xml similarity index 65% rename from uhabits-server/src/main/resources/logback.xml rename to uhabits-android/src/main/res/values-gu-rIN/strings.xml index 9a9dfca31..3a895c006 100644 --- a/uhabits-server/src/main/resources/logback.xml +++ b/uhabits-android/src/main/res/values-gu-rIN/strings.xml @@ -1,3 +1,4 @@ + - - - - - %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - + diff --git a/uhabits-android/src/main/res/values-hi-rIN/strings.xml b/uhabits-android/src/main/res/values-hi-rIN/strings.xml index 916cf90d0..2bd2de184 100644 --- a/uhabits-android/src/main/res/values-hi-rIN/strings.xml +++ b/uhabits-android/src/main/res/values-hi-rIN/strings.xml @@ -28,36 +28,38 @@ आदत जोड़ें रंग बदलें आदत बनायी गई + + Habit changed + Habits changed + - आदत हटाई गई - आदतें हटाई गई + Habit deleted + Habits deleted - आदत संग्रहित की गई - आदतें संग्रहीत की गई + Habit archived + Habits archived - आदत असंग्रहीत की गई + आदतें असंग्रहीत की गई आदतें असंग्रहीत की गई अवलोकन - आदत शक्ति - पूर्वलेख - साफ करें - अनुस्मारक - सहेजें - प्रवर्ति - \"आपकी कोई सक्रिय आदत नही है -\" - आप के आज के सभी कार्य समाप्त होते हैं - चेक या अनचेक करने के लिए दबाएँ व दबाएँ रखें - बंद + आदत की मजबूती + पुराना आदत + खाली करें + याद दिलाए + सेव करें + सिलसीला + आपकी कोई सक्रिय आदत नहीं है + आप के आज के लिए काम तमाम ! + चेक या अनचेक करने के लिए दबाएँ या दबा के रखे + बंद करे नयी आदत बनाएं आदत में बद्लाव करें - अंकित करें + जाञ्च करें बाद में - \" -स्वागत हे\" + स्वागत है लूप हैबिट ट्रैकर नई और अच्छी आदतों को बनाए रखने मे मदद करता है । कुछ नई अच्छी आदतें बनाएँ हर दिन, अपनी आदत के प्रदर्शन के बाद, ऐप पर एक सही का निशान डालें @@ -75,6 +77,7 @@ हमेशा पूछें अपने तरीके से बनाएं टॉगल पुनरावृत्ति हल्का दबाने से + प्रेस-एंड-होल्ड के बजाय एक टैप से चेकमार्क लगाएं। \" गूगले प्ले पर इस ऐप्लिकेशन को रेट करें\" डेवेलपर को प्रतिक्रिया भेजें @@ -99,8 +102,7 @@ आदत हटाई गई / नहीं मिली \" सप्ताहांत\" - \" -सोमवार से शुक्रवार\" + सोमवार से शुक्रवार \" सप्ताह का कोई भी दिन\" दिन चुनें @@ -172,6 +174,7 @@ कोई आवाज नहीं\" फिल्टर पूर्ण छुपाएं + गुप्त प्रवेश संग्रहीत छुपाएं सुचनाए स्थयी रखे नोटिफिकेशन को स्वाइप करने से रोकता है! @@ -191,8 +194,12 @@ स्थिति से एक्सपोर्ट करे बदलने के लिए दबाकर रखें + मान कैलेंडर इकाई + लक्ष्य प्रकार + कम से कम + ज्यादा से ज्यादा जैसे आपने आज व्यायाम किया? प्रश्न लक्ष्य diff --git a/uhabits-android/src/main/res/values-hr-rHR/strings.xml b/uhabits-android/src/main/res/values-hr-rHR/strings.xml index 950eb1b46..a73ec99b7 100644 --- a/uhabits-android/src/main/res/values-hr-rHR/strings.xml +++ b/uhabits-android/src/main/res/values-hr-rHR/strings.xml @@ -28,6 +28,21 @@ Dodaj naviku Promijeni boju Navika je stvorena + + Navika je obrisana + Navike su izbrisane + Navike su izbrisane + + + Navika je arhivirana + Navike su arhivirane + Navike su arhivirane + + + Navika je dearhivitana + Navike su dearhivirane + Navike su dearhivirane + Pregled Snaga navike Povijest @@ -36,6 +51,7 @@ Spremi Niz Nemate aktivnih navika + Navike za danas su završene Pritisnite i držite za označavanje ili odznačavanje. Isključen Stvori naviku @@ -55,6 +71,8 @@ 4 sata 8 sati 24 sata + Uvijek pitaj + Prilagođeno … Označi ponavljanja sa kratkim pritisk. Ocijeni ovu aplikaciju na Google Playu Pošalji povratne informacije raz. programeru @@ -62,6 +80,7 @@ Poveznice Naziv Postavke + Odaberi vrijeme odgode Jeste li znali? Za razmještanje unosa, pritisnite i držite naziv navike, pa ih premjestite na točno mjesto. Možete vidjeti više dana prebacivanjem uređaja u vodoravnu orijentaciju. @@ -110,6 +129,7 @@ Četvrtina Godina Ukupno + Da ili Ne Svaka %d dana Svaka %d tjedna Rezultat @@ -117,9 +137,12 @@ Nijedan Filtar Sakrij završeno + Sakrij unesene Sakrij arhivirano Učini obavijesti trajnima Spriječava da se obavijesti zanemare. + Svjetlo obavijesti + Pali bljeskalicu za podsjetnike. Dostupno samo na uređajima s LED svjetlosnim obavijestima. Popravi bazu podataka Baza podataka je popravljena. Odznači @@ -131,6 +154,48 @@ Po nazivu Po boji Po rezultatu + Po statusu Izvezi + Pritisni i zadrži za promjenu vrijednosti + Vrijednost + Kalendar + Jedinica + Vrsta cilja + Najmanje + Najviše + npr. Jesi li vježbao/la danas? + Pitanje + Cilj + Da + Ne + Postavi zvuk, vibraciju, svjetlo i druge postavke obavijesti + Prilagodi obavijesti + Prikaži pravila o privatnosti + Pregledaj sve suradnike… + Baza podataka + Prozirnost widgeta + Povećava ili smanjuje prozirnost widgeta na početnom zaslonu. + Prvi dan u tjednu + Jesi li ispunio/la ovu naviku danas? + Bilješke + (Neobvezno) + npr. Jesi li se danas rano probudio/la? Jesi li vježbao/la? Jesi li igrao/la šah? + Mjerljivo + npr. Koliko si kilometara danas istrčao/la? Koliko si stranica pročitao/la? + %d puta tjedno + %d puta mjesečno %d puta u %d dani + npr. Vježbaj + Boja + npr. 15 + npr. Trči + npr. Koliko si kilometara danas trčao/la? + npr. kilometri + Svaki mjesec + Ne može ostati prazno + Danas + Unesi + Navike nisu pronađene + Mjerljive navike nisu pronađene + Da/Ne navike nisu pronađene diff --git a/uhabits-android/src/main/res/values-hu-rHU/strings.xml b/uhabits-android/src/main/res/values-hu-rHU/strings.xml index ec0953246..f206c05fc 100644 --- a/uhabits-android/src/main/res/values-hu-rHU/strings.xml +++ b/uhabits-android/src/main/res/values-hu-rHU/strings.xml @@ -75,6 +75,7 @@ Mindig rákérdez Egyedi... Bejelölés rövid koppintással + Nyomva tartás helyett koppintással tudja a napokat kipipálni. Értékeld az alkalmazást a Google Play-en Visszajelzés küldése a fejlesztőnek Forráskód megtekintése a GitHub-on @@ -151,6 +152,7 @@ Nem ismétlődik Szűrő Elvégzettek elrejtése + Ha bekapcsolta a kérdőjelek megjelenítését, akkor az \"Elvégzettek elrejtése\" helyett a \"Beírtak elrejtése\" fog megjelenni. Ez a beállítás elrejti az összes olyan szokást, amelyhez adat lett megadva, nem csak az elvégzetteket. Így el tudja rejteni azokat a szokásokat is, amelyekkel a nap elején kudarcot vallott. Archiváltak elrejtése Az értesítések legyenek ragadósak Megakadályozza az értesítések eltávolítását @@ -170,8 +172,12 @@ Állapot szerint Exportálás Az érték módosításához tartsd lenyomva + Érték Naptár Egység + Célkitűzés típusa + Legalább + Legfeljebb pl. Edzettél ma? Kérdés Cél diff --git a/uhabits-android/src/main/res/values-is-rIS/strings.xml b/uhabits-android/src/main/res/values-is-rIS/strings.xml new file mode 100644 index 000000000..7753f38f5 --- /dev/null +++ b/uhabits-android/src/main/res/values-is-rIS/strings.xml @@ -0,0 +1,173 @@ + + + + Venjur + Stillingar + Breyta + Eyða + Setja í geymslu + Taka úr geymslu + Ný venja + Breyta lit + Venja sköpuð + + Venju breytt + Venjur breyttar + + Yfirlit + Ferill + Hreinsa + Áminning + Vista + Þú ert búin(n) í dag! + Af + Búa til venju + Breyta venju + Merkja + Seinna + Velkomin(n) + Fylgstu með framförum þínum + 15 mínútur + 30 mínútur + 1 klukkustund + 2 Klukkustundir + 4 klukkustundir + 8 klukkustundir + Sólarhring + Alltaf spyrja + Sérsniðið… + Gefa forriti einkunn á Google Play + Senda athugasemdir til höfunda + Skoða frumkóðann á GitHub + Tenglar + Heiti + Stillingar + Stilla töf á blundi + Vissir þú? + + Eyða venju? + Eyða venjum? + + Helgar + Virka daga + Alla daga + Veldu daga + Flytja út sem CSV + Í lagi + Hreinsa + Veldu klukkustundir + Veldu mínútur + Um + Þýðendur + Hönnuðir + Útgáfa %s + Tíðni + Gátmerki + Daglega + Vikulega + Aðstoð og algengar spurningar + Mistókst að flytja gögn út. + Mistókst að flytja inn gögn. + Skrá ekki þekkt. + Venjur fluttar inn. + Flytja inn gögn + Flytja út fullt öryggisafrit + Mistókst að búa til villuskýrslu. + Búa til villuskýrslu + Leysa vandamál + Hjálpa til við að þýða + Dökkt þema + Nota kolsvarta þemu + Viðmót + Dagur + Vika + Mánuður + 3 mánuðir + Ár + Samtals + Já eða nei + Á %d daga fresti + Á %d vikna fresti + Árangur + Tilkynningarhljóð + Ekkert + Sía + Fela lokuð + Fela í geymslu + Tilkynningaljós + Lagfæra gagnagrunn + Gagnagrunnur lagfærður. + Afmerkja + Víxla + Aðgerð + Venja + Raða + Handvirkt + Eftir heiti + Eftir lit + Eftir árangri + Eftir stöðu + Flytja út + Haltu inni til að breyta gildi + Gildi + Dagatal + Mælieining + Tegund markmiðs + Að minnsta kosti + Í mesta lagi + t.d., Æfðir þú þig í dag? + Spurning + Markmið + + Nei + Breyta hljóði, titringi, ljósi og öðrum tilkynningastillingum + Sérsníða tilkynningar + Skoða persónuverndarstefnu + Skoða alla þátttakendur… + Gagnagrunnur + Ógegnsæi græju + Fyrsti dagur vikunar + Hefurðu gert þetta í dag? + Minnispunktur + (Valfrjálst) + t.d., Vaknaðir þú snemma í dag? Æfðir þú þig? Tefldir þú skák? + Mælanlegt + t.d., Hversu marga kílómetra hljópstu í dag? Hvað lasstu margar blaðsíður? + %d sinnum í viku + %d sinnum á mánuði + %d sinnum á %d dögum + t.d., Æfa sig + Litur + t.d., 15 + t.d., Hlaupa + t.d., Hversu marga kílómetra hljópstu í dag? + t.d., kílómetra + Hvern mánuð + Má ekki vera autt + Í dag + Setja inn + Engar venjur fundust + Engar mælanlegar venjur fundust + Engar já/nei venjur fundust + Hækka + Lækka + Lengja daginn nokkrar klukkustundir yfir miðnætti + Bíða til klukkan 03:00 til að sýna nýjan dag. Gagnlegt ef þú ferð að sofa eftir miðnætti. Krefst endurræsingar forritsins. + diff --git a/uhabits-android/src/main/res/values-it-rIT/strings.xml b/uhabits-android/src/main/res/values-it-rIT/strings.xml index a9a3e5b13..2ddf6e76f 100644 --- a/uhabits-android/src/main/res/values-it-rIT/strings.xml +++ b/uhabits-android/src/main/res/values-it-rIT/strings.xml @@ -136,7 +136,7 @@ Giorno Settimana Mese - Quadrimestre + Trimestre Anno Totale Sì o No diff --git a/uhabits-android/src/main/res/values-iw-rIL/strings.xml b/uhabits-android/src/main/res/values-iw-rIL/strings.xml index 35bec1fff..6c2b6f396 100644 --- a/uhabits-android/src/main/res/values-iw-rIL/strings.xml +++ b/uhabits-android/src/main/res/values-iw-rIL/strings.xml @@ -29,10 +29,10 @@ שינוי צבע ההרגל נוצר - ההרגל השתנה - ההרגלים השתנו - ההרגלים השתנו - ההרגלים השתנו + ההרגל שוּנה + ההרגלים שונו + ההרגלים שונו + ההרגלים שונו ההרגל נמחק @@ -52,27 +52,27 @@ ההרגלים הוצאו מארכיון ההרגלים הוצאו מארכיון - סקירה כללית + מבט על חוזק ההרגל היסטוריה ניקוי תזכורת שמירה - רצפים + שיאים אין לך הרגלים פעילים - סיימת הכול להיום! - לחיצה והחזקה יסמנו או יבטלו את הסימון + זהו להיום! + לחיצה ארוכה תסמן או תבטל את הסימון כבוי יצירת הרגל עריכת הרגל סימון מאוחר יותר ברוך בואך - יישום ”Loop לניהול הרגלים“ מסייע לך להתחיל ולשמר הרגלים טובים. + ‏”Loop לניהול הרגלים“ מסייע לך להתחיל ולשמר הרגלים טובים. יצירת הרגלים חדשים - בכל יום, לאחר ביצוע ההרגל, יש לסמן זאת ביישום. + בכל יום, לאחר ביצוע ההרגל, מסמנים את זה ביישום. מעקב אחר ההתקדמות - גרפים מפורטים מציגים כיצד שיפרת את ההרגלים לאורך זמן. + גרפים מפורטים מציגים את השתפרות ההרגלים לאורך זמן. רבע שעה חצי שעה שעה @@ -83,17 +83,17 @@ תמיד לשאול התאמה אישית... סימון הרגלים בלחיצה קצרה - סימון הרגלים בעזרת הקשה יחידה במקום בעזרת הקשה והחזקה. + סימון הרגלים בלחיצה פשוטה במקום לחיצה והחזקה. דירוג היישום ב־Google Play שליחת משוב למפתח צפייה בקוד המקור ב־GitHub קישורים שם הגדרות - נא לבחור זמן לדחיית התזכורת + נא לבחור בכמה זמן לדחות את התזכורת הידעת? - לשינוי סדר ההרגלים, יש ללחוץ לחיצה ארוכה על ההרגל ולגרור אותו למקום הרצוי. - אפשר לראות ימים נוספים בעזרת סיבוב המסך לתצוגה אופקית. + אפשר לשנות את סדר ההרגלים בעזרת לחיצה ארוכה על הרגל וגרירתו למקום הרצוי. + אפשר לסובב את המסך לרוחב ולראות ימים נוספים. למחוק את ההרגל? למחוק את ההרגלים? @@ -116,32 +116,32 @@ ניקוי בחירת שעות בחירת דקות - על אודות + מידע כללי תרגום פיתוח גרסה %s תדירות סימון הרגל - רצף שיא + שיאי התמדה כל יום כל שבוע עזרה ושאלות נפוצות ייצוא הנתונים נכשל. ייבוא הנתונים נכשל. - הקובץ אינו מזוהה. - ההרגלים יובאו בהצלחה. + קובץ לא מזוהה. + ייבוא ההרגלים הצליח. ייבוא נתונים ייצוא גיבוי מלא - תומך בכל הגיבויים שיוצאו מהיישום הזה, כמו־גם בקבצים שנוצרו על ידי Tickmate, ‏HabitBull או Rewire. למידע נוסף נא לעיין בשאלות הנפוצות. - ליצירת קבצים שנפתחים בתוכנת גיליון אלקטרוני כגון Microsoft Exel או OpenOffice Calc. לא ניתן לייבא את הקובץ בחזרה. + יש תמיכה בכל הגיבויים שיוצאו מיישום זה, וגם בקבצים שנוצרו על ידי Tickmate, ‏HabitBull או Rewire. למידע נוסף נא לעיין בשאלות הנפוצות. + ליצירת קבצים שנפתחים בתוכנת גיליונות אלקטרוניים כמו Microsoft Exel או OpenOffice Calc. לא ניתן לייבא את הקובץ בחזרה. ליצירת קובץ שמכיל את כל הנתונים שלך. לא ניתן לייבא את הקובץ בחזרה. יצירת דו״ח התקלה נכשלה. יצירת דו״ח תקלה פתרון תקלות - עזרה בתרגום היישום + סיוע בתרגום היישום ערכת נושא כהה רקע שחור מוחלט בערכת הנושא הכהה - להחלפת הרקע האפור בערכת הנושא הכהה לשחור מוחלט. זה מפחית את צריכת הסוללה במכשירים עם תצוגת AMOLED. + החלפת הרקע האפור בערכת הנושא הכהה לשחור מוחלט. מפחית את צריכת הסוללה במכשירים עם תצוגת AMOLED. ממשק סדר ימים הפוך הצגת הימים בסדר הפוך במסך הראשי. @@ -150,7 +150,7 @@ חודש רבעון שנה - בסך הכול + סה״כ כן או לא כל %d ימים כל %d שבועות @@ -159,15 +159,15 @@ ללא סינון הסתרת יעדים שהושגו - הסתרת ההרגלים שהושלמו + הסתרת ההרגלים שסומנו הסתרת הארכיון - יצירת תזכורות נעוצות + הצמדת כל ההתראות למניעת התעלמות מתזכורות. תאורת התראה - להצגת אור מהבהב לתזכורות. זמין רק בטלפונים עם נורות LED להתראות. + להצגת אור מהבהב לתזכורות. התכונה זמינה רק בטלפונים עם נורות LED להתראות. תיקון מסד הנתונים מסד הנתונים תוקן. - ביטול סימון + ביטול הסימון סימון או ביטול הסימון פעולה הרגל @@ -178,7 +178,7 @@ לפי ציון לפי מצב ייצוא - לחיצה והחזקה ישנו את הערך + לחיצה ארוכה תשנה את הערך ערך לוח שנה יחידה @@ -191,12 +191,12 @@ כן לא שינוי הצליל, הרטט, התאורה והגדרות התראה אחרות - התאמת ההתראות - הצגת מדיניות הפרטיות + אפשרויות התראה + צפייה במדיניות הפרטיות הצגת כל המתנדבים… מסד נתונים אטימות היישומונים - להפיכת היישומונים שקופים או אטומים יותר במסך הבית שלך. + הפיכת היישומונים במסך הבית לשקופים או אטומים יותר. היום הראשון בשבוע השלמת את ההרגל הזה היום? הערות @@ -207,7 +207,7 @@ %d פעמים בשבוע %d פעמים בחודש %d פעמים ב־%d ימים - למשל: התעמלות + למשל: פעילות גופנית צבע למשל: 15 למשל: ריצה diff --git a/uhabits-android/src/main/res/values-ja-rJP/strings.xml b/uhabits-android/src/main/res/values-ja-rJP/strings.xml index dc7d077f2..2f2a419d3 100644 --- a/uhabits-android/src/main/res/values-ja-rJP/strings.xml +++ b/uhabits-android/src/main/res/values-ja-rJP/strings.xml @@ -48,7 +48,7 @@ 保存 連続記録 習慣はありません - 今日は終わり! + 今日の習慣はすべて完了しました! 長押しするとチェックを付けたり外したりできます オフ 習慣を作成 @@ -104,7 +104,7 @@ バージョン %s 頻度 チェック - 最高の連続記録 + 最長の連続記録 毎日 毎週 ヘルプ & FAQ @@ -151,20 +151,22 @@ データベースが修復されました。 チェックを外す 切り替え - 動作 + アクション 習慣 並び替え 手動で並び替え 名前で並び替え 色で並び替え - 得点で並び替え - ステータス順 + スコアで並び替え + ステータスで並び替え エクスポート 長押しすると値を変更できます カレンダー 単位 + 目標タイプ 少なくとも + 最大でも 例:今日は運動しましたか? 質問 目標 @@ -183,7 +185,7 @@ (省略可) 例:今日は早く起きましたか?運動しましたか?チェスをしましたか? 数えられるもの - 例:今日は何キロ走ったの?何ページ読んだの? + 例:今日は何キロ走りましたか?何ページ読みましたか? 1 週間に %d 回 1 か月に %d 回 %d 回 %d 日 @@ -198,7 +200,16 @@ 今日 入力 習慣が見つかりませんでした + 量を記録するタイプの習慣は見つかりませんでした + はい/いいえタイプの習慣は見つかりませんでした + 増加 + 減少 スキップ日を有効にする + 2回切り替えることで、チェックマークの代わりにスキップを追加できます。スキップはスコアに影響を与えず、連続記録を継続させたままにできます。 + 入力のない日に?マークを表示する + データが未入力である日と実行しなかった日とを区別します。実行しなかったことを記録するには、2回切り替えます。 これで開発者になりました! この操作を行うアプリが見つかりませんでした。 + 一日の終わりを午前0時から数時間延長する + 一日の始まりを午前3時にします。よく午前0時以降に就寝する場合に役立ちます。アプリの再起動が必要です。 diff --git a/uhabits-android/src/main/res/values-ka-rGE/strings.xml b/uhabits-android/src/main/res/values-ka-rGE/strings.xml new file mode 100644 index 000000000..7c01aceb4 --- /dev/null +++ b/uhabits-android/src/main/res/values-ka-rGE/strings.xml @@ -0,0 +1,221 @@ + + + + Loop — ჩვევების ტრეკერი + ჩვევები + პარამეტრები + რედაქტირება + წაშლა + დაარქივება + არქივიდან გამოტანა + ჩვევის დამატება + ფერის შეცვლა + ჩვევა შეიქმნა + + ჩვევა დარედაქტირდა + ჩვევები დარედაქტირდა + + + ჩვევა წაიშალა + ჩვევები წაიშალა + + + ჩვევა დაარქივდა + ჩვევები დაარქივდა + + + ჩვევა აღდგა არქივიდან + ჩვევები აღდგა არქივიდან + + მიმოხილვა + ჩვევის გაჯდომის დონე + ისტორია + წაშლა + შეხსენება + შენახვა + სერიები + არ გაქვს მოქმედი ჩვევები + დღეისთვის სულ ეს იყო, ყველაფერი შეასრულე! + დააჭირე ხანგრძლივად თოლიის (✓) ჩასანიშნად / მოსახსნელად + გამორთული + ჩვევის შექმნა + ჩვევის დარედაქტირება + ჩანიშვნა + მოგვიანებით + მოგესალმები + Loop — ჩვევების ტრეკერი: ხელშემწყობი კარგი ჩვევების გამომუშავებასა და შენარჩუნებისათვის. + გამოიმუშავე ახალი ჩვევები + ყოველდღიურად, როგორც კი ჩვევას შეასრულებ, ეს აპლიკაციაში ჩაინიშნე. + თვალი ადევნე შენს პროგრესს + დეტალური გრაფიკებით შეგიძლია დროთა განმავლობაში იხილო თუ როგორ ყალიბდება შენი ჩვევა. + 15 წუთი + 30 წუთი + 1 საათი + 2 საათი + 4 საათი + 8 საათი + 24 საათი + ყოველთვის მკითხე + პერსონალიზებული… + გადართვა ხანმოკლე შეხებით + ხანგრძლივი დაჭერის მაგივრად თოლიების (✓) ხანმოკლე შეხებით ჩანიშვნა. + აპლიკაციის შეფასება Google Play-ზე + გამოეხმაურე დეველოპერს + საწყისი კოდის ნახვა GitHub-ზე + ბმულები + სათაური + პარამეტრები + გადადების დროის არჩევა + იცოდი? + ჩვევის ადგილის გადასანაცვლებლად სახელს ხანგრძლივად დააჭირე და სასურველ ადგილას დასვი. + ტელეფონს ჰორიზონტალურად თუ დაიჭერ მეტი დღის ნახვას შეძლებ. + + ჩვევა წაიშალოს? + ჩვევები წაიშალოს? + + + ჩვევა სამუდამოდ წაიშლება. ამ მოქმედების შედეგის გაუქმება შეუძლებელია. + ჩვევები სამუდამოდ წაიშლება. ამ მოქმედების შედეგის გაუქმება შეუძლებელია. + + ჩვევა წაშლილია / ვერ მოიძებნა + შაბათ-კვირაობით + ორშაბათიდან პარასკევის ჩათვლით + კვირის ყოველ დღეს + დღეების მონიშვნა + ექსპორტი CSV-ფაილად + მზადაა + წაშლა + საათების მონიშვნა + წუთების მონიშვნა + Loop-ის შესახებ + მთარგმნელები + დეველოპერები + ვერსია: %s + სიხშირე + თოლია + საუკეთესო სერიები + ყოველდღე + ყოველკვირა + დახმარება და ხდკ + მონაცემების ექსპორტი ვერ მოხერხდა. + მონაცემების იმპორტირება ვერ მოხერხდა. + ფაილის ამოცნობა ვერ მოხერხდა. + ჩვევების იმპორტირება წარმატებით განხორციელდა. + მონაცემების იმპორტი + სრული სარეზერვო ასლის ექსპორტი + მხარდაჭერილია ამ აპლიკაციით შექმნილი სარეზერვო ასლები, ასევე ფაილები, რომლებიც შექმნილია Tickmate-ით, HabitBull-ითა და Rewire-ით. მეტი ინფორმაციისათვის იხილე ხშირად დასმული კითხვები. + ქმნის ფაილებს, რომელთა გახსნა შესაძლებელია ელექტრონული ცხრილის პროგრამებით, როგორებიცაა Microsoft Excel და OpenOffice Calc. ამ ფაილის უკან დაიმპორტირება შეუძლებელია. + ქმნის ფაილს, რომელიც შენს ყველა მონაცემებს შეიცავს. ამ ფაილის უკან დაიმპორტირება შეუძლებელია. + ხარვეზების ანგარიში ვერ შეიქმნა. + ხარვეზების ანგარიშის შექმნა + უწესივრობათა დიაგნოსტიკა და აღმოფხვრა + მოგვეხმარე აპლიკაციის გადათარგმნაში + მუქი რეჟიმი + მუქ რეჟიმში სუფთა შავის გამოყენება + მუქ რეჟიმში რუხი ფონები სუფთა შავით ჩანაცვლდება. AMOLED-ეკრანიან ტელეფონებში ეს ელემენტის ენერგიას ზოგავს. + ინტერფეისი + დღეების თანმიმდევრობის შებრუნება + დღეების თანმიმდევრობის შემობრუნება მთავარ ეკრანზე. + დღე + კვირა + თვე + კვარტალი + წელი + ჯამში + კი თუ არა + ყოველ %d დღეს + ყოველ %d კვირას + შეფასება + შემახსენებელი შეტყობინების ხმა + არცერთი + ფილტრი + შესრულებული ჩვევების დამალვა + მონაცემებშეტანილი ჩვევების დამალვა + დაარქივებული ჩვევების დამალვა + შეტყობინებების დამაგრება + ხელს უშლის შეტყობინებების თითის გასმით წაშლას. + შეტყობინების ციმციმა + ციმციმას რთავს შემახსენებელი შეტყობინებებისთვის. ხელმისაწვდომია მხოლოდ ისეთი მოწყობილობებისთვის, რომლებსაც შეტყობინების LED აქვთ. + მონაცემთა ბაზის შეკეთება + მონაცემთა ბაზა შეკეთდა. + თოლიის (✓) მოხსნა + გადართვა + მოქმედება + ჩვევა + დალაგება + ხელით + სათაურის მიხედვით + ფერის მიხედვით + შეფასების მიხედვით + სტატუსის მიხედვით + ექსპორტი + მნიშვნელობის შესაცვლელად დააჭირე ხანგრძლივად + მნიშვნელობა + კალენდარი + ერთეული + მიზნის ტიპი + მინიმუმ + მაქსიმუმ + მაგ. დღეს ივარჯიშე? + კითხვა + მიზანი + კი + არა + ხმის, ვიბრაციის, სინათლისა და შეტყობინებების სხვა პარამეტრების შეცვლა. + შეტყობინებების მორგება + კონფიდენციალურობის პოლიტიკა + ყველა წვლილის შემტანის ნახვა… + მონაცემთა ბაზა + ვიჯეტის გამჭვირვალობა + ცვლის საწყისი ეკრანის ვიჯეტების გამჭვირვალობას. + კვირის პირველი დღე + დღეს ეს ჩვევა შეასრულე? + ჩანაწერები + (სურვილისამებრ) + მაგ. დღეს ადრე გაიღვიძე? ივარჯიშე? ჭადრაკი ითამაშე? + გაზომვადი + მაგ. დღეს რამდენი კილომეტრი გაირბინე? რამდენი გვერდი წაიკითხე? + კვირაში %d-ჯერ + თვეში %d-ჯერ + %d-ჯერ %d დღის განმავლობაში + მაგ. ვარჯიში + ფერი + მაგ. 15 + მაგ. რბენა + მაგ. დღეს რამდენი კილომეტრი დაფარე? + მაგ. კილომეტრი + ყოველთვე + ცარიელი ვერ იქნება + დღეს + შეყვანა + ჩვევები ვერ მოიძებნა + გამზომვადი ჩვევები ვერ მოიძებნა + „კი თუ არა“ ტიპის ჩვევები ვერ მოიძებნა + გაზრდა + შემცირება + დღეების გამოტოვების ჩართვა + ორჯერ გადართე, რათა გამოტოვება ჩაამატო თოლიის (✓) მაგივრად. გამოტოვებების მეშვეობით შეფასება უცვლელი დარჩება, ხოლო სერია შენარჩუნდება. + კითხვის ნიშნის ჩვენება მონაცემთა არარსებობის შემთხვევაში + უმონაცემო დღეებისა და გაცდენების განსხვავებულად განხილვა. გაცდენის შესატანად ორჯერ გადართე. + ახლა დეველოპერი ხარ + ვერ მოიძებნა აპლიკაცია ამ ოპერაციის განსახორციელებლად + ახალი დღის დასაწყისის გადატანა ნაშუაღამევის რამდენიმე საათისთვის + ახალი დღის 03:00 საათზე დაწყება. ხელსაყრელია თუ ზოგადად შუაღამის შემდეგ იძინებ. საჭიროებს აპლიკაციის გადატვირთვას. + diff --git a/uhabits-android/src/main/res/values-ko-rKR/strings.xml b/uhabits-android/src/main/res/values-ko-rKR/strings.xml index 5394968e1..fcea1557a 100644 --- a/uhabits-android/src/main/res/values-ko-rKR/strings.xml +++ b/uhabits-android/src/main/res/values-ko-rKR/strings.xml @@ -69,11 +69,12 @@ 8시간 24시간 항상 묻기 - 사용자 지정. + 사용자 지정... 짧게 눌러서 전환하기 + 길게 누르는 대신 탭 한 번으로 확인 표시를 합니다. Google Play에서 평가 개발자에게 피드백 보내기 - Github에서 소스보기 + Github에서 소스 보기 링크 제목 설정 @@ -98,7 +99,7 @@ 시간 선택 분 선택 정보 - 번역자 + 번역한 사람들 개발자 버전 %s 빈도 @@ -106,7 +107,7 @@ 최고 연속 기록 매일 매주 - 도움& FAQ + 도움 & FAQ 데이터 내보내기에 실패했습니다. 데이터 가져오기에 실패했습니다. 파일을 인식할 수 없습니다. @@ -140,6 +141,7 @@ 무음 필터 완료된 항목 숨기기 + 입력한 항목을 숨기기 보관된 항목 숨기기 알림 고정하기 알림을 스와이프해서 제거하는 것을 방지합니다. @@ -159,8 +161,12 @@ 상태별로 내보내기 길게 누르면 값이 변경됩니다. + 캘린더 단위 + 목표 유형 + 적어도 + 최대 예 : 오늘 운동을 했습니까? 질문 목표 @@ -186,6 +192,24 @@ 예) 운동 예) 15 + 예) 달리기 + 예) 오늘 몇 km를 달렸나요? + 예) km 매월 + 비워 둘 수 없습니다 오늘 + 입력 + 설정한 습관이 없습니다 + 수치형 습관 목표가 없습니다 + 단답형 습관 목표가 없습니다 + 증가 + 감소 + 날짜 스킵 허용 + 두번 토글하면, 확인 표시 대신에 해당 일자의 기록을 제외합니다. 제외된 날은 점수에 반영되지 않고, 연속 기록도 유지됩니다. + 기록이 없는 날에 물음표 표시 + 데이터가 없는 날과 넘겼다고 실제로 기록한 날에 차이를 둡니다. 넘겼다고 기록하려면 두 번 누르세요. + 당신은 이제 개발자입니다. + 이 작업을 지원하는 앱을 찾을 수 없습니다. + 하루를 자정 이후까지 연장합니다. + 오전 3시를 기점으로 하루가 변경됩니다. 자정 이후 잠드는 경우 유용합니다. 변경시 앱 재시작 후 적용됩니다. diff --git a/uhabits-android/src/main/res/values-ml-rIN/strings.xml b/uhabits-android/src/main/res/values-ml-rIN/strings.xml new file mode 100644 index 000000000..f078bbacc --- /dev/null +++ b/uhabits-android/src/main/res/values-ml-rIN/strings.xml @@ -0,0 +1,221 @@ + + + + ലൂപ്പ് ഹാബിറ്റ് ട്രാക്കർ + ശീലങ്ങൾ + ക്രമീകരണങ്ങൾ + തിരുത്തുക + ഇല്ലാതാക്കുക + ആർക്കൈവ് + അൺ ആർക്കൈവ് ചെയ്യുക + ശീലം ചേർക്കുക + നിറം മാറ്റുക + ശീലം സൃഷ്ടിച്ചു + + ശീലം മാറി + ശീലങ്ങൾ മാറി + + + ശീലം ഇല്ലാതാക്കി + ശീലങ്ങൾ ഇല്ലാതാക്കി + + + ശീലം ആർക്കൈവ് ചെയ്തു + ശീലങ്ങൾ ആർക്കൈവ് ചെയ്തു + + + ശീലം ആർക്കൈവ് ചെയ്‌തിട്ടില്ല + ശീലങ്ങൾ ആർക്കൈവ് ചെയ്‌തിട്ടില്ല + + അവലോകനം + ശീലത്തിന്റെ ശക്തി + ചരിത്രം + ക്ലിയർ + ഓർമ്മപ്പെടുത്തൽ + സംരക്ഷിക്കുക + സ്ട്രീക്ക് + നിങ്ങൾക്ക് സജീവമായ ശീലങ്ങളൊന്നും ആഡ് ചെയ്തിട്ടില്ല + ഇന്നത്തെ ശീലങ്ങൾ എല്ലാം നിങ്ങൾ പൂർത്തിയാക്കി! + ആഡ് ചെയ്യുന്നതിനോ റിമൂവ് ചെയ്യുന്നതിനോ അമർത്തിപ്പിടിക്കുക + ഓഫ് + ശീലം ആഡ് ചെയ്യുക + എഡിറ്റ് ശീലം + ചെക്ക് + പിന്നീട് + സ്വാഗതം + നല്ല ശീലങ്ങൾ സൃഷ്ടിക്കാനും നിലനിർത്താനും ലൂപ്പ് ഹാബിറ്റ് ട്രാക്കർ നിങ്ങളെ സഹായിക്കുന്നു. + പുതിയ ചില ശീലങ്ങൾ ഉണ്ടാക്കുക + എല്ലാ ദിവസവും, നിങ്ങളുടെ ശീലം നടപ്പിലാക്കിയ ശേഷം, ആപ്പിൽ ഒരു ചെക്ക്മാർക്ക് ഇടുക. + നിങ്ങളുടെ പുരോഗതി ട്രാക്ക് ചെയ്യുക + കാലക്രമേണ നിങ്ങളുടെ ശീലങ്ങൾ എങ്ങനെ മെച്ചപ്പെട്ടുവെന്ന് വിശദമായ ഗ്രാഫുകൾ കാണിക്കുന്നു. + 15 മിനിറ്റ് + 30 മിനിറ്റ് + 1 മണിക്കൂർ + 2 മണിക്കൂർ + 4 മണിക്കൂർ + 8 മണിക്കൂർ + 24 മണിക്കൂർ + എപ്പോഴും ചോദിക്കുക + കസ്റ്റം... + ഷോർട്ട് പ്രസ്സ് ഉപയോഗിച്ച് ടോഗിൾ ചെയ്യുക + അമർത്തിപ്പിടിക്കുക എന്നതിനുപകരം ഒരൊറ്റ ടാപ്പിലൂടെ ചെക്ക്മാർക്കുകൾ ഇടുക. + ഗൂഗിൾ പ്ലേയിൽ ഈ ആപ്പ് റേറ്റു ചെയ്യുക + ഡെവലപ്പർക്ക് ഫീഡ്ബാക്ക് അയയ്ക്കുക + GitHub-ൽ സോഴ്സ് കോഡ് കാണുക + ലിങ്കുകൾ + പേര് + ക്രമീകരണങ്ങൾ + സ്‌നൂസ് കാലതാമസം തിരഞ്ഞെടുക്കുക + നിനക്കറിയാമോ? + എൻട്രികൾ പുനഃക്രമീകരിക്കാൻ, ശീലത്തിന്റെ പേരിൽ അമർത്തിപ്പിടിക്കുക, തുടർന്ന് അത് ശരിയായ സ്ഥലത്തേക്ക് വലിച്ചിടുക. + നിങ്ങളുടെ ഫോൺ ലാൻഡ്‌സ്‌കേപ്പ് മോഡിൽ വെച്ചാൽ നിങ്ങൾക്ക് കൂടുതൽ ദിവസം കാണാൻ കഴിയും. + + ശീലം ഇല്ലാതാക്കണോ? + ശീലങ്ങൾ ഇല്ലാതാക്കണോ? + + + ശീലം ശാശ്വതമായി ഇല്ലാതാക്കപ്പെടും. ഈ പ്രവർത്തനം പഴയപടിയാക്കാനാകില്ല. + ശീലങ്ങൾ ശാശ്വതമായി ഇല്ലാതാക്കപ്പെടും. ഈ പ്രവർത്തനം പഴയപടിയാക്കാനാകില്ല. + + ശീലം ഇല്ലാതാക്കി / കണ്ടെത്തിയില്ല + വാരാന്ത്യങ്ങൾ + തിങ്കൾ മുതൽ വെള്ളി വരെ + ആഴ്ചയിലെ ഏത് ദിവസവും + ദിവസങ്ങൾ തിരഞ്ഞെടുക്കുക + CSV ആയി കയറ്റുമതി ചെയ്യുക + ചെയ്തു + ക്ലിയർ + മണിക്കൂർ തിരഞ്ഞെടുക്കുക + മിനിറ്റ് തിരഞ്ഞെടുക്കുക + കുറിച്ച് + പരിഭാഷകർ + ഡെവലപ്പർമാർ + പതിപ്പുകൾ + ആവൃത്തി + ചെക്ക്മാർക്ക് + മികച്ച വരകൾ + എല്ലാ ദിവസവും + എല്ലാ ആഴ്ചയും + സഹായം & പതിവുചോദ്യങ്ങൾ + ഡാറ്റ കയറ്റുമതി ചെയ്യുന്നതിൽ പരാജയപ്പെട്ടു. + ഡാറ്റ ഇറക്കുമതി ചെയ്യുന്നതിൽ പരാജയപ്പെട്ടു. + ഫയൽ തിരിച്ചറിഞ്ഞില്ല. + ശീലങ്ങൾ വിജയകരമായി ഇറക്കുമതി ചെയ്തു. + ഡാറ്റ ഇറക്കുമതി ചെയ്യുക + പൂർണ്ണ ബാക്കപ്പ് കയറ്റുമതി ചെയ്യുക + ഈ ആപ്പ് എക്‌സ്‌പോർട്ടുചെയ്‌ത മുഴുവൻ ബാക്കപ്പുകളും ടിക്ക്‌മേറ്റ്, ഹാബിറ്റ്‌ബുൾ അല്ലെങ്കിൽ റിവയർ സൃഷ്‌ടിച്ച ഫയലുകളും പിന്തുണയ്ക്കുന്നു. കൂടുതൽ വിവരങ്ങൾക്ക് പതിവ് ചോദ്യങ്ങൾ കാണുക. + മൈക്രോസോഫ്റ്റ് എക്സൽ അല്ലെങ്കിൽ ഓപ്പൺ ഓഫീസ് കാൽക്ക് പോലുള്ള സ്‌പ്രെഡ്‌ഷീറ്റ് സോഫ്‌റ്റ്‌വെയർ ഉപയോഗിച്ച് തുറക്കാൻ കഴിയുന്ന ഫയലുകൾ ജനറേറ്റുചെയ്യുന്നു. ഈ ഫയൽ തിരികെ ഇറക്കുമതി ചെയ്യാൻ കഴിയില്ല. + നിങ്ങളുടെ എല്ലാ ഡാറ്റയും അടങ്ങുന്ന ഒരു ഫയൽ സൃഷ്ടിക്കുന്നു. ഈ ഫയൽ തിരികെ ഇറക്കുമതി ചെയ്യാൻ കഴിയും. + ബഗ് റിപ്പോർട്ട് സൃഷ്ടിക്കുന്നതിൽ പരാജയപ്പെട്ടു. + ബഗ് റിപ്പോർട്ട് സൃഷ്ടിക്കുക + ട്രബിൾഷൂട്ടിംഗ് + ഈ ആപ്പ് വിവർത്തനം ചെയ്യാൻ സഹായിക്കുക + ഇരുണ്ട തീം + ഇരുണ്ട തീമിൽ ശുദ്ധമായ കറുപ്പ് ഉപയോഗിക്കുക + ഇരുണ്ട തീമിൽ ചാരനിറത്തിലുള്ള പശ്ചാത്തലം ശുദ്ധമായ കറുപ്പ് ഉപയോഗിച്ച് മാറ്റിസ്ഥാപിക്കുക. അമോൾഡ് ഡിസ്പ്ലേ ഉള്ള ഫോണുകളിൽ ബാറ്ററി ഉപയോഗം കുറയ്ക്കുക. + ഇന്റർഫേസ് + ദിവസങ്ങളുടെ വിപരീത ക്രമം + പ്രധാന സ്ക്രീനിൽ വിപരീത ക്രമത്തിൽ ദിവസങ്ങൾ കാണിക്കുക. + ദിവസം + ആഴ്ച + മാസം + ക്വാർട്ടർ + വർഷം + ആകെ + ഉവ്വോ ഇല്ലയോ + ഓരോ %d ദിവസത്തിലും + ഓരോ %d ആഴ്ചയിലും + സ്കോർ + ഓർമ്മപ്പെടുത്തൽ ശബ്ദം + ഒന്നുമില്ല + ഫിൽട്ടർ ചെയ്യുക + മറയ്ക്കൽ പൂർത്തിയായി + പ്രവേശിച്ചത് മറയ്ക്കുക + ആർക്കൈവുചെയ്‌തത് മറയ്‌ക്കുക + അറിയിപ്പുകൾ സ്റ്റിക്കി ആക്കുക + അറിയിപ്പുകൾ സ്വൈപ്പ് ചെയ്യുന്നതിൽ നിന്ന് തടയുന്നു. + അറിയിപ്പ് ലൈറ്റ് + ഓർമ്മപ്പെടുത്തലുകൾക്കായി മിന്നുന്ന പ്രകാശം കാണിക്കുന്നു. LED നോട്ടിഫിക്കേഷൻ ലൈറ്റുകൾ ഉള്ള ഫോണുകളിൽ മാത്രമേ ലഭ്യമാകൂ. + റിപ്പയർ ഡാറ്റാബേസ് + ഡാറ്റാബേസ് നന്നാക്കി. + അൺചെക്ക് ചെയ്യുക + ടോഗിൾ ചെയ്യുക + ആക്ഷൻ + ശീലം + അടുക്കുക + സ്വമേധയാ + പേരു കൊണ്ട് + നിറം പ്രകാരം + സ്കോർ പ്രകാരം + സ്റ്റാറ്റസ് പ്രകാരം + കയറ്റുമതി + മൂല്യം മാറ്റാൻ അമർത്തിപ്പിടിക്കുക + മൂല്യം + കലണ്ടർ + യൂണിറ്റ് + ടാർഗെറ്റ് തരം + ഇത്രയെങ്കിലും + പരമാവധി + ഉദാ. നിങ്ങൾ ഇന്ന് വ്യായാമം ചെയ്തോ? + ചോദ്യം + ലക്ഷ്യം + അതെ + ഇല്ല + ശബ്ദം, വൈബ്രേഷൻ, വെളിച്ചം, മറ്റ് അറിയിപ്പ് ക്രമീകരണങ്ങൾ എന്നിവ മാറ്റുക + അറിയിപ്പുകൾ ഇഷ്ടാനുസൃതമാക്കുക + സ്വകാര്യതാ നയം കാണുക + എല്ലാ സംഭാവകരെയും കാണുക... + ഡാറ്റാബേസ് + വിജറ്റ് അതാര്യത + നിങ്ങളുടെ ഹോം സ്ക്രീനിൽ വിജറ്റുകളെ കൂടുതൽ സുതാര്യമോ അതാര്യമോ ആക്കുന്നു. + ആഴ്ചയിലെ ആദ്യ ദിവസം + നിങ്ങൾ ഇന്ന് ഈ ശീലം പൂർത്തിയാക്കിയിട്ടുണ്ടോ? + കുറിപ്പുകൾ + (ഓപ്ഷണൽ) + ഉദാ. ഇന്ന് നേരത്തെ ഉണർന്നോ? നിങ്ങൾ വ്യായാമം ചെയ്തോ? നിങ്ങൾ ചെസ്സ് കളിച്ചോ? + അളക്കാവുന്നത് + ഉദാ. ഇന്ന് നിങ്ങൾ എത്ര മൈൽ ഓടി? നിങ്ങൾ എത്ര പേജുകൾ വായിച്ചു? + ആഴ്ചയിൽ %d തവണ + പ്രതിമാസം %d തവണ + %d ദിവസത്തിനുള്ളിൽ %d തവണ + ഉദാ. വ്യായാമം ചെയ്യുക + നിറം + ഉദാ. 15 + ഉദാ. ഓടുക + ഉദാ. ഇന്ന് നിങ്ങൾ എത്ര മൈൽ ഓടി? + ഉദാ. മൈലുകൾ + എല്ലാ മാസവും + ശൂന്യമാക്കാൻ കഴിയില്ല + ഇന്ന് + നൽകുക + ശീലങ്ങളൊന്നും കണ്ടെത്തിയില്ല + അളക്കാവുന്ന ശീലങ്ങളൊന്നും കണ്ടെത്തിയില്ല + അതെ അല്ലെങ്കിൽ ഇല്ല എന്ന ശീലങ്ങളൊന്നും കണ്ടെത്തിയില്ല + വർദ്ധനവ് + കുറയ്ക്കൽ + ദിവസങ്ങൾ ഒഴിവാക്കുന്നത് പ്രവർത്തനക്ഷമമാക്കുക + ഒരു ചെക്ക്മാർക്കിന് പകരം ഒരു ഒഴിവാക്കൽ ചേർക്കാൻ രണ്ടുതവണ ടോഗിൾ ചെയ്യുക. സ്കിപ്പുകൾ നിങ്ങളുടെ സ്കോർ മാറ്റമില്ലാതെ നിലനിർത്തുകയും നിങ്ങളുടെ സ്ട്രീക്ക് തകർക്കുകയുമില്ല + നഷ്ടപ്പെട്ട ഡാറ്റയ്ക്കുള്ള ചോദ്യചിഹ്നങ്ങൾ കാണിക്കുക + യഥാർത്ഥ വീഴ്ചകളിൽ നിന്ന് ഡാറ്റ ഇല്ലാതെ ദിവസങ്ങൾ വേർതിരിക്കുക. ഒരു ലാപ്‌സ് നൽകുന്നതിന്, രണ്ടുതവണ ടോഗിൾ ചെയ്യുക. + നിങ്ങൾ ഇപ്പോൾ ഒരു ഡെവലപ്പറാണ് + ഈ പ്രവർത്തനത്തെ പിന്തുണയ്ക്കുന്ന ഒരു ആപ്പും കണ്ടെത്തിയില്ല + അർദ്ധരാത്രി കഴിഞ്ഞ് കുറച്ച് മണിക്കൂറുകൾ പകൽ നീട്ടുക + ഒരു പുതിയ ദിവസം കാണിക്കാൻ 3:00 AM വരെ കാത്തിരിക്കുക. നിങ്ങൾ സാധാരണയായി അർദ്ധരാത്രിക്ക് ശേഷം ഉറങ്ങാൻ പോകുകയാണെങ്കിൽ ഉപയോഗപ്രദമാണ്. ആപ്പ് പുനരാരംഭിക്കേണ്ടതുണ്ട്. + diff --git a/uhabits-android/src/main/res/values-nl-rNL/strings.xml b/uhabits-android/src/main/res/values-nl-rNL/strings.xml index 790dcbbc7..9770354c6 100644 --- a/uhabits-android/src/main/res/values-nl-rNL/strings.xml +++ b/uhabits-android/src/main/res/values-nl-rNL/strings.xml @@ -40,6 +40,10 @@ Gewoontes gearchiveerd Gewoontes gearchiveerd + + Gewoonte niet gearchiveerd + Gewoontes hersteld uit archief + Overzicht Gewoonte-sterkte Geschiedenis @@ -82,6 +86,14 @@ Wist je dat? Om de rijen te ordenen, houdt de gewoonte ingedrukt en sleep het naar de gewenste plek. Je kunt meer dagen zien door de telefoon in landschapsmodus te zetten. + + Verwijder gewoontes + Gewoontes verwijderen? + + + De gewoonte zal permanent verwijderd worden. Deze actie kan niet ongedaan gemaakt worden. + De gewoontes zullen permanent verwijderd worden. Deze actie kan niet ongedaan gemaakt worden. + Gewoonte verwijderd / niet gevonden Weekends Maandag tot vrijdag diff --git a/uhabits-android/src/main/res/values-pl-rPL/strings.xml b/uhabits-android/src/main/res/values-pl-rPL/strings.xml index c9347762d..fcfd1b802 100644 --- a/uhabits-android/src/main/res/values-pl-rPL/strings.xml +++ b/uhabits-android/src/main/res/values-pl-rPL/strings.xml @@ -211,10 +211,10 @@ Kolor np. 15 np. Bieg - np. Ile km przebiegłeś dzisiaj? + np. Ile kilometrów dzisiaj przebiegłeś? np. kilometry - Co miesiąc - Nie może być puste + Każdego miesiąca + Pole nie może być puste Dzisiaj Wprowadź Nie znaleziono nawyków diff --git a/uhabits-android/src/main/res/values-pt-rPT/strings.xml b/uhabits-android/src/main/res/values-pt-rPT/strings.xml index 374fded4c..065c3cdf0 100644 --- a/uhabits-android/src/main/res/values-pt-rPT/strings.xml +++ b/uhabits-android/src/main/res/values-pt-rPT/strings.xml @@ -137,8 +137,10 @@ Por nome Por cor Por pontuação + Por estado Exportar Pressione e segure para alterar o valor + Valor Calendário Unidade ex.: Você se exercitou hoje? @@ -171,4 +173,9 @@ Todos os meses Não pode ficar em branco Hoje + Registar + Acrescentar + Decrementar + Agora é um programador! + Nenhuma aplicação foi encontrada para oferecer suporte a esta ação diff --git a/uhabits-android/src/main/res/values-ro-rRO/strings.xml b/uhabits-android/src/main/res/values-ro-rRO/strings.xml index 019596b0b..d9df1c25e 100644 --- a/uhabits-android/src/main/res/values-ro-rRO/strings.xml +++ b/uhabits-android/src/main/res/values-ro-rRO/strings.xml @@ -32,10 +32,11 @@ Graficul obiceiurilor Istoric Golește - Atenționare + Reamintire Salvează Zile consecutive Nu ai niciun obicei activ. + Ai terminat pe ziua de azi! Apasă și ține pentru a bifa sau a debifa Dezactivat Creează obiceiul @@ -55,19 +56,25 @@ 4 ore 8 ore 24 de ore - Intreaba mereu - Diferit... + Întreabă întotdeauna + Alt interval... Comută repetițiile printr-o apăsare scurtă - Evaluează aplicația pe Magazin Play - Trimite păreri dezvoltatorului + Bifează cu o singură atingere în loc să ții apăsat. + Evaluează aplicația pe Google Play + Trimite feedback dezvoltatorului Vezi codul sursă pe GitHub - Aplicație + Linkuri Nume Setări Selectează durata amânării Știai? Pentru a rearanja obiceiurile, apasă și ține numele obiceiului, apoi trage-l în locul corect. Poți vedea mai multe zile în modul peisaj. + + Obiceiul va fi șters permanent. Această acțiune este ireversibilă. + Obiceiurile vor fi șterse permanent. Această acțiune este ireversibilă. + Obiceiurile vor fi șterse permanent. Această acțiune este ireversibilă. + Obicei șters / negăsit Weekenduri Zile de lucru @@ -137,10 +144,14 @@ După nume După culoare După scor + După stare Exportă Ține apăsat pentru a modifica valoarea + Valoare Calendar Unități + Cel puțin + Cel mult ex.: Ai îndeplinit exerciții fizice azi? Întrebare Obiectiv @@ -151,20 +162,35 @@ Consultați politica de confidențialitate Vizualizați toți colaboratorii… Bază de date + Opacitatea widget-ului + Face widget-urile mai transparente sau mai opace pe ecranul de pornire. + Prima zi a săptămânii + Ai efectuat astăzi acest obicei? Notițe (Opţional) ex. Te-ai trezit mai devreme astăzi? Ai făcut exerciții? Ai jucat șah? Măsurabil + ex.: Câți kilometri ai alergat astăzi? Câte pagini de carte ai citit? + %d ori pe săptămână + %d ori pe lună %d ori în %d zile + ex.: Exerciții Culoare + ex.: 15 + ex.: Alergat + ex.: Câți kilometri ai alergat astăzi? de exemplu mile În fiecare lună nu poate fi gol Astăzi Introducere Nici un obicei găsit + Nu au fost găsite obiceiuri măsurabile + Nu au fost găsite obiceiuri cu \"Da\" sau \"Nu\" Activați omiterea de zile Arată semnele de întrebare pentru datele lipsă Acum ești un dezvoltator + Nu a fost găsită nicio aplicație care să efectueze această acțiune. Extinde ziua câteva ore după miezul nopții + Așteaptă până la ora 3:00 dimineața pentru a arăta o nouă zi. O funcție utilă dacă în mod normal obișnuiești să mergi la somn după miezul nopții. Necesită repornirea aplicației. diff --git a/uhabits-android/src/main/res/values-ru-rRU/strings.xml b/uhabits-android/src/main/res/values-ru-rRU/strings.xml index 1916cb0a1..892b07e8f 100644 --- a/uhabits-android/src/main/res/values-ru-rRU/strings.xml +++ b/uhabits-android/src/main/res/values-ru-rRU/strings.xml @@ -83,7 +83,7 @@ Всегда спрашивать Настроить... Отмечать коротким нажатием - Ставить галочки одним касанием вместо нажатия и удерживания. + Галочки в одно касание вместо нажатия и удержания Оценить приложение в Google Play Отправить сообщение разработчику Посмотреть исходный код на GitHub @@ -159,7 +159,7 @@ Без звука Фильтр Скрыть завершённые - Скрыть введённые + Скрыть введённые Скрыть архивированные Сделать уведомления \"липкими\" Предотвращает смахивание уведомлений. diff --git a/uhabits-android/src/main/res/values-sk-rSK/strings.xml b/uhabits-android/src/main/res/values-sk-rSK/strings.xml index 6838ff94d..09acf99fc 100644 --- a/uhabits-android/src/main/res/values-sk-rSK/strings.xml +++ b/uhabits-android/src/main/res/values-sk-rSK/strings.xml @@ -34,6 +34,24 @@ Návykov zmenených Návykov zmenených + + Návyk zmazaný + Návyky zmazané + Návykov zmazaných + Návykov zmazaných + + + Návyk dosiahnutý + Návyky dosiahnuté + Návykov dosiahnutých + Návykov dosiahnutých + + + Návyk nedosiahnutý + Návyky nedosiahnuté + Návykov nedosiahnutých + Návykov nedosiahnutých + Prehľad Sila návyku História @@ -65,6 +83,7 @@ Vždy sa spýtať Vlastné ... Prepnúť krátkym stlačením + Začiarknite jediným klepnutím namiesto stlačenia a podržania. Ohodnoťte túto aplikáciu na Google Play Odošlite spätnú väzbu vývojárovi Zobraziť zdrojový kód na stránke GitHub @@ -75,6 +94,18 @@ Vedeli ste? Pre zmenu usporiadania záznamov, stlačte a podržte názov návyku a potom ho presuňte na správne miesto. Môžete vidieť viac dní otočením telefónu do režimu na šírku. + + Odstrániť návyk? + Odstrániť návyky? + Odstrániť návyky? + Odstrániť návyky? + + + Návyk bude natrvalo odstránený. Tento krok nie je možné vrátiť späť. + Návyky budú natrvalo odstránené. Tento krok nie je možné vrátiť späť. + Návyky budú natrvalo odstránené. Tento krok nie je možné vrátiť späť. + Návyky budú natrvalo odstránené. Tento krok nie je možné vrátiť späť. + Návyk bol odstránený / nenájdený Víkendy Od pondelka do piatku @@ -128,6 +159,7 @@ Žiadny Filter Skryť dokončené + Skryť vyplnené Skryť archivované Pripnúť oznámenia Zabráni odstráneniu notifikácií odsunutím. @@ -147,8 +179,12 @@ Podľa stavu Exportovať Stlačením a podržaním zmeníte hodnotu + Hodnota Kalendár Jednotka + Typ cieľa: + Aspoň + Najviac napr. Cvičili ste dnes? Otázka Cieľ @@ -170,6 +206,7 @@ napr. Koľko kilometrov ste dnes nabehali? Koľko strán ste prečítali? %d krát týždenne %d krát za mesiac + %d krát za %d dní napr. Cvičenie Farba napr. 15 @@ -183,6 +220,8 @@ Nenašli sa žiadne návyky Nenašli sa žiadne merateľné návyky Nenašli sa žiadne áno-alebo-nie návyky + Navýšiť + Znížiť Povoliť preskočenie dní Dvojitým prepnutím pridáte namiesto začiarknutia preskočenie. Preskočenia udržia vaše skóre nezmenené a neprerušia vašu sériu. Zobraziť otázniky pre chýbajúce údaje diff --git a/uhabits-android/src/main/res/values-sl-rSI/strings.xml b/uhabits-android/src/main/res/values-sl-rSI/strings.xml index 6e1f450d5..2a8db667a 100644 --- a/uhabits-android/src/main/res/values-sl-rSI/strings.xml +++ b/uhabits-android/src/main/res/values-sl-rSI/strings.xml @@ -28,6 +28,30 @@ Dodaj navado Spremeni barvo Navada ustvarjena + + Navada spremenjena + Navadi spremenjene + Navade spremenjene + Navade spremenjene + + + Navada izbrisana + Navadi izbrisane + Navade izbrisane + Navade izbrisane + + + Navada arhivirana + Navadi arhivirani + Navade arhivirana + Navade arhivirana + + + Navada nearhivirana + Navadi nearhivirani + Navade nearhivirane + Navade nearhivirane + Pregled Moč navade Zgodovina @@ -36,6 +60,7 @@ Shrani Serije Nimate aktivnih navad + Za danes ste končali! Pritisnite-in-držite, da označite ali odznačite Izključeno Ustvari navado @@ -55,16 +80,32 @@ 4 ure 8 ur 24 ur + Vedno vprašaj + Po meri... Preklopi ponovitve s kratkim pritiskom + Postavite kljukice z enim dotikom namesto s pritiskom in držanjem. Oceni to aplikacijo na Google Play Pošlji povratne informacije razvijalcem Poglej izvorno kodo na GitHub Povezave Ime Nastavitve + Izberite zakasnitev dremeža Ali ste vedeli? Če želite preurediti vnose, pritisnite-in-držite na ime navade, nato pa jo povlecite na željeno mestu. Ogledate si lahko več dni, s tem da telefon postavite v ležeči načinu. + + Izbriši navado? + Izbriši navadi? + Izbriši navade? + Izbriši navade? + + + Navada bo trajno izbrisana. Tega dejanja ni mogoče razveljaviti. + Navadi bodo trajno izbrisani. Tega dejanja ni mogoče razveljaviti. + Navade bodo trajno izbrisane. Tega dejanja ni mogoče razveljaviti. + Navade bodo trajno izbrisane. Tega dejanja ni mogoče razveljaviti. + Izbrisana navada / ni najdena Vikendi Ponedeljek do Petka @@ -110,6 +151,7 @@ Četrtletje Leto Skupaj + Da ali Ne Vsakih %d dni Vsakih %d tednov Ocena @@ -117,9 +159,12 @@ Noben Filter Skrij končane + Skrij vneseno Skrij arhivirane Naaredi obvestila lepljiva Preprečuje, da lahko obvestila povlečete stran. + Lučka za obvestila + Prikaže utripajočo luč za opomnike. Na voljo samo v telefonih z LED lučkami za obvestila. Popravi podatkovno zbirko Podatkovna zbirka popravljena. Odznači @@ -131,6 +176,58 @@ Po imenu Po barvi Po rezultatu + Po statusu Izvozi + Pritisnite in držite, da spremenite vrednost + Vrednost + Koledar + Enota + Vrsta cilja + Vsaj + Največ + npr. Ste danes telovadili? + Vprašanje + Cilj + Da + Ne + Spremenite nastavitve zvoka, vibriranja, svetlobe in drugih obvestil + Prilagoditve obvestil + Oglejte si pravilnik o zasebnosti + Poglej vse sodelavce… + Baza podatkov + Prosojnost pripomočka + Pripomočke naredi bolj pregledne ali bolj neprozorne na domačem zaslonu. + Prvi dan v tednu + Ste danes dokončali to navado? + Opombe + (Neobvezno) + npr. Ste se danes zgodaj zbudili? Ste telovadili? Ste igrali šah? + Merljivo + npr. Koliko kilometrov ste pretekli danes? Koliko strani ste prebrali? + %d krat na teden + %d krat na mesec %d krat v %d dni + npr. Vadba + Barva + npr. 15 + npr. Tek + npr. Koliko kilometrov ste pretekli danes? + npr. km + Vsak mesec + Ne sme biti prazno + Danes + Vnesi + Ni najdenih navad + Ni najdenih merljivih navad + Ni najdenih da ali ne navad + Povečaj + Zmanjšaj + Omogoči preskok dni + Dvakrat preklopite, da dodate preskok namesto kljukice. Preskoki ohranjajo vaš rezultat nespremenjen in ne prekinejo vašega niza. + Pokaži vprašaj za manjkajoče podatke + Razlikujte dneve brez podatkov od dejanskih zamud. Če želite vnesti presledek, dvakrat preklopite. + Zdaj ste razvijalec + Najdena ni bila nobena aplikacija, ki bi podpirala to dejanje + Podaljšajte dan nekaj ur čez polnoč + Počakajte do 3.00, da prikažete nov dan. Uporabno, če greste običajno spat po polnoči. Zahteva ponovni zagon aplikacije. diff --git a/uhabits-android/src/main/res/values-sr-rCS/strings.xml b/uhabits-android/src/main/res/values-sr-rCS/strings.xml index fd7a8fcbf..0374b68ac 100644 --- a/uhabits-android/src/main/res/values-sr-rCS/strings.xml +++ b/uhabits-android/src/main/res/values-sr-rCS/strings.xml @@ -54,7 +54,7 @@ Očisti Podsetnik Sačuvaj - Nizovi + Rekordi Nemate aktivnih navika Završili ste za danas! Dug pritisak za menjanje stanja diff --git a/uhabits-android/src/main/res/values-sr-rSP/strings.xml b/uhabits-android/src/main/res/values-sr-rSP/strings.xml index cb73a795e..fcb584b3a 100644 --- a/uhabits-android/src/main/res/values-sr-rSP/strings.xml +++ b/uhabits-android/src/main/res/values-sr-rSP/strings.xml @@ -44,9 +44,9 @@ Навике архивиране - Навика деархивирана - Навике деархивиране - Навике деархивиране + Навика враћена из архиве + Навике враћене из архиве + Навике враћене из архиве Преглед Моћ навике @@ -54,7 +54,7 @@ Очисти Подсетник Сачувај - Низови + Рекорди Немате активних навика Завршили сте за данас! Дуг притисак за мењање стања @@ -79,6 +79,7 @@ Увек питај Прилагођено... Мењај стање додиром + Ставите квачице једним додиром уместо притискањем и држањем. Оцени апликацију Повратне информације Изворни кôд на Гитхабу @@ -152,6 +153,7 @@ без звука Филтер Сакриј завршено + Сакриј унесене Сакриј архивирано Учини обавештења трајним Спречава уклањање обавештења. @@ -171,8 +173,12 @@ по стању Извоз Дуг притисак за промену вредности + Вредност Календар Јединица + Врста циља + најмање + највише нпр. Да ли сте вежбали данас? Питање Циљ diff --git a/uhabits-android/src/main/res/values-sv-rSE/strings.xml b/uhabits-android/src/main/res/values-sv-rSE/strings.xml index 26fb08024..127664599 100644 --- a/uhabits-android/src/main/res/values-sv-rSE/strings.xml +++ b/uhabits-android/src/main/res/values-sv-rSE/strings.xml @@ -75,6 +75,7 @@ Fråga alltid Anpassad... Växla med snabb tryckning + Sätt bockar med en enkel tryckning i stället för att trycka och hålla nere. Betygsätt oss på Google Play Skicka feedback till utvecklarna Visa källkod på GitHub @@ -155,6 +156,7 @@ Inget Filtrera Dölj slutförda + Dölj inmatade Dölj arkiverade Gör notifikationer permanenta Förhindrar att notifikationer stängs. @@ -174,8 +176,12 @@ Efter status Exportera Tryck och håll ned för att ändra värdet + Värde Kalender Enhet + Måltyp + Minst + Högst t.ex. Tränade du idag? Fråga Mål @@ -197,7 +203,7 @@ t.ex. Hur många kilometer sprang du idag? Hur många sidor läste du? %d gånger per vecka %d gånger per månad - %d gånger i %d dagar + %d gånger per %d dag(ar) t.ex. Träna Färg t.ex. 15 diff --git a/uhabits-android/src/main/res/values-ta-rIN/strings.xml b/uhabits-android/src/main/res/values-ta-rIN/strings.xml index 3b1c16a18..a7a14be4f 100644 --- a/uhabits-android/src/main/res/values-ta-rIN/strings.xml +++ b/uhabits-android/src/main/res/values-ta-rIN/strings.xml @@ -21,53 +21,81 @@ Loop Habit Tracker பழக்கங்கள் அமைப்புகள் - திருத்துக + திருத்து நீக்கு காப்பகம் உயிர்க்க - சேர்க்க + பழக்கத்தைச் சேர் நிறம் மாற்ற பழக்கம் உருவாக்கப்பட்டது + + Hello + பழக்கம் மாற்றப்பட்டது + + + பழக்கம் நீக்கப்பட்டது + பழக்கங்கள் நீக்கப்பட்டன + + + பழக்கம் காப்பகப்படுத்தப்பட்டது + பழக்கங்கள் காப்பகப்படுத்தப்பட்டது + + + பழக்கம் ஆவண காப்பகத்திலிருந்து நீக்கப் பட்டது + பழக்கங்கள் ஆவண காப்பகத்திலிருந்து நீக்கப் பட்டது + மேற்பார்வை பழக்கத்தின் வலிமை வரலாறு அழி - நினைவூட்டல்கள் + நினைவூட்டல் சேமிக்கவும் சாதனைகள் நடப்பு பழக்கம் எதுவும் இல்லை + இன்று இனி செய்வதற்க்கு ஒன்றுமில்லை குறிக்க அல்லது குறிப்பை நீக்க அழுத்தி பிடிக்கவும் - வேண்டாம் - புதிய பழக்கம் - பழக்கத்தை திருத்த - சரிப்பார்ப்பு குறி + அணை + பழக்கம் உருவாக்கு + பழக்கத்தைத் திருத்த + சோதி பிறகு - வருக + நல்வரவு இந்த செயலி நல்ல பழக்க வழக்கங்களை துவங்க மற்றும் தொடர உதவுகிறது. சில புது பழக்கங்களை துவங்கவும்! தினமும் உங்கள் புதிய பழக்கத்தை முடித்தவுடன் இந்த செயலியில் அதை குறிக்கவும். - உங்கள் முன்னேற்றத்தை கண்காணிக்கவும் + உங்கள் முன்னேற்றத்தைக் கண்காணிக்க நாளடைவில் நீங்கள் அடைந்த முன்னேற்றத்தை வரைபடத்தின் மூலம் அறியலாம். 15 நிமிடங்கள் 30 நிமிடங்கள் - 1 மணி நேரம் - 2 மணி நேரம் - 4 மணி நேரம் - 8 மணி நேரம் - 24 மணி நேரம் + 1 மணி + 2 மணிகள் + 4 மணிகள் + 8 மணிகள் + 24 மணிகள் எப்போதும் கேள் + தனிப்பயன்... சிறிய அழுத்தலின் மூலம் தாவு - Google Play-ல் இந்த செயலியை மதிப்பிட + ஒரே தொடுதலில் தேர்ந்தெடு + Google Play-ல் இந்தச் செயலியை மதிப்பிட இந்த செயலியை மேம்படுத்த உங்கள் கருத்துகளை பகிர இந்த செயலியின் மூல நிரலை GitHub வலைதளத்தில் பார்க்கவும் இணைப்புகள் பெயர் அமைப்புகள் + ஸ்னூஜ் (snooze) நேரத்தைத் தேர்ந்தெடு உங்களுக்கு தெரியுமா? பதிவுகளை மறுசீரைமக்க, தேவையான பழக்க பதிவின் மீது அழுத்தி பிடித்து பின் தேவையான இடத்திற்கு அதை இழுக்கவும். உங்கள் கைப்பேசியை அகலவாக்கில் வைக்கும்போது இன்னும் அதிக நாட்களை காண முடியும். + + பழக்கத்தை நீக்கவா? + பழக்கங்களை நீக்கு + + + பழக்கம் நிரந்தரமாக நீக்கப்படும். இந்தச் செயலை மீட்டமைக்க இயலாது. + பழக்கங்கள் நிரந்தரமாக நீக்கப்படும். இந்தச் செயலை மீட்டமைக்க இயலாது. + பழக்கம் நீக்கப்பட்டுவிட்டது / காணவில்லை - வார இறுதிகள் + வார இறுதிநாட்கள் திங்கள் முதல் வெள்ளி வரை வாரத்தின் எந்த நாளிலும் நாட்களை தேர்வு செய்யவும் @@ -119,9 +147,12 @@ எதுவும் இல்லை வடிகட்டவும் மறைத்தல் முடிந்தது + பழக்கம் பதிவுசெய்யப்பட்டது ஆவணக் காப்பை மறைக்கவும் நினைவூட்டல்களை நிலைத்து நிற்கவை நினைவூட்டல்களை விரல்களால் தள்ளி விட முடியாத படி செய்கிறது. + அறிவிப்பு ஒளி + நினைவூட்டல்களுக்கு விளக்கு (வசதி உள்ளதெனில்) அணைந்து அணைந்து எரியும் தரவு தளத்தை பழுது பார்க்கவும் தரவுதளம் பழுதடைந்து விட்டது. சரிப்பார்க்காமல் அப்படியே விடு @@ -133,6 +164,58 @@ பெயரின் மூலம் நிறத்தின் மூலம் மதிப்பெண்களின் மூலம் + நிலைகளின்படி ஏற்றுமதி + மதிப்பை மாற்ற, அழுத்தி வைத்திருங்கள் + மதிப்பு + நாள்காட்டி + அலகு + இலக்கு வகை + குறைந்த பட்சம் + அதிக பட்சம் + எ. கா. இன்று உடற்பயிற்சி செய்தீரா? + கேள்வி + இலக்கு + ஆம் + இல்லை + சத்தம், அதிர்வு, ஒளி மற்றும் அறிவிப்பு அமைப்புகளை மாற்றவும் + அறிவிப்புகளைத் தனிப்பயனாக்கவும் + தனியுரிமைக் கொள்கையைக் காணவும் + எல்லா பங்களிப்பாளர்களையும் காண... + தகவல்தளங்கள் + விட்ஜெட்டின் மங்கல் அளவு + உங்கள் முகப்பு திரையில் விட்ஜெட்டுகளை மேலோட்டமாக அல்லது குறைவாக மங்கலாக்கு + வாரத்தின் முதல் நாள் + இன்று இந்தப் பழக்கத்தைச் செய்தீரா? + குறிப்புகள் + (விருப்பத்தேர்வு) + உதாரணமாக: இன்று நீங்கள் வழக்கம்போல முன் எழுந்தீர்களா? நீங்கள் உடற்பயிற்சி செய்தீர்களா? நீங்கள் சதுரங்கம் விளையாடினீர்களா? + மதிப்பிடக்கூடிய + எ. கா. நீங்கள் இன்று எத்தனை மைல்கள் ஓடிநீர்? நீங்கள் எத்தனை பக்கங்கள் படித்தீர்கள்? + வாரத்திற்கு %d முறை + மாதத்திற்க்கு %d முறை %d காலங்களில் %d நாட்கள் + எ. கா. உடற்பயிற்ச்சி + நிறம் + எ. கா. 15 + எ. கா. ஓடு + எ. கா. இன்று எத்தனை மைல் ஓடினாய்? + எ. கா. மைல்கள் + ஒவ்வொரு மாதமும் + வெற்றிடமாக இருக்கக் கூடாது + இன்று + உள்ளிடு + பழக்கம் இல்லை + எண்ணக்கூடிய பழக்கம் ஒன்றுமில்லை + ஆம்-இல்லை பழக்கம் ஒன்றுமில்லை + அதிகரிப்பு + குறைப்பு + தவிர்க்கக்கூடிய நாட்களைச் செயலாக்கவும் + இரண்டு முறை தொடல், \'தவிர்\' வசதியைச் சேர்க்கும். இது உங்கள் மதிப்பெண்ணை மாற்றாது மற்றும் உங்கள் தொடர்ச்சியைக் பாதிக்காது. + பதிவிடாத நாட்களுக்குக் கேள்விக்குறியை காமி + தகவல் இல்லாத நாட்களை வேறுபடுத்து.தவித்தலை பதிவிட, இருமுறை தொடவும். + நீங்கள் இப்போது டெவெலப்பராகிவிட்டீர்கள் + இந்தச் செயலைச் செய்வதற்கான பயன்பாடு எதுவுமில்லை. + நாளை, நள்ளிரவை தாண்டி சில மணிநேரங்கள் நீட்டிக்கவும் + புதிய நாளைக் காண்பிக்க அதிகாலை 3:00 மணிவரை காத்திருக்கவும். நீங்கள் பொதுவாக நடுஇரவுக்கு பின் உறங்குபவரரெனில் உபயோகமானது. பயன்பாட்டை மறுதுவக்கம் செய்தல் அவசியமானது diff --git a/uhabits-android/src/main/res/values-uk-rUA/strings.xml b/uhabits-android/src/main/res/values-uk-rUA/strings.xml index 0b5865660..725d695c5 100644 --- a/uhabits-android/src/main/res/values-uk-rUA/strings.xml +++ b/uhabits-android/src/main/res/values-uk-rUA/strings.xml @@ -83,6 +83,7 @@ Завжди запитувати Налаштувати... Відзначати коротким натисканням + Встановлюйте відмітки одним натисканням замість натискання й утримування. Оцінити цю програму в Google Play Надіслати відгук розробникові Подивитися вихідний код на GitHub @@ -167,6 +168,7 @@ Немає Фільтр Приховати завершені + Приховати введені Приховати архівовані Закріпити сповіщення Запобігає прихованню сповіщень. @@ -189,6 +191,9 @@ Значення Календар Одиниця + Тип цілі + Щонайменше + Щонайбільше напр.: Ви робили сьогодні вправи? Запитання Мета diff --git a/uhabits-android/src/main/res/values-vi-rVN/strings.xml b/uhabits-android/src/main/res/values-vi-rVN/strings.xml index 98d03b750..f0db5716b 100644 --- a/uhabits-android/src/main/res/values-vi-rVN/strings.xml +++ b/uhabits-android/src/main/res/values-vi-rVN/strings.xml @@ -141,7 +141,7 @@ Không có Lọc Ẩn mục đã hoàn thành - Ẩn đã nhập + Ẩn đã nhập Ẩn mục đã lưu trữ Gửi thông báo cố định Không cho các thông báo bị vuốt ngang mất. diff --git a/uhabits-android/src/main/res/values-zh-rCN/strings.xml b/uhabits-android/src/main/res/values-zh-rCN/strings.xml index ec3ff280c..5c80c99f6 100644 --- a/uhabits-android/src/main/res/values-zh-rCN/strings.xml +++ b/uhabits-android/src/main/res/values-zh-rCN/strings.xml @@ -53,7 +53,7 @@ 关闭 新建习惯 编辑习惯 - 标记 + 打卡 稍后提醒 欢迎 Loop 习惯记录能帮你养成和保持好习惯。 @@ -71,14 +71,14 @@ 总是询问 自定义 短按切换 - 只需轻按一下即可放置复选标记,而不是按住。 + 只需点击一下即可打卡,而不是长按。 去 Play 商店评价此应用 发送反馈给开发者 在 GitHub 上查看源代码 链接 习惯标题 设置 - 设定延后提醒间隔时间 + 设定稍后提醒的时间间隔 你知道吗? 如果要重新排列习惯,按住习惯的名字拖到想要的位置 转至横屏查看更多日期 @@ -126,8 +126,8 @@ 以纯黑色背景代替深色主题中的灰色背景。 这可以降低 AMOLED 屏幕手机的耗电量。 界面 - 逆序显示日子 - 在主界面以相反的顺序显示日子 + 逆序显示日期 + 在主界面以相反的顺序显示日期。 @@ -142,7 +142,7 @@ 筛选 隐藏已完成 - 隐藏已输入 + 隐藏已输入 隐藏已存档 使通知持久 防止通知被滑掉。 @@ -171,15 +171,15 @@ 例如:你今天锻炼了吗? 问题 目标 - - + 完成了 + 未完成 更改声音、振动、指示灯(呼吸灯)和其他通知设置 自定义通知 查看隐私政策 查看所有贡献者 数据库 微件不透明度 - 调整主屏幕上微件的不透明度。 + 调整主屏幕上小部件的不透明度。 一周的第一天 你今天完成这个习惯了吗? 备注 @@ -205,10 +205,10 @@ 找不到“是或不是”类的习惯 增加(+1) 减少(-1) - 启用跳过天数 + 启用跳过天数功能 切换两次以添加跳过而不是复选标记。跳过将保持您的得分不变,且不会打破你的连续纪录 对丢失的数据显示问号 - 区分没有数据和实际犯错的日子。要输一个过失,请切换两次。 + 区分无数据和未完成习惯的日期。要输入一个习惯未完成,请切换两次。 你现在是一个开发者! 找不到支持此操作的应用 将一天延长到午夜后的几个小时 diff --git a/uhabits-android/src/main/res/values-zh-rTW/strings.xml b/uhabits-android/src/main/res/values-zh-rTW/strings.xml index 2d425ec82..7afe2d554 100644 --- a/uhabits-android/src/main/res/values-zh-rTW/strings.xml +++ b/uhabits-android/src/main/res/values-zh-rTW/strings.xml @@ -71,6 +71,7 @@ 每次都詢問 自訂 換成輕碰來記錄習慣 + 輕碰即可打勾,不需要長按 在 Google Play 上評價這個 App 傳送改進意見給開發者 在 GitHub 上查看原始碼 @@ -144,6 +145,7 @@ 篩選 隱藏已完成的習慣 + 隱藏已記錄的習慣 隱藏已封存習慣 使提醒保持常駐 防止提醒被滑動移除 @@ -163,8 +165,12 @@ 依據狀態 匯出 持續按住來改換數值 + 日曆 單位 + 目標標準 + 以上 + 以下 例如:你今天運動了嗎? 提示問題 目標 diff --git a/uhabits-android/src/main/res/values/strings.xml b/uhabits-android/src/main/res/values/strings.xml index 1b0733768..b3e849728 100644 --- a/uhabits-android/src/main/res/values/strings.xml +++ b/uhabits-android/src/main/res/values/strings.xml @@ -233,5 +233,7 @@ No app was found to support this action Extend day a few hours past midnight Wait until 3:00 AM to show a new day. Useful if you typically go to sleep after midnight. Requires app restart. + Disable animations + Disable confetti animation after adding a checkmark. Task View Checkmark scale factor diff --git a/uhabits-android/src/main/res/xml/preferences.xml b/uhabits-android/src/main/res/xml/preferences.xml index d470af826..4983c60be 100644 --- a/uhabits-android/src/main/res/xml/preferences.xml +++ b/uhabits-android/src/main/res/xml/preferences.xml @@ -67,6 +67,13 @@ android:title="@string/use_pure_black" app:iconSpaceReserved="false" /> + + 12 \ No newline at end of file diff --git a/uhabits-core-legacy/assets/main/migrations/015.sql b/uhabits-core-legacy/assets/main/migrations/015.sql deleted file mode 100644 index afae84e20..000000000 --- a/uhabits-core-legacy/assets/main/migrations/015.sql +++ /dev/null @@ -1,3 +0,0 @@ -delete from Score -delete from Streak -delete from Checkmarks \ No newline at end of file diff --git a/uhabits-core-legacy/assets/main/migrations/016.sql b/uhabits-core-legacy/assets/main/migrations/016.sql deleted file mode 100644 index 059f2016b..000000000 --- a/uhabits-core-legacy/assets/main/migrations/016.sql +++ /dev/null @@ -1,2 +0,0 @@ -alter table Habits add column type integer not null default 0 -alter table Repetitions add column value integer not null default 2 \ No newline at end of file diff --git a/uhabits-core-legacy/assets/main/migrations/017.sql b/uhabits-core-legacy/assets/main/migrations/017.sql deleted file mode 100644 index 15430d771..000000000 --- a/uhabits-core-legacy/assets/main/migrations/017.sql +++ /dev/null @@ -1,5 +0,0 @@ -drop table Score -create table Score ( id integer primary key autoincrement, habit integer references habits(id), score real, timestamp integer) -create index idx_score_habit_timestamp on Score(habit, timestamp) -delete from streak -delete from checkmarks \ No newline at end of file diff --git a/uhabits-core-legacy/assets/main/migrations/018.sql b/uhabits-core-legacy/assets/main/migrations/018.sql deleted file mode 100644 index 4cdc9cc8d..000000000 --- a/uhabits-core-legacy/assets/main/migrations/018.sql +++ /dev/null @@ -1,3 +0,0 @@ -alter table Habits add column target_type integer not null default 0 -alter table Habits add column target_value real not null default 0 -alter table Habits add column unit text not null default "" \ No newline at end of file diff --git a/uhabits-core-legacy/assets/main/migrations/019.sql b/uhabits-core-legacy/assets/main/migrations/019.sql deleted file mode 100644 index 0569ea531..000000000 --- a/uhabits-core-legacy/assets/main/migrations/019.sql +++ /dev/null @@ -1 +0,0 @@ -create table Events ( id integer primary key autoincrement, timestamp integer, message text, server_id integer ) \ No newline at end of file diff --git a/uhabits-core-legacy/assets/main/migrations/020.sql b/uhabits-core-legacy/assets/main/migrations/020.sql deleted file mode 100644 index 254bb7b80..000000000 --- a/uhabits-core-legacy/assets/main/migrations/020.sql +++ /dev/null @@ -1,3 +0,0 @@ -drop table checkmarks -drop table streak -drop table score diff --git a/uhabits-core-legacy/assets/main/migrations/021.sql b/uhabits-core-legacy/assets/main/migrations/021.sql deleted file mode 100644 index 547b6759d..000000000 --- a/uhabits-core-legacy/assets/main/migrations/021.sql +++ /dev/null @@ -1,12 +0,0 @@ -update habits set color=19 where color=12 -update habits set color=17 where color=11 -update habits set color=15 where color=10 -update habits set color=14 where color=9 -update habits set color=13 where color=8 -update habits set color=10 where color=7 -update habits set color=9 where color=6 -update habits set color=8 where color=5 -update habits set color=7 where color=4 -update habits set color=5 where color=3 -update habits set color=4 where color=2 -update habits set color=0 where color<0 or color>19 \ No newline at end of file diff --git a/uhabits-core-legacy/assets/main/migrations/022.sql b/uhabits-core-legacy/assets/main/migrations/022.sql deleted file mode 100644 index b9ca2ba5a..000000000 --- a/uhabits-core-legacy/assets/main/migrations/022.sql +++ /dev/null @@ -1,11 +0,0 @@ -delete from repetitions where habit not in (select id from habits) -delete from repetitions where timestamp is null -delete from repetitions where habit is null -delete from repetitions where rowid not in ( select min(rowid) from repetitions group by habit, timestamp ) -alter table Repetitions rename to RepetitionsBak -create table Repetitions ( id integer primary key autoincrement, habit integer not null references habits(id), timestamp integer not null, value integer not null) -drop index if exists idx_repetitions_habit_timestamp -create unique index idx_repetitions_habit_timestamp on Repetitions( habit, timestamp) -insert into Repetitions select * from RepetitionsBak -drop table RepetitionsBak -pragma foreign_keys=ON \ No newline at end of file diff --git a/uhabits-core-legacy/assets/main/migrations/023.sql b/uhabits-core-legacy/assets/main/migrations/023.sql deleted file mode 100644 index 456a4d071..000000000 --- a/uhabits-core-legacy/assets/main/migrations/023.sql +++ /dev/null @@ -1 +0,0 @@ -create table Preferences(key text unique not null, value text not null) \ No newline at end of file diff --git a/uhabits-core-legacy/assets/test/components/BarChart/2-series.png b/uhabits-core-legacy/assets/test/components/BarChart/2-series.png deleted file mode 100644 index 833e4b19c..000000000 Binary files a/uhabits-core-legacy/assets/test/components/BarChart/2-series.png and /dev/null differ diff --git a/uhabits-core-legacy/assets/test/components/BarChart/axis-monthly.png b/uhabits-core-legacy/assets/test/components/BarChart/axis-monthly.png deleted file mode 100644 index 1313b4f94..000000000 Binary files a/uhabits-core-legacy/assets/test/components/BarChart/axis-monthly.png and /dev/null differ diff --git a/uhabits-core-legacy/assets/test/components/BarChart/axis-weekly.png b/uhabits-core-legacy/assets/test/components/BarChart/axis-weekly.png deleted file mode 100644 index 330923a42..000000000 Binary files a/uhabits-core-legacy/assets/test/components/BarChart/axis-weekly.png and /dev/null differ diff --git a/uhabits-core-legacy/assets/test/components/BarChart/axis-yearly.png b/uhabits-core-legacy/assets/test/components/BarChart/axis-yearly.png deleted file mode 100644 index ec97df8a1..000000000 Binary files a/uhabits-core-legacy/assets/test/components/BarChart/axis-yearly.png and /dev/null differ diff --git a/uhabits-core-legacy/assets/test/components/BarChart/base.png b/uhabits-core-legacy/assets/test/components/BarChart/base.png deleted file mode 100644 index 54d6862d7..000000000 Binary files a/uhabits-core-legacy/assets/test/components/BarChart/base.png and /dev/null differ diff --git a/uhabits-core-legacy/assets/test/components/CalendarChart/base.png b/uhabits-core-legacy/assets/test/components/CalendarChart/base.png deleted file mode 100644 index 762877164..000000000 Binary files a/uhabits-core-legacy/assets/test/components/CalendarChart/base.png and /dev/null differ diff --git a/uhabits-core-legacy/assets/test/components/CalendarChart/scroll.png b/uhabits-core-legacy/assets/test/components/CalendarChart/scroll.png deleted file mode 100644 index 16744a297..000000000 Binary files a/uhabits-core-legacy/assets/test/components/CalendarChart/scroll.png and /dev/null differ diff --git a/uhabits-core-legacy/assets/test/components/CanvasTest.png b/uhabits-core-legacy/assets/test/components/CanvasTest.png deleted file mode 100644 index 75b3d8f20..000000000 Binary files a/uhabits-core-legacy/assets/test/components/CanvasTest.png and /dev/null differ diff --git a/uhabits-core-legacy/assets/test/components/CheckmarkButton/explicit.png b/uhabits-core-legacy/assets/test/components/CheckmarkButton/explicit.png deleted file mode 100644 index c2b66f74e..000000000 Binary files a/uhabits-core-legacy/assets/test/components/CheckmarkButton/explicit.png and /dev/null differ diff --git a/uhabits-core-legacy/assets/test/components/CheckmarkButton/implicit.png b/uhabits-core-legacy/assets/test/components/CheckmarkButton/implicit.png deleted file mode 100644 index acc067024..000000000 Binary files a/uhabits-core-legacy/assets/test/components/CheckmarkButton/implicit.png and /dev/null differ diff --git a/uhabits-core-legacy/assets/test/components/CheckmarkButton/unchecked.png b/uhabits-core-legacy/assets/test/components/CheckmarkButton/unchecked.png deleted file mode 100644 index 283f32d40..000000000 Binary files a/uhabits-core-legacy/assets/test/components/CheckmarkButton/unchecked.png and /dev/null differ diff --git a/uhabits-core-legacy/assets/test/components/HabitListHeader/light.png b/uhabits-core-legacy/assets/test/components/HabitListHeader/light.png deleted file mode 100644 index c146b916d..000000000 Binary files a/uhabits-core-legacy/assets/test/components/HabitListHeader/light.png and /dev/null differ diff --git a/uhabits-core-legacy/assets/test/components/NumberButton/render_above.png b/uhabits-core-legacy/assets/test/components/NumberButton/render_above.png deleted file mode 100644 index 4673ef0f3..000000000 Binary files a/uhabits-core-legacy/assets/test/components/NumberButton/render_above.png and /dev/null differ diff --git a/uhabits-core-legacy/assets/test/components/NumberButton/render_below.png b/uhabits-core-legacy/assets/test/components/NumberButton/render_below.png deleted file mode 100644 index c3ffb68de..000000000 Binary files a/uhabits-core-legacy/assets/test/components/NumberButton/render_below.png and /dev/null differ diff --git a/uhabits-core-legacy/assets/test/components/NumberButton/render_zero.png b/uhabits-core-legacy/assets/test/components/NumberButton/render_zero.png deleted file mode 100644 index 235de2f62..000000000 Binary files a/uhabits-core-legacy/assets/test/components/NumberButton/render_zero.png and /dev/null differ diff --git a/uhabits-core-legacy/assets/test/components/Ring/draw1.png b/uhabits-core-legacy/assets/test/components/Ring/draw1.png deleted file mode 100644 index d5e80f455..000000000 Binary files a/uhabits-core-legacy/assets/test/components/Ring/draw1.png and /dev/null differ diff --git a/uhabits-core-legacy/assets/test/hello.txt b/uhabits-core-legacy/assets/test/hello.txt deleted file mode 100644 index e432ffe94..000000000 --- a/uhabits-core-legacy/assets/test/hello.txt +++ /dev/null @@ -1,2 +0,0 @@ -Hello World! -This is a resource. \ No newline at end of file diff --git a/uhabits-core-legacy/build.gradle b/uhabits-core-legacy/build.gradle deleted file mode 100644 index dc545c340..000000000 --- a/uhabits-core-legacy/build.gradle +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -plugins { - id 'kotlin-multiplatform' version "1.3.72" -} - -repositories { - mavenCentral() -} - -kotlin { - targets { - def sdkName = System.getenv('SDK_NAME') - def isIphone = sdkName?.startsWith("iphoneos") - def iosPreset = isIphone ? presets.iosArm64 : presets.iosX64 - - fromPreset(iosPreset, 'ios') { - binaries { - framework { - baseName = "LoopHabitTracker" - } - } - compilations.main { - cinterops { - sqlite3 { - defFile project.file("src/main/c_interop/sqlite3.def") - } - } - } - } - - fromPreset(presets.jvm, 'jvm') { - - } - - fromPreset(presets.js, 'js') { - compilations.main.kotlinOptions { - moduleKind = "commonjs" - } - compilations.test.kotlinOptions { - moduleKind = "commonjs" - } - } - } - - sourceSets { - commonMain { - kotlin { srcDir "src/main/common" } - dependencies { - implementation kotlin('stdlib-common') - implementation "$KX_COROUTINES-core-common:$KX_COROUTINES_VERSION" - } - } - - commonTest { - kotlin { srcDir "src/test/common" } - dependencies { - implementation kotlin('test-common') - implementation kotlin('test-annotations-common') - } - } - - jvmMain { - kotlin { srcDir "src/main/jvm" } - dependencies { - implementation kotlin('stdlib-jdk8') - implementation "$KX_COROUTINES-core:$KX_COROUTINES_VERSION" - } - } - - jvmTest { - kotlin { srcDir "src/test/jvm" } - dependencies { - implementation kotlin('test') - implementation kotlin('test-junit') - implementation 'org.xerial:sqlite-jdbc:3.25.2' - } - } - - jsMain { - kotlin { srcDir "src/main/js" } - dependencies { - implementation kotlin('stdlib-js') - implementation "$KX_COROUTINES-core-js:$KX_COROUTINES_VERSION" - } - } - - jsTest { - kotlin { srcDir "src/test/js" } - dependencies { - implementation kotlin('test-js') - } - } - - iosMain { - kotlin { srcDir "src/main/ios" } - dependencies { - implementation "$KX_COROUTINES-core-native:$KX_COROUTINES_VERSION" - } - } - - iosTest { - kotlin { srcDir "src/test/ios" } - dependencies { - implementation "$KX_COROUTINES-core-native:$KX_COROUTINES_VERSION" - } - } - } - - task iosTestCopyResources(type: Copy) { - from 'assets/test/' - from 'assets/main/' - into 'build/bin/ios/debugTest' - } - - if (project.tasks.findByName('iosTest')) { - iosTest.dependsOn(iosTestCopyResources) - } -} diff --git a/uhabits-core-legacy/gradle.properties b/uhabits-core-legacy/gradle.properties deleted file mode 100644 index fae8ffca6..000000000 --- a/uhabits-core-legacy/gradle.properties +++ /dev/null @@ -1,2 +0,0 @@ -KX_COROUTINES_VERSION=1.3.6 -KX_COROUTINES=org.jetbrains.kotlinx:kotlinx-coroutines \ No newline at end of file diff --git a/uhabits-core-legacy/settings.gradle b/uhabits-core-legacy/settings.gradle deleted file mode 100644 index 20ee303a3..000000000 --- a/uhabits-core-legacy/settings.gradle +++ /dev/null @@ -1,9 +0,0 @@ -pluginManagement { - resolutionStrategy { - eachPlugin { - if (requested.id.id == "kotlin-multiplatform") { - useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}") - } - } - } -} diff --git a/uhabits-core-legacy/src/main/c_interop/sqlite3.def b/uhabits-core-legacy/src/main/c_interop/sqlite3.def deleted file mode 100644 index 08646e486..000000000 --- a/uhabits-core-legacy/src/main/c_interop/sqlite3.def +++ /dev/null @@ -1,25 +0,0 @@ -package = sqlite3 -headers = sqlite3.h -headerFilter = sqlite3*.h -compilerOpts = -std=c11 -linkerOpts.ios = -lsqlite3 -excludedFunctions = sqlite3_mutex_held \ - sqlite3_mutex_notheld \ - sqlite3_snapshot_cmp \ - sqlite3_snapshot_free \ - sqlite3_snapshot_get \ - sqlite3_snapshot_open \ - sqlite3_snapshot_recover \ - sqlite3_set_last_insert_rowid \ - sqlite3_stmt_scanstatus \ - sqlite3_stmt_scanstatus_reset \ - sqlite3_column_database_name \ - sqlite3_column_database_name16 \ - sqlite3_column_origin_name \ - sqlite3_column_origin_name16 \ - sqlite3_column_table_name \ - sqlite3_column_table_name16 \ - sqlite3_enable_load_extension \ - sqlite3_load_extension \ - sqlite3_unlock_notify -noStringConversion = sqlite3_prepare_v2 sqlite3_prepare_v3 diff --git a/uhabits-core-legacy/src/main/common/org/isoron/platform/concurrency/Observable.kt b/uhabits-core-legacy/src/main/common/org/isoron/platform/concurrency/Observable.kt deleted file mode 100644 index 9aa11a5e6..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/platform/concurrency/Observable.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.concurrency - -class Observable { - private val listeners = mutableListOf() - - fun addListener(listener: T) { - listeners.add(listener) - } - - fun notifyListeners(action: (T) -> Unit) { - for (l in listeners) action.invoke(l) - } - - fun removeListener(listener: T) { - listeners.remove(listener) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/platform/gui/Canvas.kt b/uhabits-core-legacy/src/main/common/org/isoron/platform/gui/Canvas.kt deleted file mode 100644 index b397febb4..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/platform/gui/Canvas.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.gui - -enum class TextAlign { - LEFT, CENTER, RIGHT -} - -enum class Font { - REGULAR, - BOLD, - FONT_AWESOME -} - -interface Canvas { - fun setColor(color: Color) - fun drawLine(x1: Double, y1: Double, x2: Double, y2: Double) - fun drawText(text: String, x: Double, y: Double) - fun fillRect(x: Double, y: Double, width: Double, height: Double) - fun drawRect(x: Double, y: Double, width: Double, height: Double) - fun getHeight(): Double - fun getWidth(): Double - fun setFont(font: Font) - fun setFontSize(size: Double) - fun setStrokeWidth(size: Double) - fun fillArc(centerX: Double, - centerY: Double, - radius: Double, - startAngle: Double, - swipeAngle: Double) - fun fillCircle(centerX: Double, centerY: Double, radius: Double) - fun setTextAlign(align: TextAlign) - fun toImage(): Image -} - diff --git a/uhabits-core-legacy/src/main/common/org/isoron/platform/gui/Colors.kt b/uhabits-core-legacy/src/main/common/org/isoron/platform/gui/Colors.kt deleted file mode 100644 index 4161c1218..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/platform/gui/Colors.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.gui - -data class PaletteColor(val index: Int) - -data class Color(val red: Double, - val green: Double, - val blue: Double, - val alpha: Double) { - - val luminosity: Double - get() { - return 0.21 * red + 0.72 * green + 0.07 * blue - } - - constructor(rgb: Int) : this(((rgb shr 16) and 0xFF) / 255.0, - ((rgb shr 8) and 0xFF) / 255.0, - ((rgb shr 0) and 0xFF) / 255.0, - 1.0) - - fun blendWith(other: Color, weight: Double): Color { - return Color(red * (1 - weight) + other.red * weight, - green * (1 - weight) + other.green * weight, - blue * (1 - weight) + other.blue * weight, - alpha * (1 - weight) + other.alpha * weight) - } -} diff --git a/uhabits-core-legacy/src/main/common/org/isoron/platform/gui/Component.kt b/uhabits-core-legacy/src/main/common/org/isoron/platform/gui/Component.kt deleted file mode 100644 index d7ab56a68..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/platform/gui/Component.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.gui - -interface Component { - fun draw(canvas: Canvas) -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/platform/gui/FontAwesome.kt b/uhabits-core-legacy/src/main/common/org/isoron/platform/gui/FontAwesome.kt deleted file mode 100644 index 3791228df..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/platform/gui/FontAwesome.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.gui - -class FontAwesome { - companion object { - val CHECK = "\uf00c" - val TIMES = "\uf00d" - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/platform/gui/Image.kt b/uhabits-core-legacy/src/main/common/org/isoron/platform/gui/Image.kt deleted file mode 100644 index 044df1c6f..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/platform/gui/Image.kt +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.gui - -import kotlin.math.* - -interface Image { - val width: Int - val height: Int - - fun getPixel(x: Int, y: Int): Color - fun setPixel(x: Int, y: Int, color: Color) - - suspend fun export(path: String) - - fun diff(other: Image) { - if (width != other.width) error("Width must match: $width !== ${other.width}") - if (height != other.height) error("Height must match: $height !== ${other.height}") - - for (x in 0 until width) { - for (y in 0 until height) { - val p1 = getPixel(x, y) - var l = 1.0 - for (dx in -2..2) { - if (x + dx < 0 || x + dx >= width) continue - for (dy in -2..2) { - if (y + dy < 0 || y + dy >= height) continue - val p2 = other.getPixel(x + dx, y + dy) - l = min(l, abs(p1.luminosity - p2.luminosity)) - } - } - setPixel(x, y, Color(l, l, l, 1.0)) - } - } - } - - val averageLuminosity: Double - get() { - var luminosity = 0.0 - for (x in 0 until width) { - for (y in 0 until height) { - luminosity += getPixel(x, y).luminosity - } - } - return luminosity / (width * height) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/platform/io/Database.kt b/uhabits-core-legacy/src/main/common/org/isoron/platform/io/Database.kt deleted file mode 100644 index ab0409214..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/platform/io/Database.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.io - -interface PreparedStatement { - fun step(): StepResult - fun finalize() - fun getInt(index: Int): Int - fun getLong(index: Int): Long - fun getText(index: Int): String - fun getReal(index: Int): Double - fun bindInt(index: Int, value: Int) - fun bindLong(index: Int, value: Long) - fun bindText(index: Int, value: String) - fun bindReal(index: Int, value: Double) - fun reset() -} - -enum class StepResult { - ROW, - DONE -} - -interface DatabaseOpener { - fun open(file: UserFile): Database -} - -interface Database { - fun prepareStatement(sql: String): PreparedStatement - fun close() -} - -fun Database.run(sql: String) { - val stmt = prepareStatement(sql) - stmt.step() - stmt.finalize() -} - -fun Database.queryInt(sql: String): Int { - val stmt = prepareStatement(sql) - stmt.step() - val result = stmt.getInt(0) - stmt.finalize() - return result -} - -fun Database.nextId(tableName: String): Int { - val stmt = prepareStatement("select seq from sqlite_sequence where name='$tableName'") - if (stmt.step() == StepResult.ROW) { - val result = stmt.getInt(0) - stmt.finalize() - return result + 1 - } else { - return 0 - } -} - -fun Database.begin() = run("begin") - -fun Database.commit() = run("commit") - -fun Database.getVersion() = queryInt("pragma user_version") - -fun Database.setVersion(v: Int) = run("pragma user_version = $v") - -suspend fun Database.migrateTo(newVersion: Int, - fileOpener: FileOpener, - log: Log) { - val currentVersion = getVersion() - log.debug("Database", "Current database version: $currentVersion") - - if (currentVersion == newVersion) return - log.debug("Database", "Upgrading to version: $newVersion") - - if (currentVersion > newVersion) - throw RuntimeException("database produced by future version of the application") - - begin() - for (v in (currentVersion + 1)..newVersion) { - val sv = if (v < 10) "00$v" else if (v < 100) "0$v" else "$v" - val filename = "migrations/$sv.sql" - val migrationFile = fileOpener.openResourceFile(filename) - for (line in migrationFile.lines()) { - if (line.isEmpty()) continue - run(line) - } - setVersion(v) - } - commit() -} diff --git a/uhabits-core-legacy/src/main/common/org/isoron/platform/io/Files.kt b/uhabits-core-legacy/src/main/common/org/isoron/platform/io/Files.kt deleted file mode 100644 index babecf082..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/platform/io/Files.kt +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.io - -import org.isoron.platform.gui.* - -interface FileOpener { - /** - * Opens a file which was shipped bundled with the application, such as a - * migration file. - * - * The path is relative to the assets folder. For example, to open - * assets/main/migrations/09.sql you should provide migrations/09.sql - * as the path. - * - * This function always succeed, even if the file does not exist. - */ - fun openResourceFile(path: String): ResourceFile - - /** - * Opens a file which was not shipped with the application, such as - * databases and logs. - * - * The path is relative to the user folder. For example, if the application - * stores the user data at /home/user/.loop/ and you wish to open the file - * /home/user/.loop/crash.log, you should provide crash.log as the path. - * - * This function always succeed, even if the file does not exist. - */ - fun openUserFile(path: String): UserFile -} - -/** - * Represents a file that was created after the application was installed, as a - * result of some user action, such as databases and logs. - */ -interface UserFile { - /** - * Deletes the user file. If the file does not exist, nothing happens. - */ - suspend fun delete() - - /** - * Returns true if the file exists. - */ - suspend fun exists(): Boolean - - /** - * Returns the lines of the file. If the file does not exist, throws an - * exception. - */ - suspend fun lines(): List -} - -/** - * Represents a file that was shipped with the application, such as migration - * files or database templates. - */ -interface ResourceFile { - /** - * Copies the resource file to the specified user file. If the user file - * already exists, it is replaced. If not, a new file is created. - */ - suspend fun copyTo(dest: UserFile) - - /** - * Returns the lines of the resource file. If the file does not exist, - * throws an exception. - */ - suspend fun lines(): List - - /** - * Returns true if the file exists. - */ - suspend fun exists(): Boolean - - /** - * Loads resource file as an image. - */ - suspend fun toImage(): Image -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/platform/io/Log.kt b/uhabits-core-legacy/src/main/common/org/isoron/platform/io/Log.kt deleted file mode 100644 index 60c372237..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/platform/io/Log.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.io - -interface Log { - fun info(tag: String, msg: String) - fun debug(tag: String, msg: String) - fun warn(tag: String, msg: String) -} - -/** - * A Log that prints to the standard output. - */ -class StandardLog : Log { - override fun warn(tag: String, msg: String) { - val ftag = format("%-20s", tag) - println("W $ftag $msg") - } - - override fun info(tag: String, msg: String) { - val ftag = format("%-20s", tag) - println("I $ftag $msg") - } - - override fun debug(tag: String, msg: String) { - val ftag = format("%-20s", tag) - println("D $ftag $msg") - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/platform/io/Strings.kt b/uhabits-core-legacy/src/main/common/org/isoron/platform/io/Strings.kt deleted file mode 100644 index 1a631e131..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/platform/io/Strings.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.io - -expect fun format(format: String, arg: String): String -expect fun format(format: String, arg: Int): String -expect fun format(format: String, arg: Double): String \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/platform/time/Dates.kt b/uhabits-core-legacy/src/main/common/org/isoron/platform/time/Dates.kt deleted file mode 100644 index ea102004f..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/platform/time/Dates.kt +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.time - -import kotlin.math.* - -enum class DayOfWeek(val index: Int) { - SUNDAY(0), - MONDAY(1), - TUESDAY(2), - WEDNESDAY(3), - THURSDAY(4), - FRIDAY(5), - SATURDAY(6), -} - -data class Timestamp(val millisSince1970: Long) { - val localDate: LocalDate - get() { - val millisSince2000 = millisSince1970 - 946684800000 - val daysSince2000 = millisSince2000 / 86400000 - return LocalDate(daysSince2000.toInt()) - } -} - -data class LocalDate(val daysSince2000: Int) { - - var yearCache = -1 - var monthCache = -1 - var dayCache = -1 - -// init { -// if (daysSince2000 < 0) -// throw IllegalArgumentException("$daysSince2000 < 0") -// } - - constructor(year: Int, month: Int, day: Int) : - this(daysSince2000(year, month, day)) - - val dayOfWeek: DayOfWeek - get() { - return when (daysSince2000 % 7) { - 0 -> DayOfWeek.SATURDAY - 1 -> DayOfWeek.SUNDAY - 2 -> DayOfWeek.MONDAY - 3 -> DayOfWeek.TUESDAY - 4 -> DayOfWeek.WEDNESDAY - 5 -> DayOfWeek.THURSDAY - else -> DayOfWeek.FRIDAY - } - } - - val timestamp: Timestamp - get() { - return Timestamp(946684800000 + daysSince2000.toLong() * 86400000) - } - - val year: Int - get() { - if (yearCache < 0) updateYearMonthDayCache() - return yearCache - } - - val month: Int - get() { - if (monthCache < 0) updateYearMonthDayCache() - return monthCache - } - - val day: Int - get() { - if (dayCache < 0) updateYearMonthDayCache() - return dayCache - } - - private fun updateYearMonthDayCache() { - var currYear = 2000 - var currDay = 0 - - while (true) { - val currYearLength = if (isLeapYear(currYear)) 366 else 365 - if (daysSince2000 < currDay + currYearLength) { - yearCache = currYear - break - } else { - currYear++ - currDay += currYearLength - } - } - - var currMonth = 1 - val monthOffset = if (isLeapYear(currYear)) leapOffset else nonLeapOffset - - while (true) { - if (daysSince2000 < currDay + monthOffset[currMonth]) { - monthCache = currMonth - break - } else { - currMonth++ - } - } - - currDay += monthOffset[currMonth - 1] - dayCache = daysSince2000 - currDay + 1 - - } - - fun isOlderThan(other: LocalDate): Boolean { - return daysSince2000 < other.daysSince2000 - } - - fun isNewerThan(other: LocalDate): Boolean { - return daysSince2000 > other.daysSince2000 - } - - fun plus(days: Int): LocalDate { - return LocalDate(daysSince2000 + days) - } - - fun minus(days: Int): LocalDate { - return LocalDate(daysSince2000 - days) - } - - fun distanceTo(other: LocalDate): Int { - return abs(daysSince2000 - other.daysSince2000) - } -} - -interface LocalDateFormatter { - fun shortWeekdayName(date: LocalDate): String - fun shortMonthName(date: LocalDate): String -} - -private fun isLeapYear(year: Int): Boolean { - return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0 -} - -val leapOffset = arrayOf(0, 31, 60, 91, 121, 152, 182, - 213, 244, 274, 305, 335, 366) -val nonLeapOffset = arrayOf(0, 31, 59, 90, 120, 151, 181, - 212, 243, 273, 304, 334, 365) - -private fun daysSince2000(year: Int, month: Int, day: Int): Int { - - var result = 365 * (year - 2000) - result += ceil((year - 2000) / 4.0).toInt() - result -= ceil((year - 2000) / 100.0).toInt() - result += ceil((year - 2000) / 400.0).toInt() - if (isLeapYear(year)) { - result += leapOffset[month - 1] - } else { - result += nonLeapOffset[month - 1] - } - result += (day - 1) - return result -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/Config.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/Config.kt deleted file mode 100644 index fe543e044..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/Config.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits - -const val LOOP_DATABASE_VERSION = 23 \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/backend/Backend.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/backend/Backend.kt deleted file mode 100644 index 0137d3463..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/backend/Backend.kt +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.backend - -import kotlinx.coroutines.* -import org.isoron.platform.concurrency.* -import org.isoron.platform.io.* -import org.isoron.uhabits.* -import org.isoron.uhabits.components.* -import org.isoron.uhabits.i18n.* -import org.isoron.uhabits.models.* -import kotlin.coroutines.* - - -open class BackendScope(private val ctx: CoroutineContext, - private val log: Log) : CoroutineScope { - - private val job = Job() - - private val exceptionHandler = CoroutineExceptionHandler { _, throwable -> - log.info("Coroutine", throwable.toString()) - } - - override val coroutineContext: CoroutineContext - get() = ctx + job + exceptionHandler -} - -class Backend(private val databaseName: String, - private val databaseOpener: DatabaseOpener, - private val fileOpener: FileOpener, - private val localeHelper: LocaleHelper, - private val log: Log, - private val scope: CoroutineContext - ) : CoroutineScope by BackendScope(scope, log) { - - - private lateinit var database: Database - private lateinit var habitsRepository: HabitRepository - private lateinit var checkmarkRepository: CheckmarkRepository - lateinit var preferences: Preferences - - lateinit var mainScreenDataSource: MainScreenDataSource - - private val habits = mutableMapOf() - private val checkmarks = mutableMapOf() - private val scores = mutableMapOf() - - var strings = localeHelper.getStringsForCurrentLocale() - var theme: Theme = LightTheme() - - val observable = Observable() - - fun init() { - launch { - initDatabase() - initRepositories() - initDataSources() - observable.notifyListeners { it.onReady() } - } - } - - private fun initRepositories() { - preferences = Preferences(PreferencesRepository(database)) - habitsRepository = HabitRepository(database) - checkmarkRepository = CheckmarkRepository(database) - habits.putAll(habitsRepository.findAll()) - log.info("Backend", "${habits.size} habits loaded") - for ((key, habit) in habits) { - val checks = checkmarkRepository.findAll(key) - checkmarks[habit] = CheckmarkList(habit.frequency, habit.type) - checkmarks[habit]?.setManualCheckmarks(checks) - scores[habit] = ScoreList(checkmarks[habit]!!) - } - } - - private fun initDataSources() { - mainScreenDataSource = - MainScreenDataSource(preferences, habits, checkmarks, scores) - } - - private suspend fun initDatabase() { - val dbFile = fileOpener.openUserFile(databaseName) - if (!dbFile.exists()) { - val templateFile = fileOpener.openResourceFile("databases/template.db") - templateFile.copyTo(dbFile) - } - database = databaseOpener.open(dbFile) - database.migrateTo(LOOP_DATABASE_VERSION, fileOpener, log) - } - - fun createHabit(habit: Habit) { - val id = habitsRepository.nextId() - habit.id = id - habit.position = habits.size - habits[id] = habit - checkmarks[habit] = CheckmarkList(habit.frequency, habit.type) - habitsRepository.insert(habit) - mainScreenDataSource.requestData() - } - - fun deleteHabit(id: Int) { - habits[id]?.let { habit -> - habitsRepository.delete(habit) - habits.remove(id) - mainScreenDataSource.requestData() - } - } - - fun updateHabit(modified: Habit) { - habits[modified.id]?.let { existing -> - modified.position = existing.position - habitsRepository.update(modified) - } - } - - interface Listener { - fun onReady() - } -} diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/backend/MainScreenDataSource.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/backend/MainScreenDataSource.kt deleted file mode 100644 index 9cadb8cb3..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/backend/MainScreenDataSource.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.backend - -import org.isoron.platform.concurrency.* -import org.isoron.platform.time.* -import org.isoron.uhabits.models.* -import org.isoron.uhabits.models.Checkmark.Companion.UNCHECKED - -class MainScreenDataSource(val preferences: Preferences, - val habits: MutableMap, - val checkmarks: MutableMap, - val scores: MutableMap) { - - val maxNumberOfButtons = 60 - private val today = LocalDate(2019, 3, 30) /* TODO */ - - data class Data(val habits: List, - val scores: Map, - val checkmarks: Map>) - - val observable = Observable() - - interface Listener { - fun onDataChanged(newData: Data) - } - - fun requestData() { - var filtered = habits.values.toList() - - if (!preferences.showArchived) { - filtered = filtered.filter { !it.isArchived } - } - - val checkmarks = filtered.associate { habit -> - val allValues = checkmarks.getValue(habit).getUntil(today) - if (allValues.size <= maxNumberOfButtons) habit to allValues - else habit to allValues.subList(0, maxNumberOfButtons) - } - - if (!preferences.showCompleted) { - filtered = filtered.filter { habit -> - (habit.type == HabitType.BOOLEAN_HABIT && checkmarks.getValue(habit)[0].value == UNCHECKED) || - (habit.type == HabitType.NUMERICAL_HABIT && checkmarks.getValue(habit)[0].value * 1000 < habit.target) - } - } - - val scores = filtered.associate { habit -> - habit to scores[habit]!!.getAt(today) - } - - observable.notifyListeners { listener -> - val data = Data(filtered, scores, checkmarks) - listener.onDataChanged(data) - } - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/BarChart.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/BarChart.kt deleted file mode 100644 index ba3f631a2..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/BarChart.kt +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.components - -import org.isoron.platform.gui.* -import org.isoron.platform.time.* -import kotlin.math.* - -class BarChart(var theme: Theme, - var dateFormatter: LocalDateFormatter) : Component { - - // Data - var series = mutableListOf>() - var colors = mutableListOf() - var axis = listOf() - - // Style - var paddingTop = 20.0 - var paddingLeft = 5.0 - var paddingRight = 5.0 - var footerHeight = 40.0 - var barGroupMargin = 4.0 - var barMargin = 4.0 - var barWidth = 20.0 - var nGridlines = 6 - var backgroundColor = theme.cardBackgroundColor - - override fun draw(canvas: Canvas) { - val width = canvas.getWidth() - val height = canvas.getHeight() - - val n = series.size - val barGroupWidth = 2 * barGroupMargin + n * (barWidth + 2 * barMargin) - val safeWidth = width - paddingLeft - paddingRight - val nColumns = floor((safeWidth) / barGroupWidth).toInt() - val marginLeft = (safeWidth - nColumns * barGroupWidth) / 2 - val maxBarHeight = height - footerHeight - paddingTop - var maxValue = series.map { it.max()!! }.max()!! - maxValue = max(maxValue, 1.0) - - canvas.setColor(backgroundColor) - canvas.fillRect(0.0, 0.0, width, height) - - fun barGroupOffset(c: Int) = marginLeft + paddingLeft + - (c) * barGroupWidth - - fun barOffset(c: Int, s: Int) = barGroupOffset(c) + - barGroupMargin + - s * (barWidth + 2 * barMargin) + - barMargin - - fun drawColumn(s: Int, c: Int) { - val value = if (c < series[s].size) series[s][c] else 0.0 - val perc = value / maxValue - val barColorPerc = if (n > 1) 1.0 else round(perc / 0.20) * 0.20 - val barColor = theme.lowContrastTextColor.blendWith(colors[s], - barColorPerc) - val barHeight = round(maxBarHeight * perc) - val x = barOffset(c, s) - val y = height - footerHeight - barHeight - canvas.setColor(barColor) - val r = round(barWidth * 0.33) - canvas.fillRect(x, y + r, barWidth, barHeight - r) - canvas.fillRect(x + r, y, barWidth - 2 * r, r) - canvas.fillCircle(x + r, y + r, r) - canvas.fillCircle(x + barWidth - r, y + r, r) - canvas.setFontSize(theme.smallTextSize) - canvas.setTextAlign(TextAlign.CENTER) - canvas.setColor(backgroundColor) - canvas.fillRect(x - barMargin, - y - theme.smallTextSize * 1.25, - barWidth + 2 * barMargin, - theme.smallTextSize * 1.0) - canvas.setColor(theme.mediumContrastTextColor) - canvas.drawText(value.toShortString(), - x + barWidth / 2, - y - theme.smallTextSize * 0.80) - } - - fun drawSeries(s: Int) { - for (c in 0 until nColumns) drawColumn(s, c) - } - - fun drawMajorGrid() { - canvas.setStrokeWidth(1.0) - if (n > 1) { - canvas.setColor(backgroundColor.blendWith( - theme.lowContrastTextColor, - 0.5)) - for (c in 0 until nColumns - 1) { - val x = barGroupOffset(c) - canvas.drawLine(x, paddingTop, x, paddingTop + maxBarHeight) - } - } - for (k in 1 until nGridlines) { - val pct = 1.0 - (k.toDouble() / (nGridlines - 1)) - val y = paddingTop + maxBarHeight * pct - canvas.setColor(theme.lowContrastTextColor) - canvas.drawLine(0.0, y, width, y) - } - } - - fun drawFooter() { - val y = paddingTop + maxBarHeight - canvas.setColor(backgroundColor) - canvas.fillRect(0.0, y, width, height - y) - canvas.setColor(theme.lowContrastTextColor) - canvas.drawLine(0.0, y, width, y) - canvas.setColor(theme.mediumContrastTextColor) - canvas.setTextAlign(TextAlign.CENTER) - var prevMonth = -1 - var prevYear = -1 - val isLargeInterval = (axis[0].distanceTo(axis[1]) > 300) - - for (c in 0 until nColumns) { - val x = barGroupOffset(c) - val date = axis[c] - if(isLargeInterval) { - canvas.drawText(date.year.toString(), - x + barGroupWidth / 2, - y + theme.smallTextSize * 1.0) - } else { - if (date.month != prevMonth) { - canvas.drawText(dateFormatter.shortMonthName(date), - x + barGroupWidth / 2, - y + theme.smallTextSize * 1.0) - } else { - canvas.drawText(date.day.toString(), - x + barGroupWidth / 2, - y + theme.smallTextSize * 1.0) - } - if (date.year != prevYear) { - canvas.drawText(date.year.toString(), - x + barGroupWidth / 2, - y + theme.smallTextSize * 2.3) - } - } - prevMonth = date.month - prevYear = date.year - } - } - - drawMajorGrid() - for (k in 0 until n) drawSeries(k) - drawFooter() - } -} diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/CalendarChart.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/CalendarChart.kt deleted file mode 100644 index 20594df19..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/CalendarChart.kt +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.components - -import org.isoron.platform.gui.* -import org.isoron.platform.time.* -import kotlin.math.* - -class CalendarChart(var today: LocalDate, - var color: Color, - var theme: Theme, - var dateFormatter: LocalDateFormatter) : Component { - - var padding = 5.0 - var backgroundColor = Color(0xFFFFFF) - var squareSpacing = 1.0 - var series = listOf() - var scrollPosition = 0 - private var squareSize = 0.0 - - override fun draw(canvas: Canvas) { - val width = canvas.getWidth() - val height = canvas.getHeight() - canvas.setColor(backgroundColor) - canvas.fillRect(0.0, 0.0, width, height) - squareSize = round((height - 2 * padding) / 8.0) - canvas.setFontSize(height * 0.06) - - val nColumns = floor((width - 2 * padding) / squareSize).toInt() - 2 - val todayWeekday = today.dayOfWeek - val topLeftOffset = (nColumns - 1 + scrollPosition) * 7 + todayWeekday.index - val topLeftDate = today.minus(topLeftOffset) - - repeat(nColumns) { column -> - val topOffset = topLeftOffset - 7 * column - val topDate = topLeftDate.plus(7 * column) - drawColumn(canvas, column, topDate, topOffset) - } - - canvas.setColor(theme.mediumContrastTextColor) - repeat(7) { row -> - val date = topLeftDate.plus(row) - canvas.setTextAlign(TextAlign.LEFT) - canvas.drawText(dateFormatter.shortWeekdayName(date), - padding + nColumns * squareSize + padding, - padding + squareSize * (row+1) + squareSize / 2) - } - } - - private fun drawColumn(canvas: Canvas, - column: Int, - topDate: LocalDate, - topOffset: Int) { - drawHeader(canvas, column, topDate) - repeat(7) { row -> - val offset = topOffset - row - val date = topDate.plus(row) - if (offset < 0) return - drawSquare(canvas, - padding + column * squareSize, - padding + (row + 1) * squareSize, - squareSize - squareSpacing, - squareSize - squareSpacing, - date, - offset) - } - } - - private fun drawHeader(canvas: Canvas, column: Int, date: LocalDate) { - if (date.day >= 8) return - - canvas.setColor(theme.mediumContrastTextColor) - if (date.month == 1) { - canvas.drawText(date.year.toString(), - padding + column * squareSize + squareSize / 2, - padding + squareSize / 2) - - } else { - canvas.drawText(dateFormatter.shortMonthName(date), - padding + column * squareSize + squareSize / 2, - padding + squareSize / 2) - } - } - - private fun drawSquare(canvas: Canvas, - x: Double, - y: Double, - width: Double, - height: Double, - date: LocalDate, - offset: Int) { - - var value = if (offset >= series.size) 0.0 else series[offset] - value = round(value * 5.0) / 5.0 - - var squareColor = color.blendWith(backgroundColor, 1 - value) - var textColor = backgroundColor - - if (value == 0.0) squareColor = theme.lowContrastTextColor - if (squareColor.luminosity > 0.8) - textColor = squareColor.blendWith(theme.highContrastTextColor, 0.5) - - canvas.setColor(squareColor) - canvas.fillRect(x, y, width, height) - canvas.setColor(textColor) - canvas.drawText(date.day.toString(), x + width / 2, y + width / 2) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/CheckmarkButton.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/CheckmarkButton.kt deleted file mode 100644 index 5fdf99de0..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/CheckmarkButton.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.components - -import org.isoron.platform.gui.* - -class CheckmarkButton(private val value: Int, - private val color: Color, - private val theme: Theme) : Component { - override fun draw(canvas: Canvas) { - canvas.setFont(Font.FONT_AWESOME) - canvas.setFontSize(theme.smallTextSize * 1.5) - canvas.setColor(when (value) { - 2 -> color - else -> theme.lowContrastTextColor - }) - val text = when (value) { - 0 -> FontAwesome.TIMES - else -> FontAwesome.CHECK - } - canvas.drawText(text, canvas.getWidth() / 2.0, canvas.getHeight() / 2.0) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/HabitListHeader.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/HabitListHeader.kt deleted file mode 100644 index f3e401fa4..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/HabitListHeader.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.components - -import org.isoron.platform.gui.* -import org.isoron.platform.time.* - -class HabitListHeader(private val today: LocalDate, - private val nButtons: Int, - private val theme: Theme, - private val fmt: LocalDateFormatter) : Component { - - override fun draw(canvas: Canvas) { - val width = canvas.getWidth() - val height = canvas.getHeight() - val buttonSize = theme.checkmarkButtonSize - canvas.setColor(theme.headerBackgroundColor) - canvas.fillRect(0.0, 0.0, width, height) - - canvas.setColor(theme.headerBorderColor) - canvas.setStrokeWidth(0.5) - canvas.drawLine(0.0, height - 0.5, width, height - 0.5) - - canvas.setColor(theme.headerTextColor) - canvas.setFont(Font.BOLD) - canvas.setFontSize(theme.smallTextSize) - - repeat(nButtons) { index -> - val date = today.minus(nButtons - index - 1) - val name = fmt.shortWeekdayName(date).toUpperCase() - val number = date.day.toString() - - val x = width - (index + 1) * buttonSize + buttonSize / 2 - val y = height / 2 - canvas.drawText(name, x, y - theme.smallTextSize * 0.6) - canvas.drawText(number, x, y + theme.smallTextSize * 0.6) - } - } -} diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/NumberButton.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/NumberButton.kt deleted file mode 100644 index 313d6f22d..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/NumberButton.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.components - -import org.isoron.platform.gui.* -import org.isoron.platform.io.* -import kotlin.math.* - -fun Double.toShortString(): String = when { - this >= 1e9 -> format("%.1fG", this / 1e9) - this >= 1e8 -> format("%.0fM", this / 1e6) - this >= 1e7 -> format("%.1fM", this / 1e6) - this >= 1e6 -> format("%.1fM", this / 1e6) - this >= 1e5 -> format("%.0fk", this / 1e3) - this >= 1e4 -> format("%.1fk", this / 1e3) - this >= 1e3 -> format("%.1fk", this / 1e3) - this >= 1e2 -> format("%.0f", this) - this >= 1e1 -> when { - round(this) == this -> format("%.0f", this) - else -> format("%.1f", this) - } - else -> when { - round(this) == this -> format("%.0f", this) - round(this * 10) == this * 10 -> format("%.1f", this) - else -> format("%.2f", this) - } -} - -class NumberButton(val color: Color, - val value: Double, - val threshold: Double, - val units: String, - val theme: Theme) : Component { - - override fun draw(canvas: Canvas) { - val width = canvas.getWidth() - val height = canvas.getHeight() - val em = theme.smallTextSize - - canvas.setColor(when { - value >= threshold -> color - value >= 0.01 -> theme.mediumContrastTextColor - else -> theme.lowContrastTextColor - }) - - canvas.setFontSize(theme.regularTextSize) - canvas.setFont(Font.BOLD) - canvas.drawText(value.toShortString(), width / 2, height / 2 - 0.6 * em) - - canvas.setFontSize(theme.smallTextSize) - canvas.setFont(Font.REGULAR) - canvas.drawText(units, width / 2, height / 2 + 0.6 * em) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/Ring.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/Ring.kt deleted file mode 100644 index 806770163..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/Ring.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.components - -import org.isoron.platform.gui.* -import org.isoron.platform.io.* -import kotlin.math.* - -class Ring(val color: Color, - val percentage: Double, - val thickness: Double, - val radius: Double, - val theme: Theme, - val label: Boolean = false) : Component { - - override fun draw(canvas: Canvas) { - val width = canvas.getWidth() - val height = canvas.getHeight() - val angle = 360.0 * max(0.0, min(360.0, percentage)) - - canvas.setColor(theme.lowContrastTextColor) - canvas.fillCircle(width/2, height/2, radius) - - canvas.setColor(color) - canvas.fillArc(width/2, height/2, radius, 90.0, -angle) - - canvas.setColor(theme.cardBackgroundColor) - canvas.fillCircle(width/2, height/2, radius - thickness) - - if(label) { - canvas.setColor(color) - canvas.setFontSize(radius * 0.4) - canvas.drawText(format("%.0f%%", percentage * 100), width / 2, height / 2) - } - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/Themes.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/Themes.kt deleted file mode 100644 index a2d5eedc0..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/components/Themes.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.components - -import org.isoron.platform.gui.* - -abstract class Theme { - val toolbarColor = Color(0xffffff) - - val lowContrastTextColor = Color(0xe0e0e0) - val mediumContrastTextColor = Color(0x808080) - val highContrastTextColor = Color(0x202020) - - val cardBackgroundColor = Color(0xFFFFFF) - val appBackgroundColor = Color(0xf4f4f4) - val toolbarBackgroundColor = Color(0xf4f4f4) - val statusBarBackgroundColor = Color(0x333333) - - val headerBackgroundColor = Color(0xeeeeee) - val headerBorderColor = Color(0xcccccc) - val headerTextColor = mediumContrastTextColor - - val itemBackgroundColor = Color(0xffffff) - - fun color(paletteIndex: Int): Color { - return when (paletteIndex) { - 0 -> Color(0xD32F2F) - 1 -> Color(0x512DA8) - 2 -> Color(0xF57C00) - 3 -> Color(0xFF8F00) - 4 -> Color(0xF9A825) - 5 -> Color(0xAFB42B) - 6 -> Color(0x7CB342) - 7 -> Color(0x388E3C) - 8 -> Color(0x00897B) - 9 -> Color(0x00ACC1) - 10 -> Color(0x039BE5) - 11 -> Color(0x1976D2) - 12 -> Color(0x303F9F) - 13 -> Color(0x5E35B1) - 14 -> Color(0x8E24AA) - 15 -> Color(0xD81B60) - 16 -> Color(0x5D4037) - else -> Color(0x000000) - } - } - - val checkmarkButtonSize = 48.0 - val smallTextSize = 12.0 - val regularTextSize = 17.0 -} - -class LightTheme : Theme() \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/i18n/LocaleHelper.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/i18n/LocaleHelper.kt deleted file mode 100644 index a73af82a3..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/i18n/LocaleHelper.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.i18n - -interface LocaleHelper { - fun getStringsForCurrentLocale(): Strings -} diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/i18n/Strings.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/i18n/Strings.kt deleted file mode 100644 index 823ac364c..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/i18n/Strings.kt +++ /dev/null @@ -1,190 +0,0 @@ -package org.isoron.uhabits.i18n - -@Suppress("PropertyName", "unused") -open class Strings() { - open val about = "About" - open val action = "Action" - open val action_settings = "Settings" - open val add_habit = "Add habit" - open val all_time = "All time" - open val any_day = "Any day of the week" - open val any_weekday = "Monday to Friday" - open val app_name = "Loop Habit Tracker" - open val archive = "Archive" - open val behavior = "Behavior" - open val best_streaks = "Best streaks" - open val bug_report_failed = "Failed to generate bug report." - open val by_color = "By color" - open val by_name = "By name" - open val by_score = "By score" - open val calendar = "Calendar" - open val cancel = "Cancel" - open val change_value = "Change value" - open val check = "Check" - open val checkmark = "Checkmark" - open val checkmark_stack_widget = "Checkmark Stack Widget" - open val clear = "Clear" - open val clear_label = "Clear" - open val color_picker_default_title = "Change color" - open val could_not_export = "Failed to export data." - open val could_not_import = "Failed to import data." - open val count = "Count" - open val create_habit = "Create habit" - open val create_stackview_widget_button = "StackView Widget For All Habits" - open val current_streaks = "Current streak" - open val custom_frequency = "Custom …" - open val customize_notification = "Customize notifications" - open val customize_notification_summary = "Change sound, vibration, light and other notification settings" - open val database_repaired = "Database repaired." - open val day = "Day" - open val days = "days" - open val delete = "Delete" - open val delete_habits = "Delete Habits" - open val delete_habits_message = "The habits will be permanently deleted. This action cannot be undone." - open val description_hint = "Question (Did you … today?)" - open val developers = "Developers" - open val discard = "Discard" - open val done_label = "Done" - open val download = "Download" - open val edit = "Edit" - open val edit_habit = "Edit habit" - open val every_day = "Every day" - open val every_week = "Every week" - open val every_x_days = "Every %d days" - open val every_x_months = "Every %d months" - open val every_x_weeks = "Every %d weeks" - open val example_question_boolean = "e.g. Did you exercise today?" - open val example_question_numerical = "e.g. How many steps did you walk today?" - open val example_units = "e.g. steps" - open val export = "Export" - open val export_as_csv_summary = "Generates files that can be opened by spreadsheet software such as Microsoft Excel or OpenOffice Calc. This file cannot be imported back." - open val export_full_backup = "Export full backup" - open val export_full_backup_summary = "Generates a file that contains all your data. This file can be imported back." - open val export_to_csv = "Export as CSV" - open val file_not_recognized = "File not recognized." - open val filter = "Filter" - open val five_times_per_week = "5 times per week" - open val frequency = "Frequency" - open val frequency_stack_widget = "Frequency Stack Widget" - open val full_backup_success = "Full backup successfully exported." - open val generate_bug_report = "Generate bug report" - open val habit = "Habit" - open val habit_not_found = "Habit deleted / not found" - open val habit_strength = "Habit strength" - open val habits_imported = "Habits imported successfully." - open val help = "Help & FAQ" - open val help_translate = "Help translate this app" - open val hide_archived = "Hide archived" - open val hide_completed = "Hide completed" - open val hint_drag = "To rearrange the entries, press-and-hold on the name of the habit, then drag it to the correct place." - open val hint_landscape = "You can see more days by putting your phone in landscape mode." - open val hint_title = "Did you know?" - open val history = "History" - open val history_stack_widget = "History Stack Widget" - open val import_data = "Import data" - open val import_data_summary = "Supports full backups exported by this app, as well as files generated by Tickmate, HabitBull or Rewire. See FAQ for more information." - open val interface_preferences = "Interface" - open val interval_15_minutes = "15 minutes" - open val interval_1_hour = "1 hour" - open val interval_24_hour = "24 hours" - open val interval_2_hour = "2 hours" - open val interval_30_minutes = "30 minutes" - open val interval_4_hour = "4 hours" - open val interval_8_hour = "8 hours" - open val interval_always_ask = "Always ask" - open val interval_custom = "Custom..." - open val intro_description_1 = "Loop Habit Tracker helps you create and maintain good habits." - open val intro_description_2 = "Every day, after performing your habit, put a checkmark on the app." - open val intro_description_3 = "Habits performed consistently for a long time will earn a full star." - open val intro_description_4 = "Detailed graphs show you how your habits improved over time." - open val intro_title_1 = "Welcome" - open val intro_title_2 = "Create some new habits" - open val intro_title_3 = "Keep doing it" - open val intro_title_4 = "Track your progress" - open val last_x_days = "Last %d days" - open val last_x_months = "Last %d months" - open val last_x_weeks = "Last %d weeks" - open val last_x_years = "Last %d years" - open val led_notifications = "Notification light" - open val led_notifications_description = "Shows a blinking light for reminders. Only available in phones with LED notification lights." - open val links = "Links" - open val long_press_to_edit = "Press-and-hold to change the value" - open val long_press_to_toggle = "Press-and-hold to check or uncheck" - open val main_activity_title = "Habits" - open val manually = "Manually" - open val month = "Month" - open val name = "Name" - open val night_mode = "Night mode" - open val no = "No" - open val no_habits_found = "You have no active habits" - open val none = "None" - open val number_of_repetitions = "Number of repetitions" - open val overview = "Overview" - open val pref_rate_this_app = "Rate this app on Google Play" - open val pref_send_feedback = "Send feedback to developer" - open val pref_snooze_interval_title = "Snooze interval on reminders" - open val pref_toggle_description = "Put checkmarks with a single tap instead of press-and-hold. More convenient, but might cause accidental toggles." - open val pref_toggle_title = "Toggle with short press" - open val pref_view_app_introduction = "View app introduction" - open val pref_view_source_code = "View source code at GitHub" - open val pure_black_description = "Replaces gray backgrounds with pure black in night mode. Reduces battery usage in phones with AMOLED display." - open val quarter = "Quarter" - open val question = "Question" - open val reminder = "Reminder" - open val reminder_off = "Off" - open val reminder_sound = "Reminder sound" - open val repair_database = "Repair database" - open val repeat = "Repeat" - open val reverse_days = "Reverse order of days" - open val reverse_days_description = "Show days in reverse order on the main screen." - open val save = "Save" - open val score = "Score" - open val score_stack_widget = "Score Stack Widget" - open val select_habit_requirement_prompt = "Please select at least one habit" - open val select_hours = "Select hours" - open val select_minutes = "Select minutes" - open val select_snooze_delay = "Select snooze delay" - open val select_weekdays = "Select days" - open val settings = "Settings" - open val show_archived = "Show archived" - open val show_completed = "Show completed" - open val snooze = "Later" - open val snooze_interval = "Snooze interval" - open val sort = "Sort" - open val sticky_notifications = "Make notifications sticky" - open val sticky_notifications_description = "Prevents notifications from being swiped away." - open val streaks = "Streaks" - open val streaks_stack_widget = "Streaks Stack Widget" - open val strength = "Strength" - open val target = "Target" - open val time_every = "time in" - open val times_every = "times in" - open val toast_habit_archived = "Habits archived" - open val toast_habit_changed = "Habit changed" - open val toast_habit_changed_back = "Habit changed back" - open val toast_habit_created = "Habit created" - open val toast_habit_deleted = "Habits deleted" - open val toast_habit_restored = "Habits restored" - open val toast_habit_unarchived = "Habits unarchived" - open val toast_nothing_to_redo = "Nothing to redo" - open val toast_nothing_to_undo = "Nothing to undo" - open val toggle = "Toggle" - open val total = "Total" - open val translators = "Translators" - open val troubleshooting = "Troubleshooting" - open val two_times_per_week = "2 times per week" - open val unarchive = "Unarchive" - open val uncheck = "Uncheck" - open val unit = "Unit" - open val use_pure_black = "Use pure black in night mode" - open val validation_at_most_one_rep_per_day = "You can have at most one repetition per day" - open val validation_name_should_not_be_blank = "Name cannot be blank." - open val validation_number_should_be_positive = "Number must be positive." - open val validation_show_not_be_blank = "This field should not be blank" - open val version_n = "Version %s" - open val week = "Week" - open val weekends = "Weekends" - open val year = "Year" - open val yes = "Yes" - open val day_mode = "Day mode" -} diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Checkmark.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Checkmark.kt deleted file mode 100644 index f2fd97673..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Checkmark.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -import org.isoron.platform.time.* - -data class Checkmark(var date: LocalDate, - var value: Int) { - - companion object { - /** - * Value assigned when the user has explicitly marked the habit as - * completed. - */ - const val CHECKED_MANUAL = 2 - - /** - * Value assigned when the user has not explicitly marked the habit as - * completed, however, due to the frequency of the habit, an automatic - * checkmark was added. - */ - const val CHECKED_AUTOMATIC = 1 - - /** - * Value assigned when the user has not completed the habit, and the app - * has not automatically a checkmark. - */ - const val UNCHECKED = 0 - } -} diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/CheckmarkList.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/CheckmarkList.kt deleted file mode 100644 index 55eda4ae8..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/CheckmarkList.kt +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -import org.isoron.platform.time.* -import org.isoron.uhabits.models.Checkmark.Companion.CHECKED_AUTOMATIC -import org.isoron.uhabits.models.Checkmark.Companion.CHECKED_MANUAL -import org.isoron.uhabits.models.Checkmark.Companion.UNCHECKED - -class CheckmarkList(val frequency: Frequency, - val habitType: HabitType) { - - private val manualCheckmarks = mutableListOf() - private val computedCheckmarks = mutableListOf() - - /** - * Replaces the entire list of manual checkmarks by the ones provided. The - * list of automatic checkmarks will be automatically updated. - */ - fun setManualCheckmarks(checks: List) { - manualCheckmarks.clear() - computedCheckmarks.clear() - manualCheckmarks.addAll(checks) - if (habitType == HabitType.NUMERICAL_HABIT) { - computedCheckmarks.addAll(checks) - } else { - val computed = computeCheckmarks(checks, frequency) - computedCheckmarks.addAll(computed) - } - } - - /** - * Returns values of all checkmarks (manual and automatic) from the oldest - * entry until the date provided. - * - * The interval is inclusive, and the list is sorted from newest to oldest. - * That is, the first element of the returned list corresponds to the date - * provided. - */ - fun getUntil(date: LocalDate): List { - if (computedCheckmarks.isEmpty()) return listOf() - - val result = mutableListOf() - val newest = computedCheckmarks.first().date - val distToNewest = newest.distanceTo(date) - - var k = 0 - var fromIndex = 0 - val toIndex = computedCheckmarks.size - if (newest.isOlderThan(date)) { - repeat(distToNewest) { result.add(Checkmark(date.minus(k++), UNCHECKED)) } - } else { - fromIndex = distToNewest - } - val subList = computedCheckmarks.subList(fromIndex, toIndex) - result.addAll(subList.map { Checkmark(date.minus(k++), it.value) }) - return result - } - - companion object { - /** - * Computes the list of automatic checkmarks a list of manual ones. - */ - fun computeCheckmarks(checks: List, - frequency: Frequency - ): MutableList { - - val intervals = buildIntervals(checks, frequency) - snapIntervalsTogether(intervals) - return buildCheckmarksFromIntervals(checks, intervals) - } - - /** - * Modifies the intervals so that gaps between intervals are eliminated. - * - * More specifically, this function shifts the beginning and the end of - * intervals so that they overlap the least as possible. The center of - * the interval, however, still falls within the interval. The length of - * the intervals are also not modified. - */ - fun snapIntervalsTogether(intervals: MutableList) { - - for (i in 1 until intervals.size) { - val (begin, center, end) = intervals[i] - val (_, _, prevEnd) = intervals[i - 1] - - val gap = prevEnd.distanceTo(begin) - 1 - if (gap <= 0 || end.minus(gap).isOlderThan(center)) continue - intervals[i] = Interval(begin.minus(gap), - center, - end.minus(gap)) - } - } - - /** - * Converts a list of (manually checked) checkmarks and computed - * intervals into a list of unchecked, manually checked and - * automatically checked checkmarks. - * - * Manual checkmarks are simply copied over to the output list. Days - * that are an interval, but which do not have manual checkmarks receive - * automatic checkmarks. Days that fall in the gaps between intervals - * receive unchecked checkmarks. - */ - fun buildCheckmarksFromIntervals(checks: List, - intervals: List - ): MutableList { - - if (checks.isEmpty()) throw IllegalArgumentException() - if (intervals.isEmpty()) throw IllegalArgumentException() - - var oldest = intervals[0].begin - var newest = intervals[0].end - for (interval in intervals) { - if (interval.begin.isOlderThan(oldest)) oldest = interval.begin - if (interval.end.isNewerThan(newest)) newest = interval.end - } - for (check in checks) { - if (check.date.isOlderThan(oldest)) oldest = check.date - if (check.date.isNewerThan(newest)) newest = check.date - } - - val distance = oldest.distanceTo(newest) - val checkmarks = mutableListOf() - for (offset in 0..distance) - checkmarks.add(Checkmark(newest.minus(offset), - UNCHECKED)) - - for (interval in intervals) { - val beginOffset = newest.distanceTo(interval.begin) - val endOffset = newest.distanceTo(interval.end) - - for (offset in endOffset..beginOffset) { - checkmarks.set(offset, - Checkmark(newest.minus(offset), - CHECKED_AUTOMATIC)) - } - } - - for (check in checks) { - val offset = newest.distanceTo(check.date) - checkmarks.set(offset, Checkmark(check.date, CHECKED_MANUAL)) - } - - return checkmarks - } - - /** - * Constructs a list of intervals based on a list of (manual) - * checkmarks. - */ - fun buildIntervals(checks: List, - frequency: Frequency): MutableList { - - val num = frequency.numerator - val den = frequency.denominator - - val intervals = mutableListOf() - for (i in 0..(checks.size - num)) { - val first = checks[i] - val last = checks[i + num - 1] - - if (first.date.distanceTo(last.date) >= den) continue - - val end = first.date.plus(den - 1) - intervals.add(Interval(first.date, last.date, end)) - } - - return intervals - } - } - - /* - * For non-daily habits, some groups of repetitions generate many - * automatic checkmarks. For weekly habits, each repetition generates - * seven checkmarks. For twice-a-week habits, two repetitions that are close - * enough together also generate seven checkmarks. This group of generated - * checkmarks is represented by an interval. - * - * The fields `begin` and `end` indicate the length of the interval, and are - * inclusive. The field `center` indicates the newest day within the interval - * that has a manual checkmark. - */ - data class Interval(val begin: LocalDate, - val center: LocalDate, - val end: LocalDate) -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/CheckmarkRepository.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/CheckmarkRepository.kt deleted file mode 100644 index 0b35bc275..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/CheckmarkRepository.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -import org.isoron.platform.io.* -import org.isoron.platform.time.* - -class CheckmarkRepository(db: Database) { - - private val findStatement = db.prepareStatement("select timestamp, value from Repetitions where habit = ? order by timestamp desc") - private val insertStatement = db.prepareStatement("insert into Repetitions(habit, timestamp, value) values (?, ?, ?)") - private val deleteStatement = db.prepareStatement("delete from Repetitions where habit=? and timestamp=?") - - fun findAll(habitId: Int): List { - findStatement.bindInt(0, habitId) - val result = mutableListOf() - while (findStatement.step() == StepResult.ROW) { - val date = Timestamp(findStatement.getLong(0)).localDate - val value = findStatement.getInt(1) - result.add(Checkmark(date, value)) - } - findStatement.reset() - return result - } - - fun insert(habitId: Int, checkmark: Checkmark) { - val timestamp = checkmark.date.timestamp - insertStatement.bindInt(0, habitId) - insertStatement.bindLong(1, timestamp.millisSince1970) - insertStatement.bindInt(2, checkmark.value) - insertStatement.step() - insertStatement.reset() - } - - fun delete(habitId: Int, date: LocalDate) { - val timestamp = date.timestamp - deleteStatement.bindInt(0, habitId) - deleteStatement.bindLong(1, timestamp.millisSince1970) - deleteStatement.step() - deleteStatement.reset() - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Frequency.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Frequency.kt deleted file mode 100644 index f09a32a51..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Frequency.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -data class Frequency(val numerator: Int, - val denominator: Int) { - - fun toDouble(): Double { - return numerator.toDouble() / denominator - } - - companion object { - val WEEKLY = Frequency(1, 7) - val DAILY = Frequency(1, 1) - val TWO_TIMES_PER_WEEK = Frequency(2, 7) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Habit.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Habit.kt deleted file mode 100644 index 7ddfa6188..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Habit.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -import org.isoron.platform.gui.* - -data class Habit(var id: Int, - var name: String, - var description: String, - var frequency: Frequency, - var color: PaletteColor, - var isArchived: Boolean, - var position: Int, - var unit: String, - var target: Double, - var type: HabitType) \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/HabitRepository.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/HabitRepository.kt deleted file mode 100644 index 961956f51..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/HabitRepository.kt +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -import org.isoron.platform.gui.* -import org.isoron.platform.io.Database -import org.isoron.platform.io.PreparedStatement -import org.isoron.platform.io.StepResult -import org.isoron.platform.io.nextId - -class HabitRepository(var db: Database) { - - companion object { - const val SELECT_COLUMNS = "id, name, description, freq_num, freq_den, color, archived, position, unit, target_value, type" - const val SELECT_PLACEHOLDERS = "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?" - const val UPDATE_COLUMNS = "id=?, name=?, description=?, freq_num=?, freq_den=?, color=?, archived=?, position=?, unit=?, target_value=?, type=?" - } - - private val findAllStatement = db.prepareStatement("select $SELECT_COLUMNS from habits order by position") - private val insertStatement = db.prepareStatement("insert into Habits($SELECT_COLUMNS) values ($SELECT_PLACEHOLDERS)") - private val updateStatement = db.prepareStatement("update Habits set $UPDATE_COLUMNS where id=?") - private val deleteStatement = db.prepareStatement("delete from Habits where id=?") - - fun nextId(): Int { - return db.nextId("Habits") - } - - fun findAll(): MutableMap { - val result = mutableMapOf() - while (findAllStatement.step() == StepResult.ROW) { - val habit = buildHabitFromStatement(findAllStatement) - result[habit.id] = habit - } - findAllStatement.reset() - return result - } - - fun insert(habit: Habit) { - bindHabitToStatement(habit, insertStatement) - insertStatement.step() - insertStatement.reset() - } - - fun update(habit: Habit) { - bindHabitToStatement(habit, updateStatement) - updateStatement.bindInt(11, habit.id) - updateStatement.step() - updateStatement.reset() - } - - private fun buildHabitFromStatement(stmt: PreparedStatement): Habit { - return Habit(id = stmt.getInt(0), - name = stmt.getText(1), - description = stmt.getText(2), - frequency = Frequency(stmt.getInt(3), stmt.getInt(4)), - color = PaletteColor(stmt.getInt(5)), - isArchived = stmt.getInt(6) != 0, - position = stmt.getInt(7), - unit = stmt.getText(8), - target = stmt.getReal(9), - type = if (stmt.getInt(10) == 0) HabitType.BOOLEAN_HABIT else HabitType.NUMERICAL_HABIT) - } - - private fun bindHabitToStatement(habit: Habit, statement: PreparedStatement) { - statement.bindInt(0, habit.id) - statement.bindText(1, habit.name) - statement.bindText(2, habit.description) - statement.bindInt(3, habit.frequency.numerator) - statement.bindInt(4, habit.frequency.denominator) - statement.bindInt(5, habit.color.index) - statement.bindInt(6, if (habit.isArchived) 1 else 0) - statement.bindInt(7, habit.position) - statement.bindText(8, habit.unit) - statement.bindReal(9, habit.target) - statement.bindInt(10, habit.type.code) - } - - fun delete(habit: Habit) { - deleteStatement.bindInt(0, habit.id) - deleteStatement.step() - deleteStatement.reset() - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/HabitType.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/HabitType.kt deleted file mode 100644 index a02beff5c..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/HabitType.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -enum class HabitType(val code: Int) { - BOOLEAN_HABIT(0), - NUMERICAL_HABIT(1), -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Preferences.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Preferences.kt deleted file mode 100644 index 2c5e51449..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Preferences.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -class Preferences(private val repository: PreferencesRepository) { - var showArchived = repository.getBoolean("show_archived", false) - set(value) { - repository.putBoolean("show_archived", value) - field = value - } - - var showCompleted = repository.getBoolean("show_completed", true) - set(value) { - repository.putBoolean("show_completed", value) - field = value - } - - var nightMode = repository.getBoolean("night_mode", false) - set(value) { - repository.putBoolean("night_mode", value) - field = value - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/PreferencesRepository.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/PreferencesRepository.kt deleted file mode 100644 index 8c0d77f06..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/PreferencesRepository.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -import org.isoron.platform.io.* - -class PreferencesRepository(private val db: Database) { - - private val insertStatement = db.prepareStatement("insert into Preferences(key, value) values (?, ?)") - private val deleteStatement = db.prepareStatement("delete from Preferences where key=?") - private val selectStatement = db.prepareStatement("select value from Preferences where key=?") - - fun putBoolean(key: String, value: Boolean) { - putString(key, value.toString()) - } - - fun getBoolean(key: String, default: Boolean): Boolean { - val value = getString(key, "NULL") - return if (value == "NULL") default else value.toBoolean() - } - - fun putLong(key: String, value: Long) { - putString(key, value.toString()) - } - - fun getLong(key: String, default: Long): Long { - val value = getString(key, "NULL") - return if (value == "NULL") default else value.toLong() - } - - fun putString(key: String, value: String) { - deleteStatement.bindText(0, key) - deleteStatement.step() - deleteStatement.reset() - insertStatement.bindText(0, key) - insertStatement.bindText(1, value) - insertStatement.step() - insertStatement.reset() - } - - fun getString(key: String, default: String): String { - selectStatement.bindText(0, key) - if (selectStatement.step() == StepResult.DONE) { - selectStatement.reset() - return default - } else { - val value = selectStatement.getText(0) - selectStatement.reset() - return value - } - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Score.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Score.kt deleted file mode 100644 index 35382dc8a..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Score.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -import org.isoron.platform.time.* - -/** - * A Score is a number which indicates how strong the habit is at a given date. - * - * Scores are computed by taking an exponential moving average of the values of - * the checkmarks in preceding days. For boolean habits, when computing the - * average, each checked day (whether the check was manual or automatic) has - * value as 1, while days without checkmarks have value 0. - * - * For numerical habits, each day that exceeded the target has value 1, while - * days which failed to exceed the target receive a partial value, based on the - * proportion that was completed. For example, if the target is 100 units and - * the user completed 70 units, then the value for that day is 0.7 when - * computing the average. - */ -data class Score(val date: LocalDate, - val value: Double) \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/ScoreList.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/ScoreList.kt deleted file mode 100644 index 46fb993d7..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/ScoreList.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -import org.isoron.platform.time.* -import kotlin.math.* - -class ScoreList(private val checkmarkList: CheckmarkList) { - /** - * Returns a list of all scores, from the beginning of the habit history - * until the specified date. - * - * The interval is inclusive, and the list is sorted from newest to oldest. - * That is, the first element of the returned list corresponds to the date - * provided. - */ - fun getUntil(date: LocalDate): List { - val frequency = checkmarkList.frequency - val checks = checkmarkList.getUntil(date) - val scores = mutableListOf() - val type = checkmarkList.habitType - - var currentScore = 0.0 - checks.reversed().forEach { check -> - val value = if (type == HabitType.BOOLEAN_HABIT) { - min(1, check.value) - } else { - check.value - } - currentScore = compute(frequency, currentScore, value) - scores.add(Score(check.date, currentScore)) - } - return scores.reversed() - } - - fun getAt(date: LocalDate): Score { - return getUntil(date)[0] - } - - companion object { - /** - * Given the frequency of the habit, the previous score, and the value of - * the current checkmark, computes the current score for the habit. - */ - fun compute(frequency: Frequency, - previousScore: Double, - checkmarkValue: Int): Double { - val multiplier = 0.5.pow(frequency.toDouble() / 13.0) - val score = previousScore * multiplier + checkmarkValue * (1 - multiplier) - return floor(score * 1e6) / 1e6 - } - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Streak.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Streak.kt deleted file mode 100644 index 1bcdc2d37..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/Streak.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -import org.isoron.platform.time.* - -/** - * A streak is an uninterrupted sequence of days where the habit was performed. - * - * For daily boolean habits, the definition is straightforward: a streak is a - * sequence of days that have checkmarks. For non-daily habits, note - * that automatic checkmarks (the ones added by the app) can also keep the - * streak going. For numerical habits, a streak is a sequence of days where the - * user has consistently exceeded the target for the habit. - */ -data class Streak(val start: LocalDate, - val end: LocalDate) \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/StreakList.kt b/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/StreakList.kt deleted file mode 100644 index 0d037b6c8..000000000 --- a/uhabits-core-legacy/src/main/common/org/isoron/uhabits/models/StreakList.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -class StreakList(private val checkmarkList: CheckmarkList) { - - /** - * Returns the longest streaks. - * - * The argument specifies the maximum number of streaks to find. The - * returned list is sorted by date (descending). That is, the first element - * corresponds to the most recent streak. - */ - fun getBest(limit: Int): List { - TODO() - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/ios/org/isoron/platform/concurrency/UIDispatcher.kt b/uhabits-core-legacy/src/main/ios/org/isoron/platform/concurrency/UIDispatcher.kt deleted file mode 100644 index d4aece983..000000000 --- a/uhabits-core-legacy/src/main/ios/org/isoron/platform/concurrency/UIDispatcher.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.concurrency - -import kotlinx.coroutines.* -import platform.darwin.* -import kotlin.coroutines.* - -class UIDispatcher : CoroutineDispatcher() { - override fun dispatch(context: CoroutineContext, block: Runnable) { - val queue = dispatch_get_main_queue() - dispatch_async(queue) { - block.run() - } - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/ios/org/isoron/platform/gui/IosCanvas.kt b/uhabits-core-legacy/src/main/ios/org/isoron/platform/gui/IosCanvas.kt deleted file mode 100644 index 085021dc2..000000000 --- a/uhabits-core-legacy/src/main/ios/org/isoron/platform/gui/IosCanvas.kt +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.gui - -import kotlinx.cinterop.* -import platform.CoreGraphics.* -import platform.Foundation.* -import platform.UIKit.* -import kotlin.math.* - -val Color.uicolor: UIColor - get() = UIColor.colorWithRed(this.red, this.green, this.blue, this.alpha) - -val Color.cgcolor: CGColorRef? - get() = uicolor.CGColor - -class IosCanvas(val width: Double, - val height: Double, - val scale: Double = 2.0 - ) : Canvas { - - var textColor = UIColor.blackColor - var font = Font.REGULAR - var fontSize = 12.0 - var textAlign = TextAlign.CENTER - val ctx = UIGraphicsGetCurrentContext()!! - - override fun setColor(color: Color) { - CGContextSetStrokeColorWithColor(ctx, color.cgcolor) - CGContextSetFillColorWithColor(ctx, color.cgcolor) - textColor = color.uicolor - } - - override fun drawLine(x1: Double, y1: Double, x2: Double, y2: Double) { - CGContextMoveToPoint(ctx, x1 * scale, y1 * scale) - CGContextAddLineToPoint(ctx, x2 * scale, y2 * scale) - CGContextStrokePath(ctx) - } - - @Suppress("CAST_NEVER_SUCCEEDS") - override fun drawText(text: String, x: Double, y: Double) { - val sx = scale * x - val sy = scale * y - val nsText = (text as NSString) - val uiFont = when (font) { - Font.REGULAR -> UIFont.systemFontOfSize(fontSize) - Font.BOLD -> UIFont.boldSystemFontOfSize(fontSize) - Font.FONT_AWESOME -> UIFont.fontWithName("FontAwesome", fontSize) - } - val size = nsText.sizeWithFont(uiFont) - val width = size.useContents { width } - val height = size.useContents { height } - val origin = when (textAlign) { - TextAlign.CENTER -> CGPointMake(sx - width / 2, sy - height / 2) - TextAlign.LEFT -> CGPointMake(sx, sy - height / 2) - TextAlign.RIGHT -> CGPointMake(sx - width, sy - height / 2) - } - nsText.drawAtPoint(origin, uiFont) - } - - override fun fillRect(x: Double, y: Double, width: Double, height: Double) { - CGContextFillRect(ctx, - CGRectMake(x * scale, - y * scale, - width * scale, - height * scale)) - } - - override fun drawRect(x: Double, y: Double, width: Double, height: Double) { - CGContextStrokeRect(ctx, - CGRectMake(x * scale, - y * scale, - width * scale, - height * scale)) - } - - override fun getHeight(): Double { - return height - } - - override fun getWidth(): Double { - return width - } - - override fun setFont(font: Font) { - this.font = font - } - - override fun setFontSize(size: Double) { - this.fontSize = size * scale - } - - override fun setStrokeWidth(size: Double) { - CGContextSetLineWidth(ctx, size * scale) - } - - override fun fillArc(centerX: Double, - centerY: Double, - radius: Double, - startAngle: Double, - swipeAngle: Double) { - val a1 = startAngle / 180 * PI * (-1) - val a2 = a1 - swipeAngle / 180 * PI - CGContextBeginPath(ctx) - CGContextMoveToPoint(ctx, centerX * scale, centerY * scale) - CGContextAddArc(ctx, - centerX * scale, - centerY * scale, - radius * scale, - a1, - a2, - if (swipeAngle > 0) 1 else 0) - CGContextClosePath(ctx) - CGContextFillPath(ctx) - } - - override fun fillCircle(centerX: Double, centerY: Double, radius: Double) { - val rect = CGRectMake(scale * (centerX - radius), - scale * (centerY - radius), - scale * radius * 2.0, - scale * radius * 2.0) - CGContextFillEllipseInRect(ctx, rect) - } - - override fun setTextAlign(align: TextAlign) { - this.textAlign = align - } - - override fun toImage(): Image { - return IosImage(UIGraphicsGetImageFromCurrentImageContext()!!) - } -} diff --git a/uhabits-core-legacy/src/main/ios/org/isoron/platform/gui/IosImage.kt b/uhabits-core-legacy/src/main/ios/org/isoron/platform/gui/IosImage.kt deleted file mode 100644 index 33e1c2254..000000000 --- a/uhabits-core-legacy/src/main/ios/org/isoron/platform/gui/IosImage.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.gui - -import platform.UIKit.* -import platform.CoreGraphics.* -import platform.Foundation.* - -class IosImage(val image: UIImage) : Image { - - override val width: Int - get() { - return CGImageGetWidth(image.CGImage).toInt() - } - - override val height: Int - get() { - return CGImageGetHeight(image.CGImage).toInt() - } - - override fun getPixel(x: Int, y: Int): Color { - return Color(1.0, 0.0, 0.0, 1.0) - } - - override fun setPixel(x: Int, y: Int, color: Color) { - } - - @Suppress("CAST_NEVER_SUCCEEDS") - override suspend fun export(path: String) { - val tmpPath = "${NSTemporaryDirectory()}/$path" - val dir = (tmpPath as NSString).stringByDeletingLastPathComponent - NSFileManager.defaultManager.createDirectoryAtPath(dir, true, null, null) - val data = UIImagePNGRepresentation(image)!! - val success = data.writeToFile(tmpPath, true) - if (!success) throw RuntimeException("could not write to $tmpPath") - println(tmpPath) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/ios/org/isoron/platform/io/IosDatabase.kt b/uhabits-core-legacy/src/main/ios/org/isoron/platform/io/IosDatabase.kt deleted file mode 100644 index 34a12376f..000000000 --- a/uhabits-core-legacy/src/main/ios/org/isoron/platform/io/IosDatabase.kt +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.io - -import kotlinx.cinterop.* -import platform.Foundation.* -import sqlite3.* - -fun sqlite3_errstr(db: CPointer): String { - return "SQLite3 error: " + sqlite3_errmsg(db).toString() -} - -@Suppress("CAST_NEVER_SUCCEEDS") -class IosDatabaseOpener : DatabaseOpener { - override fun open(file: UserFile): Database = memScoped { - val path = (file as IosFile).path - val dirname = (path as NSString).stringByDeletingLastPathComponent - NSFileManager.defaultManager.createDirectoryAtPath(dirname, true, null, null) - - val db = alloc>() - val result = sqlite3_open(path, db.ptr) - if (result != SQLITE_OK) - throw Exception("sqlite3_open failed (code $result)") - - return IosDatabase(db.value!!) - } -} - -class IosDatabase(val db: CPointer) : Database { - override fun prepareStatement(sql: String): PreparedStatement = memScoped { - if (sql.isEmpty()) throw Exception("empty SQL query") - val stmt = alloc>() - val result = sqlite3_prepare_v2(db, sql.cstr, -1, stmt.ptr, null) - if (result != SQLITE_OK) - throw Exception("sqlite3_prepare_v2 failed (code $result)") - return IosPreparedStatement(db, stmt.value!!) - } - override fun close() { - sqlite3_close(db) - } -} - -class IosPreparedStatement(val db: CPointer, - val stmt: CPointer) : PreparedStatement { - override fun step(): StepResult { - when (sqlite3_step(stmt)) { - SQLITE_ROW -> return StepResult.ROW - SQLITE_DONE -> return StepResult.DONE - else -> throw Exception(sqlite3_errstr(db)) - } - } - - override fun finalize() { - sqlite3_finalize(stmt) - } - - override fun getInt(index: Int): Int { - return sqlite3_column_int(stmt, index) - } - - override fun getLong(index: Int): Long { - return sqlite3_column_int64(stmt, index) - } - - override fun getText(index: Int): String { - return sqlite3_column_text(stmt, index)!! - .reinterpret() - .toKString() - } - - override fun getReal(index: Int): Double { - return sqlite3_column_double(stmt, index) - } - - override fun bindInt(index: Int, value: Int) { - sqlite3_bind_int(stmt, index + 1, value) - } - - override fun bindLong(index: Int, value: Long) { - sqlite3_bind_int64(stmt, index + 1, value) - } - - override fun bindText(index: Int, value: String) { - sqlite3_bind_text(stmt, index + 1, value, -1, SQLITE_TRANSIENT) - } - - override fun bindReal(index: Int, value: Double) { - sqlite3_bind_double(stmt, index + 1, value) - } - - override fun reset() { - sqlite3_reset(stmt) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/ios/org/isoron/platform/io/IosFiles.kt b/uhabits-core-legacy/src/main/ios/org/isoron/platform/io/IosFiles.kt deleted file mode 100644 index 16d189133..000000000 --- a/uhabits-core-legacy/src/main/ios/org/isoron/platform/io/IosFiles.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - - -package org.isoron.platform.io - -import org.isoron.platform.gui.* -import platform.Foundation.* -import platform.UIKit.* - -class IosFileOpener : FileOpener { - override fun openResourceFile(path: String): ResourceFile { - val resPath = NSBundle.mainBundle.resourcePath!! - return IosFile("$resPath/$path") - } - - override fun openUserFile(path: String): UserFile { - val manager = NSFileManager.defaultManager - val basePath = manager.URLsForDirectory(NSDocumentDirectory, NSUserDomainMask) - val filePath = (basePath.first() as NSURL).URLByAppendingPathComponent(path)!!.path!! - return IosFile(filePath) - } -} - -class IosFile(val path: String) : UserFile, ResourceFile { - override suspend fun delete() { - NSFileManager.defaultManager.removeItemAtPath(path, null) - } - - override suspend fun exists(): Boolean { - return NSFileManager.defaultManager.fileExistsAtPath(path) - } - - override suspend fun lines(): List { - if (!exists()) throw Exception("File not found: $path") - val contents = NSString.stringWithContentsOfFile(path) - return contents.toString().lines() - } - - @Suppress("CAST_NEVER_SUCCEEDS") - override suspend fun copyTo(dest: UserFile) { - val destPath = (dest as IosFile).path - val manager = NSFileManager.defaultManager - val destParentPath = (destPath as NSString).stringByDeletingLastPathComponent - NSFileManager.defaultManager.createDirectoryAtPath(destParentPath, true, null, null) - manager.copyItemAtPath(path, destPath, null) - } - - override suspend fun toImage(): Image { - return IosImage(UIImage.imageWithContentsOfFile(path)!!) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/ios/org/isoron/platform/io/Strings.kt b/uhabits-core-legacy/src/main/ios/org/isoron/platform/io/Strings.kt deleted file mode 100644 index e774348ea..000000000 --- a/uhabits-core-legacy/src/main/ios/org/isoron/platform/io/Strings.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.io - -import kotlinx.cinterop.* - -// Although the three following methods have exactly the same implementation, -// replacing them all by a single format(format: String, arg: Any) breaks -// everything, as of Kotlin/Native 1.3.72. Apparently, Kotlin/Native is not -// able to do proper type conversions for variables of type Any when calling -// C functions. - -actual fun format(format: String, arg: String): String { - val buffer = ByteArray(1000) - buffer.usePinned { p -> platform.posix.sprintf(p.addressOf(0), format, arg) } - return buffer.toKString() -} - -actual fun format(format: String, arg: Int): String { - val buffer = ByteArray(1000) - buffer.usePinned { p -> platform.posix.sprintf(p.addressOf(0), format, arg) } - return buffer.toKString() -} - -actual fun format(format: String, arg: Double): String { - val buffer = ByteArray(1000) - buffer.usePinned { p -> platform.posix.sprintf(p.addressOf(0), format, arg) } - return buffer.toKString() -} diff --git a/uhabits-core-legacy/src/main/ios/org/isoron/platform/time/IosDates.kt b/uhabits-core-legacy/src/main/ios/org/isoron/platform/time/IosDates.kt deleted file mode 100644 index 424d6db92..000000000 --- a/uhabits-core-legacy/src/main/ios/org/isoron/platform/time/IosDates.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.time - -import platform.Foundation.* - -fun LocalDate.toNsDate(): NSDate { - val calendar = NSCalendar.calendarWithIdentifier(NSCalendarIdentifierGregorian)!! - val dc = NSDateComponents() - dc.year = year.toLong() - dc.month = month.toLong() - dc.day = day.toLong() - dc.hour = 13 - dc.minute = 0 - return calendar.dateFromComponents(dc)!! -} - -class IosLocalDateFormatter(val locale: String) : LocalDateFormatter { - - constructor() : this(NSLocale.preferredLanguages[0] as String) - - private val fmt = NSDateFormatter() - - init { - fmt.setLocale(NSLocale.localeWithLocaleIdentifier(locale)) - } - - override fun shortWeekdayName(date: LocalDate): String { - fmt.dateFormat = "EEE" - return fmt.stringFromDate(date.toNsDate()) - } - - override fun shortMonthName(date: LocalDate): String { - fmt.dateFormat = "MMM" - return fmt.stringFromDate(date.toNsDate()) - } - -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/ios/org/isoron/uhabits/IosLocaleHelper.kt b/uhabits-core-legacy/src/main/ios/org/isoron/uhabits/IosLocaleHelper.kt deleted file mode 100644 index 4937339f6..000000000 --- a/uhabits-core-legacy/src/main/ios/org/isoron/uhabits/IosLocaleHelper.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -@file:Suppress("UNCHECKED_CAST") - -package org.isoron.uhabits - -import org.isoron.platform.io.* -import org.isoron.uhabits.i18n.* -import platform.Foundation.* - -class IosLocaleHelper(private val log: Log) : LocaleHelper { - override fun getStringsForCurrentLocale(): Strings { - val pref = NSLocale.preferredLanguages as List - val lang = if (pref.isEmpty()) "en-US" else pref[0] - log.info("IosLocaleHelper", lang) - return when { - else -> Strings() - } - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/js/org/isoron/platform/gui/JsCanvas.kt b/uhabits-core-legacy/src/main/js/org/isoron/platform/gui/JsCanvas.kt deleted file mode 100644 index 33a42a7f5..000000000 --- a/uhabits-core-legacy/src/main/js/org/isoron/platform/gui/JsCanvas.kt +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.gui - -import kotlinx.coroutines.* -import org.w3c.dom.* -import kotlin.js.* -import kotlin.math.* - -class JsCanvas(val element: HTMLCanvasElement, - val pixelScale: Double) : Canvas { - - - val ctx = element.getContext("2d") as CanvasRenderingContext2D - var fontSize = 12.0 - var fontFamily = "NotoRegular" - var align = CanvasTextAlign.CENTER - - private fun toPixel(x: Double): Double { - return pixelScale * x - } - - private fun toDp(x: Int): Double { - return x / pixelScale - } - - override fun setColor(color: Color) { - val c = "rgb(${color.red * 255}, ${color.green * 255}, ${color.blue * 255})" - ctx.fillStyle = c; - ctx.strokeStyle = c; - } - - override fun drawLine(x1: Double, y1: Double, x2: Double, y2: Double) { - ctx.beginPath() - ctx.moveTo(toPixel(x1), toPixel(y1)) - ctx.lineTo(toPixel(x2), toPixel(y2)) - ctx.stroke() - } - - override fun drawText(text: String, x: Double, y: Double) { - ctx.font = "${fontSize}px ${fontFamily}" - ctx.textAlign = align - ctx.textBaseline = CanvasTextBaseline.MIDDLE - ctx.fillText(text, toPixel(x), toPixel(y + fontSize * 0.025)) - } - - override fun fillRect(x: Double, y: Double, width: Double, height: Double) { - ctx.fillRect(toPixel(x), - toPixel(y), - toPixel(width), - toPixel(height)) - } - - override fun drawRect(x: Double, y: Double, width: Double, height: Double) { - ctx.strokeRect(toPixel(x), - toPixel(y), - toPixel(width), - toPixel(height)) - } - - override fun getHeight(): Double { - return toDp(element.height) - } - - override fun getWidth(): Double { - return toDp(element.width) - } - - override fun setFont(font: Font) { - fontFamily = when (font) { - Font.REGULAR -> "NotoRegular" - Font.BOLD -> "NotoBold" - Font.FONT_AWESOME -> "FontAwesome" - } - } - - override fun setFontSize(size: Double) { - fontSize = size * pixelScale - } - - override fun setStrokeWidth(size: Double) { - ctx.lineWidth = size * pixelScale - } - - override fun fillArc(centerX: Double, - centerY: Double, - radius: Double, - startAngle: Double, - swipeAngle: Double) { - val x = toPixel(centerX) - val y = toPixel(centerY) - val from = startAngle / 180 * PI - val to = (startAngle + swipeAngle) / 180 * PI - ctx.beginPath() - ctx.moveTo(x, y) - ctx.arc(x, y, toPixel(radius), -from, -to, swipeAngle >= 0) - ctx.lineTo(x, y) - ctx.fill() - } - - override fun fillCircle(centerX: Double, centerY: Double, radius: Double) { - ctx.beginPath() - ctx.arc(toPixel(centerX), - toPixel(centerY), - toPixel(radius), - 0.0, - 2 * PI) - ctx.fill() - } - - override fun setTextAlign(align: TextAlign) { - this.align = when (align) { - TextAlign.LEFT -> CanvasTextAlign.LEFT - TextAlign.CENTER -> CanvasTextAlign.CENTER - TextAlign.RIGHT -> CanvasTextAlign.RIGHT - } - } - - override fun toImage(): Image { - return JsImage(this, - ctx.getImageData(0.0, - 0.0, - element.width.toDouble(), - element.height.toDouble())) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/js/org/isoron/platform/gui/JsImage.kt b/uhabits-core-legacy/src/main/js/org/isoron/platform/gui/JsImage.kt deleted file mode 100644 index 66a60f1ef..000000000 --- a/uhabits-core-legacy/src/main/js/org/isoron/platform/gui/JsImage.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.gui - -import org.khronos.webgl.* -import org.w3c.dom.* -import kotlin.browser.* -import kotlin.math.* - -class JsImage(val canvas: JsCanvas, - val imageData: ImageData) : Image { - - override val width: Int - get() = imageData.width - - override val height: Int - get() = imageData.height - - val pixels = imageData.unsafeCast() - - init { - console.log(width, height, imageData.data.length) - } - - override suspend fun export(path: String) { - canvas.ctx.putImageData(imageData, 0.0, 0.0) - val container = document.createElement("div") - container.className = "export" - val title = document.createElement("div") - title.innerHTML = path - document.body?.appendChild(container) - container.appendChild(title) - container.appendChild(canvas.element) - } - - override fun getPixel(x: Int, y: Int): Color { - val offset = 4 * (y * width + x) - return Color(imageData.data[offset + 0] / 255.0, - imageData.data[offset + 1] / 255.0, - imageData.data[offset + 2] / 255.0, - imageData.data[offset + 3] / 255.0) - } - - override fun setPixel(x: Int, y: Int, color: Color) { - val offset = 4 * (y * width + x) - inline fun map(x: Double): Byte { - return (x * 255).roundToInt().unsafeCast() - } - imageData.data.set(offset + 0, map(color.red)) - imageData.data.set(offset + 1, map(color.green)) - imageData.data.set(offset + 2, map(color.blue)) - imageData.data.set(offset + 3, map(color.alpha)) - } - -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/js/org/isoron/platform/io/JsDatabase.kt b/uhabits-core-legacy/src/main/js/org/isoron/platform/io/JsDatabase.kt deleted file mode 100644 index db4c2c992..000000000 --- a/uhabits-core-legacy/src/main/js/org/isoron/platform/io/JsDatabase.kt +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.io - -external fun require(module: String): dynamic - -class JsPreparedStatement(val stmt: dynamic) : PreparedStatement { - - override fun step(): StepResult { - val isRowAvailable = stmt.step() as Boolean - return if(isRowAvailable) StepResult.ROW else StepResult.DONE - } - - override fun finalize() { - stmt.free() - } - - override fun getInt(index: Int): Int { - return (stmt.getNumber(index) as Double).toInt() - } - - override fun getLong(index: Int): Long { - return (stmt.getNumber(index) as Double).toLong() - } - - override fun getText(index: Int): String { - return stmt.getString(index) as String - } - - override fun getReal(index: Int): Double { - return stmt.getNumber(index) as Double - } - - override fun bindInt(index: Int, value: Int) { - stmt.bindNumber(value, index + 1) - } - - override fun bindLong(index: Int, value: Long) { - stmt.bindNumber(value, index + 1) - } - - override fun bindText(index: Int, value: String) { - stmt.bindString(value, index + 1) - } - - override fun bindReal(index: Int, value: Double) { - stmt.bindNumber(value, index + 1) - } - - override fun reset() { - stmt.reset() - } - -} - -class JsDatabase(val db: dynamic) : Database { - override fun prepareStatement(sql: String): PreparedStatement { - return JsPreparedStatement(db.prepare(sql)) - } - - override fun close() { - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/js/org/isoron/platform/io/JsFiles.kt b/uhabits-core-legacy/src/main/js/org/isoron/platform/io/JsFiles.kt deleted file mode 100644 index 7b8257856..000000000 --- a/uhabits-core-legacy/src/main/js/org/isoron/platform/io/JsFiles.kt +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.io - -import kotlinx.coroutines.* -import org.isoron.platform.gui.* -import org.isoron.platform.gui.Image -import org.w3c.dom.* -import org.w3c.xhr.* -import kotlin.browser.* -import kotlin.js.* - -class JsFileStorage { - private val TAG = "JsFileStorage" - private val log = StandardLog() - - private val indexedDB = eval("indexedDB") - private var db: dynamic = null - - private val DB_NAME = "Main" - private val OS_NAME = "Files" - - suspend fun init() { - log.info(TAG, "Initializing") - Promise { resolve, reject -> - val req = indexedDB.open(DB_NAME, 2) - req.onerror = { reject(Exception("could not open IndexedDB")) } - req.onupgradeneeded = { - log.info(TAG, "Creating document store") - req.result.createObjectStore(OS_NAME) - } - req.onsuccess = { - log.info(TAG, "Ready") - db = req.result - resolve(0) - } - }.await() - } - - suspend fun delete(path: String) { - Promise { resolve, reject -> - val transaction = db.transaction(OS_NAME, "readwrite") - val os = transaction.objectStore(OS_NAME) - val req = os.delete(path) - req.onerror = { reject(Exception("could not delete $path")) } - req.onsuccess = { resolve(0) } - }.await() - } - - suspend fun put(path: String, content: String) { - Promise { resolve, reject -> - val transaction = db.transaction(OS_NAME, "readwrite") - val os = transaction.objectStore(OS_NAME) - val req = os.put(content, path) - req.onerror = { reject(Exception("could not put $path")) } - req.onsuccess = { resolve(0) } - }.await() - } - - suspend fun get(path: String): String { - return Promise { resolve, reject -> - val transaction = db.transaction(OS_NAME, "readonly") - val os = transaction.objectStore(OS_NAME) - val req = os.get(path) - req.onerror = { reject(Exception("could not get $path")) } - req.onsuccess = { resolve(req.result) } - }.await() - } - - suspend fun exists(path: String): Boolean { - return Promise { resolve, reject -> - val transaction = db.transaction(OS_NAME, "readonly") - val os = transaction.objectStore(OS_NAME) - val req = os.count(path) - req.onerror = { reject(Exception("could not count $path")) } - req.onsuccess = { resolve(req.result > 0) } - }.await() - } -} - -class JsFileOpener(val fileStorage: JsFileStorage) : FileOpener { - - override fun openUserFile(path: String): UserFile { - return JsUserFile(fileStorage, path) - } - - override fun openResourceFile(path: String): ResourceFile { - return JsResourceFile(path) - } -} - -class JsUserFile(val fs: JsFileStorage, - val filename: String) : UserFile { - override suspend fun lines(): List { - return fs.get(filename).lines() - } - - override suspend fun delete() { - fs.delete(filename) - } - - override suspend fun exists(): Boolean { - return fs.exists(filename) - } -} - -class JsResourceFile(val filename: String) : ResourceFile { - override suspend fun exists(): Boolean { - return Promise { resolve, reject -> - val xhr = XMLHttpRequest() - xhr.open("GET", "/assets/$filename", true) - xhr.onload = { resolve(xhr.status.toInt() != 404) } - xhr.onerror = { reject(Exception()) } - xhr.send() - }.await() - } - - override suspend fun lines(): List { - return Promise> { resolve, reject -> - val xhr = XMLHttpRequest() - xhr.open("GET", "/assets/$filename", true) - xhr.onload = { resolve(xhr.responseText.lines()) } - xhr.onerror = { reject(Exception()) } - xhr.send() - }.await() - } - - override suspend fun copyTo(dest: UserFile) { - val fs = (dest as JsUserFile).fs - fs.put(dest.filename, lines().joinToString("\n")) - } - - override suspend fun toImage(): Image { - return Promise { resolve, reject -> - val img = org.w3c.dom.Image() - img.onload = { - val canvas = JsCanvas(document.createElement("canvas") as HTMLCanvasElement, 1.0) - canvas.element.width = img.naturalWidth - canvas.element.height = img.naturalHeight - canvas.setColor(Color(0xffffff)) - canvas.fillRect(0.0, 0.0, canvas.getWidth(), canvas.getHeight()) - canvas.ctx.drawImage(img, 0.0, 0.0) - resolve(canvas.toImage()) - } - img.src = "/assets/$filename" - }.await() - } -} diff --git a/uhabits-core-legacy/src/main/js/org/isoron/platform/io/JsStrings.kt b/uhabits-core-legacy/src/main/js/org/isoron/platform/io/JsStrings.kt deleted file mode 100644 index 2d583967c..000000000 --- a/uhabits-core-legacy/src/main/js/org/isoron/platform/io/JsStrings.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.io - -actual fun format(format: String, arg: String): String { - return js("vsprintf")(format, arg) as String -} - -actual fun format(format: String, arg: Int): String { - return js("vsprintf")(format, arg) as String -} - -actual fun format(format: String, arg: Double): String { - return js("vsprintf")(format, arg) as String -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/js/org/isoron/platform/time/JsDates.kt b/uhabits-core-legacy/src/main/js/org/isoron/platform/time/JsDates.kt deleted file mode 100644 index 0810d9df2..000000000 --- a/uhabits-core-legacy/src/main/js/org/isoron/platform/time/JsDates.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.time - -import kotlin.js.* - -fun LocalDate.toJsDate(): Date { - return Date(year, month - 1, day) -} - -class JsDateFormatter(private val locale: String) : LocalDateFormatter { - override fun shortWeekdayName(date: LocalDate): String { - val options = dateLocaleOptions { weekday = "short" } - return date.toJsDate().toLocaleString(locale, options) - } - - override fun shortMonthName(date: LocalDate): String { - val options = dateLocaleOptions { month = "short" } - return date.toJsDate().toLocaleString(locale, options) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/jvm/org/isoron/platform/gui/JavaCanvas.kt b/uhabits-core-legacy/src/main/jvm/org/isoron/platform/gui/JavaCanvas.kt deleted file mode 100644 index 04740b3d3..000000000 --- a/uhabits-core-legacy/src/main/jvm/org/isoron/platform/gui/JavaCanvas.kt +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.gui - -import kotlinx.coroutines.* -import org.isoron.platform.io.* -import java.awt.* -import java.awt.RenderingHints.* -import java.awt.font.* -import java.awt.image.* -import kotlin.math.* - - -class JavaCanvas(val image: BufferedImage, - val pixelScale: Double = 2.0) : Canvas { - override fun toImage(): Image { - return JavaImage(image) - } - - private val frc = FontRenderContext(null, true, true) - private var fontSize = 12.0 - private var font = Font.REGULAR - private var textAlign = TextAlign.CENTER - val widthPx = image.width - val heightPx = image.height - val g2d = image.createGraphics() - - private val NOTO_REGULAR_FONT = createFont("fonts/NotoSans-Regular.ttf") - private val NOTO_BOLD_FONT = createFont("fonts/NotoSans-Bold.ttf") - private val FONT_AWESOME_FONT = createFont("fonts/FontAwesome.ttf") - - init { - g2d.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON); - g2d.setRenderingHint(KEY_TEXT_ANTIALIASING, VALUE_TEXT_ANTIALIAS_ON); - g2d.setRenderingHint(KEY_FRACTIONALMETRICS, VALUE_FRACTIONALMETRICS_ON); - updateFont() - } - - private fun toPixel(x: Double): Int { - return (pixelScale * x).toInt() - } - - private fun toDp(x: Int): Double { - return x / pixelScale - } - - override fun setColor(color: Color) { - g2d.color = java.awt.Color(color.red.toFloat(), - color.green.toFloat(), - color.blue.toFloat(), - color.alpha.toFloat()) - } - - override fun drawLine(x1: Double, y1: Double, x2: Double, y2: Double) { - g2d.drawLine(toPixel(x1), toPixel(y1), toPixel(x2), toPixel(y2)) - } - - override fun drawText(text: String, x: Double, y: Double) { - updateFont() - val bounds = g2d.font.getStringBounds(text, frc) - val bWidth = bounds.width.roundToInt() - val bHeight = bounds.height.roundToInt() - val bx = bounds.x.roundToInt() - val by = bounds.y.roundToInt() - - if (textAlign == TextAlign.CENTER) { - g2d.drawString(text, - toPixel(x) - bx - bWidth / 2, - toPixel(y) - by - bHeight / 2) - } else if (textAlign == TextAlign.LEFT) { - g2d.drawString(text, - toPixel(x) - bx, - toPixel(y) - by - bHeight / 2) - } else { - g2d.drawString(text, - toPixel(x) - bx - bWidth, - toPixel(y) - by - bHeight / 2) - } - } - - override fun fillRect(x: Double, y: Double, width: Double, height: Double) { - g2d.fillRect(toPixel(x), toPixel(y), toPixel(width), toPixel(height)) - } - - override fun drawRect(x: Double, y: Double, width: Double, height: Double) { - g2d.drawRect(toPixel(x), toPixel(y), toPixel(width), toPixel(height)) - } - - override fun getHeight(): Double { - return toDp(heightPx) - } - - override fun getWidth(): Double { - return toDp(widthPx) - } - - - override fun setFont(font: Font) { - this.font = font - updateFont() - } - - override fun setFontSize(size: Double) { - fontSize = size - updateFont() - } - - override fun setStrokeWidth(size: Double) { - g2d.stroke = BasicStroke((size * pixelScale).toFloat()) - } - - private fun updateFont() { - val size = (fontSize * pixelScale).toFloat() - g2d.font = when (font) { - Font.REGULAR -> NOTO_REGULAR_FONT.deriveFont(size) - Font.BOLD -> NOTO_BOLD_FONT.deriveFont(size) - Font.FONT_AWESOME -> FONT_AWESOME_FONT.deriveFont(size) - } - } - - override fun fillCircle(centerX: Double, centerY: Double, radius: Double) { - g2d.fillOval(toPixel(centerX - radius), - toPixel(centerY - radius), - toPixel(radius * 2), - toPixel(radius * 2)) - } - - override fun fillArc(centerX: Double, - centerY: Double, - radius: Double, - startAngle: Double, - swipeAngle: Double) { - - g2d.fillArc(toPixel(centerX - radius), - toPixel(centerY - radius), - toPixel(radius * 2), - toPixel(radius * 2), - startAngle.roundToInt(), - swipeAngle.roundToInt()) - } - - override fun setTextAlign(align: TextAlign) { - this.textAlign = align - } - - private fun createFont(path: String) = runBlocking { - val file = JavaFileOpener().openResourceFile(path) as JavaResourceFile - if (!file.exists()) throw RuntimeException("File not found: ${file.path}") - java.awt.Font.createFont(0, file.stream()) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/jvm/org/isoron/platform/gui/JavaImage.kt b/uhabits-core-legacy/src/main/jvm/org/isoron/platform/gui/JavaImage.kt deleted file mode 100644 index db6d5cb5a..000000000 --- a/uhabits-core-legacy/src/main/jvm/org/isoron/platform/gui/JavaImage.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.gui - -import java.awt.image.* -import java.io.* -import javax.imageio.* - -class JavaImage(val bufferedImage: BufferedImage) : Image { - override fun setPixel(x: Int, y: Int, color: Color) { - bufferedImage.setRGB(x, y, java.awt.Color(color.red.toFloat(), - color.green.toFloat(), - color.blue.toFloat()).rgb) - } - - override suspend fun export(path: String) { - val file = File(path) - file.parentFile.mkdirs() - ImageIO.write(bufferedImage, "png", file) - } - - override val width: Int - get() = bufferedImage.width - - override val height: Int - get() = bufferedImage.height - - override fun getPixel(x: Int, y: Int): Color { - return Color(bufferedImage.getRGB(x, y)) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/jvm/org/isoron/platform/io/JavaDatabase.kt b/uhabits-core-legacy/src/main/jvm/org/isoron/platform/io/JavaDatabase.kt deleted file mode 100644 index df99f0693..000000000 --- a/uhabits-core-legacy/src/main/jvm/org/isoron/platform/io/JavaDatabase.kt +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.io - -import java.sql.* -import java.sql.PreparedStatement - -class JavaPreparedStatement(private var stmt: PreparedStatement) : org.isoron.platform.io.PreparedStatement { - private var rs: ResultSet? = null - - private var hasExecuted = false - - override fun step(): StepResult { - if (!hasExecuted) { - hasExecuted = true - val hasResult = stmt.execute() - if (hasResult) rs = stmt.resultSet - } - - if (rs == null || !rs!!.next()) return StepResult.DONE - return StepResult.ROW - } - - override fun finalize() { - stmt.close() - } - - override fun getInt(index: Int): Int { - return rs!!.getInt(index + 1) - } - - override fun getLong(index: Int): Long { - return rs!!.getLong(index + 1) - } - - override fun getText(index: Int): String { - return rs!!.getString(index + 1) - } - - override fun getReal(index: Int): Double { - return rs!!.getDouble(index + 1) - } - - override fun bindInt(index: Int, value: Int) { - stmt.setInt(index + 1, value) - } - - override fun bindLong(index: Int, value: Long) { - stmt.setLong(index + 1, value) - } - - override fun bindText(index: Int, value: String) { - stmt.setString(index + 1, value) - } - - override fun bindReal(index: Int, value: Double) { - stmt.setDouble(index + 1, value) - } - - override fun reset() { - stmt.clearParameters() - hasExecuted = false - } -} - -class JavaDatabase(private var conn: Connection, - private val log: Log) : Database { - - override fun prepareStatement(sql: String): org.isoron.platform.io.PreparedStatement { - return JavaPreparedStatement(conn.prepareStatement(sql)) - } - - override fun close() { - conn.close() - } -} - -class JavaDatabaseOpener(val log: Log) : DatabaseOpener { - override fun open(file: UserFile): Database { - val platformFile = file as JavaUserFile - val conn = DriverManager.getConnection("jdbc:sqlite:${platformFile.path}") - return JavaDatabase(conn, log) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/jvm/org/isoron/platform/io/JavaFiles.kt b/uhabits-core-legacy/src/main/jvm/org/isoron/platform/io/JavaFiles.kt deleted file mode 100644 index 1bb3384e8..000000000 --- a/uhabits-core-legacy/src/main/jvm/org/isoron/platform/io/JavaFiles.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.io - -import org.isoron.platform.gui.* -import java.io.* -import java.nio.file.* -import javax.imageio.* - -class JavaResourceFile(val path: String) : ResourceFile { - private val javaPath: Path - get() { - val mainPath = Paths.get("assets/main/$path") - val testPath = Paths.get("assets/test/$path") - if (Files.exists(mainPath)) return mainPath - else return testPath - } - - override suspend fun exists(): Boolean { - return Files.exists(javaPath) - } - - override suspend fun lines(): List { - return Files.readAllLines(javaPath) - } - - override suspend fun copyTo(dest: UserFile) { - if (dest.exists()) dest.delete() - val destPath = (dest as JavaUserFile).path - destPath.toFile().parentFile?.mkdirs() - Files.copy(javaPath, destPath) - } - - fun stream(): InputStream { - return Files.newInputStream(javaPath) - } - - override suspend fun toImage(): Image { - return JavaImage(ImageIO.read(stream())) - } -} - -class JavaUserFile(val path: Path) : UserFile { - override suspend fun lines(): List { - return Files.readAllLines(path) - } - - override suspend fun exists(): Boolean { - return Files.exists(path) - } - - override suspend fun delete() { - Files.delete(path) - } -} - -class JavaFileOpener : FileOpener { - override fun openUserFile(path: String): UserFile { - val path = Paths.get("/tmp/$path") - return JavaUserFile(path) - } - - override fun openResourceFile(path: String): ResourceFile { - return JavaResourceFile(path) - } -} diff --git a/uhabits-core-legacy/src/main/jvm/org/isoron/platform/io/Strings.kt b/uhabits-core-legacy/src/main/jvm/org/isoron/platform/io/Strings.kt deleted file mode 100644 index edb787583..000000000 --- a/uhabits-core-legacy/src/main/jvm/org/isoron/platform/io/Strings.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.io - -actual fun format(format: String, arg: String): String = - String.format(format, arg) - -actual fun format(format: String, arg: Int): String = - String.format(format, arg) - -actual fun format(format: String, arg: Double): String = - String.format(format, arg) \ No newline at end of file diff --git a/uhabits-core-legacy/src/main/jvm/org/isoron/platform/time/JavaDates.kt b/uhabits-core-legacy/src/main/jvm/org/isoron/platform/time/JavaDates.kt deleted file mode 100644 index ebb0a0862..000000000 --- a/uhabits-core-legacy/src/main/jvm/org/isoron/platform/time/JavaDates.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.time - -import java.util.* -import java.util.Calendar.* - -fun LocalDate.toGregorianCalendar(): GregorianCalendar { - val cal = GregorianCalendar() - cal.timeZone = TimeZone.getTimeZone("GMT") - cal.set(MILLISECOND, 0) - cal.set(SECOND, 0) - cal.set(MINUTE, 0) - cal.set(HOUR_OF_DAY, 0) - cal.set(YEAR, this.year) - cal.set(MONTH, this.month - 1) - cal.set(DAY_OF_MONTH, this.day) - return cal -} - -class JavaLocalDateFormatter(private val locale: Locale) : LocalDateFormatter { - override fun shortMonthName(date: LocalDate): String { - val cal = date.toGregorianCalendar() - val longName = cal.getDisplayName(MONTH, LONG, locale) - val shortName = cal.getDisplayName(MONTH, SHORT, locale) - - // For some locales, such as Japan, SHORT name is exceedingly short - return if (longName.length <= 3) longName else shortName - } - - override fun shortWeekdayName(date: LocalDate): String { - val cal = date.toGregorianCalendar() - return cal.getDisplayName(DAY_OF_WEEK, SHORT, locale); - } -} diff --git a/uhabits-core-legacy/src/test/common/org/isoron/AsyncTests.kt b/uhabits-core-legacy/src/test/common/org/isoron/AsyncTests.kt deleted file mode 100644 index 323e2c234..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/AsyncTests.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron - -/** - * Workaround until Kotlin adds support for testing suspend functions - * https://youtrack.jetbrains.com/issue/KT-22228 - */ -expect fun asyncTest(block: suspend () -> Unit) \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/common/org/isoron/DependencyResolver.kt b/uhabits-core-legacy/src/test/common/org/isoron/DependencyResolver.kt deleted file mode 100644 index e7208049c..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/DependencyResolver.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron - -import org.isoron.platform.gui.* -import org.isoron.platform.io.* -import org.isoron.platform.time.* - -enum class Locale { - US, JAPAN -} - -expect object DependencyResolver { - val ignoreViewTests: Boolean - suspend fun getFileOpener(): FileOpener - suspend fun getDatabase(): Database - fun getDateFormatter(locale: Locale): LocalDateFormatter - fun createCanvas(width: Int, height: Int): Canvas -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/common/org/isoron/platform/concurrency/ObservableTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/platform/concurrency/ObservableTest.kt deleted file mode 100644 index 25fd37659..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/platform/concurrency/ObservableTest.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.concurrency - -import kotlin.test.* - -class ObservableTest { - - interface TestListener { - fun onDataChanged(data: Int) - } - - @Test - fun testNotifyListeners() { - var wasCalled = false - - val listener = object : TestListener { - override fun onDataChanged(data: Int) { - assertEquals(42, data) - wasCalled = true - } - } - - val observable = Observable() - observable.addListener(listener) - observable.notifyListeners { it.onDataChanged(42) } - assertTrue(wasCalled) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/common/org/isoron/platform/gui/CanvasTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/platform/gui/CanvasTest.kt deleted file mode 100644 index 1c2065cde..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/platform/gui/CanvasTest.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.gui - -import org.isoron.* -import org.isoron.uhabits.* -import kotlin.test.* - -class CanvasTest: BaseViewTest() { - @Test - fun run() = asyncTest{ - val canvas = DependencyResolver.createCanvas(500, 400) - - canvas.setColor(Color(0x303030)) - canvas.fillRect(0.0, 0.0, 500.0, 400.0) - - canvas.setColor(Color(0x606060)) - canvas.setStrokeWidth(25.0) - canvas.drawRect(100.0, 100.0, 300.0, 200.0) - - canvas.setColor(Color(0xFFFF00)) - canvas.setStrokeWidth(1.0) - canvas.drawRect(0.0, 0.0, 100.0, 100.0) - canvas.fillCircle(50.0, 50.0, 30.0) - canvas.drawRect(0.0, 100.0, 100.0, 100.0) - canvas.fillArc(50.0, 150.0, 30.0, 90.0, 135.0) - canvas.drawRect(0.0, 200.0, 100.0, 100.0) - canvas.fillArc(50.0, 250.0, 30.0, 90.0, -135.0) - canvas.drawRect(0.0, 300.0, 100.0, 100.0) - canvas.fillArc(50.0, 350.0, 30.0, 45.0, 90.0) - - canvas.setColor(Color(0xFF0000)) - canvas.setStrokeWidth(2.0) - canvas.drawLine(0.0, 0.0, 500.0, 400.0) - canvas.drawLine(500.0, 0.0, 0.0, 400.0) - - canvas.setFont(Font.BOLD) - canvas.setFontSize(50.0) - canvas.setColor(Color(0x00FF00)) - canvas.setTextAlign(TextAlign.CENTER) - canvas.drawText("HELLO", 250.0, 100.0) - - canvas.setTextAlign(TextAlign.RIGHT) - canvas.drawText("HELLO", 250.0, 150.0) - - canvas.setTextAlign(TextAlign.LEFT) - canvas.drawText("HELLO", 250.0, 200.0) - - canvas.setFont(Font.FONT_AWESOME) - canvas.drawText(FontAwesome.CHECK, 250.0, 300.0) - - assertRenders("components/CanvasTest.png", canvas) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/common/org/isoron/platform/io/DatabaseTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/platform/io/DatabaseTest.kt deleted file mode 100644 index 8e46e0872..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/platform/io/DatabaseTest.kt +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.io - -import org.isoron.* -import kotlin.test.* - -class DatabaseTest { - @Test - fun testUsage() = asyncTest{ - val db = DependencyResolver.getDatabase() - - db.setVersion(0) - assertEquals(0, db.getVersion()) - - db.setVersion(23) - assertEquals(23, db.getVersion()) - - var stmt = db.prepareStatement("drop table if exists demo") - stmt.step() - stmt.finalize() - - stmt = db.prepareStatement("create table if not exists demo(key int, value text)") - stmt.step() - stmt.finalize() - - stmt = db.prepareStatement("insert into demo(key, value) values (?, ?)") - stmt.bindInt(0, 42) - stmt.bindText(1, "Hello World") - stmt.step() - stmt.finalize() - - stmt = db.prepareStatement("select * from demo where key > ?") - stmt.bindInt(0, 10) - - var result = stmt.step() - assertEquals(StepResult.ROW, result) - assertEquals(42, stmt.getInt(0)) - assertEquals("Hello World", stmt.getText(1)) - - result = stmt.step() - assertEquals(StepResult.DONE, result) - - stmt.finalize() - db.close() - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/common/org/isoron/platform/io/FilesTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/platform/io/FilesTest.kt deleted file mode 100644 index f039abc93..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/platform/io/FilesTest.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.io - -import org.isoron.* -import kotlin.test.* - -class FilesTest() { - @Test - fun testLines() = asyncTest { - val fileOpener = DependencyResolver.getFileOpener() - - assertFalse(fileOpener.openUserFile("non-existing-usr.txt").exists(), - "non-existing-usr.txt shouldn't exist") - - assertFalse(fileOpener.openResourceFile("non-existing-res.txt").exists(), - "non-existing-res.txt shouldn't exist") - - val hello = fileOpener.openResourceFile("hello.txt") - assertTrue(hello.exists(), "hello.txt should exist") - var lines = hello.lines() - assertEquals(2, lines.size) - assertEquals("Hello World!", lines[0]) - assertEquals("This is a resource.", lines[1]) - - val helloCopy = fileOpener.openUserFile("copies/hello.txt") - hello.copyTo(helloCopy) - lines = helloCopy.lines() - assertEquals("Hello World!", lines[0]) - assertEquals("This is a resource.", lines[1]) - - assertTrue(helloCopy.exists(), "helloCopy should exist") - helloCopy.delete() - assertFalse(helloCopy.exists(), "helloCopy shouldn't exist") - - - val migration = fileOpener.openResourceFile("migrations/012.sql") - assertTrue(migration.exists(), "migrations/012.sql should exist") - lines = migration.lines() - assertEquals("delete from Score", lines[0]) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/common/org/isoron/platform/io/StringsTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/platform/io/StringsTest.kt deleted file mode 100644 index 1573e620a..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/platform/io/StringsTest.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.io - -import kotlin.test.* - -class StringsTest { - @Test - fun testSprintf() { - assertEquals("hello world!", format("hello %s!", "world")) - assertEquals(" 5", format("%3d", 5)) - assertEquals("005", format("%03d", 5)) - assertEquals("005", format("%03d", 5)) - assertEquals(" 45", format("%3d", 45)) - assertEquals("145", format("%3d", 145)) - assertEquals(" 13.42", format("%8.2f", 13.419187263)) - assertEquals("00013.42", format("%08.2f", 13.419187263)) - assertEquals("13.42 ", format("%-8.2f", 13.419187263)) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/common/org/isoron/platform/time/DatesTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/platform/time/DatesTest.kt deleted file mode 100644 index cf64f50de..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/platform/time/DatesTest.kt +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.platform.time - -import org.isoron.* -import kotlin.test.* - -class DatesTest { - private val d1 = LocalDate(2019, 3, 25) - private val d2 = LocalDate(2019, 4, 4) - private val d3 = LocalDate(2019, 5, 12) - - @Test - fun testPlusMinusDays() { - val today = LocalDate(2019, 3, 25) - assertEquals(today.minus(28), LocalDate(2019, 2, 25)) - assertEquals(today.plus(7), LocalDate(2019, 4, 1)) - assertEquals(today.plus(42), LocalDate(2019, 5, 6)) - } - - @Test - fun testFormatter() { - var fmt = DependencyResolver.getDateFormatter(Locale.US) - assertEquals("Mon", fmt.shortWeekdayName(d1)) - assertEquals("Thu", fmt.shortWeekdayName(d2)) - assertEquals("Sun", fmt.shortWeekdayName(d3)) - assertEquals("Mar", fmt.shortMonthName(d1)) - assertEquals("Apr", fmt.shortMonthName(d2)) - assertEquals("May", fmt.shortMonthName(d3)) - - fmt = DependencyResolver.getDateFormatter(Locale.JAPAN) - assertEquals("月", fmt.shortWeekdayName(d1)) - assertEquals("木", fmt.shortWeekdayName(d2)) - assertEquals("日", fmt.shortWeekdayName(d3)) - assertEquals("3月", fmt.shortMonthName(d1)) - assertEquals("4月", fmt.shortMonthName(d2)) - assertEquals("5月", fmt.shortMonthName(d3)) - } - - @Test - fun testTimestamps() { - val timestamps = listOf(Timestamp(1555977600000), - Timestamp(968716800000), - Timestamp(946684800000)) - val dates = listOf(LocalDate(2019, 4, 23), - LocalDate(2000, 9, 12), - LocalDate(2000, 1, 1)) - assertEquals(timestamps, dates.map { d -> d.timestamp }) - assertEquals(dates, timestamps.map { t -> t.localDate }) - } - - @Test - fun testIsOlderThan() { - val ref = LocalDate(2010, 10, 5) - assertTrue(ref.isOlderThan(LocalDate(2010, 10, 10))) - assertTrue(ref.isOlderThan(LocalDate(2010, 11, 4))) - assertTrue(ref.isOlderThan(LocalDate(2011, 1, 5))) - assertTrue(ref.isOlderThan(LocalDate(2015, 3, 1))) - - assertFalse(ref.isOlderThan(LocalDate(2010, 10, 5))) - assertFalse(ref.isOlderThan(LocalDate(2010, 10, 4))) - assertFalse(ref.isOlderThan(LocalDate(2010, 9, 1))) - assertFalse(ref.isOlderThan(LocalDate(2005, 10, 5))) - } - - @Test - fun testDistanceInDays() { - val d1 = LocalDate(2019, 5, 10) - val d2 = LocalDate(2019, 5, 30) - val d3 = LocalDate(2019, 6, 5) - - assertEquals(0, d1.distanceTo(d1)) - assertEquals(20, d1.distanceTo(d2)) - assertEquals(20, d2.distanceTo(d1)) - assertEquals(26, d1.distanceTo(d3)) - assertEquals(6, d2.distanceTo(d3)) - } - - @Test - fun testGregorianCalendarConversion() { - fun check(daysSince2000: Int, - expectedYear: Int, - expectedMonth: Int, - expectedDay: Int, - expectedWeekday: Int) { - val date = LocalDate(daysSince2000) - assertEquals(expectedYear, date.year) - assertEquals(expectedMonth, date.month) - assertEquals(expectedDay, date.day) - assertEquals(expectedWeekday, date.dayOfWeek.index) - assertEquals(date, date.timestamp.localDate) - } - - check(0, 2000, 1, 1, 6) - check(626, 2001, 9, 18, 2) - check(915, 2002, 7, 4, 4) - check(2759, 2007, 7, 22, 0) - check(2791, 2007, 8, 23, 4) - check(6524, 2017, 11, 11, 6) - check(7517, 2020, 7, 31, 5) - check(10031, 2027, 6, 19, 6) - check(13091, 2035, 11, 4, 0) - check(14849, 2040, 8, 27, 1) - check(17330, 2047, 6, 13, 4) - check(20566, 2056, 4, 22, 6) - check(23617, 2064, 8, 29, 5) - check(27743, 2075, 12, 16, 1) - check(31742, 2086, 11, 27, 3) - check(36659, 2100, 5, 15, 6) - check(39224, 2107, 5, 24, 2) - check(39896, 2109, 3, 26, 2) - check(40819, 2111, 10, 5, 1) - check(43983, 2120, 6, 3, 1) - check(46893, 2128, 5, 22, 6) - check(51013, 2139, 9, 2, 3) - check(55542, 2152, 1, 26, 3) - check(58817, 2161, 1, 13, 2) - check(63769, 2174, 8, 5, 5) - check(64893, 2177, 9, 2, 2) - check(66840, 2183, 1, 1, 3) - check(68011, 2186, 3, 17, 5) - check(70060, 2191, 10, 26, 3) - check(70733, 2193, 8, 29, 4) - } -} diff --git a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/BaseViewTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/uhabits/BaseViewTest.kt deleted file mode 100644 index 1e9b103e6..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/BaseViewTest.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits - -import org.isoron.* -import org.isoron.platform.gui.* -import org.isoron.uhabits.components.* -import kotlin.test.* - -open class BaseViewTest { - var theme = LightTheme() - suspend fun assertRenders(width: Int, - height: Int, - expectedPath: String, - component: Component) { - if (DependencyResolver.ignoreViewTests) { - println("WARN: Ignoring BaseViewTest assertion") - return - } - val canvas = DependencyResolver.createCanvas(width, height) - component.draw(canvas) - assertRenders(expectedPath, canvas) - } - - suspend fun assertRenders(path: String, - canvas: Canvas) { - if (DependencyResolver.ignoreViewTests) { - println("WARN: Ignoring BaseViewTest assertion") - return - } - val actualImage = canvas.toImage() - val failedActualPath = "/tmp/failed/${path}" - val failedExpectedPath = failedActualPath.replace(".png", - ".expected.png") - val failedDiffPath = failedActualPath.replace(".png", ".diff.png") - val fileOpener = DependencyResolver.getFileOpener() - val expectedFile = fileOpener.openResourceFile(path) - if (expectedFile.exists()) { - val expectedImage = expectedFile.toImage() - val diffImage = expectedFile.toImage() - diffImage.diff(actualImage) - val distance = diffImage.averageLuminosity * 100 - if (distance >= 1.0) { - expectedImage.export(failedExpectedPath) - actualImage.export(failedActualPath) - diffImage.export(failedDiffPath) - fail("Images differ (distance=${distance})") - } - } else { - actualImage.export(failedActualPath) - fail("Expected image file is missing. Actual image: $failedActualPath") - } - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/BarChartTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/BarChartTest.kt deleted file mode 100644 index 9017f41cf..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/BarChartTest.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.components - -import org.isoron.* -import org.isoron.platform.time.* -import org.isoron.uhabits.* -import kotlin.test.* - -class BarChartTest : BaseViewTest() { - val base = "components/BarChart" - val today = LocalDate(2015, 1, 25) - val dailyAxis = (0..100).map { today.minus(it) } - val weeklyAxis = (0..100).map { today.minus(it * 7) } - val monthlyAxis = (0..100).map { today.minus(it * 30) } - val yearlyAxis = (0..100).map { today.minus(it * 365) } - val fmt = DependencyResolver.getDateFormatter(Locale.US) - val component = BarChart(theme, fmt) - - val series1 = listOf(200.0, 80.0, 150.0, 437.0, 50.0, 80.0, 420.0, - 350.0, 100.0, 375.0, 300.0, 50.0, 60.0, 350.0, - 125.0) - - val series2 = listOf(300.0, 500.0, 280.0, 50.0, 425.0, 300.0, 150.0, - 10.0, 50.0, 200.0, 230.0, 20.0, 60.0, 34.0, 100.0) - - init { - component.axis = dailyAxis - component.series.add(series1) - component.colors.add(theme.color(1)) - } - - @Test - fun testDraw() = asyncTest { - assertRenders(400, 200, "$base/base.png", component) - } - - @Test - fun testDrawWeeklyAxis() = asyncTest { - component.axis = weeklyAxis - assertRenders(400, 200, "$base/axis-weekly.png", component) - } - - @Test - fun testDrawMonthlyAxis() = asyncTest { - component.axis = monthlyAxis - assertRenders(400, 200, "$base/axis-monthly.png", component) - } - - @Test - fun testDrawYearlyAxis() = asyncTest { - component.axis = yearlyAxis - assertRenders(400, 200, "$base/axis-yearly.png", component) - } - - @Test - fun testDrawTwoSeries() = asyncTest { - component.series.add(series2) - component.colors.add(theme.color(3)) - assertRenders(400, 200, "$base/2-series.png", component) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/CalendarChartTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/CalendarChartTest.kt deleted file mode 100644 index dee24ccf8..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/CalendarChartTest.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.components - -import org.isoron.* -import org.isoron.platform.time.* -import org.isoron.uhabits.* -import kotlin.test.* - -class CalendarChartTest : BaseViewTest() { - val base = "components/CalendarChart" - - @Test - fun testDraw() = asyncTest { - val fmt = DependencyResolver.getDateFormatter(Locale.US) - val component = CalendarChart(LocalDate(2015, 1, 25), - theme.color(4), - theme, - fmt) - component.series = listOf(1.0, // today - 0.2, 0.5, 0.7, 0.0, 0.3, 0.4, 0.6, - 0.6, 0.0, 0.3, 0.6, 0.5, 0.8, 0.0, - 0.0, 0.0, 0.0, 0.6, 0.5, 0.7, 0.7, - 0.5, 0.5, 0.8, 0.9, 1.0, 1.0, 1.0, - 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.2) - assertRenders(400, 200, "$base/base.png", component) - - component.scrollPosition = 2 - assertRenders(400, 200, "$base/scroll.png", component) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/CheckmarkButtonTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/CheckmarkButtonTest.kt deleted file mode 100644 index 9a325917d..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/CheckmarkButtonTest.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.components - -import org.isoron.* -import org.isoron.uhabits.* -import kotlin.test.* - -class CheckmarkButtonTest : BaseViewTest() { - val base = "components/CheckmarkButton" - - @Test - fun testDrawExplicit() = asyncTest { - val component = CheckmarkButton(2, theme.color(8), theme) - assertRenders(48, 48, "$base/explicit.png", component) - } - - @Test - fun testDrawImplicit() = asyncTest { - val component = CheckmarkButton(1, theme.color(8), theme) - assertRenders(48, 48, "$base/implicit.png", component) - } - - @Test - fun testDrawUnchecked() = asyncTest { - val component = CheckmarkButton(0, theme.color(8), theme) - assertRenders(48, 48, "$base/unchecked.png", component) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/HabitListHeaderTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/HabitListHeaderTest.kt deleted file mode 100644 index 41c4d9e5b..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/HabitListHeaderTest.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.components - -import org.isoron.* -import org.isoron.platform.time.* -import org.isoron.uhabits.* -import kotlin.test.* - -class HabitListHeaderTest : BaseViewTest() { - @Test - fun testDraw() = asyncTest { - val fmt = DependencyResolver.getDateFormatter(Locale.US) - val header = HabitListHeader(LocalDate(2019, 3, 25), 5, theme, fmt) - assertRenders(600, 48, "components/HabitListHeader/light.png", header) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/NumberButtonTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/NumberButtonTest.kt deleted file mode 100644 index 7f65a95ac..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/NumberButtonTest.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.components - -import org.isoron.* -import org.isoron.uhabits.* -import kotlin.test.* - -class NumberButtonTest : BaseViewTest() { - val base = "components/NumberButton" - - @Test - fun testFormatValue() = asyncTest{ - assertEquals("0.12", 0.1235.toShortString()) - assertEquals("0.1", 0.1000.toShortString()) - assertEquals("5", 5.0.toShortString()) - assertEquals("5.25", 5.25.toShortString()) - assertEquals("12.3", 12.3456.toShortString()) - assertEquals("123", 123.123.toShortString()) - assertEquals("321", 321.2.toShortString()) - assertEquals("4.3k", 4321.2.toShortString()) - assertEquals("54.3k", 54321.2.toShortString()) - assertEquals("654k", 654321.2.toShortString()) - assertEquals("7.7M", 7654321.2.toShortString()) - assertEquals("87.7M", 87654321.2.toShortString()) - assertEquals("988M", 987654321.2.toShortString()) - assertEquals("2.0G", 1987654321.2.toShortString()) - } - - @Test - fun testRenderAbove() = asyncTest { - val btn = NumberButton(theme.color(8), 500.0, 100.0, "steps", theme) - assertRenders(48, 48, "$base/render_above.png", btn) - } - - @Test - fun testRenderBelow() = asyncTest { - val btn = NumberButton(theme.color(8), 99.0, 100.0, "steps", theme) - assertRenders(48, 48, "$base/render_below.png", btn) - } -} diff --git a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/RingTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/RingTest.kt deleted file mode 100644 index a91c4a056..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/RingTest.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.components - -import org.isoron.* -import org.isoron.uhabits.* -import kotlin.test.* - -class RingTest : BaseViewTest() { - val base = "components/Ring" - - @Test - fun testDraw() = asyncTest { - val component = Ring(theme.color(8), - percentage = 0.30, - thickness = 5.0, - radius = 30.0, - theme = theme, - label = true) - assertRenders(60, 60, "$base/draw1.png", component) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/models/CheckmarkListTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/uhabits/models/CheckmarkListTest.kt deleted file mode 100644 index b96965066..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/models/CheckmarkListTest.kt +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -import org.isoron.platform.time.* -import org.isoron.uhabits.models.Checkmark.Companion.CHECKED_AUTOMATIC -import org.isoron.uhabits.models.Checkmark.Companion.CHECKED_MANUAL -import org.isoron.uhabits.models.Checkmark.Companion.UNCHECKED -import kotlin.test.* - -class CheckmarkListTest { - - private val today = LocalDate(2019, 1, 30) - - private fun day(offset: Int): LocalDate { - return today.minus(offset) - } - - @Test - fun buildIntervalsWeekly() { - val checks = listOf(Checkmark(day(23), CHECKED_MANUAL), - Checkmark(day(18), CHECKED_MANUAL), - Checkmark(day(8), CHECKED_MANUAL)) - val expected = listOf( - CheckmarkList.Interval(day(23), day(23), day(17)), - CheckmarkList.Interval(day(18), day(18), day(12)), - CheckmarkList.Interval(day(8), day(8), day(2))) - val actual = CheckmarkList.buildIntervals(checks, - Frequency.WEEKLY) - assertEquals(expected, actual) - } - - @Test - fun buildIntervalsDaily() { - val checks = listOf(Checkmark(day(23), CHECKED_MANUAL), - Checkmark(day(18), CHECKED_MANUAL), - Checkmark(day(8), CHECKED_MANUAL)) - val expected = listOf( - CheckmarkList.Interval(day(23), day(23), day(23)), - CheckmarkList.Interval(day(18), day(18), day(18)), - CheckmarkList.Interval(day(8), day(8), day(8))) - val actual = CheckmarkList.buildIntervals(checks, - Frequency.DAILY) - assertEquals(expected, actual) - } - - @Test - fun buildIntervalsTwoPerWeek() { - val checks = listOf(Checkmark(day(23), CHECKED_MANUAL), - Checkmark(day(22), CHECKED_MANUAL), - Checkmark(day(18), CHECKED_MANUAL), - Checkmark(day(15), CHECKED_MANUAL), - Checkmark(day(8), CHECKED_MANUAL)) - val expected = listOf( - CheckmarkList.Interval(day(23), day(22), day(17)), - CheckmarkList.Interval(day(22), day(18), day(16)), - CheckmarkList.Interval(day(18), day(15), day(12))) - val actual = CheckmarkList.buildIntervals(checks, - Frequency.TWO_TIMES_PER_WEEK) - assertEquals(expected, actual) - } - - @Test - fun testSnapIntervalsTogether() { - val original = mutableListOf( - CheckmarkList.Interval(day(40), day(40), day(34)), - CheckmarkList.Interval(day(25), day(25), day(19)), - CheckmarkList.Interval(day(16), day(16), day(10)), - CheckmarkList.Interval(day(8), day(8), day(2))) - val expected = listOf( - CheckmarkList.Interval(day(40), day(40), day(34)), - CheckmarkList.Interval(day(25), day(25), day(19)), - CheckmarkList.Interval(day(18), day(16), day(12)), - CheckmarkList.Interval(day(11), day(8), day(5))) - CheckmarkList.snapIntervalsTogether(original) - assertEquals(expected, original) - } - - @Test - fun testBuildCheckmarksFromIntervals() { - val checks = listOf(Checkmark(day(10), CHECKED_MANUAL), - Checkmark(day(5), CHECKED_MANUAL), - Checkmark(day(2), CHECKED_MANUAL), - Checkmark(day(1), CHECKED_MANUAL)) - val intervals = listOf(CheckmarkList.Interval(day(10), day(8), day(8)), - CheckmarkList.Interval(day(6), day(5), day(4)), - CheckmarkList.Interval(day(2), day(2), day(1))) - val expected = listOf(Checkmark(day(1), CHECKED_MANUAL), - Checkmark(day(2), CHECKED_MANUAL), - Checkmark(day(3), UNCHECKED), - Checkmark(day(4), CHECKED_AUTOMATIC), - Checkmark(day(5), CHECKED_MANUAL), - Checkmark(day(6), CHECKED_AUTOMATIC), - Checkmark(day(7), UNCHECKED), - Checkmark(day(8), CHECKED_AUTOMATIC), - Checkmark(day(9), CHECKED_AUTOMATIC), - Checkmark(day(10), CHECKED_MANUAL)) - val actual = CheckmarkList.buildCheckmarksFromIntervals(checks, intervals) - assertEquals(expected, actual) - } - - @Test - fun testBuildCheckmarksFromIntervals2() { - val reps = listOf(Checkmark(day(0), CHECKED_MANUAL)) - val intervals = listOf(CheckmarkList.Interval(day(5), day(0), day(0))) - val expected = listOf(Checkmark(day(0), CHECKED_MANUAL), - Checkmark(day(1), CHECKED_AUTOMATIC), - Checkmark(day(2), CHECKED_AUTOMATIC), - Checkmark(day(3), CHECKED_AUTOMATIC), - Checkmark(day(4), CHECKED_AUTOMATIC), - Checkmark(day(5), CHECKED_AUTOMATIC)) - val actual = CheckmarkList.buildCheckmarksFromIntervals(reps, intervals) - assertEquals(expected, actual) - } - - @Test - fun computeAutomaticCheckmarks() { - val checks = listOf(Checkmark(day(10), CHECKED_MANUAL), - Checkmark(day(5), CHECKED_MANUAL), - Checkmark(day(2), CHECKED_MANUAL), - Checkmark(day(1), CHECKED_MANUAL)) - val expected = listOf(Checkmark(day(-1), CHECKED_AUTOMATIC), - Checkmark(day(0), CHECKED_AUTOMATIC), - Checkmark(day(1), CHECKED_MANUAL), - Checkmark(day(2), CHECKED_MANUAL), - Checkmark(day(3), CHECKED_AUTOMATIC), - Checkmark(day(4), CHECKED_AUTOMATIC), - Checkmark(day(5), CHECKED_MANUAL), - Checkmark(day(6), CHECKED_AUTOMATIC), - Checkmark(day(7), CHECKED_AUTOMATIC), - Checkmark(day(8), CHECKED_AUTOMATIC), - Checkmark(day(9), CHECKED_AUTOMATIC), - Checkmark(day(10), CHECKED_MANUAL)) - val actual = CheckmarkList.computeCheckmarks(checks, Frequency(1, 3)) - assertEquals(expected, actual) - } - - @Test - fun testGetUntil() { - val list = CheckmarkList(Frequency(1, 2), HabitType.BOOLEAN_HABIT) - list.setManualCheckmarks(listOf(Checkmark(day(4), CHECKED_MANUAL), - Checkmark(day(7), CHECKED_MANUAL))) - val expected = listOf(Checkmark(day(0), UNCHECKED), - Checkmark(day(1), UNCHECKED), - Checkmark(day(2), UNCHECKED), - Checkmark(day(3), CHECKED_AUTOMATIC), - Checkmark(day(4), CHECKED_MANUAL), - Checkmark(day(5), UNCHECKED), - Checkmark(day(6), CHECKED_AUTOMATIC), - Checkmark(day(7), CHECKED_MANUAL)) - assertEquals(expected, list.getUntil(day(0))) - - val expected2 = listOf(Checkmark(day(3), CHECKED_AUTOMATIC), - Checkmark(day(4), CHECKED_MANUAL), - Checkmark(day(5), UNCHECKED), - Checkmark(day(6), CHECKED_AUTOMATIC), - Checkmark(day(7), CHECKED_MANUAL)) - assertEquals(expected2, list.getUntil(day(3))) - } - - @Test - fun testGetValuesUntil2() { - val list = CheckmarkList(Frequency(1, 2), HabitType.BOOLEAN_HABIT) - val expected = listOf() - assertEquals(expected, list.getUntil(day(0))) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/models/CheckmarkRepositoryTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/uhabits/models/CheckmarkRepositoryTest.kt deleted file mode 100644 index f5e933760..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/models/CheckmarkRepositoryTest.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -import org.isoron.* -import org.isoron.platform.io.* -import org.isoron.platform.time.* -import kotlin.test.* - -class CheckmarkRepositoryTest() { - @Test - fun testCRUD() = asyncTest { - val db = DependencyResolver.getDatabase() - - val habitA = 10 - var checkmarksA = listOf(Checkmark(LocalDate(2019, 1, 15), 100), - Checkmark(LocalDate(2019, 1, 7), 500), - Checkmark(LocalDate(2019, 1, 1), 900)) - - val habitB = 35 - val checkmarksB = listOf(Checkmark(LocalDate(2019, 1, 30), 50), - Checkmark(LocalDate(2019, 1, 29), 30), - Checkmark(LocalDate(2019, 1, 27), 900), - Checkmark(LocalDate(2019, 1, 25), 450), - Checkmark(LocalDate(2019, 1, 20), 1000)) - - val repository = CheckmarkRepository(db) - - for (c in checkmarksA) repository.insert(habitA, c) - for (c in checkmarksB) repository.insert(habitB, c) - assertEquals(checkmarksA, repository.findAll(habitA)) - assertEquals(checkmarksB, repository.findAll(habitB)) - assertEquals(listOf(), repository.findAll(999)) - - checkmarksA = listOf(Checkmark(LocalDate(2019, 1, 15), 100), - Checkmark(LocalDate(2019, 1, 1), 900)) - repository.delete(habitA, LocalDate(2019, 1, 7)) - assertEquals(checkmarksA, repository.findAll(habitA)) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/models/HabitRepositoryTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/uhabits/models/HabitRepositoryTest.kt deleted file mode 100644 index faa234d78..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/models/HabitRepositoryTest.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -import org.isoron.* -import org.isoron.platform.gui.* -import kotlin.test.* - -class HabitRepositoryTest() { - @Test - fun testCRUD() = asyncTest{ - val db = DependencyResolver.getDatabase() - val original0 = Habit(id = 0, - name = "Wake up early", - description = "Did you wake up before 6am?", - frequency = Frequency(1, 1), - color = PaletteColor(3), - isArchived = false, - position = 0, - unit = "", - target = 0.0, - type = HabitType.BOOLEAN_HABIT) - - val original1 = Habit(id = 1, - name = "Exercise", - description = "Did you exercise for at least 20 minutes?", - frequency = Frequency(1, 2), - color = PaletteColor(4), - isArchived = false, - position = 1, - unit = "", - target = 0.0, - type = HabitType.BOOLEAN_HABIT) - - val original2 = Habit(id = 2, - name = "Learn Japanese", - description = "Did you study Japanese today?", - frequency = Frequency(1, 1), - color = PaletteColor(3), - isArchived = false, - position = 2, - unit = "", - target = 0.0, - type = HabitType.BOOLEAN_HABIT) - - val repository = HabitRepository(db) - - var habits = repository.findAll() - assertEquals(0, repository.nextId()) - assertEquals(0, habits.size) - - repository.insert(original0) - repository.insert(original1) - repository.insert(original2) - habits = repository.findAll() - assertEquals(3, habits.size) - assertEquals(original0, habits[0]) - assertEquals(original1, habits[1]) - assertEquals(original2, habits[2]) - - assertEquals(3, repository.nextId()) - - original0.description = "New description" - repository.update(original0) - habits = repository.findAll() - assertEquals(original0, habits[0]) - - repository.delete(original0) - habits = repository.findAll() - assertEquals(2, habits.size) - assertEquals(original1, habits[1]) - assertEquals(original2, habits[2]) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/models/PreferencesRepositoryTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/uhabits/models/PreferencesRepositoryTest.kt deleted file mode 100644 index b24b65ecb..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/models/PreferencesRepositoryTest.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -import org.isoron.* -import org.isoron.platform.io.* -import kotlin.test.* - -class PreferencesRepositoryTest() { - @Test - fun testUsage() = asyncTest{ - val db = DependencyResolver.getDatabase() - val prefs = PreferencesRepository(db) - assertEquals("default", prefs.getString("non_existing_key", "default")) - prefs.putString("ringtone_path", "/tmp") - assertEquals("/tmp", prefs.getString("ringtone_path", "none")) - - assertEquals(42, prefs.getLong("non_existing_key", 42)) - prefs.putLong("times_launched", 130) - assertEquals(130, prefs.getLong("times_launched", 0)) - - assertEquals(true, prefs.getBoolean("non_existing_key", true)) - assertEquals(false, prefs.getBoolean("non_existing_key", false)) - prefs.putBoolean("show_archived", true) - assertEquals(true, prefs.getBoolean("show_archived", false)) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/models/ScoreListTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/uhabits/models/ScoreListTest.kt deleted file mode 100644 index c9e86f5c5..000000000 --- a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/models/ScoreListTest.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models - -import org.isoron.platform.time.* -import org.isoron.uhabits.models.Checkmark.Companion.CHECKED_MANUAL -import org.isoron.uhabits.models.Frequency.Companion.DAILY -import org.isoron.uhabits.models.ScoreList.Companion.compute -import kotlin.test.* - -class ScoreListTest { - val today = LocalDate(2019, 1, 1) - - @Test - fun computeWithDailyHabit() { - val freq = DAILY - var check = 1 - assertEquals(compute(freq, 0.0, check), 0.051922) - assertEquals(compute(freq, 0.5, check), 0.525961) - assertEquals(compute(freq, 0.75, check), 0.762980) - - check = 0 - assertEquals(compute(freq, 0.0, check), 0.0) - assertEquals(compute(freq, 0.5, check), 0.474038) - assertEquals(compute(freq, 0.75, check), 0.711058) - } - - @Test - fun computeWithNonDailyHabit() { - var check = 1 - val freq = Frequency(1, 3) - assertEquals(compute(freq, 0.0, check), 0.017615) - assertEquals(compute(freq, 0.5, check), 0.508807) - assertEquals(compute(freq, 0.75, check), 0.754403) - - check = 0 - assertEquals(compute(freq, 0.0, check), 0.0) - assertEquals(compute(freq, 0.5, check), 0.491192) - assertEquals(compute(freq, 0.75, check), 0.736788) - } - - @Test - fun getValueUntilWithBooleanHabit() { - val checks = CheckmarkList(DAILY, - HabitType.BOOLEAN_HABIT) - checks.setManualCheckmarks((0..19).map { - Checkmark(today.minus(it), CHECKED_MANUAL) - }) - val scoreList = ScoreList(checks) - val actual = scoreList.getUntil(today) - val expected = listOf(Score(today.minus(0), 0.655741), - Score(today.minus(1), 0.636888), - Score(today.minus(2), 0.617002), - Score(today.minus(3), 0.596027), - Score(today.minus(4), 0.573903), - Score(today.minus(5), 0.550568), - Score(today.minus(6), 0.525955), - Score(today.minus(7), 0.499994), - Score(today.minus(8), 0.472611), - Score(today.minus(9), 0.443729), - Score(today.minus(10), 0.413265), - Score(today.minus(11), 0.381132), - Score(today.minus(12), 0.347240), - Score(today.minus(13), 0.311491), - Score(today.minus(14), 0.273785), - Score(today.minus(15), 0.234014), - Score(today.minus(16), 0.192065), - Score(today.minus(17), 0.147818), - Score(today.minus(18), 0.101148), - Score(today.minus(19), 0.051922)) - - assertEquals(expected, actual) - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/ios/org/isoron/DependencyResolver.kt b/uhabits-core-legacy/src/test/ios/org/isoron/DependencyResolver.kt deleted file mode 100644 index 4cd3fd7ed..000000000 --- a/uhabits-core-legacy/src/test/ios/org/isoron/DependencyResolver.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron - -import org.isoron.platform.gui.* -import org.isoron.platform.io.* -import org.isoron.platform.time.* -import org.isoron.uhabits.* -import platform.CoreGraphics.* -import platform.UIKit.* - -actual object DependencyResolver { - actual val ignoreViewTests = true - - actual suspend fun getFileOpener(): FileOpener = IosFileOpener() - - actual fun getDateFormatter(locale: Locale): LocalDateFormatter { - return when (locale) { - Locale.US -> IosLocalDateFormatter("en-US") - Locale.JAPAN -> IosLocalDateFormatter("ja-JP") - } - } - - actual fun createCanvas(width: Int, height: Int): Canvas { - val scale = 2.0 - UIGraphicsBeginImageContext(CGSizeMake(width * scale, height * scale)) - return IosCanvas(width * scale, height * scale, scale = scale) - } - - actual suspend fun getDatabase(): Database { - val log = StandardLog() - val fileOpener = IosFileOpener() - val databaseOpener = IosDatabaseOpener() - - val dbFile = fileOpener.openUserFile("test.sqlite3") - if (dbFile.exists()) dbFile.delete() - val db = databaseOpener.open(dbFile) - db.migrateTo(LOOP_DATABASE_VERSION, fileOpener, log) - return db - } -} \ No newline at end of file diff --git a/uhabits-core-legacy/src/test/ios/org/isoron/IosAsyncTests.kt b/uhabits-core-legacy/src/test/ios/org/isoron/IosAsyncTests.kt deleted file mode 100644 index 711209fc3..000000000 --- a/uhabits-core-legacy/src/test/ios/org/isoron/IosAsyncTests.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron - -import kotlinx.coroutines.* - -/** - * Workaround until Kotlin adds support for testing suspend functions - * https://youtrack.jetbrains.com/issue/KT-22228 - */ -actual fun asyncTest(block: suspend () -> Unit) = runBlocking { block() } diff --git a/uhabits-core-legacy/src/test/js/org/isoron/DependencyResolver.kt b/uhabits-core-legacy/src/test/js/org/isoron/DependencyResolver.kt deleted file mode 100644 index 3a28427e4..000000000 --- a/uhabits-core-legacy/src/test/js/org/isoron/DependencyResolver.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron - -import org.isoron.platform.gui.* -import org.isoron.platform.io.* -import org.isoron.platform.time.* -import org.isoron.uhabits.* -import org.w3c.dom.* -import kotlin.browser.* - -actual object DependencyResolver { - actual val ignoreViewTests = false - - var fileOpener: JsFileOpener? = null - - actual suspend fun getFileOpener(): FileOpener { - if (fileOpener == null) { - val fs = JsFileStorage() - fs.init() - fileOpener = JsFileOpener(fs) - } - return fileOpener!! - } - - actual suspend fun getDatabase(): Database { - val nativeDB = eval("new SQL.Database()") - val db = JsDatabase(nativeDB) - db.migrateTo(LOOP_DATABASE_VERSION, getFileOpener(), StandardLog()) - return db - } - - actual fun getDateFormatter(locale: Locale): LocalDateFormatter { - return when (locale) { - Locale.US -> JsDateFormatter("en-US") - Locale.JAPAN -> JsDateFormatter("ja-JP") - } - } - - actual fun createCanvas(width: Int, height: Int): Canvas { - val element = document.createElement("canvas") as HTMLCanvasElement - element.width = 2 * width - element.height = 2 * height - element.style.width = "${2 * width}px" - element.style.height = "${2 * height}px" - val canvas = JsCanvas(element, 2.0) - canvas.setColor(Color(0xffffff)) - canvas.fillRect(0.0, 0.0, width.toDouble(), height.toDouble()) - return canvas - } -} diff --git a/uhabits-core-legacy/src/test/js/org/isoron/JsAsyncTests.kt b/uhabits-core-legacy/src/test/js/org/isoron/JsAsyncTests.kt deleted file mode 100644 index 6281be452..000000000 --- a/uhabits-core-legacy/src/test/js/org/isoron/JsAsyncTests.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron - -import kotlinx.coroutines.* - -/** - * Workaround until Kotlin adds support for testing suspend functions - * https://youtrack.jetbrains.com/issue/KT-22228 - */ -actual fun asyncTest(block: suspend () -> Unit): dynamic = GlobalScope.promise { block() } diff --git a/uhabits-core-legacy/src/test/jvm/org/isoron/DependencyResolver.kt b/uhabits-core-legacy/src/test/jvm/org/isoron/DependencyResolver.kt deleted file mode 100644 index 9f5d1c093..000000000 --- a/uhabits-core-legacy/src/test/jvm/org/isoron/DependencyResolver.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron - -import org.isoron.platform.gui.* -import org.isoron.platform.io.* -import org.isoron.platform.time.* -import org.isoron.uhabits.* -import java.awt.image.* - -actual object DependencyResolver { - actual val ignoreViewTests = false - - actual suspend fun getFileOpener(): FileOpener = JavaFileOpener() - - actual suspend fun getDatabase(): Database { - val log = StandardLog() - val fileOpener = JavaFileOpener() - val databaseOpener = JavaDatabaseOpener(log) - - val dbFile = fileOpener.openUserFile("test.sqlite3") - if (dbFile.exists()) dbFile.delete() - val db = databaseOpener.open(dbFile) - db.migrateTo(LOOP_DATABASE_VERSION, fileOpener, log) - return db - } - - actual fun getDateFormatter(locale: Locale): LocalDateFormatter { - return when (locale) { - Locale.US -> JavaLocalDateFormatter(java.util.Locale.US) - Locale.JAPAN -> JavaLocalDateFormatter(java.util.Locale.JAPAN) - } - } - - actual fun createCanvas(width: Int, height: Int): Canvas { - val widthPx = width * 2 - val heightPx = height * 2 - val image = BufferedImage(widthPx, - heightPx, - BufferedImage.TYPE_INT_ARGB) - return JavaCanvas(image, pixelScale = 2.0) - } -} diff --git a/uhabits-core-legacy/src/test/jvm/org/isoron/JavaAsyncTests.kt b/uhabits-core-legacy/src/test/jvm/org/isoron/JavaAsyncTests.kt deleted file mode 100644 index 711209fc3..000000000 --- a/uhabits-core-legacy/src/test/jvm/org/isoron/JavaAsyncTests.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron - -import kotlinx.coroutines.* - -/** - * Workaround until Kotlin adds support for testing suspend functions - * https://youtrack.jetbrains.com/issue/KT-22228 - */ -actual fun asyncTest(block: suspend () -> Unit) = runBlocking { block() } diff --git a/uhabits-core/build.gradle.kts b/uhabits-core/build.gradle.kts index 226cc9989..0baa70d72 100644 --- a/uhabits-core/build.gradle.kts +++ b/uhabits-core/build.gradle.kts @@ -19,7 +19,7 @@ plugins { kotlin("multiplatform") - id("org.jlleitschuh.gradle.ktlint") + alias(libs.plugins.ktlint.plugin) } kotlin { @@ -30,7 +30,7 @@ kotlin { val commonMain by getting { dependencies { implementation(kotlin("stdlib-common")) - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-common:1.3.8") + implementation(libs.kotlinx.coroutines.core.common) } } @@ -44,14 +44,14 @@ kotlin { val jvmMain by getting { dependencies { implementation(kotlin("stdlib-jdk8")) - compileOnly("com.google.dagger:dagger:2.51.1") - implementation("com.google.guava:guava:33.1.0-android") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.1") - implementation("androidx.annotation:annotation:1.7.1") - implementation("com.google.code.findbugs:jsr305:3.0.2") - implementation("com.opencsv:opencsv:5.9") - implementation("commons-codec:commons-codec:1.16.0") - implementation("org.apache.commons:commons-lang3:3.14.0") + compileOnly(libs.dagger) + implementation(libs.guava) + implementation(libs.kotlinx.coroutines.core.jvm) + implementation(libs.annotation) + implementation(libs.jsr305) + implementation(libs.opencsv) + implementation(libs.commons.codec) + implementation(libs.commons.lang3) } } @@ -59,19 +59,16 @@ kotlin { dependencies { implementation(kotlin("test")) implementation(kotlin("test-junit")) - implementation("org.xerial:sqlite-jdbc:3.45.1.0") - implementation("org.hamcrest:hamcrest:2.2") - implementation("org.apache.commons:commons-io:1.3.2") - implementation("org.mockito.kotlin:mockito-kotlin:5.4.0") - implementation("org.junit.jupiter:junit-jupiter:5.10.1") + implementation(libs.sqlite.jdbc) + implementation(libs.hamcrest) + implementation(libs.commons.io) + implementation(libs.mockito.kotlin) + implementation(libs.junit.jupiter) } } } } -tasks.named("jvmProcessResources") { - duplicatesStrategy = DuplicatesStrategy.INCLUDE -} -tasks.named("jvmTestProcessResources") { +tasks.withType { duplicatesStrategy = DuplicatesStrategy.INCLUDE } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/preferences/Preferences.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/preferences/Preferences.kt index f01000f33..0f28d6af6 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/preferences/Preferences.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/preferences/Preferences.kt @@ -135,6 +135,12 @@ open class Preferences(private val storage: Storage) { storage.putBoolean("pref_short_toggle", enabled) } + var isConfettiAnimationDisabled: Boolean + get() = storage.getBoolean("pref_disable_animation", false) + set(enabled) { + storage.putBoolean("pref_disable_animation", enabled) + } + fun removeListener(listener: Listener) { listeners.remove(listener) } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt index b66b08be6..e412d04d1 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt @@ -51,11 +51,11 @@ open class ListHabitsBehavior @Inject constructor( screen.showHabitScreen(h) } - fun onEdit(habit: Habit, timestamp: Timestamp?) { + fun onEdit(habit: Habit, timestamp: Timestamp?, x: Float, y: Float) { val entry = habit.computedEntries.get(timestamp!!) if (habit.type == HabitType.NUMERICAL) { val oldValue = entry.value.toDouble() / 1000 - screen.showNumberPopup(oldValue, entry.notes) { newValue: Double, newNotes: String, x: Float, y: Float -> + screen.showNumberPopup(oldValue, entry.notes) { newValue: Double, newNotes: String -> val value = (newValue * 1000).roundToInt() if (newValue != oldValue) { if ( @@ -72,7 +72,7 @@ open class ListHabitsBehavior @Inject constructor( entry.value, entry.notes, habit.color - ) { newValue: Int, newNotes: String, x: Float, y: Float -> + ) { newValue: Int, newNotes: String -> if (newValue != entry.value && newValue == YES_MANUAL) screen.showConfetti(habit.color, x, y) commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, newValue, newNotes)) } @@ -159,9 +159,7 @@ open class ListHabitsBehavior @Inject constructor( fun interface NumberPickerCallback { fun onNumberPicked( newValue: Double, - notes: String, - x: Float, - y: Float + notes: String ) fun onNumberPickerDismissed() {} } @@ -169,9 +167,7 @@ open class ListHabitsBehavior @Inject constructor( fun interface CheckMarkDialogCallback { fun onNotesSaved( value: Int, - notes: String, - x: Float, - y: Float + notes: String ) fun onNotesDismissed() {} } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt index 0a28c801f..cfbe5e0f3 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt @@ -98,7 +98,7 @@ class HistoryCardPresenter( entry.value, entry.notes, habit.color - ) { newValue, newNotes, _: Float, _: Float -> + ) { newValue, newNotes -> commandRunner.run( CreateRepetitionCommand( habitList, @@ -135,7 +135,7 @@ class HistoryCardPresenter( screen.showNumberPopup( value = oldValue / 1000.0, notes = entry.notes - ) { newValue: Double, newNotes: String, _: Float, _: Float -> + ) { newValue: Double, newNotes: String -> val thousands = (newValue * 1000).roundToInt() commandRunner.run( CreateRepetitionCommand( diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt index 26dd82df8..19f49a8a4 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt @@ -78,13 +78,13 @@ class ListHabitsBehaviorTest : BaseUnitTest() { @Test fun testOnEdit() { - behavior.onEdit(habit2, getToday()) + behavior.onEdit(habit2, getToday(), 0f, 0f) verify(screen).showNumberPopup( eq(0.1), eq(""), picker.capture() ) - picker.lastValue.onNumberPicked(100.0, "", 0f, 0f) + picker.lastValue.onNumberPicked(100.0, "") val today = getTodayWithOffset() assertThat(habit2.computedEntries.get(today).value, equalTo(100000)) } diff --git a/uhabits-ios/Application/AppDelegate.swift b/uhabits-ios/Application/AppDelegate.swift deleted file mode 100644 index df6fc7c0f..000000000 --- a/uhabits-ios/Application/AppDelegate.swift +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -import UIKit - -@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, BackendListener { - - var window: UIWindow? - var nav: UINavigationController? - let log = StandardLog() - var backend: Backend? - - func application(_ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - - backend = Backend(databaseName: "uhabits.db", - databaseOpener: IosDatabaseOpener(), - fileOpener: IosFileOpener(), - localeHelper: IosLocaleHelper(log: log), - log: log, - scope: UIDispatcher()) - - backend?.observable.addListener(listener: self) - backend?.doInit() - - window = UIWindow(frame: UIScreen.main.bounds) - nav = UINavigationController() - window?.backgroundColor = UIColor.white - window?.rootViewController = nav - window?.makeKeyAndVisible() - - return true - } - - func onReady() { - nav?.viewControllers = [MainScreenController(withBackend: backend!)] - } -} diff --git a/uhabits-ios/Application/Assets.xcassets/AppIcon.appiconset/Contents.json b/uhabits-ios/Application/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 9e5fe95b3..000000000 --- a/uhabits-ios/Application/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,100 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "loop-120.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "loop-180.png", - "scale" : "3x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "83.5x83.5", - "scale" : "2x" - }, - { - "idiom" : "ios-marketing", - "size" : "1024x1024", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/uhabits-ios/Application/Assets.xcassets/AppIcon.appiconset/loop-120.png b/uhabits-ios/Application/Assets.xcassets/AppIcon.appiconset/loop-120.png deleted file mode 100644 index 1fde27933..000000000 Binary files a/uhabits-ios/Application/Assets.xcassets/AppIcon.appiconset/loop-120.png and /dev/null differ diff --git a/uhabits-ios/Application/Assets.xcassets/AppIcon.appiconset/loop-180.png b/uhabits-ios/Application/Assets.xcassets/AppIcon.appiconset/loop-180.png deleted file mode 100644 index 99bc3ce9b..000000000 Binary files a/uhabits-ios/Application/Assets.xcassets/AppIcon.appiconset/loop-180.png and /dev/null differ diff --git a/uhabits-ios/Application/Assets.xcassets/Contents.json b/uhabits-ios/Application/Assets.xcassets/Contents.json deleted file mode 100644 index da4a164c9..000000000 --- a/uhabits-ios/Application/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/uhabits-ios/Application/Assets.xcassets/ic_more.imageset/Contents.json b/uhabits-ios/Application/Assets.xcassets/ic_more.imageset/Contents.json deleted file mode 100644 index 0a782055b..000000000 --- a/uhabits-ios/Application/Assets.xcassets/ic_more.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "baseline_more_horiz_black_24pt_1x.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "baseline_more_horiz_black_24pt_2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "baseline_more_horiz_black_24pt_3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/uhabits-ios/Application/Assets.xcassets/ic_more.imageset/baseline_more_horiz_black_24pt_1x.png b/uhabits-ios/Application/Assets.xcassets/ic_more.imageset/baseline_more_horiz_black_24pt_1x.png deleted file mode 100644 index cd5bd1d9a..000000000 Binary files a/uhabits-ios/Application/Assets.xcassets/ic_more.imageset/baseline_more_horiz_black_24pt_1x.png and /dev/null differ diff --git a/uhabits-ios/Application/Assets.xcassets/ic_more.imageset/baseline_more_horiz_black_24pt_2x.png b/uhabits-ios/Application/Assets.xcassets/ic_more.imageset/baseline_more_horiz_black_24pt_2x.png deleted file mode 100644 index a104c327e..000000000 Binary files a/uhabits-ios/Application/Assets.xcassets/ic_more.imageset/baseline_more_horiz_black_24pt_2x.png and /dev/null differ diff --git a/uhabits-ios/Application/Assets.xcassets/ic_more.imageset/baseline_more_horiz_black_24pt_3x.png b/uhabits-ios/Application/Assets.xcassets/ic_more.imageset/baseline_more_horiz_black_24pt_3x.png deleted file mode 100644 index 539e3ebe7..000000000 Binary files a/uhabits-ios/Application/Assets.xcassets/ic_more.imageset/baseline_more_horiz_black_24pt_3x.png and /dev/null differ diff --git a/uhabits-ios/Application/BridgingHeader.h b/uhabits-ios/Application/BridgingHeader.h deleted file mode 100644 index 7032ff4f2..000000000 --- a/uhabits-ios/Application/BridgingHeader.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#import "LoopHabitTracker.h" diff --git a/uhabits-ios/Application/Frontend/AboutScreenController.swift b/uhabits-ios/Application/Frontend/AboutScreenController.swift deleted file mode 100644 index f4cbe355b..000000000 --- a/uhabits-ios/Application/Frontend/AboutScreenController.swift +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -import UIKit - -class AboutScreenController : UITableViewController { -} diff --git a/uhabits-ios/Application/Frontend/DetailScreenController.swift b/uhabits-ios/Application/Frontend/DetailScreenController.swift deleted file mode 100644 index c9473c337..000000000 --- a/uhabits-ios/Application/Frontend/DetailScreenController.swift +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -import UIKit - -class DetailScreenController : UITableViewController { - - let theme: Theme - let habit: Habit - let color: Color - var cells = [UITableViewCell]() - - required init?(coder aDecoder: NSCoder) { - fatalError() - } - - init(habit: Habit, backend: Backend) { - self.theme = backend.theme - self.habit = habit - self.color = theme.color(paletteIndex: self.habit.color.index) - super.init(style: .grouped) - } - - override func viewDidLoad() { - self.title = habit.name - self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, - target: self, - action: #selector(self.onEditHabitClicked)) - cells.append(buildBarChartCell()) - cells.append(buildHistoryChartCell()) - } - - func buildBarChartCell() -> UITableViewCell { - let today = LocalDate(year: 2019, month: 3, day: 15) - let axis = (0...365).map { today.minus(days: $0) } - let component = BarChart(theme: theme, - dateFormatter: IosLocalDateFormatter()) - component.axis = axis - let cell = UITableViewCell() - let view = ComponentView(frame: cell.frame, component: component) - for k in 0...0 { - var series = [KotlinDouble]() - for _ in 1...365 { - series.append(KotlinDouble(value: Double.random(in: 0...5000))) - } - component.series.add(series) - let color = (self.habit.color.index + Int32(k * 3)) % 16 - component.colors.add(theme.color(paletteIndex: color)) - } - view.autoresizingMask = [.flexibleWidth, .flexibleHeight] - cell.contentView.addSubview(view) - return cell - } - - func buildHistoryChartCell() -> UITableViewCell { - let component = CalendarChart(today: LocalDate(year: 2019, month: 3, day: 15), - color: color, - theme: theme, - dateFormatter: IosLocalDateFormatter()) - let cell = UITableViewCell() - let view = ComponentView(frame: cell.frame, component: component) - var series = [KotlinDouble]() - for _ in 1...365 { - series.append(KotlinDouble(value: Double.random(in: 0...1))) - } - component.series = series - view.autoresizingMask = [.flexibleWidth, .flexibleHeight] - cell.contentView.addSubview(view) - return cell - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - self.navigationController?.navigationBar.barStyle = .blackOpaque - self.navigationController?.navigationBar.barTintColor = color.uicolor - self.navigationController?.navigationBar.tintColor = .white - self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white] - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return 1 - } - - override func numberOfSections(in tableView: UITableView) -> Int { - return cells.count - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - return cells[indexPath.section] - } - - @objc func onEditHabitClicked() { - self.navigationController?.pushViewController(EditHabitController(), animated: true) - } - - override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - return 200 - } -} diff --git a/uhabits-ios/Application/Frontend/EditHabitController.swift b/uhabits-ios/Application/Frontend/EditHabitController.swift deleted file mode 100644 index 5f7d5fc4e..000000000 --- a/uhabits-ios/Application/Frontend/EditHabitController.swift +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -import UIKit - -class EditHabitTableViewController: NSObject, UITableViewDataSource, UITableViewDelegate { - func disclosure(title: String, subtitle: String) -> UITableViewCell { - let cell = UITableViewCell(style: .value1, reuseIdentifier: nil) - cell.textLabel?.text = title - cell.detailTextLabel?.text = subtitle - cell.accessoryType = .disclosureIndicator - return cell - } - - func input(title: String) -> UITableViewCell { - let cell = UITableViewCell() - let field = UITextField(frame: cell.bounds.insetBy(dx: 20, dy: 0)) - field.placeholder = title - field.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth, - UIView.AutoresizingMask.flexibleHeight] - cell.contentView.addSubview(field) - return cell - } - - var primary = [UITableViewCell]() - var secondary = [UITableViewCell]() - var parentController: EditHabitController - - init(withParentController parentController: EditHabitController) { - self.parentController = parentController - super.init() - primary.append(input(title: "Name")) - primary.append(input(title: "Question (e.g. Did you wake up early today?)")) - secondary.append(disclosure(title: "Color", subtitle: "Blue")) - secondary.append(disclosure(title: "Repeat", subtitle: "Daily")) - secondary.append(disclosure(title: "Reminder", subtitle: "Disabled")) - } - - func numberOfSections(in tableView: UITableView) -> Int { - return 2 - } - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return section == 0 ? primary.count : secondary.count - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - return indexPath.section == 0 ? primary[indexPath.item] : secondary[indexPath.item] - } - -// func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { -// let alert = UIAlertController(title: "Hello", message: "You selected something", preferredStyle: .alert) -// parentController.present(alert, animated: true) -// } -} - -class EditHabitController: UIViewController { - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - let bounds = UIScreen.main.bounds - let tableController = EditHabitTableViewController(withParentController: self) - let table = UITableView(frame: bounds, style: .grouped) - table.dataSource = tableController - table.delegate = tableController - self.view = table - } - - override func viewDidLoad() { - self.title = "Edit Habit" - } -} diff --git a/uhabits-ios/Application/Frontend/MainScreenController.swift b/uhabits-ios/Application/Frontend/MainScreenController.swift deleted file mode 100644 index 7c4d9136d..000000000 --- a/uhabits-ios/Application/Frontend/MainScreenController.swift +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -import UIKit - -class MainScreenCell : UITableViewCell { - var ring = ComponentView(frame: CGRect(), component: nil) - var label = UILabel() - var buttons: [ComponentView] = [] - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: .default, reuseIdentifier: reuseIdentifier) - } - required init?(coder aDecoder: NSCoder) { - fatalError() - } - - func update(habit: Habit, checkmarks: [Checkmark], score: Score, theme: Theme, nButtons: Int) { - if buttons.count != nButtons { - buttons.removeAll() - for v in contentView.subviews { v.removeFromSuperview() } - - let size = CGFloat(theme.checkmarkButtonSize) - let stack = UIStackView(frame: contentView.frame) - stack.autoresizingMask = [.flexibleWidth, .flexibleHeight] - stack.axis = .horizontal - stack.distribution = .fill - stack.alignment = .center - contentView.addSubview(stack) - - ring.backgroundColor = .white - ring.widthAnchor.constraint(equalToConstant: size * 0.75).isActive = true - ring.heightAnchor.constraint(equalToConstant: size).isActive = true - stack.addArrangedSubview(ring) - - label.backgroundColor = .white - label.heightAnchor.constraint(equalToConstant: size).isActive = true - stack.addArrangedSubview(label) - - for _ in 1...nButtons { - let btn = ComponentView(frame: frame, component: nil) - btn.backgroundColor = .white - btn.widthAnchor.constraint(equalToConstant: size).isActive = true - btn.heightAnchor.constraint(equalToConstant: size).isActive = true - buttons.append(btn) - stack.addArrangedSubview(btn) - } - } - - var color = theme.color(paletteIndex: habit.color.index) - if habit.isArchived { color = theme.mediumContrastTextColor } - label.text = habit.name - label.textColor = color.uicolor - ring.component = Ring(color: color, - percentage: score.value, - thickness: 2.5, - radius: 7, - theme: theme, - label: false) - ring.setNeedsDisplay() - - for i in 0.. Int { - return data?.habits.count ?? 0 - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MainScreenCell - let habit = data!.habits[indexPath.row] - cell.update(habit: habit, - checkmarks: data!.checkmarks[habit]!, - score: data!.scores[habit]!, - theme: theme, - nButtons: nButtons) - return cell - } - - override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - let component = HabitListHeader(today: LocalDate(year: 2019, month: 3, day: 24), - nButtons: Int32(nButtons), - theme: theme, - fmt: IosLocalDateFormatter()) - return ComponentView(frame: CGRect(x: 0, y: 0, width: 100, height: CGFloat(theme.checkmarkButtonSize)), - component: component) - } - - override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - return CGFloat(theme.checkmarkButtonSize) - } - - override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - return CGFloat(theme.checkmarkButtonSize) + 3 - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let habit = data!.habits[indexPath.row] - self.navigationController?.pushViewController(DetailScreenController(habit: habit, backend: backend), animated: true) - } - - override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { - computeNumberOfButtons(Double(size.width)) - reload() - } - - @objc func onCreateHabitClicked() { - self.navigationController?.pushViewController(EditHabitController(), animated: true) - } - - @objc func onMoreActionsClicked() { - let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - - if isThereAnyArchivedHabit() { - if preferences.showArchived { - alert.addAction(UIAlertAction(title: strings.hide_archived, style: .default) { - (action: UIAlertAction) -> Void in - self.preferences.showArchived = false - self.dataSource.requestData() - }) - } else { - alert.addAction(UIAlertAction(title: strings.show_archived, style: .default) { - (action: UIAlertAction) -> Void in - self.preferences.showArchived = true - self.dataSource.requestData() - }) - } - } - - if preferences.showCompleted { - alert.addAction(UIAlertAction(title: strings.hide_completed, style: .default) { - (action: UIAlertAction) -> Void in - self.preferences.showCompleted = false - self.dataSource.requestData() - }) - } else { - alert.addAction(UIAlertAction(title: strings.show_completed, style: .default) { - (action: UIAlertAction) -> Void in - self.preferences.showCompleted = true - self.dataSource.requestData() - }) - } - - if preferences.nightMode { - alert.addAction(UIAlertAction(title: strings.day_mode, style: .default) { - (action: UIAlertAction) -> Void in - self.preferences.nightMode = false - }) - } else { - alert.addAction(UIAlertAction(title: strings.night_mode, style: .default) { - (action: UIAlertAction) -> Void in - self.preferences.nightMode = true - }) - } - - alert.addAction(UIAlertAction(title: strings.help, style: .default) { - (action: UIAlertAction) -> Void in - if let link = URL(string: "http://loophabits.org/faq") { - UIApplication.shared.open(link) - } - }) - alert.addAction(UIAlertAction(title: strings.about, style: .default) { - (action: UIAlertAction) -> Void in - self.navigationController?.pushViewController(AboutScreenController(), animated: true) - }) - alert.addAction(UIAlertAction(title: strings.cancel, style: .cancel) { - (action: UIAlertAction) -> Void in - // Do nothing - }) - present(alert, animated: true, completion: nil) - } - - func onDataChanged(newData: MainScreenDataSource.Data) { - data = newData - reload() - } - - func computeNumberOfButtons(_ width: Double) { - nButtons = Int((width - 220) / theme.checkmarkButtonSize) - nButtons = max(nButtons, 3) - nButtons = min(nButtons, Int(dataSource.maxNumberOfButtons)) - } - - func reload() { - let sections = NSIndexSet(indexesIn: NSMakeRange(0, self.tableView.numberOfSections)) - tableView.reloadSections(sections as IndexSet, with: .automatic) - } - - func isThereAnyArchivedHabit() -> Bool { - return data!.habits.filter({ $0.isArchived }).count > 0 - } -} diff --git a/uhabits-ios/Application/Info.plist b/uhabits-ios/Application/Info.plist deleted file mode 100644 index bb68c7e1f..000000000 --- a/uhabits-ios/Application/Info.plist +++ /dev/null @@ -1,49 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Loop - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UIAppFonts - - fonts/FontAwesome.ttf - - UILaunchStoryboardName - Launch.storyboard - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/uhabits-ios/Application/Launch.storyboard b/uhabits-ios/Application/Launch.storyboard deleted file mode 100644 index f9a048edf..000000000 --- a/uhabits-ios/Application/Launch.storyboard +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/uhabits-ios/Application/Platform/ComponentView.swift b/uhabits-ios/Application/Platform/ComponentView.swift deleted file mode 100644 index 8b111651c..000000000 --- a/uhabits-ios/Application/Platform/ComponentView.swift +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2016-2019 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -import UIKit - -class ComponentView : UIView { - var component: Component? - - init(frame: CGRect, component: Component?) { - self.component = component - super.init(frame: frame) - } - - required init?(coder aDecoder: NSCoder) { - fatalError() - } - - override func draw(_ rect: CGRect) { - let canvas = IosCanvas(width: Double(rect.width), - height: Double(rect.height), - scale: 1.0) - component?.draw(canvas: canvas) - } - - override func layoutSubviews() { - setNeedsDisplay() - } -} diff --git a/uhabits-ios/Tests/Info.plist b/uhabits-ios/Tests/Info.plist deleted file mode 100644 index 866537f58..000000000 --- a/uhabits-ios/Tests/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - UIAppFonts - - fonts/FontAwesome.ttf - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/uhabits-ios/uhabits.xcodeproj/project.pbxproj b/uhabits-ios/uhabits.xcodeproj/project.pbxproj deleted file mode 100644 index 75fc10fc7..000000000 --- a/uhabits-ios/uhabits.xcodeproj/project.pbxproj +++ /dev/null @@ -1,584 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 50; - objects = { - -/* Begin PBXBuildFile section */ - 001592642260AE0F00D2814F /* LoopHabitTracker.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C0C6C92246E543003D8AF0 /* LoopHabitTracker.framework */; }; - 005166D12471C02D00C6CFD6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00A5B42722009F590024E00C /* AppDelegate.swift */; }; - 006EFE50225432B8008464E0 /* AboutScreenController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 006EFE4F225432B8008464E0 /* AboutScreenController.swift */; }; - 00A5B42822009F590024E00C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00A5B42722009F590024E00C /* AppDelegate.swift */; }; - 00A5B42A22009F590024E00C /* MainScreenController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00A5B42922009F590024E00C /* MainScreenController.swift */; }; - 00A5B42F22009F5A0024E00C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 00A5B42E22009F5A0024E00C /* Assets.xcassets */; }; - 00C0C6BD22465F65003D8AF0 /* fonts in Resources */ = {isa = PBXBuildFile; fileRef = 00C0C6BA22465F65003D8AF0 /* fonts */; }; - 00C0C6BE22465F65003D8AF0 /* databases in Resources */ = {isa = PBXBuildFile; fileRef = 00C0C6BB22465F65003D8AF0 /* databases */; }; - 00C0C6BF22465F65003D8AF0 /* migrations in Resources */ = {isa = PBXBuildFile; fileRef = 00C0C6BC22465F65003D8AF0 /* migrations */; }; - 00C0C6CA2246E543003D8AF0 /* LoopHabitTracker.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C0C6C92246E543003D8AF0 /* LoopHabitTracker.framework */; }; - 00C0C6CC2246E550003D8AF0 /* LoopHabitTracker.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 00C0C6C92246E543003D8AF0 /* LoopHabitTracker.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 00C0C6D122470705003D8AF0 /* ComponentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00C0C6D022470705003D8AF0 /* ComponentView.swift */; }; - 00C0C6E0224A3602003D8AF0 /* DetailScreenController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00C0C6DE224A35FC003D8AF0 /* DetailScreenController.swift */; }; - 00D48BD12200A31300CC4527 /* Launch.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 00D48BD02200A31300CC4527 /* Launch.storyboard */; }; - 00D48BD32200AC1600CC4527 /* EditHabitController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00D48BD22200AC1600CC4527 /* EditHabitController.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 00A5B43922009F5A0024E00C /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 00A5B41C22009F590024E00C /* Project object */; - proxyType = 1; - remoteGlobalIDString = 00A5B42322009F590024E00C; - remoteInfo = uhabits; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 00C0C6B522465C47003D8AF0 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 00C0C6CC2246E550003D8AF0 /* LoopHabitTracker.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 006EFE4F225432B8008464E0 /* AboutScreenController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutScreenController.swift; sourceTree = ""; }; - 00A5B42422009F590024E00C /* uhabits.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = uhabits.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 00A5B42722009F590024E00C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 00A5B42922009F590024E00C /* MainScreenController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainScreenController.swift; sourceTree = ""; }; - 00A5B42E22009F5A0024E00C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 00A5B43322009F5A0024E00C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 00A5B43822009F5A0024E00C /* uhabitsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = uhabitsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 00A5B43E22009F5A0024E00C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 00C0C6AE224655D8003D8AF0 /* BridgingHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BridgingHeader.h; sourceTree = ""; }; - 00C0C6BA22465F65003D8AF0 /* fonts */ = {isa = PBXFileReference; lastKnownFileType = folder; path = fonts; sourceTree = ""; }; - 00C0C6BB22465F65003D8AF0 /* databases */ = {isa = PBXFileReference; lastKnownFileType = folder; path = databases; sourceTree = ""; }; - 00C0C6BC22465F65003D8AF0 /* migrations */ = {isa = PBXFileReference; lastKnownFileType = folder; path = migrations; sourceTree = ""; }; - 00C0C6C92246E543003D8AF0 /* LoopHabitTracker.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LoopHabitTracker.framework; path = "../uhabits-core-legacy/build/bin/ios/debugFramework/LoopHabitTracker.framework"; sourceTree = ""; }; - 00C0C6D022470705003D8AF0 /* ComponentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComponentView.swift; sourceTree = ""; }; - 00C0C6DE224A35FC003D8AF0 /* DetailScreenController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailScreenController.swift; sourceTree = ""; }; - 00D48BD02200A31300CC4527 /* Launch.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Launch.storyboard; sourceTree = ""; }; - 00D48BD22200AC1600CC4527 /* EditHabitController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditHabitController.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 00A5B42122009F590024E00C /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 00C0C6CA2246E543003D8AF0 /* LoopHabitTracker.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 00A5B43522009F5A0024E00C /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 001592642260AE0F00D2814F /* LoopHabitTracker.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 006EFE49224FF41B008464E0 /* Frontend */ = { - isa = PBXGroup; - children = ( - 006EFE4F225432B8008464E0 /* AboutScreenController.swift */, - 00C0C6DE224A35FC003D8AF0 /* DetailScreenController.swift */, - 00D48BD22200AC1600CC4527 /* EditHabitController.swift */, - 00A5B42922009F590024E00C /* MainScreenController.swift */, - ); - path = Frontend; - sourceTree = ""; - }; - 00A5B41B22009F590024E00C = { - isa = PBXGroup; - children = ( - 00C0C6C022465F80003D8AF0 /* Assets */, - 00A5B42622009F590024E00C /* Application */, - 00A5B43B22009F5A0024E00C /* Tests */, - 00A5B42522009F590024E00C /* Products */, - 00C0C6B0224658CD003D8AF0 /* Frameworks */, - ); - sourceTree = ""; - }; - 00A5B42522009F590024E00C /* Products */ = { - isa = PBXGroup; - children = ( - 00A5B42422009F590024E00C /* uhabits.app */, - 00A5B43822009F5A0024E00C /* uhabitsTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 00A5B42622009F590024E00C /* Application */ = { - isa = PBXGroup; - children = ( - 00C0C6AE224655D8003D8AF0 /* BridgingHeader.h */, - 00A5B43322009F5A0024E00C /* Info.plist */, - 00D48BD02200A31300CC4527 /* Launch.storyboard */, - 00A5B42722009F590024E00C /* AppDelegate.swift */, - 00A5B42E22009F5A0024E00C /* Assets.xcassets */, - 006EFE49224FF41B008464E0 /* Frontend */, - 00C0C6D622471BA3003D8AF0 /* Platform */, - ); - path = Application; - sourceTree = ""; - }; - 00A5B43B22009F5A0024E00C /* Tests */ = { - isa = PBXGroup; - children = ( - 00A5B43E22009F5A0024E00C /* Info.plist */, - ); - path = Tests; - sourceTree = ""; - }; - 00C0C6B0224658CD003D8AF0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 00C0C6C92246E543003D8AF0 /* LoopHabitTracker.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 00C0C6C022465F80003D8AF0 /* Assets */ = { - isa = PBXGroup; - children = ( - 00C0C6BB22465F65003D8AF0 /* databases */, - 00C0C6BA22465F65003D8AF0 /* fonts */, - 00C0C6BC22465F65003D8AF0 /* migrations */, - ); - name = Assets; - path = "../uhabits-core-legacy/assets/main"; - sourceTree = ""; - }; - 00C0C6D622471BA3003D8AF0 /* Platform */ = { - isa = PBXGroup; - children = ( - 00C0C6D022470705003D8AF0 /* ComponentView.swift */, - ); - path = Platform; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 00A5B42322009F590024E00C /* uhabits */ = { - isa = PBXNativeTarget; - buildConfigurationList = 00A5B44122009F5A0024E00C /* Build configuration list for PBXNativeTarget "uhabits" */; - buildPhases = ( - 00C0C6D32247134F003D8AF0 /* Build Core Module */, - 00A5B42022009F590024E00C /* Sources */, - 00A5B42122009F590024E00C /* Frameworks */, - 00A5B42222009F590024E00C /* Resources */, - 00C0C6B522465C47003D8AF0 /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = uhabits; - productName = uhabits; - productReference = 00A5B42422009F590024E00C /* uhabits.app */; - productType = "com.apple.product-type.application"; - }; - 00A5B43722009F5A0024E00C /* uhabitsTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 00A5B44422009F5A0024E00C /* Build configuration list for PBXNativeTarget "uhabitsTests" */; - buildPhases = ( - 00A5B43422009F5A0024E00C /* Sources */, - 00A5B43522009F5A0024E00C /* Frameworks */, - 00A5B43622009F5A0024E00C /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 00A5B43A22009F5A0024E00C /* PBXTargetDependency */, - ); - name = uhabitsTests; - productName = uhabitsTests; - productReference = 00A5B43822009F5A0024E00C /* uhabitsTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 00A5B41C22009F590024E00C /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 1010; - LastUpgradeCheck = 1010; - ORGANIZATIONNAME = Loop; - TargetAttributes = { - 00A5B42322009F590024E00C = { - CreatedOnToolsVersion = 10.1; - }; - 00A5B43722009F5A0024E00C = { - CreatedOnToolsVersion = 10.1; - TestTargetID = 00A5B42322009F590024E00C; - }; - }; - }; - buildConfigurationList = 00A5B41F22009F590024E00C /* Build configuration list for PBXProject "uhabits" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 00A5B41B22009F590024E00C; - productRefGroup = 00A5B42522009F590024E00C /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 00A5B42322009F590024E00C /* uhabits */, - 00A5B43722009F5A0024E00C /* uhabitsTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 00A5B42222009F590024E00C /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 00C0C6BD22465F65003D8AF0 /* fonts in Resources */, - 00C0C6BE22465F65003D8AF0 /* databases in Resources */, - 00C0C6BF22465F65003D8AF0 /* migrations in Resources */, - 00A5B42F22009F5A0024E00C /* Assets.xcassets in Resources */, - 00D48BD12200A31300CC4527 /* Launch.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 00A5B43622009F5A0024E00C /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 00C0C6D32247134F003D8AF0 /* Build Core Module */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = "Build Core Module"; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "cd ../uhabits-core-legacy\n../gradlew linkDebugFrameworkIos\n"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 00A5B42022009F590024E00C /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 00C0C6D122470705003D8AF0 /* ComponentView.swift in Sources */, - 00C0C6E0224A3602003D8AF0 /* DetailScreenController.swift in Sources */, - 00A5B42A22009F590024E00C /* MainScreenController.swift in Sources */, - 00A5B42822009F590024E00C /* AppDelegate.swift in Sources */, - 00D48BD32200AC1600CC4527 /* EditHabitController.swift in Sources */, - 006EFE50225432B8008464E0 /* AboutScreenController.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 00A5B43422009F5A0024E00C /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 005166D12471C02D00C6CFD6 /* AppDelegate.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 00A5B43A22009F5A0024E00C /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 00A5B42322009F590024E00C /* uhabits */; - targetProxy = 00A5B43922009F5A0024E00C /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 00A5B43F22009F5A0024E00C /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - FRAMEWORK_SEARCH_PATHS = ""; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = ""; - IPHONEOS_DEPLOYMENT_TARGET = 12.1; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 00A5B44022009F5A0024E00C /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - FRAMEWORK_SEARCH_PATHS = ""; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = ""; - IPHONEOS_DEPLOYMENT_TARGET = 12.1; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 00A5B44222009F5A0024E00C /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = R5YTHGE3PS; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(PROJECT_DIR)/../uhabits-core-legacy/build/bin/ios/debugFramework/", - "$(PROJECT_DIR)", - ); - HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../uhabits-core-legacy/build/bin/ios/debugFramework/LoopHabitTracker.framework/Headers/"; - INFOPLIST_FILE = Application/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = org.isoron.uhabits; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OBJC_BRIDGING_HEADER = Application/BridgingHeader.h; - SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; - SWIFT_VERSION = 4.2; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 00A5B44322009F5A0024E00C /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = R5YTHGE3PS; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(PROJECT_DIR)/../uhabits-core-legacy/build/bin/ios/debugFramework/", - "$(PROJECT_DIR)", - ); - HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../uhabits-core-legacy/build/bin/ios/debugFramework/LoopHabitTracker.framework/Headers/"; - INFOPLIST_FILE = Application/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = org.isoron.uhabits; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OBJC_BRIDGING_HEADER = Application/BridgingHeader.h; - SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; - SWIFT_VERSION = 4.2; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 00A5B44522009F5A0024E00C /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = R5YTHGE3PS; - FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../core/build/bin/ios/mainDebugFramework/"; - HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../core/build/bin/ios/mainDebugFramework/main.framework/Headers/"; - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = org.isoron.uhabitsTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = ""; - SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; - SWIFT_VERSION = 4.2; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/uhabits.app/uhabits"; - }; - name = Debug; - }; - 00A5B44622009F5A0024E00C /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = R5YTHGE3PS; - FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../core/build/bin/ios/mainDebugFramework/"; - HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../core/build/bin/ios/mainDebugFramework/main.framework/Headers/"; - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = org.isoron.uhabitsTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = ""; - SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; - SWIFT_VERSION = 4.2; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/uhabits.app/uhabits"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 00A5B41F22009F590024E00C /* Build configuration list for PBXProject "uhabits" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 00A5B43F22009F5A0024E00C /* Debug */, - 00A5B44022009F5A0024E00C /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 00A5B44122009F5A0024E00C /* Build configuration list for PBXNativeTarget "uhabits" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 00A5B44222009F5A0024E00C /* Debug */, - 00A5B44322009F5A0024E00C /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 00A5B44422009F5A0024E00C /* Build configuration list for PBXNativeTarget "uhabitsTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 00A5B44522009F5A0024E00C /* Debug */, - 00A5B44622009F5A0024E00C /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 00A5B41C22009F590024E00C /* Project object */; -} diff --git a/uhabits-ios/uhabits.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/uhabits-ios/uhabits.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 156ec4d58..000000000 --- a/uhabits-ios/uhabits.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/uhabits-ios/uhabits.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/uhabits-ios/uhabits.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/uhabits-ios/uhabits.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/uhabits-ios/uhabits.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/uhabits-ios/uhabits.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index 0c67376eb..000000000 --- a/uhabits-ios/uhabits.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/uhabits-server/.gitignore b/uhabits-server/.gitignore deleted file mode 100644 index fae6b746e..000000000 --- a/uhabits-server/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -/.gradle -/.idea -/out -/build -*.iml -*.ipr -*.iws diff --git a/uhabits-server/Dockerfile b/uhabits-server/Dockerfile deleted file mode 100644 index 34d77779a..000000000 --- a/uhabits-server/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM openjdk:8-jre-alpine -RUN mkdir /app -COPY uhabits-server.jar /app/uhabits-server.jar -ENV LOOP_REPO_PATH /data/ -WORKDIR /app -CMD ["java", \ - "-server", \ - "-XX:MaxGCPauseMillis=100", \ - "-XX:+UseStringDeduplication", \ - "-jar", \ - "uhabits-server.jar"] \ No newline at end of file diff --git a/uhabits-server/build.gradle.kts b/uhabits-server/build.gradle.kts deleted file mode 100644 index 9f2fda06a..000000000 --- a/uhabits-server/build.gradle.kts +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar - -plugins { - application - id("kotlin") - id("com.github.johnrengelman.shadow") version "8.1.1" -} - -kotlin { - jvmToolchain(17) -} - - -application { - group = "org.isoron.uhabits" - version = "0.0.1" - mainClass.set("io.ktor.server.netty.EngineMain") -} - -dependencies { - val ktorVersion = "1.6.8" - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.22") - implementation("io.ktor:ktor-server-netty:$ktorVersion") - implementation("ch.qos.logback:logback-classic:1.4.14") - implementation("io.ktor:ktor-server-core:$ktorVersion") - implementation("io.ktor:ktor-html-builder:$ktorVersion") - implementation("io.ktor:ktor-jackson:$ktorVersion") - implementation("org.jetbrains:kotlin-css-jvm:1.0.0-pre.148-kotlin-1.4.30") - implementation("io.prometheus:simpleclient:0.16.0") - implementation("io.prometheus:simpleclient_httpserver:0.16.0") - implementation("io.prometheus:simpleclient_hotspot:0.16.0") - testImplementation("io.ktor:ktor-server-tests:$ktorVersion") - testImplementation("org.mockito.kotlin:mockito-kotlin:5.2.1") - testImplementation(kotlin("test")) - testImplementation(kotlin("test-junit")) -} - -tasks.withType { - archiveBaseName.set("uhabits-server") - archiveClassifier.set("") - archiveVersion.set("") -} - diff --git a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/SyncData.kt b/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/SyncData.kt deleted file mode 100644 index d60319d6e..000000000 --- a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/SyncData.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync - -import com.fasterxml.jackson.databind.* - -data class SyncData( - val version: Long, - val content: String -) - -data class RegisterReponse(val key: String) - -data class GetDataVersionResponse(val version: Long) - -val defaultMapper = ObjectMapper() -fun SyncData.toJson(): String = defaultMapper.writeValueAsString(this) -fun GetDataVersionResponse.toJson(): String = defaultMapper.writeValueAsString(this) \ No newline at end of file diff --git a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/SyncException.kt b/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/SyncException.kt deleted file mode 100644 index 30689ad86..000000000 --- a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/SyncException.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync - -open class SyncException: RuntimeException() - -class KeyNotFoundException: SyncException() - -class ServiceUnavailable: SyncException() - -class EditConflictException: SyncException() \ No newline at end of file diff --git a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/app/LinkModule.kt b/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/app/LinkModule.kt deleted file mode 100644 index 32ed88349..000000000 --- a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/app/LinkModule.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.app - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.request.* -import io.ktor.response.* -import io.ktor.routing.* -import org.isoron.uhabits.sync.* - -data class LinkRegisterRequestData( - val syncKey: String, -) -fun LinkRegisterRequestData.toJson(): String = defaultMapper.writeValueAsString(this) - -fun Routing.links(app: SyncApplication) { - post("/links") { - try { - val data = call.receive() - val link = app.server.registerLink(data.syncKey) - call.respond(HttpStatusCode.OK, link) - } catch (e: ServiceUnavailable) { - call.respond(HttpStatusCode.ServiceUnavailable) - } - } - get("/links/{id}") { - try { - val id = call.parameters["id"]!! - val link = app.server.getLink(id) - call.respond(HttpStatusCode.OK, link) - } catch (e: ServiceUnavailable) { - call.respond(HttpStatusCode.ServiceUnavailable) - } catch (e: KeyNotFoundException) { - call.respond(HttpStatusCode.NotFound) - } - } -} diff --git a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/app/MetricsModule.kt b/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/app/MetricsModule.kt deleted file mode 100644 index f367dd552..000000000 --- a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/app/MetricsModule.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.app - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import io.ktor.routing.* -import io.prometheus.client.* -import io.prometheus.client.exporter.common.* -import io.prometheus.client.hotspot.* -import java.io.* - - -fun Routing.metrics(app: SyncApplication) { - // Register JVM metrics - DefaultExports.initialize() - - get("/metrics") { - val writer = StringWriter() - TextFormat.write004( - writer, - CollectorRegistry.defaultRegistry.filteredMetricFamilySamples(setOf()), - ) - call.respond(HttpStatusCode.OK, writer.toString()) - } -} diff --git a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/app/RegistrationModule.kt b/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/app/RegistrationModule.kt deleted file mode 100644 index 1501b243a..000000000 --- a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/app/RegistrationModule.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.app - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import io.ktor.routing.* -import org.isoron.uhabits.sync.* - -fun Routing.registration(app: SyncApplication) { - post("/register") { - try { - val key = app.server.register() - call.respond(HttpStatusCode.OK, RegisterReponse(key)) - } catch (e: ServiceUnavailable) { - call.respond(HttpStatusCode.ServiceUnavailable) - } - } -} diff --git a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/app/StorageModule.kt b/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/app/StorageModule.kt deleted file mode 100644 index 3e67d359c..000000000 --- a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/app/StorageModule.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.app - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.request.* -import io.ktor.response.* -import io.ktor.routing.* -import org.isoron.uhabits.sync.* - -fun Routing.storage(app: SyncApplication) { - route("/db/{key}") { - get { - val key = call.parameters["key"]!! - try { - val data = app.server.getData(key) - call.respond(HttpStatusCode.OK, data) - } catch(e: KeyNotFoundException) { - call.respond(HttpStatusCode.NotFound) - } - } - put { - val key = call.parameters["key"]!! - val data = call.receive() - try { - app.server.put(key, data) - call.respond(HttpStatusCode.OK) - } catch (e: KeyNotFoundException) { - call.respond(HttpStatusCode.NotFound) - } catch (e: EditConflictException) { - call.respond(HttpStatusCode.Conflict) - } - } - get("version") { - val key = call.parameters["key"]!! - try { - val version = app.server.getDataVersion(key) - call.respond(HttpStatusCode.OK, GetDataVersionResponse(version)) - } catch(e: KeyNotFoundException) { - call.respond(HttpStatusCode.NotFound) - } - } - } -} \ No newline at end of file diff --git a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/app/SyncApplication.kt b/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/app/SyncApplication.kt deleted file mode 100644 index 71344b16f..000000000 --- a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/app/SyncApplication.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.app - -import io.ktor.application.* -import io.ktor.features.* -import io.ktor.jackson.* -import io.ktor.routing.* -import org.isoron.uhabits.sync.* -import org.isoron.uhabits.sync.repository.* -import org.isoron.uhabits.sync.server.* -import java.nio.file.* - -fun Application.main() = SyncApplication().apply { main() } - -val REPOSITORY_PATH: Path = Paths.get(System.getenv("LOOP_REPO_PATH")!!) - -class SyncApplication( - val server: AbstractSyncServer = RepositorySyncServer( - FileRepository(REPOSITORY_PATH), - ), -) { - fun Application.main() { - install(DefaultHeaders) - install(CallLogging) - install(ContentNegotiation) { - jackson { } - } - routing { - registration(this@SyncApplication) - storage(this@SyncApplication) - links(this@SyncApplication) - metrics(this@SyncApplication) - } - } -} diff --git a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/links/Link.kt b/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/links/Link.kt deleted file mode 100644 index 9adf50614..000000000 --- a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/links/Link.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.links - -import org.isoron.uhabits.sync.defaultMapper - -/** - * A Link maps a public URL (such as https://sync.loophabits.org/links/B752A6) - * to a synchronization key. They are used to transfer sync keys between devices - * without ever exposing the original sync key. Unlike sync keys, links expire - * after a few minutes. - */ -data class Link( - val id: String, - val syncKey: String, - val createdAt: Long, -) - -fun Link.toJson(): String = defaultMapper.writeValueAsString(this) diff --git a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/links/LinkManager.kt b/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/links/LinkManager.kt deleted file mode 100644 index 4b153861c..000000000 --- a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/links/LinkManager.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.links - -import org.isoron.uhabits.sync.* -import org.isoron.uhabits.sync.utils.* - -class LinkManager( - private val timeoutInMillis: Long = 900_000, -) { - private val links = HashMap() - - fun register(syncKey: String): Link { - val link = Link( - id = randomString(64), - syncKey = syncKey, - createdAt = System.currentTimeMillis(), - ) - links[link.id] = link - return link - } - - fun get(id: String): Link { - val link = links[id] ?: throw KeyNotFoundException() - val ageInMillis = System.currentTimeMillis() - link.createdAt - if (ageInMillis > timeoutInMillis) { - links.remove(id) - throw KeyNotFoundException() - } - return link - } -} \ No newline at end of file diff --git a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/repository/FileRepository.kt b/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/repository/FileRepository.kt deleted file mode 100644 index 1faf93fc7..000000000 --- a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/repository/FileRepository.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.repository - -import org.isoron.uhabits.sync.* -import java.io.* -import java.nio.file.* - -class FileRepository( - private val basepath: Path, -) : Repository { - - override suspend fun put(key: String, data: SyncData) { - // Create directory - val dataPath = key.toDataPath() - val dataDir = dataPath.toFile() - dataDir.mkdirs() - - // Create metadata - val metadataFile = dataPath.resolve("version").toFile() - metadataFile.outputStream().use { outputStream -> - PrintWriter(outputStream).use { printWriter -> - printWriter.print(data.version) - } - } - - // Create data file - val dataFile = dataPath.resolve("content").toFile() - dataFile.outputStream().use { outputStream -> - PrintWriter(outputStream).use { printWriter -> - printWriter.print(data.content) - } - } - } - - override suspend fun get(key: String): SyncData { - val dataPath = key.toDataPath() - val contentFile = dataPath.resolve("content").toFile() - val versionFile = dataPath.resolve("version").toFile() - if (!contentFile.exists() || !versionFile.exists()) { - throw KeyNotFoundException() - } - val version = versionFile.readText().trim().toLong() - return SyncData(version, contentFile.readText()) - } - - override suspend fun contains(key: String): Boolean { - val dataPath = key.toDataPath() - val versionFile = dataPath.resolve("version").toFile() - return versionFile.exists() - } - - private fun String.toDataPath(): Path { - return basepath.resolve("${this[0]}/${this[1]}/${this[2]}/${this[3]}/$this") - } -} \ No newline at end of file diff --git a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/repository/Repository.kt b/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/repository/Repository.kt deleted file mode 100644 index 651ca679f..000000000 --- a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/repository/Repository.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.repository - -import org.isoron.uhabits.sync.KeyNotFoundException -import org.isoron.uhabits.sync.SyncData - -/** - * A class that knows how to store and retrieve a large number of [SyncData] items. - */ -interface Repository { - /** - * Stores a data item, under the provided key. The item can be later retrieved with [get]. - * Replaces existing items silently. - */ - suspend fun put(key: String, data: SyncData) - - /** - * Retrieves a data item that was previously stored using [put]. - * @throws KeyNotFoundException If no such key exists. - */ - suspend fun get(key: String): SyncData - - /** - * Returns true if the repository contains a given key. - */ - suspend fun contains(key: String): Boolean -} - diff --git a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/server/AbstractSyncServer.kt b/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/server/AbstractSyncServer.kt deleted file mode 100644 index bd18c7b30..000000000 --- a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/server/AbstractSyncServer.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.server - -import org.isoron.uhabits.sync.* -import org.isoron.uhabits.sync.links.* - -interface AbstractSyncServer { - /** - * Generates and returns a new sync key, which can be used to store and retrive - * data. - * - * @throws ServiceUnavailable If key cannot be generated at this time, for example, - * due to insufficient server resources, temporary server maintenance or network problems. - */ - suspend fun register(): String - - /** - * Replaces data for a given sync key. - * - * @throws KeyNotFoundException If key is not found - * @throws EditConflictException If the version of the data provided is not - * exactly the current data version plus one. - * @throws ServiceUnavailable If data cannot be put at this time, for example, due - * to insufficient server resources or network problems. - */ - suspend fun put(key: String, newData: SyncData) - - /** - * Returns data for a given sync key. - * - * @throws KeyNotFoundException If key is not found - * @throws ServiceUnavailable If data cannot be retrieved at this time, for example, due - * to insufficient server resources or network problems. - */ - suspend fun getData(key: String): SyncData - - /** - * Returns the current data version for the given key - * - * @throws KeyNotFoundException If key is not found - * @throws ServiceUnavailable If data cannot be retrieved at this time, for example, due - * to insufficient server resources or network problems. - */ - suspend fun getDataVersion(key: String): Long - - /** - * Registers a new temporary link (mapping to the given sync key) and returns it. - * - * @throws ServiceUnavailable If the link cannot be generated at this time due to - * insufficient server resources. - */ - suspend fun registerLink(syncKey: String): Link - - /** - * Retrieves the syncKey associated with the given link id. - * - * @throws ServiceUnavailable If the link cannot be resolved at this time due to - * insufficient server resources. - * @throws KeyNotFoundException If the link id cannot be found, or if it has - * expired. - */ - suspend fun getLink(id: String): Link -} diff --git a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/server/RepositorySyncServer.kt b/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/server/RepositorySyncServer.kt deleted file mode 100644 index cdde98d91..000000000 --- a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/server/RepositorySyncServer.kt +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.server - -import io.prometheus.client.* -import org.isoron.uhabits.sync.* -import org.isoron.uhabits.sync.links.* -import org.isoron.uhabits.sync.repository.* -import org.isoron.uhabits.sync.utils.* - -/** - * An AbstractSyncServer that stores all data in a [Repository]. - */ -class RepositorySyncServer( - private val repo: Repository, - private val linkManager: LinkManager = LinkManager(), -) : AbstractSyncServer { - - private val requestsCounter: Counter = Counter.build() - .name("requests_total") - .help("Total number of requests") - .labelNames("method") - .register() - - override suspend fun register(): String { - requestsCounter.labels("register").inc() - val key = generateKey() - repo.put(key, SyncData(0, "")) - return key - } - - override suspend fun put(key: String, newData: SyncData) { - requestsCounter.labels("put").inc() - if (!repo.contains(key)) { - throw KeyNotFoundException() - } - val prevData = repo.get(key) - if (newData.version != prevData.version + 1) { - throw EditConflictException() - } - repo.put(key, newData) - } - - override suspend fun getData(key: String): SyncData { - requestsCounter.labels("getData").inc() - if (!repo.contains(key)) { - throw KeyNotFoundException() - } - return repo.get(key) - } - - override suspend fun getDataVersion(key: String): Long { - requestsCounter.labels("getDataVersion").inc() - if (!repo.contains(key)) { - throw KeyNotFoundException() - } - return repo.get(key).version - } - - override suspend fun registerLink(syncKey: String): Link { - requestsCounter.labels("registerLink").inc() - return linkManager.register(syncKey) - } - - override suspend fun getLink(id: String): Link { - requestsCounter.labels("getLink").inc() - return linkManager.get(id) - } - - private suspend fun generateKey(): String { - while (true) { - val key = randomString(64) - if (!repo.contains(key)) - return key - } - } -} diff --git a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/utils/String.kt b/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/utils/String.kt deleted file mode 100644 index da043764f..000000000 --- a/uhabits-server/src/main/kotlin/org/isoron/uhabits/sync/utils/String.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.utils - -import java.util.* -import kotlin.streams.* - -fun randomString(length: Long): String { - val chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - return Random().ints(length, 0, chars.length) - .asSequence() - .map(chars::get) - .joinToString("") -} \ No newline at end of file diff --git a/uhabits-server/src/main/resources/application.conf b/uhabits-server/src/main/resources/application.conf deleted file mode 100644 index d5b282277..000000000 --- a/uhabits-server/src/main/resources/application.conf +++ /dev/null @@ -1,9 +0,0 @@ -ktor { - deployment { - port = 8080 - port = ${?PORT} - } - application { - modules = [ org.isoron.uhabits.sync.app.SyncApplicationKt.main ] - } -} diff --git a/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/app/BaseApplicationTest.kt b/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/app/BaseApplicationTest.kt deleted file mode 100644 index 3c1aa33dd..000000000 --- a/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/app/BaseApplicationTest.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.app - -import org.mockito.kotlin.mock -import io.ktor.application.* -import org.isoron.uhabits.sync.server.* - -open class BaseApplicationTest { - - protected val server: AbstractSyncServer = mock() - - protected fun app(): Application.() -> Unit = { - SyncApplication(server).apply { - main() - } - } -} diff --git a/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/app/LinksModuleTest.kt b/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/app/LinksModuleTest.kt deleted file mode 100644 index 7ee49aa14..000000000 --- a/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/app/LinksModuleTest.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.app - -import org.mockito.kotlin.whenever -import io.ktor.http.ContentType -import io.ktor.http.HttpHeaders -import io.ktor.http.HttpMethod -import io.ktor.http.HttpStatusCode -import io.ktor.server.testing.TestApplicationCall -import io.ktor.server.testing.TestApplicationEngine -import io.ktor.server.testing.handleRequest -import io.ktor.server.testing.setBody -import io.ktor.server.testing.withTestApplication -import kotlinx.coroutines.runBlocking -import org.isoron.uhabits.sync.KeyNotFoundException -import org.isoron.uhabits.sync.links.Link -import org.isoron.uhabits.sync.links.toJson -import org.junit.Test -import kotlin.test.assertEquals - -class LinksModuleTest : BaseApplicationTest() { - private val link = Link( - id = "ABC123", - syncKey = "SECRET", - createdAt = System.currentTimeMillis(), - ) - - @Test - fun `when POST is successful should return link`(): Unit = runBlocking { - whenever(server.registerLink("SECRET")).thenReturn(link) - withTestApplication(app()) { - handlePost("/links", LinkRegisterRequestData(syncKey = "SECRET")).apply { - assertEquals(HttpStatusCode.OK, response.status()) - assertEquals(link.toJson(), response.content) - } - } - } - - @Test - fun `when GET is successful should return link`(): Unit = runBlocking { - whenever(server.getLink("ABC123")).thenReturn(link) - withTestApplication(app()) { - handleGet("/links/ABC123").apply { - assertEquals(HttpStatusCode.OK, response.status()) - assertEquals(link.toJson(), response.content) - } - } - } - - @Test - fun `GET with invalid link id should return 404`(): Unit = runBlocking { - whenever(server.getLink("ABC123")).thenThrow(KeyNotFoundException()) - withTestApplication(app()) { - handleGet("/links/ABC123").apply { - assertEquals(HttpStatusCode.NotFound, response.status()) - } - } - } - - private fun TestApplicationEngine.handlePost( - url: String, - data: LinkRegisterRequestData - ): TestApplicationCall { - return handleRequest(HttpMethod.Post, url) { - addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString()) - setBody(data.toJson()) - } - } - - private fun TestApplicationEngine.handleGet(url: String): TestApplicationCall { - return handleRequest(HttpMethod.Get, url) - } -} diff --git a/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/app/RegistrationModuleTest.kt b/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/app/RegistrationModuleTest.kt deleted file mode 100644 index 8b5710743..000000000 --- a/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/app/RegistrationModuleTest.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.app - -import org.mockito.kotlin.whenever -import io.ktor.http.HttpMethod -import io.ktor.http.HttpStatusCode -import io.ktor.server.testing.handleRequest -import io.ktor.server.testing.withTestApplication -import kotlinx.coroutines.runBlocking -import org.isoron.uhabits.sync.ServiceUnavailable -import org.junit.Test -import kotlin.test.assertEquals - -class RegistrationModuleTest : BaseApplicationTest() { - @Test - fun `when register succeeds should return generated key`(): Unit = runBlocking { - whenever(server.register()).thenReturn("ABCDEF") - withTestApplication(app()) { - val call = handleRequest(HttpMethod.Post, "/register") - assertEquals(HttpStatusCode.OK, call.response.status()) - assertEquals("{\"key\":\"ABCDEF\"}", call.response.content) - } - } - - @Test - fun `when registration is unavailable should return 503`(): Unit = runBlocking { - whenever(server.register()).thenThrow(ServiceUnavailable()) - withTestApplication(app()) { - val call = handleRequest(HttpMethod.Post, "/register") - assertEquals(HttpStatusCode.ServiceUnavailable, call.response.status()) - } - } -} diff --git a/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/app/StorageModuleTest.kt b/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/app/StorageModuleTest.kt deleted file mode 100644 index 36872a194..000000000 --- a/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/app/StorageModuleTest.kt +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.app - -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever -import io.ktor.http.* -import io.ktor.server.testing.* -import kotlinx.coroutines.* -import org.isoron.uhabits.sync.* -import org.junit.Test -import kotlin.test.* - -class StorageModuleTest : BaseApplicationTest() { - private val data1 = SyncData(1, "Hello world") - private val data2 = SyncData(2, "Hello new world") - - @Test - fun `when get succeeds should return data`(): Unit = runBlocking { - whenever(server.getData("k1")).thenReturn(data1) - withTestApplication(app()) { - handleGet("/db/k1").apply { - assertEquals(HttpStatusCode.OK, response.status()) - assertEquals(data1.toJson(), response.content) - } - } - } - - @Test - fun `when get version succeeds should return version`(): Unit = runBlocking { - whenever(server.getDataVersion("k1")).thenReturn(30) - withTestApplication(app()) { - handleGet("/db/k1/version").apply { - assertEquals(HttpStatusCode.OK, response.status()) - assertEquals(GetDataVersionResponse(30).toJson(), response.content) - } - } - } - - @Test - fun `when get with invalid key should return 404`(): Unit = runBlocking { - whenever(server.getData("k1")).thenThrow(KeyNotFoundException()) - withTestApplication(app()) { - handleGet("/db/k1").apply { - assertEquals(HttpStatusCode.NotFound, response.status()) - } - } - } - - - @Test - fun `when put succeeds should return OK`(): Unit = runBlocking { - withTestApplication(app()) { - handlePut("/db/k1", data1).apply { - runBlocking { - assertEquals(HttpStatusCode.OK, response.status()) - verify(server).put("k1", data1) - } - } - } - } - - @Test - fun `when put with invalid key should return 404`(): Unit = runBlocking { - whenever(server.put("k1", data1)).thenThrow(KeyNotFoundException()) - withTestApplication(app()) { - handlePut("/db/k1", data1).apply { - assertEquals(HttpStatusCode.NotFound, response.status()) - } - } - } - - @Test - fun `when put with invalid version should return 409 and current data`(): Unit = runBlocking { - whenever(server.put("k1", data1)).thenThrow(EditConflictException()) - whenever(server.getData("k1")).thenReturn(data2) - withTestApplication(app()) { - handlePut("/db/k1", data1).apply { - assertEquals(HttpStatusCode.Conflict, response.status()) - } - } - } - - private fun TestApplicationEngine.handlePut(url: String, data: SyncData): TestApplicationCall { - return handleRequest(HttpMethod.Put, url) { - addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString()) - setBody(data.toJson()) - } - } - - private fun TestApplicationEngine.handleGet(url: String): TestApplicationCall { - return handleRequest(HttpMethod.Get, url) - } -} diff --git a/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/links/LinkManagerTest.kt b/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/links/LinkManagerTest.kt deleted file mode 100644 index d1eb88c24..000000000 --- a/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/links/LinkManagerTest.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.links - -import org.isoron.uhabits.sync.* -import org.junit.Test -import kotlin.test.* - -class LinkManagerTest { - - @Test - fun testUsage() { - val manager = LinkManager(timeoutInMillis = 250) - val originalLink = manager.register(syncKey = "SECRET") - val retrievedLink = manager.get(originalLink.id) - assertEquals(originalLink, retrievedLink) - - Thread.sleep(260) // wait until expiration - assertFailsWith { - manager.get(originalLink.id) - } - - assertFailsWith { - manager.get("INVALID") - } - } -} \ No newline at end of file diff --git a/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/repository/FileRepositoryTest.kt b/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/repository/FileRepositoryTest.kt deleted file mode 100644 index 53ce3a8c6..000000000 --- a/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/repository/FileRepositoryTest.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - - -@file:Suppress("BlockingMethodInNonBlockingContext") - -package org.isoron.uhabits.sync.repository - -import kotlinx.coroutines.* -import org.hamcrest.CoreMatchers.* -import org.isoron.uhabits.sync.* -import org.junit.* -import org.junit.Assert.* -import java.nio.file.* - -class FileRepositoryTest { - - @Test - fun testUsage() = runBlocking { - val tempdir = Files.createTempDirectory("db")!! - val repo = FileRepository(tempdir) - - val original = SyncData(10, "Hello world") - repo.put("abcdefg", original) - - val metaPath = tempdir.resolve("a/b/c/d/abcdefg/version") - assertTrue("$metaPath should exist", Files.exists(metaPath)) - assertEquals("10", metaPath.toFile().readText()) - - val dataPath = tempdir.resolve("a/b/c/d/abcdefg/content") - assertTrue("$dataPath should exist", Files.exists(dataPath)) - assertEquals("Hello world", dataPath.toFile().readText()) - - val retrieved = repo.get("abcdefg") - assertThat(retrieved, equalTo(original)) - } -} \ No newline at end of file diff --git a/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/server/RepositorySyncServerTest.kt b/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/server/RepositorySyncServerTest.kt deleted file mode 100644 index ca1576bda..000000000 --- a/uhabits-server/src/test/kotlin/org/isoron/uhabits/sync/server/RepositorySyncServerTest.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.sync.server - -import kotlinx.coroutines.* -import org.isoron.uhabits.sync.* -import org.isoron.uhabits.sync.repository.* -import org.junit.Test -import java.nio.file.* -import kotlin.test.* - -class RepositorySyncServerTest { - - private val tempdir = Files.createTempDirectory("db") - private val server = RepositorySyncServer(FileRepository(tempdir)) - private val key = runBlocking { server.register() } - - @Test - fun testUsage(): Unit = runBlocking { - val data0 = SyncData(0, "") - assertEquals(server.getData(key), data0) - - val data1 = SyncData(1, "Hello world") - server.put(key, data1) - assertEquals(server.getData(key), data1) - - val data2 = SyncData(2, "Hello new world") - server.put(key, data2) - assertEquals(server.getData(key), data2) - - assertFailsWith { - server.put(key, data2) - } - - assertFailsWith { - server.getData("INVALID") - } - - assertFailsWith { - server.put("INVALID", data0) - } - } -} \ No newline at end of file diff --git a/uhabits-web/.babelrc b/uhabits-web/.babelrc deleted file mode 100644 index e9a907edb..000000000 --- a/uhabits-web/.babelrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "presets": [ - ["env", { "modules": false }], - "react" - ] -} diff --git a/uhabits-web/Makefile b/uhabits-web/Makefile deleted file mode 100644 index 69e7fb257..000000000 --- a/uhabits-web/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -test_bundle := build/test.js -node_modules := node_modules/.bin/mocha -core_dir := ../uhabits-core-legacy - -all: $(test_bundle) - -$(node_modules): - npm install - -core: - cd $(core_dir); ./gradlew --quiet jsMainClasses jsTestClasses - cp $(core_dir)/build/classes/kotlin/js/*/*.js node_modules/ - mkdir -p build/assets - rsync -a $(core_dir)/assets/main/ build/assets/ - rsync -a $(core_dir)/assets/test/ build/assets/ - -$(test_bundle): src/test/index.js core - mkdir -p build/lib build/test build/css - npx webpack -d --mode development --target web --output $@ $< - cp src/test/*html build/test - cp node_modules/mocha/mocha.css build/lib - cp node_modules/mocha/mocha.js build/lib - cp node_modules/sql.js/js/sql.js build/lib - cp node_modules/sprintf-js/dist/sprintf.min.js build/lib - -serve: - npx serve build/ - -clean: - rm -rf build - -distclean: clean - rm -rf node_modules - -.PHONY: test clean distclean core diff --git a/uhabits-web/package-lock.json b/uhabits-web/package-lock.json deleted file mode 100644 index 1333e8561..000000000 --- a/uhabits-web/package-lock.json +++ /dev/null @@ -1,6080 +0,0 @@ -{ - "name": "loop-habit-tracker", - "version": "2.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@webassemblyjs/ast": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", - "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", - "dev": true, - "requires": { - "@webassemblyjs/helper-module-context": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/wast-parser": "1.8.5" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", - "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", - "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==", - "dev": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", - "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==", - "dev": true - }, - "@webassemblyjs/helper-code-frame": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", - "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", - "dev": true, - "requires": { - "@webassemblyjs/wast-printer": "1.8.5" - } - }, - "@webassemblyjs/helper-fsm": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", - "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==", - "dev": true - }, - "@webassemblyjs/helper-module-context": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", - "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "mamacro": "^0.0.3" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", - "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==", - "dev": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", - "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-buffer": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/wasm-gen": "1.8.5" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", - "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", - "dev": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", - "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", - "dev": true, - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", - "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", - "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-buffer": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/helper-wasm-section": "1.8.5", - "@webassemblyjs/wasm-gen": "1.8.5", - "@webassemblyjs/wasm-opt": "1.8.5", - "@webassemblyjs/wasm-parser": "1.8.5", - "@webassemblyjs/wast-printer": "1.8.5" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", - "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/ieee754": "1.8.5", - "@webassemblyjs/leb128": "1.8.5", - "@webassemblyjs/utf8": "1.8.5" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", - "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-buffer": "1.8.5", - "@webassemblyjs/wasm-gen": "1.8.5", - "@webassemblyjs/wasm-parser": "1.8.5" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", - "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-api-error": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/ieee754": "1.8.5", - "@webassemblyjs/leb128": "1.8.5", - "@webassemblyjs/utf8": "1.8.5" - } - }, - "@webassemblyjs/wast-parser": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", - "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/floating-point-hex-parser": "1.8.5", - "@webassemblyjs/helper-api-error": "1.8.5", - "@webassemblyjs/helper-code-frame": "1.8.5", - "@webassemblyjs/helper-fsm": "1.8.5", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", - "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/wast-parser": "1.8.5", - "@xtuc/long": "4.2.2" - } - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "@zeit/schemas": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.6.0.tgz", - "integrity": "sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg==", - "dev": true - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "dev": true, - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, - "acorn": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", - "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", - "dev": true - }, - "ajv": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.3.tgz", - "integrity": "sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", - "dev": true - }, - "ajv-keywords": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", - "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", - "dev": true - }, - "ansi-align": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", - "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", - "dev": true, - "requires": { - "string-width": "^2.0.0" - } - }, - "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "arch": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.1.1.tgz", - "integrity": "sha512-BLM56aPo9vLLFVa8+/+pJLnrZ7QGGTVHWsCwieAWT9o9K8UeGaQbzZbGoabWLOo2ksBCztoXdqBZBplqLDDCSg==", - "dev": true - }, - "arg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arg/-/arg-2.0.0.tgz", - "integrity": "sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - }, - "dependencies": { - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - } - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", - "dev": true, - "requires": { - "object-assign": "^4.1.1", - "util": "0.10.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "dev": true, - "requires": { - "inherits": "2.0.1" - } - } - } - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - } - }, - "babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", - "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" - } - }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", - "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" - }, - "dependencies": { - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" - } - } - }, - "babel-helper-builder-binary-assignment-operator-visitor": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", - "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", - "requires": { - "babel-helper-explode-assignable-expression": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-builder-react-jsx": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz", - "integrity": "sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "esutils": "^2.0.2" - } - }, - "babel-helper-call-delegate": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", - "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", - "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-define-map": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", - "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-helper-explode-assignable-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", - "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", - "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", - "requires": { - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-get-function-arity": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", - "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-hoist-variables": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", - "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-optimise-call-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", - "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-regex": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", - "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-helper-remap-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", - "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-replace-supers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", - "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", - "requires": { - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-loader": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.5.tgz", - "integrity": "sha512-iCHfbieL5d1LfOQeeVJEUyD9rTwBcP/fcEbRCfempxTDuqrKpu0AZjLAQHEQa3Yqyj9ORKe2iHfoj4rHLf7xpw==", - "dev": true, - "requires": { - "find-cache-dir": "^1.0.0", - "loader-utils": "^1.0.2", - "mkdirp": "^0.5.1" - }, - "dependencies": { - "find-cache-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", - "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^2.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } - } - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-check-es2015-constants": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", - "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-syntax-async-functions": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", - "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=" - }, - "babel-plugin-syntax-exponentiation-operator": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", - "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=" - }, - "babel-plugin-syntax-flow": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", - "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=" - }, - "babel-plugin-syntax-jsx": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", - "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" - }, - "babel-plugin-syntax-trailing-function-commas": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", - "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=" - }, - "babel-plugin-transform-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", - "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", - "requires": { - "babel-helper-remap-async-to-generator": "^6.24.1", - "babel-plugin-syntax-async-functions": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-arrow-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", - "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-block-scoped-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", - "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-block-scoping": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", - "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-plugin-transform-es2015-classes": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", - "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", - "requires": { - "babel-helper-define-map": "^6.24.1", - "babel-helper-function-name": "^6.24.1", - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-helper-replace-supers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-computed-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", - "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-destructuring": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", - "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-duplicate-keys": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", - "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-for-of": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", - "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", - "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", - "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-modules-amd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", - "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", - "requires": { - "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.26.2", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", - "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", - "requires": { - "babel-plugin-transform-strict-mode": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-types": "^6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-systemjs": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", - "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", - "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-modules-umd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", - "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", - "requires": { - "babel-plugin-transform-es2015-modules-amd": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-object-super": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", - "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", - "requires": { - "babel-helper-replace-supers": "^6.24.1", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-parameters": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", - "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", - "requires": { - "babel-helper-call-delegate": "^6.24.1", - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-shorthand-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", - "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-spread": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", - "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-sticky-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", - "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", - "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-template-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", - "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-typeof-symbol": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", - "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-unicode-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", - "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", - "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "regexpu-core": "^2.0.0" - } - }, - "babel-plugin-transform-exponentiation-operator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", - "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", - "requires": { - "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", - "babel-plugin-syntax-exponentiation-operator": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-flow-strip-types": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz", - "integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=", - "requires": { - "babel-plugin-syntax-flow": "^6.18.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-react-display-name": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz", - "integrity": "sha1-Z+K/Hx6ck6sI25Z5LgU5K/LMKNE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-react-jsx": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz", - "integrity": "sha1-hAoCjn30YN/DotKfDA2R9jduZqM=", - "requires": { - "babel-helper-builder-react-jsx": "^6.24.1", - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-react-jsx-self": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz", - "integrity": "sha1-322AqdomEqEh5t3XVYvL7PBuY24=", - "requires": { - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-react-jsx-source": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz", - "integrity": "sha1-ZqwSFT9c0tF7PBkmj0vwGX9E7NY=", - "requires": { - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-regenerator": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", - "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", - "requires": { - "regenerator-transform": "^0.10.0" - } - }, - "babel-plugin-transform-strict-mode": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", - "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-preset-env": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", - "integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==", - "requires": { - "babel-plugin-check-es2015-constants": "^6.22.0", - "babel-plugin-syntax-trailing-function-commas": "^6.22.0", - "babel-plugin-transform-async-to-generator": "^6.22.0", - "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoping": "^6.23.0", - "babel-plugin-transform-es2015-classes": "^6.23.0", - "babel-plugin-transform-es2015-computed-properties": "^6.22.0", - "babel-plugin-transform-es2015-destructuring": "^6.23.0", - "babel-plugin-transform-es2015-duplicate-keys": "^6.22.0", - "babel-plugin-transform-es2015-for-of": "^6.23.0", - "babel-plugin-transform-es2015-function-name": "^6.22.0", - "babel-plugin-transform-es2015-literals": "^6.22.0", - "babel-plugin-transform-es2015-modules-amd": "^6.22.0", - "babel-plugin-transform-es2015-modules-commonjs": "^6.23.0", - "babel-plugin-transform-es2015-modules-systemjs": "^6.23.0", - "babel-plugin-transform-es2015-modules-umd": "^6.23.0", - "babel-plugin-transform-es2015-object-super": "^6.22.0", - "babel-plugin-transform-es2015-parameters": "^6.23.0", - "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", - "babel-plugin-transform-es2015-spread": "^6.22.0", - "babel-plugin-transform-es2015-sticky-regex": "^6.22.0", - "babel-plugin-transform-es2015-template-literals": "^6.22.0", - "babel-plugin-transform-es2015-typeof-symbol": "^6.23.0", - "babel-plugin-transform-es2015-unicode-regex": "^6.22.0", - "babel-plugin-transform-exponentiation-operator": "^6.22.0", - "babel-plugin-transform-regenerator": "^6.22.0", - "browserslist": "^3.2.6", - "invariant": "^2.2.2", - "semver": "^5.3.0" - } - }, - "babel-preset-flow": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz", - "integrity": "sha1-5xIYiHCFrpoktb5Baa/7WZgWxJ0=", - "requires": { - "babel-plugin-transform-flow-strip-types": "^6.22.0" - } - }, - "babel-preset-react": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.24.1.tgz", - "integrity": "sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A=", - "requires": { - "babel-plugin-syntax-jsx": "^6.3.13", - "babel-plugin-transform-react-display-name": "^6.23.0", - "babel-plugin-transform-react-jsx": "^6.24.1", - "babel-plugin-transform-react-jsx-self": "^6.22.0", - "babel-plugin-transform-react-jsx-source": "^6.22.0", - "babel-preset-flow": "^6.23.0" - } - }, - "babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", - "dev": true - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true - }, - "bluebird": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", - "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==", - "dev": true - }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true - }, - "boxen": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", - "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", - "dev": true, - "requires": { - "ansi-align": "^2.0.0", - "camelcase": "^4.0.0", - "chalk": "^2.0.1", - "cli-boxes": "^1.0.0", - "string-width": "^2.0.0", - "term-size": "^1.2.0", - "widest-line": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "dev": true, - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", - "dev": true, - "requires": { - "bn.js": "^4.1.1", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.2", - "elliptic": "^6.0.0", - "inherits": "^2.0.1", - "parse-asn1": "^5.0.0" - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "dev": true, - "requires": { - "pako": "~1.0.5" - } - }, - "browserslist": { - "version": "3.2.8", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", - "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", - "requires": { - "caniuse-lite": "^1.0.30000844", - "electron-to-chromium": "^1.3.47" - } - }, - "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "dev": true, - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", - "dev": true - }, - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true - }, - "cacache": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.2.tgz", - "integrity": "sha512-ifKgxH2CKhJEg6tNdAwziu6Q33EvuG26tYcda6PT3WKisZcYDXsnEdnRv67Po3yCzFfaSoMjGZzJyD2c3DT1dg==", - "dev": true, - "requires": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" - }, - "dependencies": { - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", - "dev": true - } - } - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30000957", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000957.tgz", - "integrity": "sha512-8wxNrjAzyiHcLXN/iunskqQnJquQQ6VX8JHfW5kLgAPRSiSuKZiNfmIkP5j7jgyXqAQBSoXyJxfnbCFS0ThSiQ==" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "chokidar": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", - "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "chownr": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.2.tgz", - "integrity": "sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A==", - "dev": true - }, - "chrome-trace-event": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", - "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "cli-boxes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", - "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", - "dev": true - }, - "clipboardy": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-1.2.3.tgz", - "integrity": "sha512-2WNImOvCRe6r63Gk9pShfkwXsVtKCroMAevIbiae021mS850UkWPbevxsBz3tnvjZIEGvlwaqCPsw+4ulzNgJA==", - "dev": true, - "requires": { - "arch": "^2.1.0", - "execa": "^0.8.0" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz", - "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - } - } - }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "compressible": { - "version": "2.0.17", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz", - "integrity": "sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==", - "dev": true, - "requires": { - "mime-db": ">= 1.40.0 < 2" - } - }, - "compression": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.3.tgz", - "integrity": "sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==", - "dev": true, - "requires": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.14", - "debug": "2.6.9", - "on-headers": "~1.0.1", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "dev": true, - "requires": { - "date-now": "^0.1.4" - } - }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", - "dev": true - }, - "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", - "dev": true - }, - "convert-source-map": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "dev": true, - "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-js": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz", - "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "create-ecdh": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", - "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.0.0" - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "dev": true, - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, - "cyclist": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", - "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", - "dev": true - }, - "date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "des.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", - "dev": true - }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "requires": { - "repeating": "^2.0.0" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", - "dev": true - }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "dev": true, - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "electron-to-chromium": { - "version": "1.3.124", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.124.tgz", - "integrity": "sha512-glecGr/kFdfeXUHOHAWvGcXrxNU+1wSO/t5B23tT1dtlvYB26GY8aHzZSWD7HqhqC800Lr+w/hQul6C5AF542w==" - }, - "elliptic": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.0.tgz", - "integrity": "sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg==", - "dev": true, - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - } - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true - }, - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", - "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "tapable": "^1.0.0" - } - }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "dev": true, - "requires": { - "prr": "~1.0.1" - } - }, - "es-abstract": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", - "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-keys": "^1.0.12" - } - }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", - "dev": true, - "requires": { - "estraverse": "^4.1.0" - } - }, - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, - "events": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", - "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", - "dev": true - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dev": true, - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true - }, - "fast-url-parser": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", - "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=", - "dev": true, - "requires": { - "punycode": "^1.3.2" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - } - } - }, - "figgy-pudding": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", - "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", - "dev": true - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", - "dev": true, - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - } - }, - "flat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", - "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", - "dev": true, - "requires": { - "is-buffer": "~2.0.3" - } - }, - "flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", - "dev": true, - "optional": true, - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "dev": true, - "requires": { - "global-prefix": "^3.0.0" - }, - "dependencies": { - "global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "dev": true, - "requires": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - } - } - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - } - }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" - }, - "graceful-fs": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.1.tgz", - "integrity": "sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw==", - "dev": true - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dev": true, - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" - } - }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "requires": { - "parse-passwd": "^1.0.0" - } - }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", - "dev": true - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", - "dev": true - }, - "iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", - "dev": true - }, - "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", - "dev": true, - "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true - }, - "interpret": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", - "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", - "dev": true - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "requires": { - "loose-envify": "^1.0.0" - } - }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", - "dev": true - }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, - "requires": { - "has": "^1.0.1" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "dev": true, - "requires": { - "has-symbols": "^1.0.0" - } - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "kotlin": { - "version": "1.3.41", - "resolved": "https://registry.npmjs.org/kotlin/-/kotlin-1.3.41.tgz", - "integrity": "sha512-Lo3++B/8B/Eaht5mV5NFlwSDsRjAOh90haopf9YPP0YJcDWdFpQB9yyEucSfuqBSbioHCHx0+ZjQ4tVJ/mYhug==" - }, - "kotlin-test": { - "version": "1.3.41", - "resolved": "https://registry.npmjs.org/kotlin-test/-/kotlin-test-1.3.41.tgz", - "integrity": "sha512-6y5ANRWCXVXw9O14RXKandwr+PiZl3fGjm/07BfmXwTF5VrD5edJjA8tERUf612T35/dV8BAb6Yr/SJr8Q+X0g==", - "requires": { - "kotlin": "1.3.41" - } - }, - "kotlinx-coroutines-core": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/kotlinx-coroutines-core/-/kotlinx-coroutines-core-1.2.2.tgz", - "integrity": "sha512-03ZIn8jrqY98Ysz5K7JavRW+1KxDnw/P/eISH93SQBhioyKeT5sDxGNpoWcJeShJsY0SWymzbxOgQlKcnDJYWg==" - }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, - "requires": { - "invert-kv": "^2.0.0" - } - }, - "loader-runner": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", - "dev": true - }, - "loader-utils": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" - }, - "dependencies": { - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" - }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "mamacro": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", - "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", - "dev": true - }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "dev": true, - "requires": { - "p-defer": "^1.0.0" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dev": true, - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - } - }, - "memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "dev": true, - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - } - }, - "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", - "dev": true - }, - "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", - "dev": true, - "requires": { - "mime-db": "1.40.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mississippi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", - "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", - "dev": true, - "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - } - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - }, - "mocha": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.0.tgz", - "integrity": "sha512-qwfFgY+7EKAAUAdv7VYMZQknI7YJSGesxHyhn6qD52DV8UcSZs5XwCifcZGMVIE4a5fbmhvbotxC0DLQ0oKohQ==", - "dev": true, - "requires": { - "ansi-colors": "3.2.3", - "browser-stdout": "1.3.1", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "2.2.0", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "ms": "2.1.1", - "node-environment-flags": "1.0.5", - "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", - "wide-align": "1.1.3", - "yargs": "13.2.2", - "yargs-parser": "13.0.0", - "yargs-unparser": "1.5.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, - "supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "dev": true, - "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "dev": true, - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", - "dev": true - }, - "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node-environment-flags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", - "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - } - }, - "node-libs-browser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", - "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", - "dev": true, - "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.1", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "^1.0.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - } - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", - "dev": true - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true - }, - "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "pako": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", - "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", - "dev": true - }, - "parallel-transform": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", - "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", - "dev": true, - "requires": { - "cyclist": "~0.2.2", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - } - }, - "parse-asn1": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", - "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", - "dev": true, - "requires": { - "asn1.js": "^4.0.0", - "browserify-aes": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", - "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-to-regexp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", - "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==", - "dev": true - }, - "pbkdf2": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", - "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", - "dev": true, - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", - "dev": true - }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "dev": true, - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", - "dev": true - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, - "regenerate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", - "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==" - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "regenerator-transform": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", - "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", - "requires": { - "babel-runtime": "^6.18.0", - "babel-types": "^6.19.0", - "private": "^0.1.6" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "regexpu-core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", - "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", - "requires": { - "regenerate": "^1.2.1", - "regjsgen": "^0.2.0", - "regjsparser": "^0.1.4" - } - }, - "registry-auth-token": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", - "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", - "dev": true, - "requires": { - "rc": "^1.1.6", - "safe-buffer": "^5.0.1" - } - }, - "registry-url": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", - "dev": true, - "requires": { - "rc": "^1.0.1" - } - }, - "regjsgen": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", - "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" - }, - "regjsparser": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", - "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", - "requires": { - "jsesc": "~0.5.0" - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "requires": { - "is-finite": "^1.0.0" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "dev": true, - "requires": { - "resolve-from": "^3.0.0" - } - }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "dev": true, - "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - }, - "dependencies": { - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - } - } - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", - "dev": true, - "requires": { - "aproba": "^1.1.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" - }, - "serialize-javascript": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.7.0.tgz", - "integrity": "sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA==", - "dev": true - }, - "serve": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/serve/-/serve-11.1.0.tgz", - "integrity": "sha512-+4wpDtOSS+4ZLyDWMxThutA3iOTawX2+yDovOI8cjOUOmemyvNlHyFAsezBlSgbZKTYChI3tzA1Mh0z6XZ62qA==", - "dev": true, - "requires": { - "@zeit/schemas": "2.6.0", - "ajv": "6.5.3", - "arg": "2.0.0", - "boxen": "1.3.0", - "chalk": "2.4.1", - "clipboardy": "1.2.3", - "compression": "1.7.3", - "serve-handler": "6.1.0", - "update-check": "1.5.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "serve-handler": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.0.tgz", - "integrity": "sha512-63N075Tn3PsFYcu0NVV7tb367UbiW3gnC+/50ohL4oqOhAG6bmbaWqiRcXQgbzqc0ALBjSAzg7VTfa0Qw4E3hA==", - "dev": true, - "requires": { - "bytes": "3.0.0", - "content-disposition": "0.5.2", - "fast-url-parser": "1.1.3", - "mime-types": "2.1.18", - "minimatch": "3.0.4", - "path-is-inside": "1.0.2", - "path-to-regexp": "2.2.1", - "range-parser": "1.2.0" - }, - "dependencies": { - "mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", - "dev": true - }, - "mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", - "dev": true, - "requires": { - "mime-db": "~1.33.0" - } - } - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", - "dev": true, - "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "requires": { - "source-map": "^0.5.6" - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" - }, - "sql.js": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/sql.js/-/sql.js-0.5.0.tgz", - "integrity": "sha1-+IDeoYKAqEDkHfIgnclnQi36jYE=" - }, - "ssri": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", - "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", - "dev": true, - "requires": { - "figgy-pudding": "^3.5.1" - } - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "stream-browserify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", - "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "stream-each": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", - "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "stream-http": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", - "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", - "dev": true, - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" - } - }, - "stream-shift": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - }, - "tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "dev": true - }, - "term-size": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", - "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", - "dev": true, - "requires": { - "execa": "^0.7.0" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - } - } - }, - "terser": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.1.4.tgz", - "integrity": "sha512-+ZwXJvdSwbd60jG0Illav0F06GDJF0R4ydZ21Q3wGAFKoBGyJGo34F63vzJHgvYxc1ukOtIjvwEvl9MkjzM6Pg==", - "dev": true, - "requires": { - "commander": "^2.20.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.12" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - } - } - }, - "terser-webpack-plugin": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz", - "integrity": "sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg==", - "dev": true, - "requires": { - "cacache": "^12.0.2", - "find-cache-dir": "^2.1.0", - "is-wsl": "^1.1.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^1.7.0", - "source-map": "^0.6.1", - "terser": "^4.1.2", - "webpack-sources": "^1.4.0", - "worker-farm": "^1.7.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "timers-browserify": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", - "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", - "dev": true, - "requires": { - "setimmediate": "^1.0.4" - } - }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", - "dev": true - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" - }, - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true - }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", - "dev": true - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "dev": true, - "requires": { - "unique-slug": "^2.0.0" - } - }, - "unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, - "upath": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", - "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", - "dev": true - }, - "update-check": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.2.tgz", - "integrity": "sha512-1TrmYLuLj/5ZovwUS7fFd1jMH3NnFDN1y1A8dboedIDt7zs/zJMo6TwwlhYKkSeEwzleeiSBV5/3c9ufAQWDaQ==", - "dev": true, - "requires": { - "registry-auth-token": "3.3.2", - "registry-url": "3.1.0" - } - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dev": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - } - } - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "util": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", - "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", - "dev": true, - "requires": { - "inherits": "2.0.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "v8-compile-cache": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz", - "integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==", - "dev": true - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true - }, - "vm-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", - "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==", - "dev": true - }, - "watchpack": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", - "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", - "dev": true, - "requires": { - "chokidar": "^2.0.2", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" - } - }, - "webpack": { - "version": "4.39.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.1.tgz", - "integrity": "sha512-/LAb2TJ2z+eVwisldp3dqTEoNhzp/TLCZlmZm3GGGAlnfIWDgOEE758j/9atklNLfRyhKbZTCOIoPqLJXeBLbQ==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-module-context": "1.8.5", - "@webassemblyjs/wasm-edit": "1.8.5", - "@webassemblyjs/wasm-parser": "1.8.5", - "acorn": "^6.2.1", - "ajv": "^6.10.2", - "ajv-keywords": "^3.4.1", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^4.1.0", - "eslint-scope": "^4.0.3", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.4.0", - "loader-utils": "^1.2.3", - "memory-fs": "^0.4.1", - "micromatch": "^3.1.10", - "mkdirp": "^0.5.1", - "neo-async": "^2.6.1", - "node-libs-browser": "^2.2.1", - "schema-utils": "^1.0.0", - "tapable": "^1.1.3", - "terser-webpack-plugin": "^1.4.1", - "watchpack": "^1.6.0", - "webpack-sources": "^1.4.1" - }, - "dependencies": { - "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - } - } - }, - "webpack-cli": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.6.tgz", - "integrity": "sha512-0vEa83M7kJtxK/jUhlpZ27WHIOndz5mghWL2O53kiDoA9DIxSKnfqB92LoqEn77cT4f3H2cZm1BMEat/6AZz3A==", - "dev": true, - "requires": { - "chalk": "2.4.2", - "cross-spawn": "6.0.5", - "enhanced-resolve": "4.1.0", - "findup-sync": "3.0.0", - "global-modules": "2.0.0", - "import-local": "2.0.0", - "interpret": "1.2.0", - "loader-utils": "1.2.3", - "supports-color": "6.1.0", - "v8-compile-cache": "2.0.3", - "yargs": "13.2.4" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, - "yargs": { - "version": "13.2.4", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", - "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "os-locale": "^3.1.0", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.0" - } - }, - "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dev": true, - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "widest-line": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", - "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", - "dev": true, - "requires": { - "string-width": "^2.1.1" - } - }, - "worker-farm": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", - "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", - "dev": true, - "requires": { - "errno": "~0.1.7" - } - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - }, - "yargs": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz", - "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "os-locale": "^3.1.0", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "yargs-parser": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz", - "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "yargs-unparser": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", - "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", - "dev": true, - "requires": { - "flat": "^4.1.0", - "lodash": "^4.17.11", - "yargs": "^12.0.5" - }, - "dependencies": { - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, - "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" - } - }, - "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - } - } -} diff --git a/uhabits-web/package.json b/uhabits-web/package.json deleted file mode 100644 index 421742cd3..000000000 --- a/uhabits-web/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "loop-habit-tracker", - "version": "2.0.0", - "description": "App for creating and maintaining good habits", - "repository": { - "type": "git", - "url": "git@github.com:iSoron/uhabits.git" - }, - "main": "index.js", - "scripts": { - "compile": "webpack", - "test": "mocha" - }, - "keywords": [], - "author": "", - "license": "GPL-3.0-or-later", - "dependencies": { - "babel-core": "^6.26.3", - "babel-preset-env": "^1.7.0", - "babel-preset-react": "^6.24.1", - "kotlin": "^1.3.41", - "kotlin-test": "^1.3.41", - "kotlinx-coroutines-core": "^1.2.2", - "sprintf-js": "^1.1.2", - "sql.js": "^0.5.0" - }, - "devDependencies": { - "babel-loader": "^7.1.5", - "mocha": "^6.2.0", - "serve": "^11.1.0", - "webpack": "^4.39.1", - "webpack-cli": "^3.3.6" - } -} diff --git a/uhabits-web/src/main/index.js b/uhabits-web/src/main/index.js deleted file mode 100644 index a420803c0..000000000 --- a/uhabits-web/src/main/index.js +++ /dev/null @@ -1 +0,0 @@ -console.log('Hello World!'); diff --git a/uhabits-web/src/test/index.html b/uhabits-web/src/test/index.html deleted file mode 100644 index 5bfeb0601..000000000 --- a/uhabits-web/src/test/index.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - Mocha Tests - - - - - - - - - -   -   -   - -
- - - - - diff --git a/uhabits-web/src/test/index.js b/uhabits-web/src/test/index.js deleted file mode 100644 index c9f32ca2f..000000000 --- a/uhabits-web/src/test/index.js +++ /dev/null @@ -1,3 +0,0 @@ -let assert = require('assert'); -let coreTest = require('uhabits-core-legacy_test'); -document.coreTest = coreTest;