gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-taler-android] branch master updated (ab11f16 -> 3ad7fa1)


From: gnunet
Subject: [taler-taler-android] branch master updated (ab11f16 -> 3ad7fa1)
Date: Mon, 06 Mar 2023 19:57:06 +0100

This is an automated email from the git hooks/post-receive script.

torsten-grote pushed a change to branch master
in repository taler-android.

    from ab11f16  [wallet] release 0.9.2+p2 (Google Play only)
     new 9a30d3f  [wallet] move to qtart 0.9.3-dev.5 (now on maven central)
     new 5294787  [wallet] Refresh withdrawal detail screen after confirmation
     new b226f4d  [wallet] some fixes for previous commit
     new 3ad7fa1  [wallet] upgrade libraries and minify builds again

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 build.gradle                                       |  6 +--
 wallet/build.gradle                                | 11 +++---
 .../transactions/TransactionDepositFragment.kt     |  5 ++-
 .../transactions/TransactionDetailFragment.kt      | 11 +++---
 .../wallet/transactions/TransactionManager.kt      | 18 ++++++++-
 .../transactions/TransactionPaymentFragment.kt     | 34 ++++++++--------
 .../wallet/transactions/TransactionPeerFragment.kt |  5 ++-
 .../transactions/TransactionRefreshFragment.kt     | 28 +++++++------
 .../transactions/TransactionRefundFragment.kt      | 38 +++++++++---------
 .../wallet/transactions/TransactionTipFragment.kt  |  5 ++-
 .../transactions/TransactionWithdrawalFragment.kt  | 46 ++++++++++++----------
 .../wallet/transactions/TransactionsFragment.kt    |  2 +-
 12 files changed, 119 insertions(+), 90 deletions(-)

