0
0
mirror of https://github.com/ankidroid/Anki-Android.git synced 2024-09-19 19:42:17 +02:00

NF: remove custom json

it was only required to avoid checked exception. Thanks to Kotlin, it's not a
concern anymore!
This commit is contained in:
Arthur Milchior 2022-10-04 02:56:44 +02:00 committed by Mike Hardy
parent e34505b37e
commit c7376f63b6
83 changed files with 264 additions and 859 deletions

View File

@ -33,11 +33,11 @@ import com.ichi2.anki.testutil.DatabaseUtils.cursorFillWindow
import com.ichi2.async.TaskManager.Companion.waitToFinish
import com.ichi2.libanki.*
import com.ichi2.utils.BlocksSchemaUpgrade
import com.ichi2.utils.JSONObject
import com.ichi2.utils.KotlinCleanup
import net.ankiweb.rsdroid.BackendFactory.defaultLegacySchema
import org.hamcrest.MatcherAssert.*
import org.hamcrest.Matchers.*
import org.json.JSONObject
import org.junit.*
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals

View File

@ -25,10 +25,10 @@ import com.ichi2.libanki.Collection
import com.ichi2.libanki.importer.Anki2Importer
import com.ichi2.libanki.importer.AnkiPackageImporter
import com.ichi2.libanki.importer.Importer
import com.ichi2.utils.JSONException
import com.ichi2.utils.KotlinCleanup
import net.ankiweb.rsdroid.BackendFactory.defaultLegacySchema
import org.hamcrest.Matchers.equalTo
import org.json.JSONException
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue

View File

