diff --git a/app/build.gradle b/app/build.gradle
index 8e7e11a..cedc43c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -13,7 +13,7 @@ android {
minSdk 21
targetSdk 33
versionCode 11
- versionName "3.1.0-hardcode"
+ versionName "3.2.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -130,6 +130,9 @@ dependencies {
// Koin for Android
implementation "io.insert-koin:koin-android:$koin_version"
+ // QR code scanner para emparelhamento WhatSMS
+ implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
+
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.3")
androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e1ea357..5a0f868 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,7 @@
android:required="false" />
+
@@ -84,6 +85,10 @@
android:foregroundServiceType="dataSync"
tools:node="merge" />
+
+
diff --git a/app/src/main/java/me/capcom/smsgateway/ui/ScanPairingActivity.kt b/app/src/main/java/me/capcom/smsgateway/ui/ScanPairingActivity.kt
new file mode 100644
index 0000000..4e5083f
--- /dev/null
+++ b/app/src/main/java/me/capcom/smsgateway/ui/ScanPairingActivity.kt
@@ -0,0 +1,99 @@
+package me.capcom.smsgateway.ui
+
+import android.app.Activity
+import android.content.Intent
+import android.os.Build
+import android.os.Bundle
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import com.google.zxing.integration.android.IntentIntegrator
+import com.google.zxing.integration.android.IntentResult
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import me.capcom.smsgateway.R
+import me.capcom.smsgateway.modules.gateway.GatewaySettings
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.RequestBody.Companion.toRequestBody
+import org.json.JSONObject
+import org.koin.android.ext.android.inject
+
+class ScanPairingActivity : AppCompatActivity() {
+ private val settings: GatewaySettings by inject()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ IntentIntegrator(this).apply {
+ setPrompt(getString(R.string.scan_qr_to_pair))
+ setBeepEnabled(true)
+ setOrientationLocked(false)
+ initiateScan()
+ }
+ }
+
+ @Suppress("OVERRIDE_DEPRECATION")
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ val result: IntentResult =
+ IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
+ ?: return super.onActivityResult(requestCode, resultCode, data)
+ if (result.contents == null) {
+ Toast.makeText(this, R.string.pairing_cancelled, Toast.LENGTH_SHORT).show()
+ setResult(Activity.RESULT_CANCELED)
+ finish()
+ return
+ }
+ claimDevice(result.contents)
+ }
+
+ private fun claimDevice(qrContent: String) {
+ val deviceId = settings.deviceId
+ val username = settings.username
+ val password = settings.password
+ if (deviceId == null || username == null || password == null) {
+ Toast.makeText(this, R.string.pairing_not_registered, Toast.LENGTH_LONG).show()
+ setResult(Activity.RESULT_CANCELED)
+ finish()
+ return
+ }
+ CoroutineScope(Dispatchers.IO).launch {
+ try {
+ val qr = JSONObject(qrContent)
+ val claimUrl = qr.getString("claimUrl")
+ val pairingToken = qr.getString("pairingToken")
+ val body = JSONObject().apply {
+ put("pairingToken", pairingToken)
+ put("deviceId", deviceId)
+ put("username", username)
+ put("password", password)
+ put("deviceName", Build.MODEL)
+ }.toString()
+ val client = OkHttpClient()
+ val request = Request.Builder()
+ .url(claimUrl)
+ .post(body.toRequestBody("application/json".toMediaType()))
+ .build()
+ val response = client.newCall(request).execute()
+ val ok = response.isSuccessful
+ withContext(Dispatchers.Main) {
+ if (ok) {
+ Toast.makeText(this@ScanPairingActivity, R.string.pairing_success, Toast.LENGTH_SHORT).show()
+ setResult(Activity.RESULT_OK)
+ } else {
+ Toast.makeText(this@ScanPairingActivity, R.string.pairing_failed, Toast.LENGTH_LONG).show()
+ setResult(Activity.RESULT_CANCELED)
+ }
+ finish()
+ }
+ } catch (e: Exception) {
+ withContext(Dispatchers.Main) {
+ Toast.makeText(this@ScanPairingActivity, getString(R.string.pairing_error, e.message), Toast.LENGTH_LONG).show()
+ setResult(Activity.RESULT_CANCELED)
+ finish()
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/me/capcom/smsgateway/ui/settings/WhatSmsServerSettingsFragment.kt b/app/src/main/java/me/capcom/smsgateway/ui/settings/WhatSmsServerSettingsFragment.kt
index 546a2c8..c208fac 100644
--- a/app/src/main/java/me/capcom/smsgateway/ui/settings/WhatSmsServerSettingsFragment.kt
+++ b/app/src/main/java/me/capcom/smsgateway/ui/settings/WhatSmsServerSettingsFragment.kt
@@ -1 +1,125 @@
-cGFja2FnZSBtZS5jYXBjb20uc21zZ2F0ZXdheS51aS5zZXR0aW5ncwoKaW1wb3J0IGFuZHJvaWQuYW5ub3RhdGlvbi5TdXBwcmVzc0xpbnQKaW1wb3J0IGFuZHJvaWQub3MuQnVuZGxlCmltcG9ydCBhbmRyb2lkLnRleHQuSW5wdXRUeXBlCmltcG9ydCBhbmRyb2lkLnZpZXcuVmlldwppbXBvcnQgYW5kcm9pZHguY29yZS52aWV3LmlzVmlzaWJsZQppbXBvcnQgYW5kcm9pZHgubGlmZWN5Y2xlLmxpZmVjeWNsZVNjb3BlCmltcG9ydCBhbmRyb2lkeC5wcmVmZXJlbmNlLkVkaXRUZXh0UHJlZmVyZW5jZQppbXBvcnQgYW5kcm9pZHgucHJlZmVyZW5jZS5QcmVmZXJlbmNlCmltcG9ydCBrb3RsaW54LmNvcm91dGluZXMubGF1bmNoCmltcG9ydCBtZS5jYXBjb20uc21zZ2F0ZXdheS5SCmltcG9ydCBtZS5jYXBjb20uc21zZ2F0ZXdheS5tb2R1bGVzLmdhdGV3YXkuR2F0ZXdheVNlcnZpY2UKaW1wb3J0IG1lLmNhcGNvbS5zbXNnYXRld2F5Lm1vZHVsZXMuZ2F0ZXdheS5HYXRld2F5U2V0dGluZ3MKaW1wb3J0IG9yZy5rb2luLmFuZHJvaWQuZXh0LmFuZHJvaWQuaW5qZWN0CmltcG9ydCBqYXZhLnRleHQuRGF0ZUZvcm1hdAoKY2xhc3MgV2hhdFNtc1NlcnZlclNldHRpbmdzRnJhZ21lbnQgOiBCYXNlUHJlZmVyZW5jZUZyYWdtZW50KCkgewoKICAgIHByaXZhdGUgdmFsIHNldHRpbmdzOiBHYXRld2F5U2V0dGluZ3MgYnkgaW5qZWN0KCkKICAgIHByaXZhdGUgdmFsIHNlcnZpY2U6IEdhdGV3YXlTZXJ2aWNlIGJ5IGluamVjdCgpCgogICAgQFN1cHByZXNzTGludCgiTm90aWZ5RGF0YVNldENoYW5nZWQiKQogICAgb3ZlcnJpZGUgZnVuIG9uQ3JlYXRlUHJlZmVyZW5jZXMoc2F2ZWRJbnN0YW5jZVN0YXRlOiBCdW5kbGU/LCByb290S2V5OiBTdHJpbmc/KSB7CiAgICAgICAgc2V0UHJlZmVyZW5jZXNGcm9tUmVzb3VyY2UoUi54bWwud2hhdHNtc19zZXJ2ZXJfcHJlZmVyZW5jZXMsIHJvb3RLZXkpCgogICAgICAgIGZpbmRQcmVmZXJlbmNlPFByZWZlcmVuY2U+KCJ0cmFuc2llbnQuc2VydmVyX3VybCIpPy5zdW1tYXJ5ID0KICAgICAgICAgICAgR2F0ZXdheVNldHRpbmdzLlBVQkxJQ19VUkwKCiAgICAgICAgZmluZFByZWZlcmVuY2U8UHJlZmVyZW5jZT4oInRyYW5zaWVudC5kZXZpY2VfaWQiKT8uc3VtbWFyeSA9CiAgICAgICAgICAgIHNldHRpbmdzLmRldmljZUlkID86IGdldFN0cmluZyhSLnN0cmluZy5uX2EpCgogICAgICAgIGZpbmRQcmVmZXJlbmNlPEVkaXRUZXh0UHJlZmVyZW5jZT4oImdhdGV3YXkudXNlcm5hbWUiKT8uc2V0U3VtbWFyeVByb3ZpZGVyIHsKICAgICAgICAgICAgc2V0dGluZ3MudXNlcm5hbWUgPzogZ2V0U3RyaW5nKFIuc3RyaW5nLm5vdF9zZXQpCiAgICAgICAgfQoKICAgICAgICBmaW5kUHJlZmVyZW5jZTxFZGl0VGV4dFByZWZlcmVuY2U+KCJnYXRld2F5LnBhc3N3b3JkIik/LmFwcGx5IHsKICAgICAgICAgICAgaXNFbmFibGVkID0gc2V0dGluZ3MudXNlcm5hbWUgIT0gbnVsbCAmJiBzZXR0aW5ncy5wYXNzd29yZCAhPSBudWxsCgogICAgICAgICAgICBzZXRTdW1tYXJ5UHJvdmlkZXIgewogICAgICAgICAgICAgICAgd2hlbiB7CiAgICAgICAgICAgICAgICAgICAgc2V0dGluZ3MudXNlcm5hbWUgPT0gbnVsbCAtPiBnZXRTdHJpbmcoUi5zdHJpbmcubm90X3JlZ2lzdGVyZWQpCiAgICAgICAgICAgICAgICAgICAgc2V0dGluZ3MudXNlcm5hbWUgIT0gbnVsbCAmJiBzZXR0aW5ncy5wYXNzd29yZCA9PSBudWxsIC0+ICJDYW4ndCBiZSBjaGFuZ2VkIgogICAgICAgICAgICAgICAgICAgIGVsc2UgLT4gc2V0dGluZ3MucGFzc3dvcmQKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgc2V0T25QcmVmZXJlbmNlQ2hhbmdlTGlzdGVuZXIgeyBfLCBuZXdWYWx1ZSAtPgogICAgICAgICAgICAgICAgdmFsIHZhbHVlID0gbmV3VmFsdWUgYXM/IFN0cmluZwogICAgICAgICAgICAgICAgaWYgKHZhbHVlID09IG51bGwgfHwgdmFsdWUubGVuZ3RoIDwgMTQpIHsKICAgICAgICAgICAgICAgICAgICBzaG93VG9hc3QoZ2V0U3RyaW5nKFIuc3RyaW5nLnBhc3N3b3JkX211c3RfYmVfYXRfbGVhc3RfMTRfY2hhcmFjdGVycykpCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuQHNldE9uUHJlZmVyZW5jZUNoYW5nZUxpc3RlbmVyIGZhbHNlCiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgdGhpc0BXaGF0U21zU2VydmVyU2V0dGluZ3NGcmFnbWVudC5saWZlY3ljbGVTY29wZS5sYXVuY2ggewogICAgICAgICAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVpcmVBY3Rpdml0eSgpLmZpbmRWaWV3QnlJZDxWaWV3PihSLmlkLnByb2dyZXNzQmFyKS5pc1Zpc2libGUgPSB0cnVlCiAgICAgICAgICAgICAgICAgICAgICAgIHNlcnZpY2UuY2hhbmdlUGFzc3dvcmQoc2V0dGluZ3MucGFzc3dvcmQgPzogIiIsIHZhbHVlKQogICAgICAgICAgICAgICAgICAgICAgICBsaXN0Vmlldy5hZGFwdGVyPy5ub3RpZnlEYXRhU2V0Q2hhbmdlZCgpCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3dUb2FzdChnZXRTdHJpbmcoUi5zdHJpbmcucGFzc3dvcmRfY2hhbmdlZF9zdWNjZXNzZnVsbHkpKQogICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGU6IEV4Y2VwdGlvbikgewogICAgICAgICAgICAgICAgICAgICAgICBzaG93VG9hc3QoZ2V0U3RyaW5nKFIuc3RyaW5nLmZhaWxlZF90b19jaGFuZ2VfcGFzc3dvcmQsIGUubWVzc2FnZSkpCiAgICAgICAgICAgICAgICAgICAgfSBmaW5hbGx5IHsKICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZUFjdGl2aXR5KCkuZmluZFZpZXdCeUlkPFZpZXc+KFIuaWQucHJvZ3Jlc3NCYXIpLmlzVmlzaWJsZSA9IGZhbHNlCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHRydWUKICAgICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgZmluZFByZWZlcmVuY2U8UHJlZmVyZW5jZT4oImdhdGV3YXkubG9naW5fY29kZSIpPy5hcHBseSB7CiAgICAgICAgICAgIGlzVmlzaWJsZSA9IHNldHRpbmdzLnVzZXJuYW1lICE9IG51bGwgJiYgc2V0dGluZ3MucGFzc3dvcmQgIT0gbnVsbAoKICAgICAgICAgICAgb25QcmVmZXJlbmNlQ2xpY2tMaXN0ZW5lciA9IFByZWZlcmVuY2UuT25QcmVmZXJlbmNlQ2xpY2tMaXN0ZW5lciB7CiAgICAgICAgICAgICAgICB0aGlzQFdoYXRTbXNTZXJ2ZXJTZXR0aW5nc0ZyYWdtZW50LmxpZmVjeWNsZVNjb3BlLmxhdW5jaCB7CiAgICAgICAgICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZUFjdGl2aXR5KCkuZmluZFZpZXdCeUlkPFZpZXc+KFIuaWQucHJvZ3Jlc3NCYXIpLmlzVmlzaWJsZSA9IHRydWUKCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbCBsb2dpbkNvZGUgPSBzZXJ2aWNlLmdldExvZ2luQ29kZSgpCiAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gZ2V0U3RyaW5nKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgUi5zdHJpbmcubG9naW5fY29kZV9leHBpcmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRGF0ZUZvcm1hdC5nZXREYXRlVGltZUluc3RhbmNlKCkuZm9ybWF0KGxvZ2luQ29kZS52YWxpZFVudGlsKQogICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcnkgPSBsb2dpbkNvZGUuY29kZQoKICAgICAgICAgICAgICAgICAgICAgICAgbGlzdFZpZXcuYWRhcHRlcj8ubm90aWZ5RGF0YVNldENoYW5nZWQoKQogICAgICAgICAgICAgICAgICAgICAgICBzaG93VG9hc3QoZ2V0U3RyaW5nKFIuc3RyaW5nLnN1Y2Nlc3NfbG9uZ19wcmVzc190b19jb3B5KSkKICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlOiBFeGNlcHRpb24pIHsKICAgICAgICAgICAgICAgICAgICAgICAgc2hvd1RvYXN0KGdldFN0cmluZyhSLnN0cmluZy5mYWlsZWRfdG9fZ2V0X2xvZ2luX2NvZGUsIGUubWVzc2FnZSkpCiAgICAgICAgICAgICAgICAgICAgfSBmaW5hbGx5IHsKICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZUFjdGl2aXR5KCkuZmluZFZpZXdCeUlkPFZpZXc+KFIuaWQucHJvZ3Jlc3NCYXIpLmlzVmlzaWJsZSA9IGZhbHNlCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHRydWUKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBvdmVycmlkZSBmdW4gb25EaXNwbGF5UHJlZmVyZW5jZURpYWxvZyhwcmVmZXJlbmNlOiBQcmVmZXJlbmNlKSB7CiAgICAgICAgaWYgKHByZWZlcmVuY2Uua2V5ID09ICJnYXRld2F5LnBhc3N3b3JkIikgewogICAgICAgICAgICAocHJlZmVyZW5jZSBhcyBFZGl0VGV4dFByZWZlcmVuY2UpLnNldE9uQmluZEVkaXRUZXh0TGlzdGVuZXIgewogICAgICAgICAgICAgICAgaXQuaW5wdXRUeXBlID0gSW5wdXRUeXBlLlRZUEVfQ0xBU1NfVEVYVAogICAgICAgICAgICAgICAgaXQudGV4dCA9IG51bGwKICAgICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgc3VwZXIub25EaXNwbGF5UHJlZmVyZW5jZURpYWxvZyhwcmVmZXJlbmNlKQogICAgfQp9Cg==
\ No newline at end of file
+package me.capcom.smsgateway.ui.settings
+
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.os.Bundle
+import android.text.InputType
+import android.view.View
+import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
+import androidx.preference.EditTextPreference
+import androidx.preference.Preference
+import kotlinx.coroutines.launch
+import me.capcom.smsgateway.R
+import me.capcom.smsgateway.modules.gateway.GatewayService
+import me.capcom.smsgateway.modules.gateway.GatewaySettings
+import me.capcom.smsgateway.ui.ScanPairingActivity
+import org.koin.android.ext.android.inject
+import java.text.DateFormat
+
+class WhatSmsServerSettingsFragment : BasePreferenceFragment() {
+
+ private val settings: GatewaySettings by inject()
+ private val service: GatewayService by inject()
+
+ @SuppressLint("NotifyDataSetChanged")
+ override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
+ setPreferencesFromResource(R.xml.whatsms_server_preferences, rootKey)
+
+ findPreference("transient.server_url")?.summary =
+ GatewaySettings.PUBLIC_URL
+
+ findPreference("transient.device_id")?.summary =
+ settings.deviceId ?: getString(R.string.n_a)
+
+ findPreference("gateway.username")?.setSummaryProvider {
+ settings.username ?: getString(R.string.not_set)
+ }
+
+ findPreference("gateway.password")?.apply {
+ isEnabled = settings.username != null && settings.password != null
+
+ setSummaryProvider {
+ when {
+ settings.username == null -> getString(R.string.not_registered)
+ settings.username != null && settings.password == null -> "Can't be changed"
+ else -> settings.password
+ }
+ }
+
+ setOnPreferenceChangeListener { _, newValue ->
+ val value = newValue as? String
+ if (value == null || value.length < 14) {
+ showToast(getString(R.string.password_must_be_at_least_14_characters))
+ return@setOnPreferenceChangeListener false
+ }
+
+ this@WhatSmsServerSettingsFragment.lifecycleScope.launch {
+ try {
+ requireActivity().findViewById(R.id.progressBar).isVisible = true
+ service.changePassword(settings.password ?: "", value)
+ listView.adapter?.notifyDataSetChanged()
+ showToast(getString(R.string.password_changed_successfully))
+ } catch (e: Exception) {
+ showToast(getString(R.string.failed_to_change_password, e.message))
+ } finally {
+ requireActivity().findViewById(R.id.progressBar).isVisible = false
+ }
+ }
+
+ true
+ }
+ }
+
+ findPreference("action.pair_device")?.setOnPreferenceClickListener {
+ startActivityForResult(
+ Intent(requireContext(), ScanPairingActivity::class.java),
+ REQ_PAIR
+ )
+ true
+ }
+
+ findPreference("gateway.login_code")?.apply {
+ isVisible = settings.username != null && settings.password != null
+
+ onPreferenceClickListener = Preference.OnPreferenceClickListener {
+ this@WhatSmsServerSettingsFragment.lifecycleScope.launch {
+ try {
+ requireActivity().findViewById(R.id.progressBar).isVisible = true
+
+ val loginCode = service.getLoginCode()
+ title = getString(
+ R.string.login_code_expires,
+ DateFormat.getDateTimeInstance().format(loginCode.validUntil)
+ )
+ summary = loginCode.code
+
+ listView.adapter?.notifyDataSetChanged()
+ showToast(getString(R.string.success_long_press_to_copy))
+ } catch (e: Exception) {
+ showToast(getString(R.string.failed_to_get_login_code, e.message))
+ } finally {
+ requireActivity().findViewById(R.id.progressBar).isVisible = false
+ }
+ }
+
+ true
+ }
+ }
+ }
+
+ companion object {
+ private const val REQ_PAIR = 1001
+ }
+
+ override fun onDisplayPreferenceDialog(preference: Preference) {
+ if (preference.key == "gateway.password") {
+ (preference as EditTextPreference).setOnBindEditTextListener {
+ it.inputType = InputType.TYPE_CLASS_TEXT
+ it.text = null
+ }
+ }
+
+ super.onDisplayPreferenceDialog(preference)
+ }
+}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 39f5c4d..4534dee 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1 +1,183 @@
-PHJlc291cmNlcz4KICAgIDxzdHJpbmcgbmFtZT0iYWRkcmVzc19pcyI+JTEkczwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJhcGlfdXJsX3ByaXZhdGVfdG9rZW5fY3JlZGVudGlhbHNfZXRjIj5BUEkgVVJMLCBwcml2YXRlIHRva2VuLCBjcmVkZW50aWFscywgZXRjLjwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJhcGlfdXJsIj5BUEkgVVJMPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImFwcF9uYW1lIiB0cmFuc2xhdGFibGU9ImZhbHNlIj5XaGF0U01TIEdhdGV3YXk8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iYXBwX3ZlcnNpb25fYnVpbGQiPkFwcCB2ZXJzaW9uIChidWlsZCk8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iYmF0dGVyeV9vcHRpbWl6YXRpb25fYWxyZWFkeV9kaXNhYmxlZCI+QmF0dGVyeSBvcHRpbWl6YXRpb24gYWxyZWFkeSBkaXNhYmxlZDwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJiYXR0ZXJ5X29wdGltaXphdGlvbl9pc19ub3Rfc3VwcG9ydGVkX29uX3RoaXNfZGV2aWNlIj5CYXR0ZXJ5IG9wdGltaXphdGlvbiBpcyBub3QKICAgICAgICBzdXBwb3J0ZWQgb24gdGhpcyBkZXZpY2U8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iYmF0dGVyeV9vcHRpbWl6YXRpb24iPkJhdHRlcnkgb3B0aW1pemF0aW9uPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImJ0bl9jYW5jZWwiPkNhbmNlbDwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJidG5fY29udGludWUiPkNvbnRpbnVlPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImJ5X2NvZGUiPkJ5IENvZGU8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iY2FuX2FmZmVjdF9iYXR0ZXJ5X2xpZmUiPmNhbiBhZmZlY3QgYmF0dGVyeSBsaWZlPC9zdHJpbmc+CiAgICA8c3RyaW5nCiAgICAgICAgbmFtZT0iY2xpY2tfY29udGludWVfdG9fY3JlYXRlX2FuX2FjY291bnRfbm9fcGVyc29uYWxfaW5mb3JtYXRpb25faXNfcmVxdWlyZWRfbmJ5X2NvbnRpbnVpbmdfeW91X2FncmVlX3RvX291cl9wcml2YWN5X3BvbGljeV9hdF9odHRwc19kb2NzX3Ntc19nYXRlX2FwcF9wcml2YWN5X3BvbGljeSI+Q2xpY2sKICAgICAgICBDb250aW51ZSB0byBjcmVhdGUgYW4gYWNjb3VudC4gTm8gcGVyc29uYWwgaW5mb3JtYXRpb24gaXMgcmVxdWlyZWQuXG5CeSBjb250aW51aW5nLCB5b3UKICAgICAgICBhZ3JlZSB0byBvdXIgUHJpdmFjeSBQb2xpY3kgYXQgaHR0cHM6Ly9kb2NzLnNtcy1nYXRlLmFwcC9wcml2YWN5L3BvbGljeS88L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iY2xvdWRfc2VydmVyX2RvdGRvdGRvdCI+Q2xvdWQgc2VydmVy4oCmPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImNsb3VkX3NlcnZlciI+Q2xvdWQgc2VydmVyPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImNsb3VkIj5DbG91ZDwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJjb3BpZWRfdG9fY2xpcGJvYXJkIj5Db3BpZWQ8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iY3JlZGVudGlhbHMiPkNyZWRlbnRpYWxzPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImRlbGF5c19saW1pdHNfZXRjIj5EZWxheXMsIGxpbWl0cywgZXRjLjwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJkZWxheXNfc2Vjb25kcyI+RGVsYXlzLCBzZWNvbmRzPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImRlbGV0ZV9hZnRlcl9kYXlzIj5EZWxldGUgYWZ0ZXIsIGRheXM8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iZGV2aWNlX2lkIj5EZXZpY2UgSUQ8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iZGV2aWNlIj5EZXZpY2U8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iZGlzYWJsZWQiPkRpc2FibGVkPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImRvdHMiPuKApjwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJlbmFibGVkIj5FbmFibGVkPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImVuY3J5cHRpb24iPkVuY3J5cHRpb248L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iZmFpbGVkX3RvX2NoYW5nZV9wYXNzd29yZCI+RmFpbGVkIHRvIGNoYW5nZSBwYXNzd29yZDogJTEkczwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJmYWlsZWRfdG9fZ2V0X2xvZ2luX2NvZGUiPkZhaWxlZCB0byBnZXQgbG9naW4gY29kZTogJTEkczwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJmYWlsZWRfdG9fcmVnaXN0ZXJfZGV2aWNlIj5GYWlsZWQgdG8gcmVnaXN0ZXIgZGV2aWNlOiAlMSRzPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImlkX2NvcGllZCI+V2ViaG9vayBJRCBjb3BpZWQgdG8gY2xpcGJvYXJkPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImlmX3NpbV9udW1iZXJfaXNfbm90X3NwZWNpZmllZF91c2UiPklmIFNJTSBudW1iZXIgaXMgbm90IHNwZWNpZmllZCwgdXNlPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9Imlnbm9yZWRfZm9yX3B1YmxpY19zZXJ2ZXIiPklnbm9yZWQgZm9yIHB1YmxpYyBzZXJ2ZXI8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iaW5mb3JtYXRpb24iPkluZm9ybWF0aW9uPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImludGVybmV0X2Nvbm5lY3Rpb25fYXZhaWxhYmxlIj5JbnRlcm5ldCBjb25uZWN0aW9uOiBhdmFpbGFibGU8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iaW50ZXJuZXRfY29ubmVjdGlvbl91bmF2YWlsYWJsZSI+SW50ZXJuZXQgY29ubmVjdGlvbjogdW5hdmFpbGFibGU8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iaW50ZXJ2YWxfc2Vjb25kcyI+SW50ZXJ2YWwgKHNlY29uZHMpPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImludmFsaWRfdXJsIj5JbnZhbGlkIFVSTDwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJpc19ub3RfYV92YWxpZF9wb3J0X211c3RfYmVfYmV0d2Vlbl8xMDI0X2FuZF82NTUzNSI+JTEkcyBpcyBub3QgYSB2YWxpZCBwb3J0LiBNdXN0CiAgICAgICAgYmUgYmV0d2VlbiAxMDI0IGFuZCA2NTUzNS48L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ibGFiZWxfcGFzc3dvcmQiPlBhc3N3b3JkPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImxhYmVsX3VzZXJuYW1lIj5Vc2VybmFtZTwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJsaW1pdHMiPkxpbWl0czwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJsaXN0X29mX2xhc3RfNTBfbG9nX2VudHJpZXMiPkxpc3Qgb2YgbGFzdCA1MCBsb2cgZW50cmllczwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJsaXN0ZW5pbmdfdG9fdGhlX3NlcnZlcl9ldmVudHMiPkxpc3RlbmluZyB0byBzZXJ2ZXIgZXZlbnRz4oCmPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImxvY2FsX2FkZHJlc3MiPkxvY2FsIGFkZHJlc3M8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ibG9jYWxfc2VydmVyX2RvdGRvdGRvdCI+TG9jYWwgU2VydmVy4oCmPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImxvY2FsX3Ntc19nYXRld2F5X25vdGlmaWNhdGlvbnMiPkxvY2FsIFNNU0dhdGUgbm90aWZpY2F0aW9uczwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJsb2NhbCI+TG9jYWw8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ibG9naW5fY29kZV9leHBpcmVzIj5Mb2dpbiBDb2RlLCBleHBpcmVzICUxJHM8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ibG9naW5fY29kZSI+TG9naW4gQ29kZTwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJsb2dzIj5Mb2dzPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9Im1heGltdW0iPk1heGltdW08L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ibWVzc2FnZXNfY291bnQiPk1lc3NhZ2VzIGNvdW50PC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9Im1lc3NhZ2VzX2hlYWRlciI+TWVzc2FnZXM8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ibWVzc2FnZXMiPk1lc3NhZ2Vz4oCmPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9Im1pbmltdW0iPk1pbmltdW08L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ibW9yZV9zZXR0aW5ncyI+TW9yZSBzZXR0aW5nc+KApjwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJuX2EiPm4vYTwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJuZXdfc21zX3JlY2VpdmVkX3dlYmhvb2tzX3JlZ2lzdGVyZWQiPk5ldyBTTVMgUmVjZWl2ZWQgV2ViaG9va3MgcmVnaXN0ZXJlZDwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJub193ZWJob29rc19mb3VuZCI+Tm8gd2ViaG9va3MgY29uZmlndXJlZDwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJub3RfcmVnaXN0ZXJlZCI+bm90IHJlZ2lzdGVyZWQ8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ibm90X3NldCI+Tm90IHNldDwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJub3RpZmljYXRpb25fdGl0bGUiPlNNU0dhdGU8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ibm90aWZpY2F0aW9uX2NoYW5uZWwiPk5vdGlmaWNhdGlvbiBjaGFubmVsPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9Im5vdGlmaWNhdGlvbnMiPk5vdGlmaWNhdGlvbnM8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ib25saW5lX3N0YXR1c19hdF90aGVfY29zdF9vZl9iYXR0ZXJ5X2xpZmUiPk9ubGluZSBzdGF0dXMgYXQgdGhlIGNvc3Qgb2YgYmF0dGVyeQogICAgICAgIGxpZmU8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0icGFzc3BocmFzZSI+UGFzc3BocmFzZTwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJwYXNzd29yZF9jaGFuZ2VkX3N1Y2Nlc3NmdWxseSI+UGFzc3dvcmQgY2hhbmdlZCBzdWNjZXNzZnVsbHk8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0icGFzc3dvcmRfbXVzdF9iZV9hdF9sZWFzdF8xNF9jaGFyYWN0ZXJzIj5QYXNzd29yZCBtdXN0IGJlIGF0IGxlYXN0IDE0IGNoYXJhY3RlcnM8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0icGFzc3dvcmRfbXVzdF9iZV9hdF9sZWFzdF84X2NoYXJhY3RlcnMiPlBhc3N3b3JkIG11c3QgYmUgYXQgbGVhc3QgOCBjaGFyYWN0ZXJzPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9InBhc3N3b3JkIj5QYXNzd29yZDwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJwZXJpb2QiPlBlcmlvZDwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJwaW5nX3NlcnZpY2VfaXNfYWN0aXZlIj5QaW5nIHNlcnZpY2UgaXMgYWN0aXZlPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9InBpbmciPlBpbmc8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0icGxlYXNlX2VudGVyX29uZV90aW1lX2NvZGVfZGlzcGxheWVkX29uX2FscmVhZHlfcmVnaXN0ZXJlZF9kZXZpY2UiPlBsZWFzZSBlbnRlcgogICAgICAgIHRoZSBvbmUtdGltZSBjb2RlIGRpc3BsYXllZCBvbiB0aGUgYWxyZWFkeS1yZWdpc3RlcmVkIGRldmljZTwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJwb3J0X2NyZWRlbnRpYWxzX2V0YyI+UG9ydCwgY3JlZGVudGlhbHMsIGV0Yy48L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0icG9ydCI+UG9ydDwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJwcml2YXRlX3Rva2VuIj5Qcml2YXRlIFRva2VuPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9InB1YmxpY19hZGRyZXNzIj5QdWJsaWMgYWRkcmVzczwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJyZXF1aXJlX2ludGVybmV0X2Nvbm5lY3Rpb24iPlJlcXVpcmUgSW50ZXJuZXQgY29ubmVjdGlvbjwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJyZXN0YXJ0X3JlcXVpcmVkX3RvX2FwcGx5X2NoYW5nZXMiPlJlc3RhcnQgcmVxdWlyZWQgdG8gYXBwbHkgY2hhbmdlczwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJyZXRyaWVzX3NpZ25pbmdfZXRjIj5SZXRyaWVzLCBzaWduaW5nLCBldGMuPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9InJldHJ5X2NvdW50Ij5SZXRyeSBjb3VudDwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJzZW5kX21lc3NhZ2VzX25vdGlmaWNhdGlvbiI+U2VuZGluZyBtZXNzYWdlc+KApjwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJzZW5kaW5nX3dlYmhvb2siPlNlbmRpbmcgd2ViaG9va+KApjwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJwcm9jZXNzaW5nX3dlYmhvb2tfcXVldWUiPlByb2Nlc3Npbmcgd2ViaG9vayBxdWV1ZeKApjwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJzZXJ2ZXJfYWRkcmVzcyI+U2VydmVyIGFkZHJlc3M8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ic2VydmVyIj5TZXJ2ZXI8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ic2V0X21heGltdW1fdmFsdWVfdG9fYWN0aXZhdGUiPlNldCBtYXhpbXVtIHZhbHVlIHRvIGFjdGl2YXRlPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9InNldHRpbmdzX2FkZHJlc3NfaXNfc21zX2NhcGNvbV9tZSIgdHJhbnNsYXRhYmxlPSJmYWxzZSI+YXBpLnNtcy1nYXRlLmFwcDwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJzZXR0aW5nc19jaGFuZ2VkX3ZpYV9hcGlfcmVzdGFydF90aGVfYXBwX3RvX2FwcGx5X2NoYW5nZXMiPlNldHRpbmdzIGNoYW5nZWQgdmlhCiAgICAgICAgQVBJLiBSZXN0YXJ0IHRoZSBhcHAgdG8gYXBwbHkgY2hhbmdlcy48L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ic2V0dGluZ3NfbG9jYWxfYWRkcmVzc19pcyIgdHJhbnNsYXRhYmxlPSJmYWxzZSI+Jmx0O2EgaHJlZj4lMSRzOiUyJGQmbHQ7L2E+PC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9InNldHRpbmdzX2xvY2FsX2FkZHJlc3Nfbm90X2ZvdW5kIj5Ob3QgYXZhaWxhYmxlPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9InNldHRpbmdzX2xvY2FsX3NlcnZlciI+TG9jYWwgc2VydmVyPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9InNldHRpbmdzX29mZmxpbmUiPk9mZmxpbmU8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ic2V0dGluZ3Nfb25saW5lIj5PbmxpbmU8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ic2V0dGluZ3NfcHVibGljX2FkZHJlc3NfaXMiIHRyYW5zbGF0YWJsZT0iZmFsc2UiPiZsdDthIGhyZWY+JTEkczolMiRkJmx0Oy9hPjwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJzZXR0aW5nc19wdWJsaWNfYWRkcmVzc19ub3RfZm91bmQiPk5vdCBhdmFpbGFibGU8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ic2V0dGluZ3Nfc3RhcnRfb25fYm9vdCI+U3RhcnQgb24gYm9vdDwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJzaWduX2luIj5TaWduIEluPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9InNpZ25fdXAiPlNpZ24gVXA8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ic2lnbmluZ19rZXkiPlNpZ25pbmcgS2V5PC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9InNtc19nYXRld2F5X2lzX3J1bm5pbmdfb25fcG9ydCI+U01TR2F0ZSBpcyBydW5uaW5nIG9uIHBvcnQgJTEkZDwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJzbXNfZ2F0ZXdheSI+U01TR2F0ZTwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJzbXMiIHRyYW5zbGF0YWJsZT0iZmFsc2UiPnNtczwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJzdWNjZXNzX2xvbmdfcHJlc3NfdG9fY29weSI+U3VjY2VzcywgbG9uZyBwcmVzcyB0byBjb3B5PC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9InN5c3RlbSI+U3lzdGVtPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9InRhYl90ZXh0X2hvbWUiPkhvbWU8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0idGFiX3RleHRfbWVzc2FnZXMiPk1FU1NBR0VTPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9InRhYl90ZXh0X3NldHRpbmdzIj5TRVRUSU5HUzwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJ0aGVfd2ViaG9va19yZXF1ZXN0X3dpbGxfd2FpdF9mb3JfYW5faW50ZXJuZXRfY29ubmVjdGlvbiI+VGhlIHdlYmhvb2sgcmVxdWVzdCB3aWxsCiAgICAgICAgd2FpdCBmb3IgYW4gaW50ZXJuZXQgY29ubmVjdGlvbjwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJ0b19hZGRfYV9kZXZpY2VfdG9fYW5fZXhpc3RpbmdfYWNjb3VudF9wbGVhc2VfZmlsbF9pbl90aGVfY3JlZGVudGlhbHNfYmVsb3ciPlRvCiAgICAgICAgYWRkIGEgZGV2aWNlIHRvIGFuIGV4aXN0aW5nIGFjY291bnQsIHBsZWFzZSBmaWxsIGluIHRoZSBjcmVkZW50aWFscyBiZWxvdy48L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0idG9fYXBwbHlfdGhlX2NoYW5nZXNfcmVzdGFydF90aGVfYXBwX3VzaW5nX3RoZV9idXR0b25fYmVsb3ciPlRvIGFwcGx5IHRoZSBjaGFuZ2VzLAogICAgICAgIHJlc3RhcnQgdGhlIGFwcCB1c2luZyB0aGUgYnV0dG9uIGJlbG93Ljwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJ1c2VfZW1wdHlfdG9fZGlzYWJsZSI+VXNlIGVtcHR5IHRvIGRpc2FibGU8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0idXNlX3RoaXNfY29kZV90b19zaWduX2luX29uX2Fub3RoZXJfZGV2aWNlIj5Vc2UgdGhpcyBjb2RlIHRvIHNpZ24gaW4gb24gYW5vdGhlcgogICAgICAgIGRldmljZTwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJ1c2VybmFtZV9tdXN0X2JlX2F0X2xlYXN0XzNfY2hhcmFjdGVycyI+VXNlcm5hbWUgbXVzdCBiZSBhdCBsZWFzdCAzIGNoYXJhY3RlcnM8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0idXNlcm5hbWUiPlVzZXJuYW1lPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9InZpZXciPlZpZXc8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0id2ViaG9va19pZF9mb3JtYXQiIHRyYW5zbGF0YWJsZT0iZmFsc2UiPklEOiAlMSRzPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9IndlYmhvb2tfbGlzdF9zdW1tYXJ5Ij5WaWV3IHJlZ2lzdGVyZWQgd2ViaG9va3M8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0id2ViaG9va19saXN0X3RpdGxlIj5SZWdpc3RlcmVkIFdlYmhvb2tzPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9IndlYmhvb2tzX2RvdGRvdGRvdCI+V2ViaG9va3PigKY8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0id2ViaG9va3MiPldlYmhvb2tzPC9zdHJpbmc+CiAgICA8cGx1cmFscyBuYW1lPSJyZXZpZXdfaW5jb21pbmdfc21zX3dlYmhvb2tzIj4KICAgICAgICA8aXRlbSBxdWFudGl0eT0ib25lIj5Zb3UgaGF2ZSAlMSRkIGluY29taW5nIFNNUyB3ZWJob29rIHJlZ2lzdGVyZWQuIFBsZWFzZSByZXZpZXcgaXQgdG8KICAgICAgICAgICAgYXZvaWQgYW55IHNlY3VyaXR5IHJpc2tzLjwvaXRlbT4KICAgICAgICA8aXRlbSBxdWFudGl0eT0ib3RoZXIiPllvdSBoYXZlICUxJGQgaW5jb21pbmcgU01TIHdlYmhvb2tzIHJlZ2lzdGVyZWQuIFBsZWFzZSByZXZpZXcgdGhlbSB0bwogICAgICAgICAgICBhdm9pZCBhbnkgc2VjdXJpdHkgcmlza3MuPC9pdGVtPgogICAgPC9wbHVyYWxzPgogICAgPHN0cmluZyBuYW1lPSJwcm9jZXNzaW5nIj5Qcm9jZXNzaW5nPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9InByb2Nlc3Npbmdfb3JkZXJfdGl0bGUiPlByb2Nlc3Npbmcgb3JkZXI8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0icXVldWVfc3RhdHVzIj7wn5OKIFF1ZXVlIFN0YXR1czwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJ0b3RhbF9tZXNzYWdlcyI+VG90YWw6ICUxJGQ8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0icGVuZGluZ19tZXNzYWdlcyI+UGVuZGluZzogJTEkZDwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJzZW50X21lc3NhZ2VzIj5TZW50OiAlMSRkPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImRlbGl2ZXJlZF9tZXNzYWdlcyI+RGVsaXZlcmVkOiAlMSRkPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImZhaWxlZF9tZXNzYWdlcyI+RmFpbGVkOiAlMSRkPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImluY29taW5nX21lc3NhZ2VzIj5JTkNPTUlORzwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJpbmNvbWluZ19tZXNzYWdlc19zdGF0dXMiPvCfk6UgSW5jb21pbmcgU3RhdHVzPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImluY29taW5nX3Ntc19tZXNzYWdlcyI+U01TOiAlMSRkPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImluY29taW5nX2RhdGFfbWVzc2FnZXMiPkRhdGEgU01TOiAlMSRkPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImluY29taW5nX21tc19tZXNzYWdlcyI+TU1TOiAlMSRkPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9Imp3dCI+SldUPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9Imp3dF9kZWZhdWx0X3R0bF9zZWNvbmRzIj5KV1QgZGVmYXVsdCBUVEwgKHNlY29uZHMpPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9Imp3dF90dGxfbXVzdF9iZV9iZXR3ZWVuXzFfc2Vjb25kX2FuZF8zNjVfZGF5cyI+SldUIFRUTCBtdXN0IGJlIGJldHdlZW4gMSBzZWNvbmQKICAgICAgICBhbmQgMzY1IGRheXM8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iand0X3JlZ2VuZXJhdGVfc2VjcmV0Ij5SZWdlbmVyYXRlIEpXVCBzZWNyZXQ8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iand0X3JlZ2VuZXJhdGVfc2VjcmV0X3N1bW1hcnkiPkludmFsaWRhdGVzIGFsbCBleGlzdGluZyBKV1Qgc2lnbmF0dXJlcwogICAgICAgIGltbWVkaWF0ZWx5Ljwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJqd3Rfc2VjcmV0X3JlZ2VuZXJhdGVkIj5KV1Qgc2VjcmV0IHJlZ2VuZXJhdGVkPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImNvbmZpcm1fcmVnZW5lcmF0ZV9qd3Rfc2VjcmV0Ij5BcmUgeW91IHN1cmUgeW91IHdhbnQgdG8gcmVnZW5lcmF0ZSB0aGUgSldUIHNlY3JldD8KICAgICAgICBUaGlzIHdpbGwgaW52YWxpZGF0ZSBhbGwgZXhpc3RpbmcgSldUIHNpZ25hdHVyZXMgaW1tZWRpYXRlbHkuPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImNvbmZpcm0iPkNvbmZpcm08L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iY2FuY2VsIj5DYW5jZWw8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0ib3V0Z29pbmdfbWVzc2FnZXMiPk9VVEdPSU5HPC9zdHJpbmc+CiAgICA8c3RyaW5nIG5hbWU9ImluY29taW5nX3R5cGVfc21zIiB0cmFuc2xhdGFibGU9ImZhbHNlIj5TTVM8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iaW5jb21pbmdfdHlwZV9kYXRhX3NtcyIgdHJhbnNsYXRhYmxlPSJmYWxzZSI+RGF0YSBTTVM8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0iaW5jb21pbmdfdHlwZV9tbXMiIHRyYW5zbGF0YWJsZT0iZmFsc2UiPk1NUzwvc3RyaW5nPgogICAgPHN0cmluZyBuYW1lPSJ3aGF0c21zX3NlcnZlcl9kb3Rkb3Rkb3QiPlNlcnZpZG9yIFdoYXRTTVPigKY8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0id2hhdHNtc19zZXJ2ZXIiPlNlcnZpZG9yIFdoYXRTTVM8L3N0cmluZz4KICAgIDxzdHJpbmcgbmFtZT0idXJsX2VfY3JlZGVuY2lhaXNfZXRjIj5VUkwsIGNyZWRlbmNpYWlzLCBldGMuPC9zdHJpbmc+CjwvcmVzb3VyY2VzPgo=
\ No newline at end of file
+
+ %1$s
+ API URL, private token, credentials, etc.
+ API URL
+ WhatSMS Gateway
+ App version (build)
+ Battery optimization already disabled
+ Battery optimization is not
+ supported on this device
+ Battery optimization
+ Cancel
+ Continue
+ By Code
+ can affect battery life
+ Click
+ Continue to create an account. No personal information is required.\nBy continuing, you
+ agree to our Privacy Policy at https://docs.sms-gate.app/privacy/policy/
+ Cloud server…
+ Cloud server
+ Cloud
+ Copied
+ Credentials
+ Delays, limits, etc.
+ Delays, seconds
+ Delete after, days
+ Device ID
+ Device
+ Disabled
+ …
+ Enabled
+ Encryption
+ Failed to change password: %1$s
+ Failed to get login code: %1$s
+ Failed to register device: %1$s
+ Webhook ID copied to clipboard
+ If SIM number is not specified, use
+ Ignored for public server
+ Information
+ Internet connection: available
+ Internet connection: unavailable
+ Interval (seconds)
+ Invalid URL
+ %1$s is not a valid port. Must
+ be between 1024 and 65535.
+ Password
+ Username
+ Limits
+ List of last 50 log entries
+ Listening to server events…
+ Local address
+ Local Server…
+ Local SMSGate notifications
+ Local
+ Login Code, expires %1$s
+ Login Code
+ Logs
+ Maximum
+ Messages count
+ Messages
+ Messages…
+ Minimum
+ More settings…
+ n/a
+ New SMS Received Webhooks registered
+ No webhooks configured
+ not registered
+ Not set
+ SMSGate
+ Notification channel
+ Notifications
+ Online status at the cost of battery
+ life
+ Passphrase
+ Password changed successfully
+ Password must be at least 14 characters
+ Password must be at least 8 characters
+ Password
+ Period
+ Ping service is active
+ Ping
+ Please enter
+ the one-time code displayed on the already-registered device
+ Port, credentials, etc.
+ Port
+ Private Token
+ Public address
+ Require Internet connection
+ Restart required to apply changes
+ Retries, signing, etc.
+ Retry count
+ Sending messages…
+ Sending webhook…
+ Processing webhook queue…
+ Server address
+ Server
+ Set maximum value to activate
+ api.sms-gate.app
+ Settings changed via
+ API. Restart the app to apply changes.
+ <a href>%1$s:%2$d</a>
+ Not available
+ Local server
+ Offline
+ Online
+ <a href>%1$s:%2$d</a>
+ Not available
+ Start on boot
+ Sign In
+ Sign Up
+ Signing Key
+ SMSGate is running on port %1$d
+ SMSGate
+ sms
+ Success, long press to copy
+ System
+ Home
+ MESSAGES
+ SETTINGS
+ The webhook request will
+ wait for an internet connection
+ To
+ add a device to an existing account, please fill in the credentials below.
+ To apply the changes,
+ restart the app using the button below.
+ Use empty to disable
+ Use this code to sign in on another
+ device
+ Username must be at least 3 characters
+ Username
+ View
+ ID: %1$s
+ View registered webhooks
+ Registered Webhooks
+ Webhooks…
+ Webhooks
+
+ - You have %1$d incoming SMS webhook registered. Please review it to
+ avoid any security risks.
+ - You have %1$d incoming SMS webhooks registered. Please review them to
+ avoid any security risks.
+
+ Processing
+ Processing order
+ 📊 Queue Status
+ Total: %1$d
+ Pending: %1$d
+ Sent: %1$d
+ Delivered: %1$d
+ Failed: %1$d
+ INCOMING
+ 📥 Incoming Status
+ SMS: %1$d
+ Data SMS: %1$d
+ MMS: %1$d
+ JWT
+ JWT default TTL (seconds)
+ JWT TTL must be between 1 second
+ and 365 days
+ Regenerate JWT secret
+ Invalidates all existing JWT signatures
+ immediately.
+ JWT secret regenerated
+ Are you sure you want to regenerate the JWT secret?
+ This will invalidate all existing JWT signatures immediately.
+ Confirm
+ Cancel
+ OUTGOING
+ SMS
+ Data SMS
+ MMS
+ Servidor WhatSMS…
+ Servidor WhatSMS
+ URL, credenciais, etc.
+ Emparelhar dispositivo
+ Associar este telefone a um tenant WhatSMS via QR code
+ Aponte a câmara para o código QR no painel WhatSMS
+ Dispositivo emparelhado com sucesso!
+ Falha ao emparelhar. Verifique o QR e tente novamente.
+ Emparelhamento cancelado.
+ Dispositivo ainda não registado. Active o gateway primeiro.
+ Erro: %1$s
+
diff --git a/app/src/main/res/xml/whatsms_server_preferences.xml b/app/src/main/res/xml/whatsms_server_preferences.xml
index 632b56a..c95be57 100644
--- a/app/src/main/res/xml/whatsms_server_preferences.xml
+++ b/app/src/main/res/xml/whatsms_server_preferences.xml
@@ -1 +1,57 @@
-PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPFByZWZlcmVuY2VTY3JlZW4geG1sbnM6YW5kcm9pZD0iaHR0cDovL3NjaGVtYXMuYW5kcm9pZC5jb20vYXBrL3Jlcy9hbmRyb2lkIgogICAgeG1sbnM6YXBwPSJodHRwOi8vc2NoZW1hcy5hbmRyb2lkLmNvbS9hcGsvcmVzLWF1dG8iPgogICAgPFByZWZlcmVuY2VDYXRlZ29yeSBhcHA6dGl0bGU9IkBzdHJpbmcvc2VydmVyIj4KICAgICAgICA8UHJlZmVyZW5jZQogICAgICAgICAgICBhcHA6ZW5hYmxlQ29weWluZz0idHJ1ZSIKICAgICAgICAgICAgYXBwOmljb249IkBkcmF3YWJsZS9pY19zZXJ2ZXIiCiAgICAgICAgICAgIGFwcDprZXk9InRyYW5zaWVudC5zZXJ2ZXJfdXJsIgogICAgICAgICAgICBhcHA6cGVyc2lzdGVudD0iZmFsc2UiCiAgICAgICAgICAgIGFwcDpzZWxlY3RhYmxlPSJmYWxzZSIKICAgICAgICAgICAgYXBwOnRpdGxlPSJAc3RyaW5nL2FwaV91cmwiIC8+CiAgICAgICAgPExpc3RQcmVmZXJlbmNlCiAgICAgICAgICAgIGFwcDppY29uPSJAZHJhd2FibGUvaWNfbm90aWZpY2F0aW9ucyIKICAgICAgICAgICAgYXBwOmtleT0iZ2F0ZXdheS5ub3RpZmljYXRpb25fY2hhbm5lbCIKICAgICAgICAgICAgYXBwOmRlZmF1bHRWYWx1ZT0iQVVUTyIKICAgICAgICAgICAgYXBwOmVudHJpZXM9IkBhcnJheS9ub3RpZmljYXRpb25fY2hhbm5lbHNfdGl0bGVzIgogICAgICAgICAgICBhcHA6ZW50cnlWYWx1ZXM9IkBhcnJheS9ub3RpZmljYXRpb25fY2hhbm5lbHNfdmFsdWVzIgogICAgICAgICAgICBhcHA6dGl0bGU9IkBzdHJpbmcvbm90aWZpY2F0aW9uX2NoYW5uZWwiCiAgICAgICAgICAgIGFwcDp1c2VTaW1wbGVTdW1tYXJ5UHJvdmlkZXI9InRydWUiIC8+CiAgICA8L1ByZWZlcmVuY2VDYXRlZ29yeT4KICAgIDxQcmVmZXJlbmNlQ2F0ZWdvcnkgYXBwOnRpdGxlPSJAc3RyaW5nL2NyZWRlbnRpYWxzIj4KICAgICAgICA8RWRpdFRleHRQcmVmZXJlbmNlCiAgICAgICAgICAgIGFwcDplbmFibGVDb3B5aW5nPSJ0cnVlIgogICAgICAgICAgICBhcHA6aWNvbj0iQGRyYXdhYmxlL2ljX3VzZXJuYW1lIgogICAgICAgICAgICBhcHA6a2V5PSJnYXRld2F5LnVzZXJuYW1lIgogICAgICAgICAgICBhcHA6cGVyc2lzdGVudD0iZmFsc2UiCiAgICAgICAgICAgIGFwcDpzZWxlY3RhYmxlPSJmYWxzZSIKICAgICAgICAgICAgYXBwOnRpdGxlPSJAc3RyaW5nL3VzZXJuYW1lIiAvPgogICAgICAgIDxFZGl0VGV4dFByZWZlcmVuY2UKICAgICAgICAgICAgYXBwOmVuYWJsZUNvcHlpbmc9InRydWUiCiAgICAgICAgICAgIGFwcDppY29uPSJAZHJhd2FibGUvaWNfcGFzc3dvcmQiCiAgICAgICAgICAgIGFwcDprZXk9ImdhdGV3YXkucGFzc3dvcmQiCiAgICAgICAgICAgIGFwcDpwZXJzaXN0ZW50PSJmYWxzZSIKICAgICAgICAgICAgYXBwOnRpdGxlPSJAc3RyaW5nL3Bhc3N3b3JkIiAvPgogICAgICAgIDxQcmVmZXJlbmNlCiAgICAgICAgICAgIGFuZHJvaWQ6aWNvbj0iQGRyYXdhYmxlL2ljX2NvZGUiCiAgICAgICAgICAgIGFuZHJvaWQ6a2V5PSJnYXRld2F5LmxvZ2luX2NvZGUiCiAgICAgICAgICAgIGFuZHJvaWQ6cGVyc2lzdGVudD0iZmFsc2UiCiAgICAgICAgICAgIGFuZHJvaWQ6c3VtbWFyeT0iQHN0cmluZy91c2VfdGhpc19jb2RlX3RvX3NpZ25faW5fb25fYW5vdGhlcl9kZXZpY2UiCiAgICAgICAgICAgIGFuZHJvaWQ6dGl0bGU9IkBzdHJpbmcvbG9naW5fY29kZSIKICAgICAgICAgICAgYXBwOmVuYWJsZUNvcHlpbmc9InRydWUiIC8+CiAgICA8L1ByZWZlcmVuY2VDYXRlZ29yeT4KICAgIDxQcmVmZXJlbmNlQ2F0ZWdvcnkgYXBwOnRpdGxlPSJAc3RyaW5nL2RldmljZSI+CiAgICAgICAgPFByZWZlcmVuY2UKICAgICAgICAgICAgYW5kcm9pZDppY29uPSJAZHJhd2FibGUvaWNfZGV2aWNlX2lkIgogICAgICAgICAgICBhbmRyb2lkOmtleT0idHJhbnNpZW50LmRldmljZV9pZCIKICAgICAgICAgICAgYW5kcm9pZDp0aXRsZT0iQHN0cmluZy9kZXZpY2VfaWQiCiAgICAgICAgICAgIGFwcDplbmFibGVDb3B5aW5nPSJ0cnVlIgogICAgICAgICAgICBhcHA6cGVyc2lzdGVudD0iZmFsc2UiIC8+CiAgICA8L1ByZWZlcmVuY2VDYXRlZ29yeT4KICAgIDxQcmVmZXJlbmNlIGFwcDpzdW1tYXJ5PSJAc3RyaW5nL3Jlc3RhcnRfcmVxdWlyZWRfdG9fYXBwbHlfY2hhbmdlcyIgLz4KPC9QcmVmZXJlbmNlU2NyZWVuPgo=
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+