diff --git a/build.gradle b/build.gradle
index 96b232e..fde36e0 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,6 @@
 buildscript {
     ext {
-        kotlin_version = '1.8.0' // observe compatibility with compose compiler
+        kotlin_version = '1.8.10' // observe compatibility with compose 
compiler
         ktor_version = '2.1.3'
         nav_version = '2.5.3'
         material_version = '1.8.0'
@@ -11,14 +11,14 @@ buildscript {
         // check https://android-rebuilds.beuc.net/ for availability of free 
build tools
         build_tools_version = "33.0.1"
         // should debug build types be minified with D8 as well? good for 
catching issues early
-        minify_debug = false
+        minify_debug = true
     }
     repositories {
         google()
         mavenCentral()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:7.4.0'
+        classpath 'com.android.tools.build:gradle:7.4.2'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
         classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
         classpath 
"androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
diff --git a/wallet/build.gradle b/wallet/build.gradle
index c3f5f4c..d25229d 100644
--- a/wallet/build.gradle
+++ b/wallet/build.gradle
@@ -19,7 +19,7 @@ plugins {
     id "kotlinx-serialization"
 }
 
-def qtart_version = "0.9.3-dev.3"
+def qtart_version = "0.9.3-dev.5"
 
 static def versionCodeEpoch() {
     return (new Date().getTime() / 1000).toInteger()
@@ -86,7 +86,7 @@ android {
     }
 
     composeOptions {
-        kotlinCompilerExtensionVersion "1.4.0"
+        kotlinCompilerExtensionVersion "1.4.3"
     }
 
     buildFeatures {
@@ -117,7 +117,7 @@ dependencies {
     implementation 'androidx.preference:preference-ktx:1.2.0'
     implementation "com.google.android.material:material:$material_version"
     implementation 
"androidx.constraintlayout:constraintlayout:$constraintlayout_version"
-    implementation "androidx.browser:browser:1.4.0"
+    implementation "androidx.browser:browser:1.5.0"
 
     // Compose
     implementation 'androidx.activity:activity-compose:1.6.1'
@@ -126,6 +126,7 @@ dependencies {
     implementation "androidx.compose.material:material:1.3.1"
     implementation "androidx.compose.material3:material3:1.0.1"
     implementation "androidx.compose.material:material-icons-extended:1.3.1"
+    implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
     implementation 
"androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"
     implementation 
"com.google.accompanist:accompanist-themeadapter-material3:0.28.0"
 
@@ -143,7 +144,7 @@ dependencies {
     // QR codes
     implementation 'com.journeyapps:zxing-android-embedded:4.3.0@aar'
     // needed to support zxing library in taler-kotlin-android on API < 24
-    coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.2'
+    coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.2'
 
     // Nicer ProgressBar
     implementation 'me.zhanghai.android.materialprogressbar:library:1.6.1'
@@ -154,7 +155,7 @@ dependencies {
     implementation "io.noties.markwon:ext-tables:$markwon_version"
     implementation "io.noties.markwon:recycler:$markwon_version"
 
-    // Java Native access
+    // Java Native access for qtart
     implementation "net.java.dev.jna:jna:5.13.0@aar"
 
     testImplementation "junit:junit:$junit_version"
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDepositFragment.kt
 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDepositFragment.kt
index 60f9b20..dd09b4c 100644
--- 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDepositFragment.kt
+++ 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDepositFragment.kt
@@ -20,6 +20,7 @@ import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import androidx.compose.runtime.livedata.observeAsState
 import androidx.compose.ui.platform.ComposeView
 import net.taler.wallet.compose.TalerSurface
 import net.taler.wallet.deposit.TransactionDepositComposable
@@ -33,8 +34,8 @@ class TransactionDepositFragment : 
TransactionDetailFragment() {
     ): View = ComposeView(requireContext()).apply {
         setContent {
             TalerSurface {
-                val t = transaction ?: error("No transaction")
-                TransactionDepositComposable(t as TransactionDeposit) {
+                val t = 
transactionManager.selectedTransaction.observeAsState().value
+                if (t is TransactionDeposit) TransactionDepositComposable(t) {
                     onDeleteButtonClicked(t)
                 }
             }
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
index b4008b0..1905a05 100644
--- 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
+++ 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
@@ -37,8 +37,7 @@ import net.taler.wallet.launchInAppBrowser
 abstract class TransactionDetailFragment : Fragment() {
 
     private val model: MainViewModel by activityViewModels()
-    private val transactionManager by lazy { model.transactionManager }
-    protected val transaction: Transaction? get() = 
transactionManager.selectedTransaction
+    val transactionManager by lazy { model.transactionManager }
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
@@ -48,9 +47,11 @@ abstract class TransactionDetailFragment : Fragment() {
     @Deprecated("Deprecated in Java")
     override fun onActivityCreated(savedInstanceState: Bundle?) {
         super.onActivityCreated(savedInstanceState)
-        requireActivity().apply {
-            transaction?.generalTitleRes?.let {
-                title = getString(it)
+        transactionManager.selectedTransaction.observe(viewLifecycleOwner) {
+            requireActivity().apply {
+                it?.generalTitleRes?.let {
+                    title = getString(it)
+                }
             }
         }
     }
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
index 2da9ab4..8be3fb5 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
@@ -41,9 +41,10 @@ class TransactionManager(
     val progress: LiveData<Boolean> = mProgress
 
     var selectedCurrency: String? = null
-    var selectedTransaction: Transaction? = null
 
     val searchQuery = MutableLiveData<String>(null)
+    private val mSelectedTransaction = MutableLiveData<Transaction?>(null)
+    val selectedTransaction: LiveData<Transaction?> = mSelectedTransaction
     private val allTransactions = HashMap<String, List<Transaction>>()
     private val mTransactions = HashMap<String, 
MutableLiveData<TransactionsResult>>()
     val transactions: LiveData<TransactionsResult>
@@ -84,6 +85,14 @@ class TransactionManager(
             mProgress.value = false
             liveData.value = TransactionsResult.Success(transactions)
 
+            // update selected transaction on UiThread (if it exists)
+            val selected = selectedTransaction.value
+            if (selected != null) transactions.find {
+                it.transactionId == selected.transactionId
+            }?.let {
+                mSelectedTransaction.value = it
+            }
+
             // update all transactions on UiThread if there was a currency
             if (searchQuery == null) allTransactions[currency] = transactions
         }
@@ -92,6 +101,7 @@ class TransactionManager(
     /**
      * Returns true if given [transactionId] was found and selected, false 
otherwise.
      */
+    @UiThread
     suspend fun selectTransaction(transactionId: String): Boolean {
         var transaction: Transaction? = null
         api.request("getTransactionById", Transaction.serializer()) {
@@ -102,13 +112,17 @@ class TransactionManager(
             transaction = result
         }
         return if (transaction != null) {
-            selectedTransaction = transaction
+            mSelectedTransaction.value = transaction
             true
         } else {
             false
         }
     }
 
+    fun selectTransaction(transaction: Transaction) {
+        mSelectedTransaction.postValue(transaction)
+    }
+
     fun deleteTransaction(transactionId: String) = scope.launch {
         api.request<Unit>("deleteTransaction") {
             put("transactionId", transactionId)
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionPaymentFragment.kt
 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionPaymentFragment.kt
index e2e4f9f..ec18c98 100644
--- 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionPaymentFragment.kt
+++ 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionPaymentFragment.kt
@@ -37,22 +37,24 @@ class TransactionPaymentFragment : 
TransactionDetailFragment() {
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        val t = transaction as TransactionPayment
-        ui.timeView.text = t.timestamp.ms.toAbsoluteTime(requireContext())
-
-        ui.amountPaidWithFeesView.text = t.amountEffective.toString()
-        val fee = t.amountEffective - t.amountRaw
-        bindOrderAndFee(
-            ui.orderSummaryView,
-            ui.orderAmountView,
-            ui.orderIdView,
-            ui.feeView,
-            t.info,
-            t.amountRaw,
-            fee
-        )
-        ui.deleteButton.setOnClickListener {
-            onDeleteButtonClicked(t)
+        transactionManager.selectedTransaction.observe(viewLifecycleOwner) { t 
->
+            if (t !is TransactionPayment) return@observe
+            ui.timeView.text = t.timestamp.ms.toAbsoluteTime(requireContext())
+
+            ui.amountPaidWithFeesView.text = t.amountEffective.toString()
+            val fee = t.amountEffective - t.amountRaw
+            bindOrderAndFee(
+                ui.orderSummaryView,
+                ui.orderAmountView,
+                ui.orderIdView,
+                ui.feeView,
+                t.info,
+                t.amountRaw,
+                fee
+            )
+            ui.deleteButton.setOnClickListener {
+                onDeleteButtonClicked(t)
+            }
         }
     }
 
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionPeerFragment.kt 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionPeerFragment.kt
index f6be5c8..3d99774 100644
--- 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionPeerFragment.kt
+++ 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionPeerFragment.kt
@@ -28,6 +28,7 @@ import androidx.compose.foundation.verticalScroll
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.livedata.observeAsState
 import androidx.compose.ui.Alignment.Companion.CenterHorizontally
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
@@ -54,8 +55,8 @@ class TransactionPeerFragment : TransactionDetailFragment() {
     ): View = ComposeView(requireContext()).apply {
         setContent {
             TalerSurface {
-                val t = transaction ?: error("No transaction")
-                TransactionPeerComposable(t) {
+                val t = 
transactionManager.selectedTransaction.observeAsState(null).value
+                if (t != null) TransactionPeerComposable(t) {
                     onDeleteButtonClicked(t)
                 }
             }
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt
 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt
index d44db43..4c26449 100644
--- 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt
+++ 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt
@@ -40,19 +40,21 @@ class TransactionRefreshFragment : 
TransactionDetailFragment() {
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        val t = transaction as TransactionRefresh
-        ui.timeView.text = t.timestamp.ms.toAbsoluteTime(requireContext())
-
-        ui.effectiveAmountLabel.visibility = GONE
-        ui.effectiveAmountView.visibility = GONE
-        ui.confirmWithdrawalButton.visibility = GONE
-        ui.chosenAmountLabel.visibility = GONE
-        ui.chosenAmountView.visibility = GONE
-        val fee = t.amountEffective
-        ui.feeView.text = getString(R.string.amount_negative, fee.toString())
-        ui.exchangeView.text = cleanExchange(t.exchangeBaseUrl)
-        ui.deleteButton.setOnClickListener {
-            onDeleteButtonClicked(t)
+        transactionManager.selectedTransaction.observe(viewLifecycleOwner) { t 
->
+            if (t !is TransactionRefresh) return@observe
+            ui.timeView.text = t.timestamp.ms.toAbsoluteTime(requireContext())
+
+            ui.effectiveAmountLabel.visibility = GONE
+            ui.effectiveAmountView.visibility = GONE
+            ui.confirmWithdrawalButton.visibility = GONE
+            ui.chosenAmountLabel.visibility = GONE
+            ui.chosenAmountView.visibility = GONE
+            val fee = t.amountEffective
+            ui.feeView.text = getString(R.string.amount_negative, 
fee.toString())
+            ui.exchangeView.text = cleanExchange(t.exchangeBaseUrl)
+            ui.deleteButton.setOnClickListener {
+                onDeleteButtonClicked(t)
+            }
         }
     }
 
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefundFragment.kt
 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefundFragment.kt
index 5e6eef4..125ae0c 100644
--- 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefundFragment.kt
+++ 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefundFragment.kt
@@ -39,25 +39,27 @@ class TransactionRefundFragment : 
TransactionDetailFragment() {
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        val t = transaction as TransactionRefund
-        ui.timeView.text = t.timestamp.ms.toAbsoluteTime(requireContext())
+        transactionManager.selectedTransaction.observe(viewLifecycleOwner) { t 
->
+            if (t !is TransactionRefund) return@observe
+            ui.timeView.text = t.timestamp.ms.toAbsoluteTime(requireContext())
 
-        ui.amountPaidWithFeesLabel.text = 
getString(R.string.transaction_refund)
-        ui.amountPaidWithFeesView.setTextColor(getColor(requireContext(), 
R.color.green))
-        ui.amountPaidWithFeesView.text =
-            getString(R.string.amount_positive, t.amountEffective.toString())
-        val fee = t.amountRaw - t.amountEffective
-        bindOrderAndFee(
-            ui.orderSummaryView,
-            ui.orderAmountView,
-            ui.orderIdView,
-            ui.feeView,
-            t.info,
-            t.amountRaw,
-            fee
-        )
-        ui.deleteButton.setOnClickListener {
-            onDeleteButtonClicked(t)
+            ui.amountPaidWithFeesLabel.text = 
getString(R.string.transaction_refund)
+            ui.amountPaidWithFeesView.setTextColor(getColor(requireContext(), 
R.color.green))
+            ui.amountPaidWithFeesView.text =
+                getString(R.string.amount_positive, 
t.amountEffective.toString())
+            val fee = t.amountRaw - t.amountEffective
+            bindOrderAndFee(
+                ui.orderSummaryView,
+                ui.orderAmountView,
+                ui.orderIdView,
+                ui.feeView,
+                t.info,
+                t.amountRaw,
+                fee
+            )
+            ui.deleteButton.setOnClickListener {
+                onDeleteButtonClicked(t)
+            }
         }
     }
 
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionTipFragment.kt 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionTipFragment.kt
index e8824ed..91af805 100644
--- 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionTipFragment.kt
+++ 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionTipFragment.kt
@@ -29,6 +29,7 @@ import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Surface
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.livedata.observeAsState
 import androidx.compose.ui.Alignment.Companion.CenterHorizontally
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.ComposeView
@@ -51,8 +52,8 @@ class TransactionTipFragment : TransactionDetailFragment() {
     ): View = ComposeView(requireContext()).apply {
         setContent {
             TalerSurface {
-                val t = transaction as? TransactionTip ?: error("No or wrong 
transaction")
-                TransactionTipComposable(t) {
+                val t = 
transactionManager.selectedTransaction.observeAsState(null).value
+                if (t is TransactionTip) TransactionTipComposable(t) {
                     onDeleteButtonClicked(t)
                 }
             }
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt
 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt
index fe255ad..2778126 100644
--- 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt
+++ 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt
@@ -51,35 +51,39 @@ class TransactionWithdrawalFragment : 
TransactionDetailFragment() {
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        val t = transaction as TransactionWithdrawal
-        ui.timeView.text = t.timestamp.ms.toAbsoluteTime(requireContext())
+        transactionManager.selectedTransaction.observe(viewLifecycleOwner) { t 
->
+            if (t !is TransactionWithdrawal) return@observe
+            ui.timeView.text = t.timestamp.ms.toAbsoluteTime(requireContext())
 
-        ui.effectiveAmountLabel.text = getString(R.string.withdraw_total)
-        ui.effectiveAmountView.text = t.amountEffective.toString()
-        setupConfirmWithdrawalButton(t)
-        setupActionButton(t)
-        ui.chosenAmountLabel.text = getString(R.string.amount_chosen)
-        ui.chosenAmountView.text =
-            getString(R.string.amount_positive, t.amountRaw.toString())
-        val fee = t.amountRaw - t.amountEffective
-        ui.feeView.text = getString(R.string.amount_negative, fee.toString())
-        ui.exchangeView.text = cleanExchange(t.exchangeBaseUrl)
-        if (t.pending) {
-            ui.deleteButton.setIconResource(R.drawable.ic_cancel)
-            ui.deleteButton.setText(R.string.cancel)
-        }
-        ui.deleteButton.setOnClickListener {
-            onDeleteButtonClicked(t)
+            ui.effectiveAmountLabel.text = getString(R.string.withdraw_total)
+            ui.effectiveAmountView.text = t.amountEffective.toString()
+            setupConfirmWithdrawalButton(t)
+            setupActionButton(t)
+            ui.chosenAmountLabel.text = getString(R.string.amount_chosen)
+            ui.chosenAmountView.text =
+                getString(R.string.amount_positive, t.amountRaw.toString())
+            val fee = t.amountRaw - t.amountEffective
+            ui.feeView.text = getString(R.string.amount_negative, 
fee.toString())
+            ui.exchangeView.text = cleanExchange(t.exchangeBaseUrl)
+            if (t.pending) {
+                ui.deleteButton.setIconResource(R.drawable.ic_cancel)
+                ui.deleteButton.setText(R.string.cancel)
+            }
+            ui.deleteButton.setOnClickListener {
+                onDeleteButtonClicked(t)
+            }
         }
     }
 
+    private val isPending get() = 
transactionManager.selectedTransaction.value?.pending == true
+
     override val deleteDialogTitle: Int
-        get() = if (transaction?.pending == true) R.string.cancel else 
super.deleteDialogTitle
+        get() = if (isPending) R.string.cancel else super.deleteDialogTitle
     override val deleteDialogMessage: Int
-        get() = if (transaction?.pending == true) 
R.string.transactions_cancel_dialog_message
+        get() = if (isPending) R.string.transactions_cancel_dialog_message
         else super.deleteDialogMessage
     override val deleteDialogButton: Int
-        get() = if (transaction?.pending == true) R.string.ok else 
super.deleteDialogButton
+        get() = if (isPending) R.string.ok else super.deleteDialogButton
 
     private fun setupConfirmWithdrawalButton(t: TransactionWithdrawal) {
         if (t.pending && !t.confirmed) {
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
index cd66193..f2a74e2 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
@@ -175,7 +175,7 @@ class TransactionsFragment : Fragment(), 
OnTransactionClickListener, ActionMode.
     override fun onTransactionClicked(transaction: Transaction) {
         if (actionMode != null) return // don't react on clicks while in 
action mode
         if (transaction.detailPageNav != 0) {
-            transactionManager.selectedTransaction = transaction
+            transactionManager.selectTransaction(transaction)
             findNavController().navigate(transaction.detailPageNav)
         }
     }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]