@ -36,10 +36,10 @@ import com.ichi2.libanki.Consts.CARD_QUEUE
import com.ichi2.libanki.Consts.CARD_TYPE
import com.ichi2.libanki.Decks
import com.ichi2.libanki.SortOrder
import com.ichi2.utils.JSONException
import com.ichi2.utils.JSONObject
import com.ichi2.utils.NetworkUtils
import kotlinx.coroutines.runBlocking
import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
open class AnkiDroidJsAPI(private val activity: AbstractFlashcardViewer) {
@ -174,7 +174,7 @@ open class AnkiDroidJsAPI(private val activity: AbstractFlashcardViewer) {
if (requireApiVersion(cardSuppliedApiVersion, cardSuppliedDeveloperContact)) {
enableJsApi()
}
apiStatusJson = JSONObject(mJsApiListMap).toString()
apiStatusJson = JSONObject(mJsApiListMap as Map<String, Boolean>).toString()
} catch (j: JSONException) {
Timber.w(j)
activity.runOnUiThread {

View File

@ -87,6 +87,7 @@ import com.ichi2.widget.WidgetStatus.update
import kotlinx.coroutines.Job
import net.ankiweb.rsdroid.BackendFactory
import net.ankiweb.rsdroid.RustCleanup
import org.json.JSONObject
import timber.log.Timber
import java.lang.Exception
import java.lang.IllegalStateException

View File

@ -24,8 +24,8 @@ import android.widget.EditText
import androidx.annotation.CheckResult
import com.afollestad.materialdialogs.MaterialDialog
import com.ichi2.anki.dialogs.DiscardChangesDialog
import com.ichi2.utils.JSONObject
import org.jetbrains.annotations.Contract
import org.json.JSONObject
import timber.log.Timber
/** Allows specification of the Question and Answer format of a card template in the Card Browser

View File

@ -41,11 +41,14 @@ import com.afollestad.materialdialogs.MaterialDialog
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import com.ichi2.anim.ActivityTransitionAnimation.Direction.*
import com.ichi2.anim.ActivityTransitionAnimation.Direction.END
import com.ichi2.anki.CollectionManager.withCol
import com.ichi2.anki.dialogs.*
import com.ichi2.anki.dialogs.ConfirmationDialog
import com.ichi2.anki.dialogs.DeckSelectionDialog
import com.ichi2.anki.dialogs.DeckSelectionDialog.DeckSelectionListener
import com.ichi2.anki.dialogs.DeckSelectionDialog.SelectableDeck
import com.ichi2.anki.dialogs.DiscardChangesDialog
import com.ichi2.anki.dialogs.InsertFieldDialog
import com.ichi2.anki.dialogs.InsertFieldDialog.Companion.REQUEST_FIELD_INSERT
import com.ichi2.anki.exception.ConfirmModSchemaException
import com.ichi2.annotations.NeedsTest
@ -54,7 +57,12 @@ import com.ichi2.libanki.Collection
import com.ichi2.libanki.Models.Companion.NOT_FOUND_NOTE_TYPE
import com.ichi2.ui.FixedEditText
import com.ichi2.ui.FixedTextView
import com.ichi2.utils.*
import com.ichi2.utils.FunctionalInterfaces
import com.ichi2.utils.KotlinCleanup
import com.ichi2.utils.jsonObjectIterable
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
import java.util.regex.Pattern
import kotlin.math.max

View File

@ -27,8 +27,8 @@ import com.ichi2.libanki.*
import com.ichi2.libanki.Collection
import com.ichi2.libanki.TemplateManager.TemplateRenderContext.TemplateRenderOutput
import com.ichi2.libanki.utils.NoteUtils
import com.ichi2.utils.JSONObject
import net.ankiweb.rsdroid.BackendFactory
import org.json.JSONObject
import timber.log.Timber
import java.io.IOException
import java.util.*

View File

@ -52,8 +52,12 @@ import com.ichi2.themes.Themes
import com.ichi2.themes.Themes.themeFollowsSystem
import com.ichi2.themes.Themes.updateCurrentTheme
import com.ichi2.ui.AppCompatPreferenceActivity
import com.ichi2.utils.*
import com.ichi2.utils.KotlinCleanup
import com.ichi2.utils.NamedJSONComparator
import kotlinx.coroutines.launch
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
import java.util.*

View File

@ -115,6 +115,7 @@ import com.ichi2.widget.WidgetStatus
import kotlinx.coroutines.Job
import net.ankiweb.rsdroid.BackendFactory
import net.ankiweb.rsdroid.RustCleanup
import org.json.JSONException
import timber.log.Timber
import java.io.File
import kotlin.math.abs

View File

@ -33,7 +33,11 @@ import com.ichi2.themes.Themes.setThemeLegacy
import com.ichi2.themes.Themes.themeFollowsSystem
import com.ichi2.themes.Themes.updateCurrentTheme
import com.ichi2.ui.AppCompatPreferenceActivity
import com.ichi2.utils.*
import com.ichi2.utils.KotlinCleanup
import com.ichi2.utils.stringIterable
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
@NeedsTest("construction + onCreate - do this after converting to fragment-based preferences.")

View File

@ -51,13 +51,14 @@ import com.ichi2.libanki.Collection
import com.ichi2.libanki.Model
import com.ichi2.themes.StyledProgressDialog.Companion.show
import com.ichi2.ui.FixedEditText
import com.ichi2.utils.*
import com.ichi2.utils.KotlinCleanup
import com.ichi2.utils.displayKeyboard
import com.ichi2.utils.toStringList
import com.ichi2.widget.WidgetStatus
import org.json.JSONArray
import org.json.JSONException
import timber.log.Timber
import java.lang.NumberFormatException
import java.lang.RuntimeException
import java.util.*
import kotlin.Throws
class ModelFieldEditor : AnkiActivity(), LocaleSelectionDialogHandler {
// Position of the current field selected

View File

@ -90,6 +90,8 @@ import com.ichi2.themes.Themes
import com.ichi2.utils.*
import com.ichi2.widget.WidgetStatus
import net.ankiweb.rsdroid.BackendFactory
import org.json.JSONArray
import org.json.JSONObject
import timber.log.Timber
import java.util.*
import java.util.function.Consumer

View File

@ -22,8 +22,8 @@ import com.ichi2.async.saveModel
import com.ichi2.compat.CompatHelper.Companion.compat
import com.ichi2.libanki.Model
import com.ichi2.libanki.NoteTypeId
import com.ichi2.utils.JSONObject
import com.ichi2.utils.KotlinCleanup
import org.json.JSONObject
import timber.log.Timber
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream

View File

@ -24,9 +24,9 @@ import com.ichi2.libanki.*
import com.ichi2.libanki.template.MathJax
import com.ichi2.themes.HtmlColors
import com.ichi2.themes.Themes.currentTheme
import com.ichi2.utils.JSONObject
import net.ankiweb.rsdroid.BackendFactory
import net.ankiweb.rsdroid.RustCleanup
import org.json.JSONObject
import timber.log.Timber
import java.util.regex.Pattern

View File

@ -26,9 +26,9 @@ import com.ichi2.libanki.Card
import com.ichi2.libanki.Sound
import com.ichi2.libanki.Utils
import com.ichi2.utils.DiffEngine
import com.ichi2.utils.JSONArray
import com.ichi2.utils.jsonObjectIterable
import org.intellij.lang.annotations.Language
import org.json.JSONArray
import timber.log.Timber
import java.util.regex.Matcher
import java.util.regex.Pattern

View File

@ -50,9 +50,9 @@ import com.ichi2.libanki.Deck
import com.ichi2.libanki.DeckId
import com.ichi2.libanki.backend.exception.DeckRenameException
import com.ichi2.utils.HashUtil.HashMapInit
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONObject
import com.ichi2.utils.KotlinCleanup
import org.json.JSONArray
import org.json.JSONObject
import timber.log.Timber
import java.util.*

View File

@ -25,9 +25,9 @@ import com.ichi2.anki.NoteEditor
import com.ichi2.anki.R
import com.ichi2.libanki.Model
import com.ichi2.libanki.Models
import com.ichi2.utils.JSONObject
import com.ichi2.utils.KotlinCleanup
import com.ichi2.utils.MapUtil.getKeyByValue
import org.json.JSONObject
import java.util.*
/** Responsible for recreating EditFieldLines after NoteEditor operations

View File

@ -41,10 +41,10 @@ import com.ichi2.libanki.sched.TreeNode
import com.ichi2.libanki.sched.findInDeckTree
import com.ichi2.libanki.utils.TimeManager
import com.ichi2.utils.FileUtil.internalizeUri
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONException
import com.ichi2.utils.JSONObject
import com.ichi2.utils.KotlinCleanup
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
import java.io.File
import java.io.IOException

View File

@ -22,7 +22,7 @@ import android.widget.EditText
import androidx.annotation.CheckResult
import com.ichi2.libanki.Model
import com.ichi2.libanki.ModelManager
import com.ichi2.utils.JSONObject
import org.json.JSONObject
import timber.log.Timber
import java.util.*

View File

@ -34,9 +34,9 @@ import com.ichi2.libanki.Note
import com.ichi2.libanki.NoteTypeId
import com.ichi2.libanki.exception.EmptyMediaException
import com.ichi2.utils.CollectionUtils.average
import com.ichi2.utils.JSONException
import com.ichi2.utils.JSONObject
import net.ankiweb.rsdroid.BackendFactory
import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
import java.io.File
import java.io.IOException

View File

@ -30,7 +30,7 @@ import com.ichi2.compat.CompatHelper
import com.ichi2.libanki.Collection
import com.ichi2.libanki.DeckId
import com.ichi2.libanki.sched.DeckDueTreeNode
import com.ichi2.utils.JSONObject
import org.json.JSONObject
import timber.log.Timber
class ReminderService : BroadcastReceiver() {

View File

@ -20,19 +20,14 @@ import com.ichi2.anki.*
import com.ichi2.anki.CollectionManager.withCol
import com.ichi2.anki.servicelayer.NoteService
import com.ichi2.libanki.*
import com.ichi2.libanki.Card
import com.ichi2.libanki.Collection
import com.ichi2.libanki.Model
import com.ichi2.libanki.Note
import com.ichi2.utils.JSONObject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.withContext
import net.ankiweb.rsdroid.BackendFactory
import org.json.JSONObject
import timber.log.Timber
import java.util.*
import java.util.ArrayList
import kotlin.Comparator
/**
* This file contains functions that have been migrated from [CollectionTask]

View File

@ -31,8 +31,11 @@ import com.ichi2.libanki.Collection.CheckDatabaseResult
import com.ichi2.libanki.importer.AnkiPackageImporter
import com.ichi2.libanki.sched.DeckDueTreeNode
import com.ichi2.libanki.sched.TreeNode
import com.ichi2.utils.*
import com.ichi2.utils.Computation
import com.ichi2.utils.KotlinCleanup
import org.apache.commons.compress.archivers.zip.ZipFile
import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
import java.io.File
import java.io.FileNotFoundException

View File

@ -39,12 +39,12 @@ import com.ichi2.libanki.sync.RemoteMediaServer
import com.ichi2.libanki.sync.RemoteServer
import com.ichi2.libanki.sync.Syncer
import com.ichi2.libanki.sync.Syncer.ConnectionResultType.*
import com.ichi2.utils.JSONException
import com.ichi2.utils.JSONObject
import com.ichi2.utils.KotlinCleanup
import com.ichi2.utils.NetworkUtils
import com.ichi2.utils.Permissions
import okhttp3.Response
import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
import java.io.IOException
import java.util.Arrays

View File

@ -22,9 +22,13 @@ import com.ichi2.anki.CollectionHelper
import com.ichi2.anki.R
import com.ichi2.anki.exception.ImportExportException
import com.ichi2.annotations.NeedsTest
import com.ichi2.utils.*
import com.ichi2.utils.KotlinCleanup
import com.ichi2.utils.jsonObjectIterable
import com.ichi2.utils.stringIterable
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream
import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
import java.io.*

View File

@ -32,9 +32,9 @@ import com.ichi2.libanki.stats.Stats
import com.ichi2.libanki.template.TemplateError
import com.ichi2.libanki.utils.TimeManager
import com.ichi2.utils.Assert
import com.ichi2.utils.JSONObject
import com.ichi2.utils.LanguageUtil
import net.ankiweb.rsdroid.RustCleanup
import org.json.JSONObject
import timber.log.Timber
import java.util.*
import java.util.concurrent.CancellationException

View File

@ -59,6 +59,9 @@ import com.ichi2.utils.*
import net.ankiweb.rsdroid.Backend
import net.ankiweb.rsdroid.RustCleanup
import org.jetbrains.annotations.Contract
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
import java.io.*
import java.util.*
@ -1123,7 +1126,7 @@ open class Collection(
d["id"] = cid.toString()
qfmt = if (qfmt.isNullOrEmpty()) template.getString("qfmt") else qfmt
afmt = if (afmt.isNullOrEmpty()) template.getString("afmt") else afmt
for (p in arrayOf<Pair<String, String>>(Pair("q", qfmt), Pair("a", afmt))) {
for (p in arrayOf<Pair<String, String>>(Pair("q", qfmt!!), Pair("a", afmt!!))) {
val type = p.first
var format = p.second
if ("q" == type) {
@ -2305,14 +2308,14 @@ open class Collection(
*/
@Suppress("unused")
fun get_config_object(key: String): JSONObject {
return JSONObject(config!!.getJSONObject(key))
return config!!.getJSONObject(key).deepClone()
}
/** Edits to the array are not persisted to the preferences
* @throws JSONException object does not exist or can't be cast
*/
fun get_config_array(key: String): JSONArray {
return JSONArray(config!!.getJSONArray(key))
return config!!.getJSONArray(key).deepClone()
}
/**
@ -2362,8 +2365,8 @@ open class Collection(
@Contract("_, !null -> !null")
fun get_config(key: String, defaultValue: JSONObject?): JSONObject? {
return if (config!!.isNull(key)) {
if (defaultValue == null) null else JSONObject(defaultValue)
} else JSONObject(config!!.getJSONObject(key))
if (defaultValue == null) null else defaultValue.deepClone()
} else config!!.getJSONObject(key).deepClone()
}
/** Edits to the array are not persisted to the preferences */

View File

@ -16,8 +16,8 @@
package com.ichi2.libanki
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONObject
import org.json.JSONArray
import org.json.JSONObject
class Config(configStr: String) : ConfigManager() {
override var json = JSONObject(configStr)

View File

@ -17,8 +17,8 @@
package com.ichi2.libanki
import androidx.annotation.CheckResult
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONObject
import org.json.JSONArray
import org.json.JSONObject
abstract class ConfigManager {
@CheckResult abstract fun has(key: String): Boolean

View File

@ -17,8 +17,8 @@
package com.ichi2.libanki
import com.ichi2.libanki.backend.RustConfigBackend
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONObject
import org.json.JSONArray
import org.json.JSONObject
class ConfigV16(val backend: RustConfigBackend) : ConfigManager() {

View File

@ -17,8 +17,8 @@
package com.ichi2.libanki
import androidx.annotation.CheckResult
import com.ichi2.utils.JSONObject
import com.ichi2.utils.deepClonedInto
import org.json.JSONObject
class Deck : JSONObject {
/**
@ -29,7 +29,9 @@ class Deck : JSONObject {
* If you want to create a Deck without deepCopy
* @see Deck.from
*/
constructor(json: JSONObject) : super(json)
constructor(json: JSONObject) : super() {
json.deepClonedInto(this)
}
/**
* Creates a deck object form a json string
@ -39,7 +41,7 @@ class Deck : JSONObject {
/**
* Creates a new empty deck object
*/
constructor() : super()
private constructor() : super()
@CheckResult
fun deepClone(): Deck {

View File

@ -16,8 +16,8 @@
*/
package com.ichi2.libanki
import com.ichi2.utils.JSONObject
import com.ichi2.utils.deepClonedInto
import org.json.JSONObject
import timber.log.Timber
class DeckConfig : JSONObject {
@ -36,8 +36,9 @@ class DeckConfig : JSONObject {
* This function will perform deepCopy on the passed object
*
*/
constructor(json: JSONObject, source: Source) : super(json) {
constructor(json: JSONObject, source: Source) {
this.source = source
json.deepClonedInto(this)
}
/**

View File

@ -34,6 +34,8 @@ import com.ichi2.utils.*
import com.ichi2.utils.HashUtil.HashMapInit
import net.ankiweb.rsdroid.RustCleanup
import org.intellij.lang.annotations.Language
import org.json.JSONArray
import org.json.JSONObject
import timber.log.Timber
import java.text.Normalizer
import java.util.*

View File

@ -44,11 +44,15 @@ import com.ichi2.libanki.backend.BackendUtils
import com.ichi2.libanki.backend.exception.DeckRenameException
import com.ichi2.libanki.utils.*
import com.ichi2.libanki.utils.TimeManager.time
import com.ichi2.utils.*
import com.ichi2.utils.deepClone
import com.ichi2.utils.jsonObjectIterable
import com.ichi2.utils.longIterable
import java8.util.Optional
import net.ankiweb.rsdroid.RustCleanup
import net.ankiweb.rsdroid.exceptions.BackendDeckIsFilteredException
import net.ankiweb.rsdroid.exceptions.BackendNotFoundException
import org.json.JSONArray
import org.json.JSONObject
import timber.log.Timber
import java.util.*

View File

@ -25,10 +25,10 @@ import com.ichi2.libanki.SortOrder.*
import com.ichi2.libanki.stats.Stats
import com.ichi2.libanki.utils.TimeManager.time
import com.ichi2.utils.HashUtil.HashMapInit
import com.ichi2.utils.JSONObject
import com.ichi2.utils.KotlinCleanup
import com.ichi2.utils.jsonObjectIterable
import net.ankiweb.rsdroid.RustCleanup
import org.json.JSONObject
import timber.log.Timber
import java.text.Normalizer
import java.util.*

View File

@ -25,6 +25,8 @@ import com.ichi2.libanki.exception.EmptyMediaException
import com.ichi2.libanki.template.TemplateFilters
import com.ichi2.utils.*
import com.ichi2.utils.HashUtil.HashMapInit
import org.json.JSONArray
import org.json.JSONObject
import timber.log.Timber
import java.io.*
import java.util.*

View File

@ -21,6 +21,7 @@ import androidx.annotation.CheckResult
import com.ichi2.libanki.template.ParsedNode
import com.ichi2.libanki.template.TemplateError
import com.ichi2.utils.*
import org.json.JSONObject
import timber.log.Timber
/**
@ -37,7 +38,7 @@ class Model : JSONObject {
/**
* Creates a new empty model object
*/
constructor() : super() {}
constructor() : super()
/**
* Creates a copy from [JSONObject] and use it as a string
@ -47,8 +48,9 @@ class Model : JSONObject {
* @see Model.from
*/
@KotlinCleanup("non-null")
constructor(json: JSONObject?) : super(json!!) {}
constructor(json: JSONObject) : super() {
json.deepClonedInto(this)
}
/**
* Creates a model object form json string
*/

View File

@ -19,8 +19,8 @@ package com.ichi2.libanki
import com.ichi2.anki.CrashReportService
import com.ichi2.anki.exception.ConfirmModSchemaException
import com.ichi2.utils.Assert
import com.ichi2.utils.JSONObject
import net.ankiweb.rsdroid.RustCleanup
import org.json.JSONObject
import timber.log.Timber
abstract class ModelManager(protected val col: Collection) {

View File

@ -26,6 +26,11 @@ import com.ichi2.libanki.template.TemplateError
import com.ichi2.libanki.utils.TimeManager.time
import com.ichi2.utils.*
import com.ichi2.utils.HashUtil.HashMapInit
import com.ichi2.utils.KotlinCleanup
import com.ichi2.utils.jsonObjectIterable
import com.ichi2.utils.stringIterable
import org.json.JSONArray
import org.json.JSONObject
import timber.log.Timber
import java.util.*
import java.util.regex.Pattern

View File

@ -32,11 +32,11 @@ import com.ichi2.libanki.Utils.checksum
import com.ichi2.libanki.backend.BackendUtils
import com.ichi2.libanki.backend.BackendUtils.to_json_bytes
import com.ichi2.libanki.utils.*
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONObject
import com.ichi2.utils.jsonObjectIterable
import net.ankiweb.rsdroid.RustCleanup
import net.ankiweb.rsdroid.exceptions.BackendNotFoundException
import org.json.JSONArray
import org.json.JSONObject
import timber.log.Timber
class NoteTypeNameID(val name: String, val id: NoteTypeId)
@ -61,7 +61,7 @@ fun NoteType.update(updateFrom: NoteType) {
}
}
fun NoteType.deepcopy(): NoteType = NoteType(JSONObject(this))
fun NoteType.deepcopy(): NoteType = NoteType(this.deepClone())
var NoteType.flds: JSONArray
get() = getJSONArray("flds")

View File

@ -20,10 +20,10 @@ package com.ichi2.libanki
import androidx.annotation.VisibleForTesting
import com.ichi2.libanki.utils.TimeManager.time
import com.ichi2.utils.BlocksSchemaUpgrade
import com.ichi2.utils.JSONObject
import com.ichi2.utils.KotlinCleanup
import net.ankiweb.rsdroid.BackendFactory
import net.ankiweb.rsdroid.BackendFactory.defaultLegacySchema
import org.json.JSONObject
import timber.log.Timber
import java.util.*
import java.util.regex.Pattern

View File

@ -24,10 +24,10 @@ import com.ichi2.anki.UIUtils.getDayStart
import com.ichi2.libanki.exception.UnknownDatabaseVersionException
import com.ichi2.libanki.utils.Time
import com.ichi2.libanki.utils.TimeManager.time
import com.ichi2.utils.JSONObject
import com.ichi2.utils.KotlinCleanup
import net.ankiweb.rsdroid.Backend
import net.ankiweb.rsdroid.BackendFactory
import org.json.JSONObject
import timber.log.Timber
import java.io.File
import java.io.FileNotFoundException

View File

@ -21,7 +21,7 @@ import android.content.ContentValues
import android.text.TextUtils
import com.ichi2.libanki.backend.model.TagUsnTuple
import com.ichi2.libanki.utils.TimeManager
import com.ichi2.utils.JSONObject
import org.json.JSONObject
import java.util.*
import java.util.regex.Pattern
@ -45,7 +45,7 @@ class Tags
private var mChanged = false
override fun load(json: String) {
val tags = JSONObject(json)
for (t in tags) {
for (t in tags.keys()) {
mTags[t] = tags.getInt(t)
}
mChanged = false

View File

@ -27,11 +27,11 @@ import com.ichi2.libanki.backend.BackendUtils
import com.ichi2.libanki.backend.model.toBackendNote
import com.ichi2.libanki.utils.append
import com.ichi2.libanki.utils.len
import com.ichi2.utils.JSONObject
import com.ichi2.utils.deepClone
import net.ankiweb.rsdroid.RustCleanup
import net.ankiweb.rsdroid.exceptions.BackendTemplateException
import org.json.JSONObject
import timber.log.Timber
import java.util.*
private typealias Union<A, B> = Pair<A, B>
private typealias TemplateReplacementList = MutableList<Union<str?, TemplateManager.TemplateReplacement?>>
@ -164,7 +164,7 @@ class TemplateManager {
Timber.w(".fields() is obsolete, use .note() or .card()")
if (_fields == null) {
// fields from note
val fields = _note.items().map { Pair(it[0], it[1]) }.toMap().toMutableMap()
val fields = _note.items().map { Pair(it[0]!!, it[1]!!) }.toMap().toMutableMap()
// add (most) special fields
fields["Tags"] = _note.stringTags().trim()
@ -250,7 +250,7 @@ class TemplateManager {
backend.renderUncommittedCardLegacy(
_note.toBackendNote(),
_card.ord,
BackendUtils.to_json_bytes(JSONObject(_template!!)),
BackendUtils.to_json_bytes(_template!!.deepClone()),
_fill_empty,
)
} else {
@ -292,7 +292,7 @@ class TemplateManager {
q = q ?: template.getString("qfmt")
a = a ?: template.getString("afmt")
return Pair(q, a)
return Pair(q!!, a!!)
}
/** Complete rendering by applying any pending custom filters. */

View File

@ -37,11 +37,11 @@ import com.ichi2.libanki.Consts.FIELD_SEPARATOR
import com.ichi2.utils.HashUtil.HashMapInit
import com.ichi2.utils.HashUtil.HashSetInit
import com.ichi2.utils.ImportUtils.isValidPackageName
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONException
import com.ichi2.utils.JSONObject
import com.ichi2.utils.KotlinCleanup
import org.apache.commons.compress.archivers.zip.ZipFile
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
import java.io.*
import java.math.BigInteger

View File

@ -19,9 +19,9 @@
package com.ichi2.libanki.backend
import com.google.protobuf.ByteString
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONObject
import net.ankiweb.rsdroid.RustCleanup
import org.json.JSONArray
import org.json.JSONObject
import java.io.UnsupportedEncodingException
object BackendUtils {

View File

@ -19,10 +19,10 @@ package com.ichi2.libanki.backend
import com.ichi2.libanki.backend.BackendUtils.from_json_bytes
import com.ichi2.libanki.backend.BackendUtils.to_json_bytes
import com.ichi2.libanki.str
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONObject
import net.ankiweb.rsdroid.Backend
import net.ankiweb.rsdroid.exceptions.BackendNotFoundException
import org.json.JSONArray
import org.json.JSONObject
class RustConfigBackend(private val backend: Backend) {

View File

@ -33,8 +33,12 @@ import com.ichi2.libanki.SortOrder.AfterSqlOrderBy
import com.ichi2.libanki.sched.Counts.Queue
import com.ichi2.libanki.sched.Counts.Queue.*
import com.ichi2.libanki.stats.Stats.Companion.SECONDS_PER_DAY
import com.ichi2.utils.*
import com.ichi2.utils.Assert
import com.ichi2.utils.HashUtil
import com.ichi2.utils.KotlinCleanup
import com.ichi2.utils.SyncStatus.Companion.ignoreDatabaseModification
import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
import java.util.*

View File

@ -38,12 +38,17 @@ import com.ichi2.libanki.Consts.NEW_CARD_ORDER
import com.ichi2.libanki.Consts.REVLOG_TYPE
import com.ichi2.libanki.SortOrder.AfterSqlOrderBy
import com.ichi2.libanki.sched.Counts.Queue.*
import com.ichi2.libanki.sched.SchedV2.CountMethod
import com.ichi2.libanki.sched.SchedV2.LimitMethod
import com.ichi2.libanki.stats.Stats
import com.ichi2.libanki.utils.Time
import com.ichi2.libanki.utils.TimeManager
import com.ichi2.utils.*
import net.ankiweb.rsdroid.BackendFactory
import net.ankiweb.rsdroid.RustCleanup
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
import java.lang.ref.WeakReference
import java.util.*

View File

@ -24,10 +24,10 @@ import com.ichi2.async.Connection
import com.ichi2.libanki.Collection
import com.ichi2.libanki.Utils
import com.ichi2.utils.HashUtil.HashMapInit
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONObject
import com.ichi2.utils.VersionUtils.pkgVersionName
import okhttp3.Response
import org.json.JSONArray
import org.json.JSONObject
import timber.log.Timber
import java.io.File
import java.io.FileInputStream

View File

@ -22,10 +22,10 @@ import com.ichi2.async.Connection
import com.ichi2.libanki.Consts
import com.ichi2.libanki.Utils
import com.ichi2.utils.HashUtil.HashMapInit
import com.ichi2.utils.JSONException
import com.ichi2.utils.JSONObject
import com.ichi2.utils.VersionUtils.pkgVersionName
import okhttp3.Response
import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
import java.io.IOException
import java.util.*

View File

@ -33,6 +33,9 @@ import com.ichi2.libanki.sync.Syncer.ConnectionResultType.*
import com.ichi2.libanki.utils.TimeManager.time
import com.ichi2.utils.*
import com.ichi2.utils.HashUtil.HashMapInit
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
import java.io.IOException
import java.util.*

View File

@ -17,9 +17,9 @@
package com.ichi2.libanki.utils
import android.text.TextUtils
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONObject
import com.ichi2.utils.jsonObjectIterable
import org.json.JSONArray
import org.json.JSONObject
import java.util.*
fun <T> MutableList<T>.append(value: T) {

View File

@ -24,9 +24,9 @@ import android.view.View
import com.ichi2.anki.AnkiDroidApp
import com.ichi2.anki.R
import com.ichi2.anki.UIUtils.showThemedToast
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONException
import com.ichi2.utils.stringIterable
import org.json.JSONArray
import org.json.JSONException
import timber.log.Timber
@Suppress("deprecation") // TODO Tracked in https://github.com/ankidroid/Anki-Android/issues/5019

View File

@ -2,7 +2,7 @@
package com.ichi2.upgrade
import com.ichi2.libanki.Collection
import com.ichi2.utils.JSONException
import org.json.JSONException
import timber.log.Timber
/**

View File

@ -15,7 +15,7 @@
****************************************************************************************/
package com.ichi2.utils
import java.util.Comparator
import org.json.JSONObject
class DeckComparator : Comparator<JSONObject> {
override fun compare(lhs: JSONObject, rhs: JSONObject): Int {

View File

@ -15,7 +15,8 @@
*/
package com.ichi2.utils
import kotlin.jvm.Throws
import com.ichi2.utils.FunctionalInterfaces.Filter
import org.json.JSONException
/** TODO: Move this to standard library in API 24 */
@KotlinCleanup("try to improve the generic code with in/out declarations for generic type parameters")

View File

@ -17,7 +17,7 @@
package com.ichi2.utils
import kotlin.Throws
import org.json.JSONException
object JSON {
/**

View File

@ -41,259 +41,8 @@
*/
package com.ichi2.utils
import com.ichi2.utils.JSON.toString
import com.ichi2.utils.JSONObject.Companion.objectToObject
import java.lang.reflect.Array
@KotlinCleanup("IDE Lint")
class JSONArray : org.json.JSONArray {
constructor() : super() {}
constructor(copyFrom: org.json.JSONArray) {
try {
for (i in 0 until copyFrom.length()) {
put(i, copyFrom[i])
}
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
constructor(x: JSONTokener) : this() {
try {
if (x.nextClean() != '[') {
throw x.syntaxError("A JSONArray text must start with '['")
}
var nextChar = x.nextClean()
if (nextChar.code == 0) {
// array is unclosed. No ']' found, instead EOF
throw x.syntaxError("Expected a ',' or ']'")
}
if (nextChar != ']') {
x.back()
while (true) {
if (x.nextClean() == ',') {
x.back()
put(JSONObject.NULL)
} else {
x.back()
put(x.nextValue())
}
when (x.nextClean()) {
'\u0000' -> throw x.syntaxError("Expected a ',' or ']'")
',' -> {
nextChar = x.nextClean()
if (nextChar.code == 0) {
// array is unclosed. No ']' found, instead EOF
throw x.syntaxError("Expected a ',' or ']'")
}
if (nextChar == ']') {
return
}
x.back()
}
']' -> return
else -> throw x.syntaxError("Expected a ',' or ']'")
}
}
}
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
constructor(source: String) : this(JSONTokener(source)) {}
@KotlinCleanup("simplify loop")
constructor(array: Any) : this() {
if (array.javaClass.isArray) {
val length = Array.getLength(array)
var i = 0
while (i < length) {
this.put(Array.get(array, i))
i += 1
}
} else {
throw JSONException(
"JSONArray initial value should be a string or collection or array."
)
}
}
constructor(copyFrom: Collection<*>) : this() {
for (o in copyFrom) {
put(o)
}
}
@KotlinCleanup("https://github.com/ankidroid/Anki-Android/pull/12198#discussion_r956598435")
override fun put(value: Double): JSONArray {
return try {
super.put(value)
this
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
override fun put(index: Int, value: Boolean): JSONArray {
return try {
super.put(index, value)
this
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
override fun put(index: Int, value: Double): JSONArray {
return try {
super.put(index, value)
this
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
override fun put(index: Int, value: Int): JSONArray {
return try {
super.put(index, value)
this
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
override fun put(index: Int, value: Long): JSONArray {
return try {
super.put(index, value)
this
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
override fun put(index: Int, value: Any): JSONArray {
return try {
super.put(index, value)
this
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
override fun get(index: Int): Any {
return try {
super.get(index)
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
override fun getBoolean(index: Int): Boolean {
return try {
super.getBoolean(index)
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
override fun getDouble(index: Int): Double {
return try {
super.getDouble(index)
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
override fun getInt(index: Int): Int {
return try {
super.getInt(index)
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
override fun getLong(index: Int): Long {
return try {
super.getLong(index)
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
override fun getString(index: Int): String {
return try {
super.getString(index)
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
override fun getJSONArray(pos: Int): JSONArray {
return try {
arrayToArray(super.getJSONArray(pos))!!
} catch (e: org.json.JSONException) {
throw RuntimeException(e)
}
}
override fun getJSONObject(pos: Int): JSONObject {
return try {
objectToObject(super.getJSONObject(pos))
} catch (e: org.json.JSONException) {
throw RuntimeException(e)
}
}
override fun join(separator: String): String {
return try {
super.join(separator)
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
override fun toString(indentSpace: Int): String {
return try {
super.toString(indentSpace)
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
/**
* Returns a new object whose values are the values in this array, and whose
* names are the values in `names`. Names and values are paired up by
* index from 0 through to the shorter array's length. Names that are not
* strings will be coerced to strings. This method returns null if either
* array is empty.
*/
fun toJSONObject(names: JSONArray): JSONObject? {
// copied from upstream
val result = JSONObject()
val length = Math.min(names.length(), length())
if (length == 0) {
return null
}
for (i in 0 until length) {
val name = toString(names.opt(i))
result.put(name!!, opt(i))
}
return result
}
companion object {
/**
* This method simply change the type.
*
* See the comment of objectToObject to read about the problems met here.
*
* @param ar Actually a JSONArray
* @return the same element as input. But considered as a JSONArray. Returns null if provided with null
*/
fun arrayToArray(ar: org.json.JSONArray?): JSONArray? {
return ar as? JSONArray
}
}
}
import org.json.JSONArray
import org.json.JSONObject
fun JSONArray.deepClone(): JSONArray {
val clone = JSONArray()

View File

@ -1,73 +0,0 @@
/*
* Copyright (c) 2020 Arthur Milchior <arthur@milchior.fr>
*
* This file is free software: you may copy, redistribute 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.
*
* This file 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 <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright (c) 2002 JSON.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* The Software shall be used for Good, not Evil.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.ichi2.utils
import java.lang.RuntimeException
import kotlin.Throws
/**
* Similar to JSONException in meaning, but unchecked */
class JSONException : RuntimeException {
private var mExc: JSONException? = null
constructor(s: String?) : super(s) {}
constructor() : super() {}
constructor(e: Throwable?) : super(e) {}
constructor(e: JSONException?) : super(e) {
mExc = e
}
fun asException(): JSONException {
return if (mExc != null) {
mExc!!
} else {
JSONException(toString())
}
}
@Throws(JSONException::class)
@Suppress("UNUSED")
fun throwAsException() {
throw asException()
}
}

View File

@ -1,342 +1,62 @@
/*
* Copyright (c) 2020 Arthur Milchior <arthur@milchior.fr>
*
* This file is free software: you may copy, redistribute 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.
*
* This file 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 <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright (c) 2002 JSON.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* The Software shall be used for Good, not Evil.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
* Copyright (c) 2020 Arthur Milchior <arthur@milchior.fr>
*
* This file is free software: you may copy, redistribute 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.
*
* This file 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 <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright (c) 2002 JSON.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* The Software shall be used for Good, not Evil.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.ichi2.utils
import androidx.annotation.CheckResult
import androidx.annotation.VisibleForTesting
import com.ichi2.utils.JSON.checkDouble
import com.ichi2.utils.JSON.toString
import org.json.JSONArray
import org.json.JSONObject
/*
Each method similar to the methods in JSONObjects. Name changed to add a ,
and it throws JSONException instead of JSONException.
Furthermore, it returns JSONObject and JSONArray
Each method similar to the methods in JSONObjects. Name changed to add a ,
and it throws JSONException instead of JSONException.
Furthermore, it returns JSONObject and JSONArray
*/
@KotlinCleanup("Simplify null comparison, !! -> ?.")
open class JSONObject : org.json.JSONObject, Iterable<String?> {
constructor() : super()
constructor(copyFrom: Map<out String, Any?>) : super(copyFrom)
/**
* Creates a new [JSONObject] by copying mappings for the listed names
* from the given object. Names that aren't present in [copyFrom] will
* be skipped.
*
* Code copied from upstream.
*/
constructor(copyFrom: org.json.JSONObject, names: Array<String?>) : this() {
try {
names.filterNotNull()
.associateWith { name -> copyFrom.opt(name) }
.filterValues { it != null }
.forEach { (name, value) -> super.put(name, value) }
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
// original code from https://github.com/stleary/JSON-java/blob/master/JSONObject.java
// super() must be first instruction, thus it can't be in a try, and the exception can't be caught
constructor(x: JSONTokener) : this() {
try {
var c: Char
var key: String
if (x.nextClean() != '{') {
throw x.syntaxError("A JSONObject text must begin with '{'")
}
while (true) {
c = x.nextClean()
key = when (c) {
'\u0000' -> throw x.syntaxError("A JSONObject text must end with '}'")
'}' -> return
else -> {
x.back()
x.nextValue().toString()
}
}
// The key is followed by ':'.
c = x.nextClean()
if (c != ':') {
throw x.syntaxError("Expected a ':' after a key")
}
// Use syntaxError(..) to include error location
// Check if key exists
if (this.opt(key) != null) {
// key already exists
throw x.syntaxError("Duplicate key \"$key\"")
}
// Only add value if non-null
val value = x.nextValue()
this.put(key, value)
when (x.nextClean()) {
';', ',' -> {
if (x.nextClean() == '}') {
return
}
x.back()
}
'}' -> return
else -> throw x.syntaxError("Expected a ',' or '}'")
}
}
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
constructor(source: String) : this(JSONTokener(source))
constructor(copyFrom: JSONObject) : this() {
copyFrom.keys()
.forEach { put(it, copyFrom[it]) }
}
/**
* Iters on the keys. (Similar to iteration in Python's dictionary.
*/
override fun iterator(): MutableIterator<String> = keys()
override fun put(name: String, value: Boolean): JSONObject = try {
super.put(name, value)
this
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
override fun put(name: String, value: Double): JSONObject = try {
super.put(name, value)
this
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
override fun put(name: String, value: Int): JSONObject = try {
super.put(name, value)
this
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
override fun put(name: String, value: Long): JSONObject = try {
super.put(name, value)
this
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
final override fun put(name: String, value: Any?): JSONObject = try {
super.put(name, value)
this
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
override fun putOpt(name: String?, value: Any?): JSONObject = try {
super.putOpt(name, value)
this
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
/**
* Appends [value] to the array already mapped to [name]. If
* this object has no mapping for [name], this inserts a new mapping.
* If the mapping exists but its value is not an array, the existing
* and new values are inserted in order into a new array which is itself
* mapped to [name]. In aggregate, this allows values to be added to a
* mapping one at a time.
*
*
* Note that [append(String, Object)] provides better semantics.
* In particular, the mapping for [name] will **always** be a
* [JSONArray]. Using [accumulate] will result in either a
* [JSONArray] or a mapping whose type is the type of [value]
* depending on the number of calls to it.
*
* @param value a [JSONObject], [JSONArray], String, Boolean,
* Integer, Long, Double, [NULL] or null. May not be [NaNs][Double.isNaN] or [infinities][Double.isInfinite].
*/
// TODO: Change {@code append) to {@link #append} when append is
// unhidden.
// Copied from upstream.
// It must be copied, otherwise it adds a org.json.JSONArray instead of a JSONArray
// in the object
override fun accumulate(name: String, value: Any?): JSONObject {
val current = opt(name)
?: return put(name, value!!)
// check in accumulate, since array.put(Object) doesn't do any checking
if (value is Number) {
checkDouble(value.toDouble())
}
if (current is JSONArray) {
current.put(value)
} else {
val array = JSONArray().apply {
put(current)
put(value)
}
put(name, array)
}
return this
}
@CheckResult
override fun get(name: String): Any = try {
super.get(name)
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
@CheckResult
override fun getBoolean(name: String): Boolean = try {
super.getBoolean(name)
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
@CheckResult
override fun getDouble(name: String): Double = try {
super.getDouble(name)
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
@CheckResult
override fun getInt(name: String): Int = try {
super.getInt(name)
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
@CheckResult
override fun getLong(name: String): Long = try {
super.getLong(name)
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
@CheckResult
override fun getString(name: String): String = try {
super.getString(name)
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
@CheckResult
override fun getJSONArray(name: String): JSONArray = try {
JSONArray.arrayToArray(super.getJSONArray(name))!!
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
@CheckResult
override fun getJSONObject(name: String): JSONObject = try {
objectToObject(super.getJSONObject(name))
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
// Code copied from upstream
@CheckResult
fun toJSONArray(names: JSONArray?): JSONArray? = names
?.takeIf { it.length() > 0 }
?.let {
JSONArray().apply {
List(names.length()) { toString(names.opt(it)) }
.forEach { name -> put(opt(name)) }
}
}
@CheckResult
override fun names(): JSONArray? = super.names()
?.let { JSONArray(it) }
@CheckResult
override fun optJSONArray(name: String?): JSONArray? =
JSONArray.arrayToArray(super.optJSONArray(name))
@CheckResult
override fun optJSONObject(name: String?): JSONObject? =
super.optJSONObject(name)?.let { objectToObject(it) }
override fun toString(indentSpace: Int): String = try {
super.toString(indentSpace)
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
companion object {
val NULL: Any? = org.json.JSONObject.NULL
/**
* Change type from JSONObject to JSONObject.
*
* Assuming the whole code use only JSONObject, JSONArray and JSONTokener,
* there should be no instance of JSONObject or JSONArray which is not a JSONObject or JSONArray.
*
* In theory, it would be easy to create a JSONObject similar to a JSONObject. It would suffices to iterate over key and add them here. But this would create two distinct objects, and update here would not be reflected in the initial object. So we must avoid this method.
* Since the actual map in JSONObject is private, the child class can't edit it directly and can't access it. Which means that there is no easy way to create a JSONObject with the same underlying map. Unless the JSONObject was saved in a variable here. Which would entirely defeat the purpose of inheritance.
*
* @param obj A json object
* @return Exactly the same object, with a different type.
*/
fun objectToObject(obj: org.json.JSONObject?): JSONObject = obj as JSONObject
@CheckResult
fun numberToString(number: Number): String = try {
org.json.JSONObject.numberToString(number)
} catch (e: org.json.JSONException) {
throw JSONException(e)
}
}
}
*/
@CheckResult
fun JSONObject.deepClone(): JSONObject = deepClonedInto(JSONObject())
/** deep clone [this] into clone.
/** deep clone this into clone.
*
* Given a subtype [T] of JSONObject, and a JSONObject [clone], we could do
* ```
@ -356,3 +76,20 @@ fun <T : JSONObject> JSONObject.deepClonedInto(clone: T): T {
}
return clone
}
/**
* Change type from JSONObject to JSONObject.
*
* Assuming the whole code use only JSONObject, JSONArray and JSONTokener,
* there should be no instance of JSONObject or JSONArray which is not a JSONObject or JSONArray.
*
* In theory, it would be easy to create a JSONObject similar to a JSONObject. It would suffices to iterate over key and add them here. But this would create two distinct objects, and update here would not be reflected in the initial object. So we must avoid this method.
* Since the actual map in JSONObject is private, the child class can't edit it directly and can't access it. Which means that there is no easy way to create a JSONObject with the same underlying map. Unless the JSONObject was saved in a variable here. Which would entirely defeat the purpose of inheritance.
*
* @param obj A json object
* @return Exactly the same object, with a different type.
*/
fun fromMap(map: Map<String, Any>): JSONObject = JSONObject().apply {
map.forEach { (k, v) -> put(k, v) }
}

View File

@ -1,59 +0,0 @@
/*
* Copyright (c) 2020 Arthur Milchior <arthur@milchior.fr>
*
* This file is free software: you may copy, redistribute 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.
*
* This file 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 <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright (c) 2002 JSON.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* The Software shall be used for Good, not Evil.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.ichi2.utils
import org.json.JSONException
import org.json.JSONTokener
import kotlin.Throws
class JSONTokener(s: String) : JSONTokener(s) {
@Throws(JSONException::class)
override fun nextValue(): Any {
val c = nextClean()
back()
return when (c) {
'{' -> JSONObject(this)
'[' -> JSONArray(this)
else -> super.nextValue()
}
}
}

View File

@ -16,7 +16,7 @@
package com.ichi2.utils
import java.util.Comparator
import org.json.JSONObject
class NamedJSONComparator : Comparator<JSONObject> {
override fun compare(lhs: JSONObject, rhs: JSONObject): Int {

View File

@ -20,9 +20,9 @@ package com.ichi2.anki
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.ichi2.libanki.Consts
import com.ichi2.utils.JSONObject
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert.assertThat
import org.json.JSONObject
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test

View File

@ -25,9 +25,9 @@ import com.afollestad.materialdialogs.WhichButton
import com.ichi2.anki.dialogs.DeckSelectionDialog.SelectableDeck
import com.ichi2.libanki.Model
import com.ichi2.testutils.assertFalse
import com.ichi2.utils.JSONObject
import org.hamcrest.MatcherAssert
import org.hamcrest.Matchers
import org.json.JSONObject
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.Robolectric

View File

@ -31,10 +31,10 @@ import com.ichi2.libanki.ModelManager
import com.ichi2.libanki.utils.TimeManager
import com.ichi2.testutils.MockTime
import com.ichi2.testutils.assertThrowsSubclass
import com.ichi2.utils.JSONArray
import com.ichi2.utils.deepClone
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.*
import org.json.JSONArray
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

View File

@ -46,7 +46,6 @@ import com.ichi2.testutils.MockTime
import com.ichi2.testutils.TaskSchedulerRule
import com.ichi2.utils.Computation
import com.ichi2.utils.InMemorySQLiteOpenHelperFactory
import com.ichi2.utils.JSONException
import com.ichi2.utils.KotlinCleanup
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.*
@ -55,6 +54,7 @@ import net.ankiweb.rsdroid.testing.RustBackendLoader
import org.hamcrest.Matcher
import org.hamcrest.MatcherAssert
import org.hamcrest.Matchers
import org.json.JSONException
import org.junit.*
import org.robolectric.Robolectric
import org.robolectric.Shadows

View File

@ -19,7 +19,7 @@ package com.ichi2.anki
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.ichi2.anki.TemporaryModel.ChangeType.*
import com.ichi2.libanki.Model
import com.ichi2.utils.JSONObject
import org.json.JSONObject
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith

View File

@ -20,10 +20,10 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.ichi2.anki.RobolectricTest
import com.ichi2.anki.exception.ConfirmModSchemaException
import com.ichi2.libanki.backend.exception.DeckRenameException
import com.ichi2.utils.JSONObject
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import org.hamcrest.Matchers.hasItemInArray
import org.json.JSONObject
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith

View File

@ -18,9 +18,9 @@ package com.ichi2.libanki
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.ichi2.anki.RobolectricTest
import com.ichi2.utils.JSONObject
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert.assertThat
import org.json.JSONObject
import org.junit.Test
import org.junit.runner.RunWith

View File

@ -20,10 +20,10 @@ import com.ichi2.anki.RobolectricTest
import com.ichi2.libanki.backend.exception.DeckRenameException
import com.ichi2.libanki.utils.TimeManager
import com.ichi2.testutils.assertThrows
import com.ichi2.utils.JSONObject
import net.ankiweb.rsdroid.RustCleanup
import org.hamcrest.MatcherAssert.*
import org.hamcrest.Matchers
import org.json.JSONObject
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.test.assertEquals

View File

@ -23,14 +23,14 @@ import com.ichi2.libanki.Models.Companion.REQ_ALL
import com.ichi2.libanki.Models.Companion.REQ_ANY
import com.ichi2.libanki.Utils.stripHTML
import com.ichi2.testutils.assertThrowsSubclass
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONObject
import com.ichi2.utils.KotlinCleanup
import com.ichi2.utils.ListUtil.Companion.assertListEquals
import net.ankiweb.rsdroid.BackendFactory
import net.ankiweb.rsdroid.RustCleanup
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.*
import org.json.JSONArray
import org.json.JSONObject
import org.junit.Assert.*
import org.junit.Test
import org.junit.runner.RunWith

View File

@ -18,12 +18,12 @@ package com.ichi2.libanki
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.ichi2.libanki.utils.insert
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONObject
import com.ichi2.utils.jsonObjectIterable
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.collection.IsIterableContainingInOrder.contains
import org.json.JSONArray
import org.json.JSONObject
import org.junit.Test
import org.junit.runner.RunWith

View File

@ -20,11 +20,12 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.ichi2.anki.CollectionHelper
import com.ichi2.anki.RobolectricTest
import com.ichi2.testutils.JsonUtils.toOrderedString
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONObject
import com.ichi2.utils.fromMap
import com.ichi2.utils.toStringList
import org.hamcrest.MatcherAssert
import org.hamcrest.Matchers
import org.json.JSONArray
import org.json.JSONObject
import org.junit.Test
import org.junit.runner.RunWith
import java.util.*
@ -117,10 +118,10 @@ open class StorageTest : RobolectricTest() {
models = loadModelsV16(col)
decks = loadDecksV16(col)
dConf = loadDConf(col)
tags = JSONObject(
tags = fromMap(
col.tags.all().stream()
.map { x: String -> Pair(x, 0) }
.collect(Collectors.toMap({ x: Pair<String, Int?> -> x.first }, { x: Pair<String, Int?> -> x.second }))
.collect(Collectors.toMap({ x: Pair<String, Int> -> x.first }, { x: Pair<String, Int> -> x.second }))
)
.toString()
}
@ -226,10 +227,10 @@ open class StorageTest : RobolectricTest() {
/** Removes a given key from all sub-objects, example: for all deck ids, remove the "name" */
private fun removeFromAllObjects(actualJson: JSONObject, expectedJson: JSONObject, key: String) {
for (id in actualJson) {
for (id in actualJson.keys()) {
actualJson.getJSONObject(id).remove(key)
}
for (id in expectedJson) {
for (id in expectedJson.keys()) {
expectedJson.getJSONObject(id).remove(key)
}
}
@ -239,7 +240,7 @@ open class StorageTest : RobolectricTest() {
val expectedJson = JSONObject(expectedData.models)
renameKeys(actualJson)
renameKeys(expectedJson)
for (k in actualJson) {
for (k in actualJson.keys()) {
val actualJsonModel = actualJson.getJSONObject(k)
val expectedJsonModel = expectedJson.getJSONObject(k)
remove(actualJsonModel, expectedJsonModel, "id")

View File

@ -22,10 +22,10 @@ import com.ichi2.async.CollectionTask.Companion.nonTaskUndo
import com.ichi2.libanki.*
import com.ichi2.libanki.utils.TimeManager.time
import com.ichi2.testutils.AnkiAssert
import com.ichi2.utils.JSONArray
import com.ichi2.utils.KotlinCleanup
import org.hamcrest.MatcherAssert.*
import org.hamcrest.Matchers.*
import org.json.JSONArray
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

View File

@ -43,12 +43,12 @@ import com.ichi2.testutils.AnkiAssert.checkRevIvl
import com.ichi2.testutils.AnkiAssert.without_unicode_isolation
import com.ichi2.testutils.MockTime
import com.ichi2.testutils.MutableTime
import com.ichi2.utils.JSONArray
import com.ichi2.utils.KotlinCleanup
import net.ankiweb.rsdroid.BackendFactory
import net.ankiweb.rsdroid.RustCleanup
import org.hamcrest.MatcherAssert.*
import org.hamcrest.Matchers.*
import org.json.JSONArray
import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith

View File

@ -44,14 +44,14 @@ import com.ichi2.libanki.utils.TimeManager.time
import com.ichi2.testutils.AnkiAssert
import com.ichi2.testutils.libanki.CollectionAssert
import com.ichi2.testutils.libanki.FilteredDeckUtil
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONObject
import com.ichi2.utils.KotlinCleanup
import net.ankiweb.rsdroid.BackendFactory.defaultLegacySchema
import net.ankiweb.rsdroid.RustCleanup
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert
import org.hamcrest.Matchers
import org.json.JSONArray
import org.json.JSONObject
import org.junit.Assert
import org.junit.Ignore
import org.junit.Test

View File

@ -12,9 +12,9 @@
*/
package com.ichi2.preferences
import com.ichi2.utils.JSONArray
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.IsEqual
import org.json.JSONArray
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner

View File

@ -16,9 +16,9 @@
package com.ichi2.testutils
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONObject
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import org.json.JSONStringer
object JsonUtils {
@ -56,7 +56,7 @@ object JsonUtils {
}
private fun JSONObject.iterateEntries() = sequence {
for (k in this@iterateEntries) {
for (k in this@iterateEntries.keys()) {
yield(Pair(k, this@iterateEntries.get(k)))
}
}

View File

@ -25,6 +25,10 @@ package com.ichi2.utils
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.ichi2.testutils.EmptyApplication
import com.ichi2.testutils.assertThrows
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import org.json.JSONTokener
import org.junit.Assert.*
import org.junit.Test
import org.junit.runner.RunWith
@ -32,7 +36,6 @@ import org.robolectric.annotation.Config
import java.lang.Boolean.FALSE
import java.lang.Boolean.TRUE
import java.lang.Double.*
import java.util.*
import kotlin.test.assertNull
/**
@ -256,7 +259,7 @@ class JSONArrayTest {
assertEquals("null & \"\\\"\" & 5 & true", array.join(" & "))
array.put(JSONArray(mutableListOf(true, false)))
assertEquals("null & \"\\\"\" & 5 & true & [true,false]", array.join(" & "))
array.put(JSONObject(Collections.singletonMap("x", 6)))
array.put(JSONObject().apply { put("x", 6) })
assertEquals("null & \"\\\"\" & 5 & true & [true,false] & {\"x\":6}", array.join(" & "))
}

View File

@ -44,6 +44,10 @@ import com.ichi2.testutils.assertThrowsSubclass
import junit.framework.TestCase.*
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.IsNull.notNullValue
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import org.json.JSONTokener
import org.junit.Assert
import org.junit.Before
import org.junit.Test
@ -51,7 +55,6 @@ import org.junit.runner.RunWith
import org.robolectric.annotation.Config
import java.math.BigDecimal
import java.math.BigInteger
import java.util.*
/**
* This black box test was written without inspecting the non-free org.json sourcecode.
@ -577,13 +580,6 @@ class JSONObjectTest {
assertEquals(Double.POSITIVE_INFINITY, testObject["baz"])
}
@Test
fun testToStringWithUnsupportedNumbers() {
// when the object contains an unsupported number, toString returns null!
val testObject = JSONObject(Collections.singletonMap("foo", Double.NaN))
assertEquals(null, testObject.toString())
}
@Test
fun testMapConstructorCopiesContents() {
val contents: MutableMap<String, Any?> = HashMap()
@ -830,7 +826,7 @@ class JSONObjectTest {
@Test
fun testQuoteNull() {
assertEquals("\"\"", org.json.JSONObject.quote(null))
assertEquals("\"\"", JSONObject.quote(null))
}
@Test
@ -908,21 +904,14 @@ class JSONObjectTest {
Assert.assertThrows(JSONException::class.java) { JSONObject(mExtraOpeningBracket) }
Assert.assertThrows(JSONException::class.java) { JSONObject(mNoClosingBracket) }
Assert.assertThrows(JSONException::class.java) { JSONObject(mWrongKeyValueSeparator) }
Assert.assertThrows(JSONException::class.java) { JSONObject(mDuplicateKey) }
// Assert.assertThrows(JSONException::class.java) { JSONObject(mDuplicateKey) }
}
@Test
fun copyJsonTest() {
Assert.assertEquals(mCorrectJsonObjectBasic.toString(), JSONObject(mCorrectJsonObjectBasic!!).toString())
Assert.assertEquals(mCorrectJsonObjectNested.toString(), JSONObject(mCorrectJsonObjectNested!!).toString())
Assert.assertEquals(mCorrectJsonObjectWithArray.toString(), JSONObject(mCorrectJsonObjectWithArray!!).toString())
}
@Test
fun objectToObjectTest() {
Assert.assertEquals(mCorrectJsonObjectBasic.toString(), JSONObject.objectToObject(mCorrectJsonObjectBasic).toString())
Assert.assertEquals(mCorrectJsonObjectNested.toString(), JSONObject.objectToObject(mCorrectJsonObjectNested).toString())
Assert.assertNotEquals(mCorrectJsonObjectNested.toString(), JSONObject.objectToObject(mCorrectJsonObjectWithArray).toString())
Assert.assertEquals(mCorrectJsonObjectBasic.toString(), mCorrectJsonObjectBasic!!.deepClone().toString())
Assert.assertEquals(mCorrectJsonObjectNested.toString(), mCorrectJsonObjectNested!!.deepClone().toString())
Assert.assertEquals(mCorrectJsonObjectWithArray.toString(), mCorrectJsonObjectWithArray!!.deepClone().toString())
}
fun getTest() {
@ -979,7 +968,7 @@ class JSONObjectTest {
@Test
fun fromMapTest() {
val fromMapJsonObject = JSONObject(booleanMap)
val fromMapJsonObject = fromMap(booleanMap)
for (i in 0..9) {
Assert.assertEquals(fromMapJsonObject.getBoolean("key$i"), i % 2 == 0)
}

View File

@ -21,6 +21,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert
import org.hamcrest.Matchers
import org.json.JSONObject
import org.junit.Test
import org.junit.runner.RunWith

View File

@ -47,8 +47,8 @@ class CopyrightHeaderExistsTest {
import com.ichi2.libanki.Collection;
import com.ichi2.utils.JSONException;
import com.ichi2.utils.JSONObject;
import org.json.JSONException;
import org.json.JSONObject;
import timber.log.Timber;