merge and cleanup

This commit is contained in:
Xinto 2020-11-05 22:35:48 +04:00
commit 467fc26360
25 changed files with 108 additions and 106 deletions

View File

@ -23,7 +23,7 @@ android {
versionCode 200
versionName "2.0.0 (.nomagiskui)"
vectorDrawables.useSupportLibrary = true
vectorDrawables.useSupportLibrary true
buildConfigField "String[]", "MANAGER_LANGUAGES", "{" + surroundWithQuotes(langs) + "}"
buildConfigField "Boolean", "ENABLE_CROWDIN_AUTH", "false"
@ -41,7 +41,7 @@ android {
}
applicationVariants.all { variant ->
variant.resValue "string", "versionName", variant.versionName
resValue "string", "versionName", versionName
}
buildTypes {
@ -116,20 +116,34 @@ dependencies {
implementation 'com.google.android.material:material:1.3.0-alpha03'
// Other
// JSON parser
implementation 'com.beust:klaxon:5.4'
// Crowdin
implementation 'com.crowdin.platform:mobile-sdk:1.2.0'
// Tips
implementation 'com.github.florent37:viewtooltip:1.2.2'
// HTTP networking
implementation 'com.github.kittinunf.fuel:fuel:2.3.0'
implementation 'com.github.kittinunf.fuel:fuel-coroutines:2.2.3'
implementation 'com.github.kittinunf.fuel:fuel-json:2.2.3'
implementation 'com.github.topjohnwu.libsu:core:3.0.2'
implementation 'com.github.topjohnwu.libsu:io:3.0.2'
implementation 'com.google.android:flexbox:2.0.1'
implementation 'com.google.firebase:firebase-messaging:21.0.0'
implementation 'com.google.firebase:firebase-perf:19.0.9'
implementation 'com.google.firebase:firebase-analytics-ktx:18.0.0'
implementation 'com.google.firebase:firebase-crashlytics:17.2.2'
implementation 'com.mindorks.android:prdownloader:0.6.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0'
// Root permissions
implementation 'com.github.topjohnwu.libsu:core:3.0.2'
implementation 'com.github.topjohnwu.libsu:io:3.0.2'
// Layout
implementation 'com.google.android:flexbox:2.0.1'
// File downloader
implementation 'com.mindorks.android:prdownloader:0.6.0'
// Firebase
implementation 'com.google.firebase:firebase-analytics-ktx:18.0.0'
implementation 'com.google.firebase:firebase-crashlytics:17.2.2'
implementation 'com.google.firebase:firebase-messaging:21.0.0'
implementation 'com.google.firebase:firebase-perf:19.0.9'
}

View File

@ -122,7 +122,7 @@ object VancedDownloader {
"lang" -> {
count++
succesfulLangCount++
if (count < lang?.count()!!)
if (count < lang?.size!!)
downloadSplits(context, "lang")
else
startVancedInstall(context)
@ -134,7 +134,7 @@ object VancedDownloader {
if (type == "lang") {
count++
when {
count < lang?.count()!! -> downloadSplits(context, "lang")
count < lang?.size!! -> downloadSplits(context, "lang")
succesfulLangCount == 0 -> {
lang?.add("en")
downloadSplits(context, "lang")

View File

@ -178,7 +178,7 @@ class MainActivity : AppCompatActivity() {
}
private fun checkUpdates() {
if (InternetTools.isUpdateAvailable(this)) {
if (InternetTools.isUpdateAvailable()) {
ManagerUpdateDialog(false).show(supportFragmentManager, "UpdateCheck")
}
}

View File

@ -3,8 +3,9 @@ package com.vanced.manager.ui.core
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
import androidx.core.view.isGone
import androidx.core.view.isVisible
import com.vanced.manager.R
import kotlinx.android.synthetic.main.view_preference.view.*
@ -26,7 +27,7 @@ class EmptyPreference @JvmOverloads constructor(
fun setSummary(newSummary: String) {
preference_summary.text = newSummary
preference_summary.visibility = View.VISIBLE
preference_summary.isVisible = true
preference_title.setPadding(0, 0, 0, 0)
}
@ -38,7 +39,7 @@ class EmptyPreference @JvmOverloads constructor(
if (summary != null) {
preference_summary.text = summary
} else {
preference_summary.visibility = View.GONE
preference_summary.isGone = true
preference_title.setPadding(0, 12, 0, 12)
}
preference_title.text = title

View File

@ -5,6 +5,7 @@ import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.CompoundButton
import android.widget.FrameLayout
import androidx.core.content.edit
import androidx.databinding.BindingAdapter
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.vanced.manager.R
@ -33,7 +34,7 @@ class PreferenceSwitch @JvmOverloads constructor(
preference_switch.isChecked = !preference_switch.isChecked
}
preference_switch.setOnCheckedChangeListener { buttonView, isChecked ->
prefs.edit().putBoolean(prefKey, isChecked).apply()
prefs.edit { putBoolean(prefKey, isChecked) }
mListener?.onChecked(buttonView, isChecked)
}

View File

@ -5,6 +5,7 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import androidx.core.content.ContextCompat.startActivity
import androidx.core.content.edit
import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.vanced.manager.R
@ -34,7 +35,7 @@ object DialogContainer {
show()
}
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
prefs.edit().putBoolean("firstLaunch", false).apply()
prefs.edit { putBoolean("firstLaunch", false) }
}
private fun showMiuiDialog(context: Context) {
@ -65,7 +66,7 @@ object DialogContainer {
}
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
prefs.edit().putBoolean("statement", true).apply()
prefs.edit { putBoolean("statement", true) }
}
fun installAlertBuilder(msg: String, context: Context) {

View File

@ -4,6 +4,7 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.edit
import androidx.databinding.DataBindingUtil
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
@ -33,7 +34,7 @@ class ManagerAccentColorDialog : BottomSheetDialogFragment() {
binding.accentSave.setOnClickListener {
val newPref = binding.accentRadiogroup.getCheckedButtonTag()
if (accent != newPref) {
prefs.edit().putString("manager_accent", newPref).apply()
prefs.edit { putString("manager_accent", newPref) }
dismiss()
requireActivity().recreate()
} else {

View File

@ -6,6 +6,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import androidx.core.content.edit
import androidx.databinding.DataBindingUtil
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
@ -38,7 +39,7 @@ class ManagerLanguageDialog : BottomSheetDialogFragment() {
binding.languageSave.setOnClickListener {
val newPref = binding.languageRadiogroup.getCheckedButtonTag()
if (language != newPref) {
prefs.edit().putString("manager_lang", newPref).apply()
prefs.edit { putString("manager_lang", newPref) }
dismiss()
requireActivity().recreate()
} else {

View File

@ -4,6 +4,7 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.edit
import androidx.databinding.DataBindingUtil
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
@ -33,7 +34,7 @@ class ManagerThemeDialog : BottomSheetDialogFragment() {
binding.themeSave.setOnClickListener {
val newPref = binding.themeRadiogroup.getCheckedButtonTag()
if (theme != newPref) {
prefs.edit().putString("manager_theme", newPref).apply()
prefs.edit { putString("manager_theme", newPref) }
dismiss()
requireActivity().recreate()
} else {

View File

@ -69,7 +69,7 @@ class ManagerUpdateDialog(
}
private fun checkUpdates() {
if (isUpdateAvailable(requireActivity())) {
if (isUpdateAvailable()) {
binding.managerUpdatePatient.text = requireActivity().getString(R.string.please_be_patient)
downloadManager(requireActivity())
} else

View File

@ -5,6 +5,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.content.edit
import androidx.databinding.DataBindingUtil
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import androidx.recyclerview.widget.LinearLayoutManager
@ -41,7 +42,7 @@ class SelectAppsDialog : BottomSheetDialogFragment() {
return@setOnClickListener
}
ad.apps.forEach { app ->
prefs.edit().putBoolean("enable_${app.tag}", app.isChecked).apply()
prefs.edit { putBoolean("enable_${app.tag}", app.isChecked) }
}
dismiss()
}

View File

@ -8,6 +8,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.TextView
import androidx.core.content.edit
import androidx.fragment.app.DialogFragment
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.google.android.material.button.MaterialButton
@ -45,7 +46,7 @@ class URLChangeDialog : DialogFragment() {
}
private fun saveUrl(url: String) {
getDefaultSharedPreferences(requireActivity()).edit().putString("install_url", url).apply()
getDefaultSharedPreferences(requireActivity()).edit { putString("install_url", url) }
requireActivity().fetchData()
dismiss()
}

View File

@ -10,6 +10,7 @@ import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.widget.LinearLayout
import android.widget.Toast
import androidx.core.content.edit
import androidx.core.content.res.ResourcesCompat
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.button.MaterialButton
@ -53,7 +54,7 @@ class VancedLanguageSelectionDialog : BottomSheetDialogFragment() {
return@setOnClickListener
}
prefs?.edit()?.putString("lang", chosenLangs.joinToString())?.apply()
prefs?.edit { putString("lang", chosenLangs.joinToString()) }
dismiss()
}
}

View File

@ -57,6 +57,7 @@ class VancedPreferencesDialog : BottomSheetDialogFragment() {
dismiss()
AppVersionSelectorDialog(vancedVersionsConv, "vanced").show(requireActivity())
}
binding.chosenLang.text = requireActivity().getString(R.string.chosen_lang, showLang)
binding.openLanguageSelector.setOnClickListener {
dismiss()

View File

@ -7,6 +7,7 @@ import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.content.edit
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
@ -54,7 +55,7 @@ class AboutFragment : Fragment() {
val devSettings = prefs.getBoolean("devSettings", false)
if (!devSettings) {
Toast.makeText(requireContext(), "Dev options unlocked!", Toast.LENGTH_SHORT).show()
prefs.edit().putBoolean("devSettings", true).apply()
prefs.edit { putBoolean("devSettings", true) }
} else
Toast.makeText(requireContext(), "Dev options already unlocked", Toast.LENGTH_SHORT).show()

View File

@ -1,12 +1,13 @@
package com.vanced.manager.ui.fragments
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import androidx.core.content.edit
import androidx.core.net.toUri
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
@ -40,8 +41,10 @@ class DevSettingsFragment: PreferenceFragmentCompat() {
.create()
.show()
prefs.edit().putBoolean("firstLaunch", true).apply()
prefs.edit().putBoolean("show_changelog_tooltip", true).apply()
prefs.edit {
putBoolean("firstLaunch", true)
putBoolean("show_changelog_tooltip", true)
}
true
}
@ -51,8 +54,18 @@ class DevSettingsFragment: PreferenceFragmentCompat() {
findPreference<SwitchPreferenceCompat>("crowdin_real_time")?.isVisible = Crowdin.isAuthorized()
findPreference<Preference>("crowdin_auth")?.setOnPreferenceClickListener {
requireActivity().authCrowdin()
@RequiresApi(Build.VERSION_CODES.M)
if (!Settings.canDrawOverlays(requireActivity())) {
val intent = Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
("package:" + requireActivity().packageName).toUri()
)
startActivityForResult(intent, 69)
return@setOnPreferenceClickListener true
}
Crowdin.authorize(requireActivity())
true
}

View File

@ -6,6 +6,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.content.edit
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
@ -36,7 +37,7 @@ class GrantRootFragment : Fragment(), View.OnClickListener {
when (v?.id) {
R.id.grant_root_fab -> {
if (Shell.rootAccess()) {
getDefaultSharedPreferences(requireActivity()).edit().putString("vanced_variant", "root").apply()
getDefaultSharedPreferences(requireActivity()).edit { putString("vanced_variant", "root") }
} else {
Toast.makeText(requireActivity(), R.string.root_not_granted, Toast.LENGTH_SHORT).show()
}

View File

@ -6,6 +6,7 @@ import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle
import android.view.*
import androidx.core.content.edit
import androidx.core.content.res.ResourcesCompat
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
@ -67,7 +68,7 @@ open class HomeFragment : Fragment() {
.withShadow(false)
.corner(25)
.onHide {
prefs.edit().putBoolean("show_changelog_tooltip", false).apply()
prefs.edit { putBoolean("show_changelog_tooltip", false) }
}
.text(requireActivity().getString(R.string.app_changelog_tooltip))

View File

@ -5,6 +5,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.content.edit
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
@ -43,7 +44,7 @@ class SelectAppsFragment : Fragment() {
}
selectAdapter.apps.forEach { app ->
prefs.edit().putBoolean("enable_${app.tag}", app.isChecked).apply()
prefs.edit { putBoolean("enable_${app.tag}", app.isChecked) }
}
findNavController().navigate(SelectAppsFragmentDirections.selectAppsToGrantRoot())

View File

@ -3,8 +3,4 @@ package com.vanced.manager.ui.viewmodels
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.ViewModel
class SettingsViewModel(activity: FragmentActivity) : ViewModel() {
}
class SettingsViewModel(activity: FragmentActivity) : ViewModel()

View File

@ -8,6 +8,8 @@ import android.os.Build
import android.util.Log
import android.widget.Toast
import androidx.core.content.FileProvider
import androidx.core.content.getSystemService
import androidx.core.net.toUri
import androidx.databinding.ObservableField
import com.downloader.OnDownloadListener
import com.downloader.PRDownloader
@ -22,14 +24,14 @@ import java.io.File
object DownloadHelper {
fun download(url: String, dir: String, child: String, context: Context): Long {
val request = DownloadManager.Request(Uri.parse(url)).apply {
val request = DownloadManager.Request(url.toUri()).apply {
setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI)
setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)
setTitle(context.getString(R.string.downloading_file, child))
setDestinationInExternalFilesDir(context, dir, child)
}
val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val downloadManager = context.getSystemService<DownloadManager>()!!
return downloadManager.enqueue(request)
}

View File

@ -2,11 +2,11 @@ package com.vanced.manager.utils
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.util.Log
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.ContextCompat
import androidx.databinding.ObservableField
import androidx.core.net.toUri
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.beust.klaxon.JsonArray
import com.beust.klaxon.JsonObject
@ -33,48 +33,20 @@ object InternetTools {
//var braveTiers = ObservableField<JsonObject?>()
fun openUrl(Url: String, color: Int, context: Context) {
fun openUrl(url: String, color: Int, context: Context) {
val customTabPrefs = getDefaultSharedPreferences(context).getBoolean("use_customtabs", true)
if (customTabPrefs) {
val builder = CustomTabsIntent.Builder()
builder.setToolbarColor(ContextCompat.getColor(context, color))
val customTabsIntent = builder.build()
customTabsIntent.intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
customTabsIntent.launchUrl(context, Uri.parse(Url))
customTabsIntent.launchUrl(context, url.toUri())
} else
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(Url)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
context.startActivity(Intent(Intent.ACTION_VIEW, url.toUri()).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
}
fun getFileNameFromUrl(url: String) = url.substring(url.lastIndexOf('/')+1, url.length)
suspend fun getObjectFromJson(url: String, obj: String): String {
return try {
JsonHelper.getJson(url)?.string(obj) ?: ""
} catch (e: Exception) {
Log.e(TAG, "Error: ", e)
""
}
}
suspend fun getArrayFromJson(url: String, array: String): MutableList<String> {
return try {
JsonHelper.getJson(url)?.array<String>(array)?.value ?: mutableListOf("null")
} catch (e: Exception) {
Log.e(TAG, "Error: ", e)
mutableListOf("null")
}
}
suspend fun getJsonInt(file: String, obj: String, context: Context): Int {
val installUrl = getDefaultSharedPreferences(context).getString("install_url", baseUrl)
return try {
JsonHelper.getJson("$installUrl/$file")?.int(obj) ?: 0
} catch (e: Exception) {
Log.e(TAG, "Error: ", e)
0
}
}
fun loadJson(context: Context) = CoroutineScope(Dispatchers.IO).launch {
val installUrl = context.getDefaultPrefs().getString("install_url", baseUrl)
val latest = JsonHelper.getJson("$installUrl/latest.json?fetchTime=${SimpleDateFormat("HHmmss", Locale.getDefault())}")
@ -114,7 +86,7 @@ object InternetTools {
}
}
fun isUpdateAvailable(context: Context): Boolean {
fun isUpdateAvailable(): Boolean {
val result = manager.get()?.int("versionCode") ?: 0
return result > BuildConfig.VERSION_CODE

View File

@ -9,7 +9,7 @@ import com.github.kittinunf.fuel.httpGet
object JsonHelper {
var dataMap: HashMap<String, JsonObject> = HashMap()
private var dataMap: HashMap<String, JsonObject> = HashMap()
suspend fun getJson(url: String): JsonObject? {
return try {

View File

@ -1,13 +1,12 @@
package com.vanced.manager.utils
import android.text.TextUtils
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
object MiuiHelper {
fun isMiui(): Boolean = !TextUtils.isEmpty(getSystemProps("ro.miui.ui.version.name"))
fun isMiui(): Boolean = getSystemProps("ro.miui.ui.version.name")!!.isNotEmpty()
private fun getSystemProps(propname: String): String? {
val line: String

View File

@ -29,7 +29,7 @@ import kotlin.collections.ArrayList
import kotlin.collections.HashMap
object PackageHelper {
private const val apkInstallPath = "/data/adb/Vanced/"
fun isPackageInstalled(packageName: String, packageManager: PackageManager): Boolean {
return try {
@ -116,7 +116,7 @@ object PackageHelper {
e.printStackTrace()
}
}
fun install(path: String, context: Context) {
val callbackIntent = Intent(context, AppInstallerService::class.java)
val pendingIntent = PendingIntent.getService(context, 0, callbackIntent, 0)
@ -136,7 +136,7 @@ object PackageHelper {
outputStream.close()
session.commit(pendingIntent.intentSender)
}
fun installVanced(context: Context): Int {
val apkFolderPath = context.getExternalFilesDir("vanced/nonroot")?.path.toString() + "/"
val nameSizeMap = HashMap<String, Long>()
@ -238,7 +238,7 @@ object PackageHelper {
session!!.close()
}
}
fun installVancedRoot(context: Context) {
CoroutineScope(Dispatchers.IO).launch {
Shell.enableVerboseLogging = BuildConfig.DEBUG
@ -253,11 +253,8 @@ object PackageHelper {
val apkFilesPath = context.getExternalFilesDir("vanced/root")?.path
val fileInfoList = apkFilesPath?.let { it1 -> getFileInfoList(it1) }
if (fileInfoList != null) {
var modApk: FileInfo? = null
for (file in fileInfoList) {
if (file.name == "dark.apk" || file.name == "black.apk") {
modApk = file
}
val modApk: FileInfo? = fileInfoList.lastOrNull {
it.name == "dark.apk" || it.name == "black.apk"
}
if (modApk != null) {
if (overwriteBase(modApk, fileInfoList, vancedVersionCode!!, context)) {
@ -280,7 +277,7 @@ object PackageHelper {
}
}
private fun installSplitApkFiles(apkFiles: ArrayList<FileInfo>, context: Context) : Boolean {
var sessionId: Int?
Log.d("AppLog", "installing split apk files:$apkFiles")
@ -314,8 +311,8 @@ object PackageHelper {
val installResult = Shell.su("pm install-commit $sessionId").exec()
if (installResult.isSuccess) {
return true
} else
sendFailure(installResult.out, context)
}
sendFailure(installResult.out, context)
return false
}
@ -332,8 +329,9 @@ object PackageHelper {
if (parentFile.exists() && parentFile.canRead()) {
val listFiles = parentFile.listFiles() ?: return ArrayList()
for (file in listFiles)
result.add(FileInfo(file.name, file.length(), file))
listFiles.mapTo(result) {
FileInfo(it.name, it.length(), it)
}
return result
}
val longLines = Shell.su("ls -l $splitApkPath").exec().out
@ -424,9 +422,7 @@ object PackageHelper {
}
return true
}
else {
return fixNoInstall(baseApkFiles, context)
}
return fixNoInstall(baseApkFiles, context)
}
return fixNoInstall(baseApkFiles, context)
}
@ -507,10 +503,8 @@ object PackageHelper {
return false
}
}
else {
sendFailure(listOf("IFile_Missing").toMutableList(), context)
return false
}
sendFailure(listOf("IFile_Missing").toMutableList(), context)
return false
}
@ -533,14 +527,12 @@ object PackageHelper {
if(execRes.isSuccess) {
val result = execRes.out
var version = 0
for(line in result) {
val versionCode = line.substringAfter("=")
val versionCodeFiltered = versionCode.substringBefore(" ")
if(version < Integer.valueOf(versionCodeFiltered))
{
version = Integer.valueOf(versionCodeFiltered)
}
}
result
.asSequence()
.map { it.substringAfter("=") }
.map { it.substringBefore(" ") }
.filter { version < Integer.valueOf(it) }
.forEach { version = Integer.valueOf(it) }
return version
}
}