问:
How to maintain order while fetching the JSON data?
I am building a currency converter app and I am experiencing issues with it. I am getting problems with order. I am using two internet JSON files: first with prices, second with full names. I can see that price and currency code (image here) are matching with each other, but not the full name. How can I hardcode full name to the currency code? Is it even possible? Thank you for you're answers.

Here's the code:

```<code>// JSON FILE 1
{
  "currencies": {
    "AED": "United Arab Emirates Dirham",
    "AFN": "Afghan Afghani",
    "ALL": "Albanian Lek",
    "AMD": "Armenian Dram",
    "ANG": "Dutch Guilders",
    "AOA": "Angolan Kwanza",
    "ARS": "Argentine Peso",
    "AUD": "Australian Dollar",
    "AWG": "Aruban Florin",
    "AZN": "Azerbaijani Manat",
    "BAM": "Bosnia-Herzegovina Convertible Mark",
    "BBD": "Barbadian Dollar",
    "BDT": "Bangladeshi Taka",
    "BGN": "Bulgarian Lev",
    "BHD": "Bahraini Dinar",
    "BIF": "Burundian Franc",
    "BMD": "Bermudian Dollar",
    "BND": "Bruneian Dollar",
    "BOB": "Bolivian Boliviano",
    "BRL": "Brazilian Real",
    "BSD": "Bahamian Dollar",
    "BTN": "Bhutanese Ngultrum",
    "BWP": "Botswanan Pula",
    "BZD": "Belizean Dollar",
    "CAD": "Canadian Dollar",
    "CDF": "Congolese Franc",
    "CHF": "Swiss Franc",
    "CLF": "Chilean Unit of Account UF",
    "CLP": "Chilean Peso",
    "CNH": "Chinese Yuan Offshore",
    "CNY": "Chinese Yuan",
    "COP": "Colombian Peso",
    "CUP": "Cuban Peso",
    "CVE": "Cape Verdean Escudo",
    "CZK": "Czech Republic Koruna",
    "DJF": "Djiboutian Franc",
    "DKK": "Danish Krone",
    "DOP": "Dominican Peso",
    "DZD": "Algerian Dinar",
    "EGP": "Egyptian Pound",
    "ERN": "Eritrean Nakfa",
    "ETB": "Ethiopian Birr",
    "EUR": "Euro",
    "FJD": "Fijian Dollar",
    "FKP": "Falkland Islands Pound",
    "GBP": "British Pound Sterling",
    "GEL": "Georgian Lari",
    "GHS": "Ghanaian Cedi",
    "GIP": "Gibraltar Pound",
    "GMD": "Gambian Dalasi",
    "GNF": "Guinean Franc",
    "GTQ": "Guatemalan Quetzal",
    "GYD": "Guyanaese Dollar",
    "HKD": "Hong Kong Dollar",
    "HNL": "Honduran Lempira",
    "HRK": "Croatian Kuna",
    "HTG": "Haitian Gourde",
    "HUF": "Hungarian Forint",
    "IDR": "Indonesian Rupiah",
    "ILS": "Israeli New Sheqel",
    "INR": "Indian Rupee",
    "IQD": "Iraqi Dinar",
    "IRR": "Iranian Rial",
    "ISK": "Icelandic Krona",
    "JMD": "Jamaican Dollar",
    "JOD": "Jordanian Dinar",
    "JPY": "Japanese Yen",
    "KES": "Kenyan Shilling",
    "KGS": "Kyrgystani Som",
    "KHR": "Cambodian Riel",
    "KMF": "Comorian Franc",
    "KPW": "North Korean Won",
    "KRW": "South Korean Won",
    "KWD": "Kuwaiti Dinar",
    "KYD": "Caymanian Dollar",
    "KZT": "Kazakhstani Tenge",
    "LAK": "Laotian Kip",
    "LBP": "Lebanese Pound",
    "LKR": "Sri Lankan Rupee",
    "LRD": "Liberian Dollar",
    "LSL": "Basotho Maloti",
    "LYD": "Libyan Dinar",
    "MAD": "Moroccan Dirham",
    "MDL": "Moldovan Leu",
    "MGA": "Malagasy Ariary",
    "MKD": "Macedonian Denar",
    "MMK": "Myanma Kyat",
    "MNT": "Mongolian Tugrik",
    "MOP": "Macanese Pataca",
    "MRU": "Mauritanian Ouguiya",
    "MUR": "Mauritian Rupee",
    "MVR": "Maldivian Rufiyaa",
    "MWK": "Malawian Kwacha",
    "MXN": "Mexican Peso",
    "MYR": "Malaysian Ringgit",
    "MZN": "Mozambican Metical",
    "NAD": "Namibian Dollar",
    "NGN": "Nigerian Naira",
    "NOK": "Norwegian Krone",
    "NPR": "Nepalese Rupee",
    "NZD": "New Zealand Dollar",
    "OMR": "Omani Rial",
    "PAB": "Panamanian Balboa",
    "PEN": "Peruvian Nuevo Sol",
    "PGK": "Papua New Guinean Kina",
    "PHP": "Philippine Peso",
    "PKR": "Pakistani Rupee",
    "PLN": "Polish Zloty",
    "PYG": "Paraguayan Guarani",
    "QAR": "Qatari Rial",
    "RON": "Romanian Leu",
    "RSD": "Serbian Dinar",
    "RUB": "Russian Ruble",
    "RWF": "Rwandan Franc",
    "SAR": "Saudi Arabian Riyal",
    "SCR": "Seychellois Rupee",
    "SDG": "Sudanese Pound",
    "SEK": "Swedish Krona",
    "SGD": "Singapore Dollar",
    "SHP": "Saint Helena Pound",
    "SLL": "Sierra Leonean Leone",
    "SOS": "Somali Shilling",
    "SRD": "Surinamese Dollar",
    "SYP": "Syrian Pound",
    "SZL": "Swazi Emalangeni",
    "THB": "Thai Baht",
    "TJS": "Tajikistani Somoni",
    "TMT": "Turkmenistani Manat",
    "TND": "Tunisian Dinar",
    "TOP": "Tongan Pa'anga",
    "TRY": "Turkish Lira",
    "TTD": "Trinidad and Tobago Dollar",
    "TWD": "Taiwan New Dollar",
    "TZS": "Tanzanian Shilling",
    "UAH": "Ukrainian Hryvnia",
    "UGX": "Ugandan Shilling",
    "USD": "United States Dollar",
    "UYU": "Uruguayan Peso",
    "UZS": "Uzbekistan Som",
    "VND": "Vietnamese Dong",
    "VUV": "Ni-Vanuatu Vatu",
    "WST": "Samoan Tala",
    "XAF": "CFA Franc BEAC",
    "XCD": "East Caribbean Dollar",
    "XDR": "Special Drawing Rights",
    "XOF": "CFA Franc BCEAO",
    "XPF": "CFP Franc",
    "YER": "Yemeni Rial",
    "ZAR": "South African Rand",
    "ZMW": "Zambian Kwacha"
  },
  "ms": 6
}
</code>```
```<code>// JSON FILE 2
{
  "base": "USD",
  "results": {
    "AED": 3.67206,
    "AFN": 93.40685,
    "ALL": 106.27627,
    "AMD": 480.17107,
    "ANG": 1.78799,
    "AOA": 528.20073,
    "ARS": 105.9003,
    "AUD": 1.3922,
    "AWG": 1.79899,
    "AZN": 1.70213,
    "BAM": 1.7137,
    "BBD": 1.99913,
    "BDT": 84.84226,
    "BGN": 1.70849,
    "BHD": 0.37606,
    "BIF": 2011.72969,
    "BMD": 0.99908,
    "BND": 1.34108,
    "BOB": 6.87374,
    "BRL": 5.25859,
    "BSD": 1.00152,
    "BTN": 74.88828,
    "BWP": 11.59835,
    "BZD": 2.01424,
    "CAD": 1.26778,
    "CDF": 2000.85683,
    "CHF": 0.92368,
    "CLF": 0.02563,
    "CLP": 813.61766,
    "CNH": 6.36222,
    "CNY": 6.36106,
    "COP": 3931.5793,
    "CUP": 24.99125,
    "CVE": 96.37768,
    "CZK": 21.27424,
    "DJF": 177.90121,
    "DKK": 6.51045,
    "DOP": 57.34036,
    "DZD": 140.79316,
    "EGP": 15.70478,
    "ERN": 15.1307,
    "ETB": 50.15401,
    "EUR": 0.87483,
    "FJD": 2.12693,
    "FKP": 0.73865,
    "GBP": 0.73865,
    "GEL": 2.9288,
    "GHS": 6.25112,
    "GIP": 0.73865,
    "GMD": 53.0933,
    "GNF": 9046.03975,
    "GTQ": 7.68413,
    "GYD": 209.88012,
    "HKD": 7.78983,
    "HNL": 24.49709,
    "HRK": 6.62491,
    "HTG": 104.54045,
    "HUF": 308.55425,
    "IDR": 14339.61428,
    "ILS": 3.21294,
    "INR": 74.78561,
    "IQD": 1457.71626,
    "IRR": 42022.92755,
    "ISK": 124.39523,
    "JMD": 155.80686,
    "JOD": 0.70759,
    "JPY": 115.42734,
    "KES": 113.303,
    "KGS": 85.05721,
    "KHR": 4066.33034,
    "KMF": 430.64639,
    "KPW": 900.02438,
    "KRW": 1193.7614,
    "KWD": 0.302,
    "KYD": 0.82061,
    "KZT": 425.47661,
    "LAK": 11394.85755,
    "LBP": 1510.16006,
    "LKR": 203.02401,
    "LRD": 153.41882,
    "LSL": 15.36242,
    "LYD": 4.57184,
    "MAD": 9.30782,
    "MDL": 17.85335,
    "MGA": 3995.92268,
    "MKD": 53.81939,
    "MMK": 1773.0882,
    "MNT": 2856.09715,
    "MOP": 8.02612,
    "MRU": 36.38995,
    "MUR": 44.03891,
    "MVR": 15.66053,
    "MWK": 810.96593,
    "MXN": 20.49223,
    "MYR": 4.1845,
    "MZN": 63.66124,
    "NAD": 15.20043,
    "NGN": 416.64463,
    "NOK": 8.80997,
    "NPR": 119.8895,
    "NZD": 1.49518,
    "OMR": 0.38407,
    "PAB": 0.99908,
    "PEN": 3.80791,
    "PGK": 3.51972,
    "PHP": 51.26921,
    "PKR": 174.34464,
    "PLN": 3.932,
    "PYG": 6963.85809,
    "QAR": 3.63947,
    "RON": 4.32397,
    "RSD": 102.80611,
    "RUB": 74.5714,
    "RWF": 1012.01037,
    "SAR": 3.74805,
    "SCR": 14.50692,
    "SDG": 441.096,
    "SEK": 9.0993,
    "SGD": 1.34151,
    "SHP": 0.73865,
    "SLL": 11353.1241,
    "SOS": 585.55358,
    "SRD": 20.78836,
    "SYP": 2511.26803,
    "SZL": 15.2251,
    "THB": 32.70654,
    "TJS": 11.31708,
    "TMT": 3.50647,
    "TND": 2.85947,
    "TOP": 2.29205,
    "TRY": 13.54047,
    "TTD": 6.77401,
    "TWD": 27.81745,
    "TZS": 2311.33156,
    "UAH": 28.07199,
    "UGX": 3498.77016,
    "USD": 1,
    "UYU": 43.49342,
    "UZS": 10849.73741,
    "VND": 22714.81648,
    "VUV": 113.09101,
    "WST": 2.62152,
    "XAF": 573.7131,
    "XCD": 2.69908,
    "XDR": 0.71235,
    "XOF": 573.7131,
    "XPF": 104.29227,
    "YER": 249.84599,
    "ZAR": 15.23648,
    "ZMW": 18.60965
  },
  "updated": "2022-02-09 17:30:18",
  "ms": 2
}

</code>```
```<code>// Model
 import Foundation

struct CurrencyModel: Codable {
    var results: [String:Double]
}

struct CurrencyNameModel: Codable {
    var currencies: [String:String]
}

</code>```
```<code>// Two ViewModels
import Foundation

class CurrencyViewModel: ObservableObject {

    @Published var currencyCode: [String] = []
    @Published var exchagePrice: [Double] = []

    init() {

        fetchData { (currency) in
            switch currency {
        case .success(let prices):
                DispatchQueue.main.async {
                    self.currencyCode.append(contentsOf: prices.results.keys)
                    // self.currencyCode.sorted()
                    self.exchagePrice.append(contentsOf: prices.results.values)
            }
            case .failure(let error):
                print("Error", error)
        }
    }
}

func fetchData(completion: @escaping (Result<CurrencyModel,Error>) -> ()) {
    guard let url = URL(string: "https://api.fastforex.io/fetch-all?api_key=...") else { return }
    URLSession.shared.dataTask(with: url) { data, responce, error in
        if let error = error {
            completion(.failure(error))
            return
        }

        guard let safeData = data else { return }

        do {
            let currency = try JSONDecoder().decode(CurrencyModel.self, from: safeData)
            completion(.success(currency))
        }
        catch {
            completion(.failure(error))
        }
    }
    .resume()

    }
}

////////

import Foundation

class CurrencyViewModelNew: ObservableObject {

    @Published var currencyName: [String] = []

init() {
    fetchNewData { (name) in
        switch name {
    case .success(let prices):
            DispatchQueue.main.async {

                self.currencyName.append(contentsOf: prices.currencies.values)

            }
        case .failure(let error):
            print("Error", error)

            }
        }
    }

    func fetchNewData(completion: @escaping (Result<CurrencyNameModel,Error>) -> ()) {
        guard let url = URL(string: "https://api.fastforex.io/currencies?api_key=...") else { return }
        URLSession.shared.dataTask(with: url) { data, responce, error in
            if let error = error {
                completion(.failure(error))
                return
            }

            guard let safeData = data else { return }

            do {
                let currency = try JSONDecoder().decode(CurrencyNameModel.self, from: safeData)
                completion(.success(currency))
            }
            catch {
                completion(.failure(error))
            }
        }
        .resume()

        }

}

</code>```
```<code>// View just in case
import SwiftUI

struct CurrencyView: View {
    @ObservedObject var api1 = CurrencyViewModel()
    @ObservedObject var api2 = CurrencyViewModelNew()

    @State private var pickerSelection1 = 0
    @State private var pickerSelection2 = 0

    var body: some View {
        Picker("", selection: $pickerSelection1) {
            ForEach(0..<self.api1.currencyCode.count) {
                let currency = api1.currencyCode[$0]
        Text(currency)
            }
        }
        .id(UUID())

        Picker("", selection: $pickerSelection1) {
            ForEach(0..<self.api2.currencyName.count) {
                let name = api2.currencyName[$0]
        Text(name)
            }
        }
        .id(UUID())

        Picker("", selection: $pickerSelection1) {
            ForEach(0..<self.api1.exchagePrice.count) {
                let price = "\(api1.exchagePrice[$0])"
                Text(price)
            }
        }
        .id(UUID())
    }
}

struct CurrencyView_Previews: PreviewProvider {
    static var previews: some View {
        CurrencyView()
    }
}

</code>```

答:
Perhaps it would make more sense to create a Currency model for each currency.

```<code>struct Currency {
    let name: String
    let symbol: String
    let value_USD: Double
}
</code>```

And construct a function to parse the two dictionaries (of values and names) to map an array of currencies.

```<code>// Our parsed JSON data
let currencyValues: [String: Double] = [
    "AED": 3.67206,
    "AFN": 93.40685,
    "ALL": 106.27627
]
let currencyNames: [String: String] = [
    "AED": "United Arab Emirates Dirham",
    "AFN": "Afghan Afghani",
    "ALL": "Albanian Lek"
]

// A simple function to parse them
func getCurrencies() -> [Currency] {
    var currencies: [Currency] = []

    for entry in currencyValues {
        let symbol = entry.key
        let usdValue = entry.value

        if let name = currencyNames[symbol] {
            let c = Currency(name: name, symbol: symbol, value_USD: usdValue)
            currencies.append(c)
        }
    }
    return currencies
}

let currencies = getCurrencies()
for currency in currencies {
    print(currency.symbol, currency.name, currency.value_USD)
}

// AFN Afghan Afghani 93.40685
// AED United Arab Emirates Dirham 3.67206
// ALL Albanian Lek 106.27627
</code>```

Body:
I am building a currency converter app and I am experiencing issues with it. I am getting problems with order. I am using two internet JSON files: first with prices, second with full names. I can see that price and currency code (image here) are matching with each other, but not the full name. How can I hardcode full name to the currency code? Is it even possible? Thank you for you're answers.

Here's the code:

// JSON FILE 1
{
  "currencies": {
    "AED": "United Arab Emirates Dirham",
    "AFN": "Afghan Afghani",
    "ALL": "Albanian Lek",
    "AMD": "Armenian Dram",
    "ANG": "Dutch Guilders",
    "AOA": "Angolan Kwanza",
    "ARS": "Argentine Peso",
    "AUD": "Australian Dollar",
    "AWG": "Aruban Florin",
    "AZN": "Azerbaijani Manat",
    "BAM": "Bosnia-Herzegovina Convertible Mark",
    "BBD": "Barbadian Dollar",
    "BDT": "Bangladeshi Taka",
    "BGN": "Bulgarian Lev",
    "BHD": "Bahraini Dinar",
    "BIF": "Burundian Franc",
    "BMD": "Bermudian Dollar",
    "BND": "Bruneian Dollar",
    "BOB": "Bolivian Boliviano",
    "BRL": "Brazilian Real",
    "BSD": "Bahamian Dollar",
    "BTN": "Bhutanese Ngultrum",
    "BWP": "Botswanan Pula",
    "BZD": "Belizean Dollar",
    "CAD": "Canadian Dollar",
    "CDF": "Congolese Franc",
    "CHF": "Swiss Franc",
    "CLF": "Chilean Unit of Account UF",
    "CLP": "Chilean Peso",
    "CNH": "Chinese Yuan Offshore",
    "CNY": "Chinese Yuan",
    "COP": "Colombian Peso",
    "CUP": "Cuban Peso",
    "CVE": "Cape Verdean Escudo",
    "CZK": "Czech Republic Koruna",
    "DJF": "Djiboutian Franc",
    "DKK": "Danish Krone",
    "DOP": "Dominican Peso",
    "DZD": "Algerian Dinar",
    "EGP": "Egyptian Pound",
    "ERN": "Eritrean Nakfa",
    "ETB": "Ethiopian Birr",
    "EUR": "Euro",
    "FJD": "Fijian Dollar",
    "FKP": "Falkland Islands Pound",
    "GBP": "British Pound Sterling",
    "GEL": "Georgian Lari",
    "GHS": "Ghanaian Cedi",
    "GIP": "Gibraltar Pound",
    "GMD": "Gambian Dalasi",
    "GNF": "Guinean Franc",
    "GTQ": "Guatemalan Quetzal",
    "GYD": "Guyanaese Dollar",
    "HKD": "Hong Kong Dollar",
    "HNL": "Honduran Lempira",
    "HRK": "Croatian Kuna",
    "HTG": "Haitian Gourde",
    "HUF": "Hungarian Forint",
    "IDR": "Indonesian Rupiah",
    "ILS": "Israeli New Sheqel",
    "INR": "Indian Rupee",
    "IQD": "Iraqi Dinar",
    "IRR": "Iranian Rial",
    "ISK": "Icelandic Krona",
    "JMD": "Jamaican Dollar",
    "JOD": "Jordanian Dinar",
    "JPY": "Japanese Yen",
    "KES": "Kenyan Shilling",
    "KGS": "Kyrgystani Som",
    "KHR": "Cambodian Riel",
    "KMF": "Comorian Franc",
    "KPW": "North Korean Won",
    "KRW": "South Korean Won",
    "KWD": "Kuwaiti Dinar",
    "KYD": "Caymanian Dollar",
    "KZT": "Kazakhstani Tenge",
    "LAK": "Laotian Kip",
    "LBP": "Lebanese Pound",
    "LKR": "Sri Lankan Rupee",
    "LRD": "Liberian Dollar",
    "LSL": "Basotho Maloti",
    "LYD": "Libyan Dinar",
    "MAD": "Moroccan Dirham",
    "MDL": "Moldovan Leu",
    "MGA": "Malagasy Ariary",
    "MKD": "Macedonian Denar",
    "MMK": "Myanma Kyat",
    "MNT": "Mongolian Tugrik",
    "MOP": "Macanese Pataca",
    "MRU": "Mauritanian Ouguiya",
    "MUR": "Mauritian Rupee",
    "MVR": "Maldivian Rufiyaa",
    "MWK": "Malawian Kwacha",
    "MXN": "Mexican Peso",
    "MYR": "Malaysian Ringgit",
    "MZN": "Mozambican Metical",
    "NAD": "Namibian Dollar",
    "NGN": "Nigerian Naira",
    "NOK": "Norwegian Krone",
    "NPR": "Nepalese Rupee",
    "NZD": "New Zealand Dollar",
    "OMR": "Omani Rial",
    "PAB": "Panamanian Balboa",
    "PEN": "Peruvian Nuevo Sol",
    "PGK": "Papua New Guinean Kina",
    "PHP": "Philippine Peso",
    "PKR": "Pakistani Rupee",
    "PLN": "Polish Zloty",
    "PYG": "Paraguayan Guarani",
    "QAR": "Qatari Rial",
    "RON": "Romanian Leu",
    "RSD": "Serbian Dinar",
    "RUB": "Russian Ruble",
    "RWF": "Rwandan Franc",
    "SAR": "Saudi Arabian Riyal",
    "SCR": "Seychellois Rupee",
    "SDG": "Sudanese Pound",
    "SEK": "Swedish Krona",
    "SGD": "Singapore Dollar",
    "SHP": "Saint Helena Pound",
    "SLL": "Sierra Leonean Leone",
    "SOS": "Somali Shilling",
    "SRD": "Surinamese Dollar",
    "SYP": "Syrian Pound",
    "SZL": "Swazi Emalangeni",
    "THB": "Thai Baht",
    "TJS": "Tajikistani Somoni",
    "TMT": "Turkmenistani Manat",
    "TND": "Tunisian Dinar",
    "TOP": "Tongan Pa'anga",
    "TRY": "Turkish Lira",
    "TTD": "Trinidad and Tobago Dollar",
    "TWD": "Taiwan New Dollar",
    "TZS": "Tanzanian Shilling",
    "UAH": "Ukrainian Hryvnia",
    "UGX": "Ugandan Shilling",
    "USD": "United States Dollar",
    "UYU": "Uruguayan Peso",
    "UZS": "Uzbekistan Som",
    "VND": "Vietnamese Dong",
    "VUV": "Ni-Vanuatu Vatu",
    "WST": "Samoan Tala",
    "XAF": "CFA Franc BEAC",
    "XCD": "East Caribbean Dollar",
    "XDR": "Special Drawing Rights",
    "XOF": "CFA Franc BCEAO",
    "XPF": "CFP Franc",
    "YER": "Yemeni Rial",
    "ZAR": "South African Rand",
    "ZMW": "Zambian Kwacha"
  },
  "ms": 6
}

// JSON FILE 2
{
  "base": "USD",
  "results": {
    "AED": 3.67206,
    "AFN": 93.40685,
    "ALL": 106.27627,
    "AMD": 480.17107,
    "ANG": 1.78799,
    "AOA": 528.20073,
    "ARS": 105.9003,
    "AUD": 1.3922,
    "AWG": 1.79899,
    "AZN": 1.70213,
    "BAM": 1.7137,
    "BBD": 1.99913,
    "BDT": 84.84226,
    "BGN": 1.70849,
    "BHD": 0.37606,
    "BIF": 2011.72969,
    "BMD": 0.99908,
    "BND": 1.34108,
    "BOB": 6.87374,
    "BRL": 5.25859,
    "BSD": 1.00152,
    "BTN": 74.88828,
    "BWP": 11.59835,
    "BZD": 2.01424,
    "CAD": 1.26778,
    "CDF": 2000.85683,
    "CHF": 0.92368,
    "CLF": 0.02563,
    "CLP": 813.61766,
    "CNH": 6.36222,
    "CNY": 6.36106,
    "COP": 3931.5793,
    "CUP": 24.99125,
    "CVE": 96.37768,
    "CZK": 21.27424,
    "DJF": 177.90121,
    "DKK": 6.51045,
    "DOP": 57.34036,
    "DZD": 140.79316,
    "EGP": 15.70478,
    "ERN": 15.1307,
    "ETB": 50.15401,
    "EUR": 0.87483,
    "FJD": 2.12693,
    "FKP": 0.73865,
    "GBP": 0.73865,
    "GEL": 2.9288,
    "GHS": 6.25112,
    "GIP": 0.73865,
    "GMD": 53.0933,
    "GNF": 9046.03975,
    "GTQ": 7.68413,
    "GYD": 209.88012,
    "HKD": 7.78983,
    "HNL": 24.49709,
    "HRK": 6.62491,
    "HTG": 104.54045,
    "HUF": 308.55425,
    "IDR": 14339.61428,
    "ILS": 3.21294,
    "INR": 74.78561,
    "IQD": 1457.71626,
    "IRR": 42022.92755,
    "ISK": 124.39523,
    "JMD": 155.80686,
    "JOD": 0.70759,
    "JPY": 115.42734,
    "KES": 113.303,
    "KGS": 85.05721,
    "KHR": 4066.33034,
    "KMF": 430.64639,
    "KPW": 900.02438,
    "KRW": 1193.7614,
    "KWD": 0.302,
    "KYD": 0.82061,
    "KZT": 425.47661,
    "LAK": 11394.85755,
    "LBP": 1510.16006,
    "LKR": 203.02401,
    "LRD": 153.41882,
    "LSL": 15.36242,
    "LYD": 4.57184,
    "MAD": 9.30782,
    "MDL": 17.85335,
    "MGA": 3995.92268,
    "MKD": 53.81939,
    "MMK": 1773.0882,
    "MNT": 2856.09715,
    "MOP": 8.02612,
    "MRU": 36.38995,
    "MUR": 44.03891,
    "MVR": 15.66053,
    "MWK": 810.96593,
    "MXN": 20.49223,
    "MYR": 4.1845,
    "MZN": 63.66124,
    "NAD": 15.20043,
    "NGN": 416.64463,
    "NOK": 8.80997,
    "NPR": 119.8895,
    "NZD": 1.49518,
    "OMR": 0.38407,
    "PAB": 0.99908,
    "PEN": 3.80791,
    "PGK": 3.51972,
    "PHP": 51.26921,
    "PKR": 174.34464,
    "PLN": 3.932,
    "PYG": 6963.85809,
    "QAR": 3.63947,
    "RON": 4.32397,
    "RSD": 102.80611,
    "RUB": 74.5714,
    "RWF": 1012.01037,
    "SAR": 3.74805,
    "SCR": 14.50692,
    "SDG": 441.096,
    "SEK": 9.0993,
    "SGD": 1.34151,
    "SHP": 0.73865,
    "SLL": 11353.1241,
    "SOS": 585.55358,
    "SRD": 20.78836,
    "SYP": 2511.26803,
    "SZL": 15.2251,
    "THB": 32.70654,
    "TJS": 11.31708,
    "TMT": 3.50647,
    "TND": 2.85947,
    "TOP": 2.29205,
    "TRY": 13.54047,
    "TTD": 6.77401,
    "TWD": 27.81745,
    "TZS": 2311.33156,
    "UAH": 28.07199,
    "UGX": 3498.77016,
    "USD": 1,
    "UYU": 43.49342,
    "UZS": 10849.73741,
    "VND": 22714.81648,
    "VUV": 113.09101,
    "WST": 2.62152,
    "XAF": 573.7131,
    "XCD": 2.69908,
    "XDR": 0.71235,
    "XOF": 573.7131,
    "XPF": 104.29227,
    "YER": 249.84599,
    "ZAR": 15.23648,
    "ZMW": 18.60965
  },
  "updated": "2022-02-09 17:30:18",
  "ms": 2
}

// Model
 import Foundation

struct CurrencyModel: Codable {
    var results: [String:Double]
}

struct CurrencyNameModel: Codable {
    var currencies: [String:String]
}

// Two ViewModels
import Foundation

class CurrencyViewModel: ObservableObject {

    @Published var currencyCode: [String] = []
    @Published var exchagePrice: [Double] = []

    init() {

        fetchData { (currency) in
            switch currency {
        case .success(let prices):
                DispatchQueue.main.async {
                    self.currencyCode.append(contentsOf: prices.results.keys)
                    // self.currencyCode.sorted()
                    self.exchagePrice.append(contentsOf: prices.results.values)
            }
            case .failure(let error):
                print("Error", error)
        }
    }
}

func fetchData(completion: @escaping (Result<CurrencyModel,Error>) -> ()) {
    guard let url = URL(string: "https://api.fastforex.io/fetch-all?api_key=...") else { return }
    URLSession.shared.dataTask(with: url) { data, responce, error in
        if let error = error {
            completion(.failure(error))
            return
        }

        guard let safeData = data else { return }

        do {
            let currency = try JSONDecoder().decode(CurrencyModel.self, from: safeData)
            completion(.success(currency))
        }
        catch {
            completion(.failure(error))
        }
    }
    .resume()

    }
}

////////

import Foundation

class CurrencyViewModelNew: ObservableObject {

    @Published var currencyName: [String] = []

init() {
    fetchNewData { (name) in
        switch name {
    case .success(let prices):
            DispatchQueue.main.async {

                self.currencyName.append(contentsOf: prices.currencies.values)

            }
        case .failure(let error):
            print("Error", error)

            }
        }
    }

    func fetchNewData(completion: @escaping (Result<CurrencyNameModel,Error>) -> ()) {
        guard let url = URL(string: "https://api.fastforex.io/currencies?api_key=...") else { return }
        URLSession.shared.dataTask(with: url) { data, responce, error in
            if let error = error {
                completion(.failure(error))
                return
            }

            guard let safeData = data else { return }

            do {
                let currency = try JSONDecoder().decode(CurrencyNameModel.self, from: safeData)
                completion(.success(currency))
            }
            catch {
                completion(.failure(error))
            }
        }
        .resume()

        }

}

// View just in case
import SwiftUI

struct CurrencyView: View {
    @ObservedObject var api1 = CurrencyViewModel()
    @ObservedObject var api2 = CurrencyViewModelNew()

    @State private var pickerSelection1 = 0
    @State private var pickerSelection2 = 0

    var body: some View {
        Picker("", selection: $pickerSelection1) {
            ForEach(0..<self.api1.currencyCode.count) {
                let currency = api1.currencyCode[$0]
        Text(currency)
            }
        }
        .id(UUID())

        Picker("", selection: $pickerSelection1) {
            ForEach(0..<self.api2.currencyName.count) {
                let name = api2.currencyName[$0]
        Text(name)
            }
        }
        .id(UUID())

        Picker("", selection: $pickerSelection1) {
            ForEach(0..<self.api1.exchagePrice.count) {
                let price = "\(api1.exchagePrice[$0])"
                Text(price)
            }
        }
        .id(UUID())
    }
}

struct CurrencyView_Previews: PreviewProvider {
    static var previews: some View {
        CurrencyView()
    }
}

Body:
Perhaps it would make more sense to create a Currency model for each currency.

struct Currency {
    let name: String
    let symbol: String
    let value_USD: Double
}

And construct a function to parse the two dictionaries (of values and names) to map an array of currencies.

// Our parsed JSON data
let currencyValues: [String: Double] = [
    "AED": 3.67206,
    "AFN": 93.40685,
    "ALL": 106.27627
]
let currencyNames: [String: String] = [
    "AED": "United Arab Emirates Dirham",
    "AFN": "Afghan Afghani",
    "ALL": "Albanian Lek"
]

// A simple function to parse them
func getCurrencies() -> [Currency] {
    var currencies: [Currency] = []

    for entry in currencyValues {
        let symbol = entry.key
        let usdValue = entry.value

        if let name = currencyNames[symbol] {
            let c = Currency(name: name, symbol: symbol, value_USD: usdValue)
            currencies.append(c)
        }
    }
    return currencies
}

let currencies = getCurrencies()
for currency in currencies {
    print(currency.symbol, currency.name, currency.value_USD)
}

// AFN Afghan Afghani 93.40685
// AED United Arab Emirates Dirham 3.67206
// ALL Albanian Lek 106.27627


来源: stackexchange

问:
Javascript - Error when accessing an associative array value
I have an array, locations:

```<code>{
   "locations":[
      "{\"location_id\":\"1\",\"location_name\":\"Main Office\"}",
      "{\"location_id\":\"6\",\"location_name\":\"Secondary\"}"
   ]
}
</code>```

I am trying to loop through this array to display the location id/name, but keep getting undefined errors.

```<code>for (var i = 0; i < locations.length; ++i) {
    alert(locations[i].location_id);
}
</code>```

If I do alert(locations[i]), I can see the individual array contents for that index, but seemingly have no way go any further.

I feel like I'm missing something incredibly simple and would appreciate any help. Everything I've read suggests I should just be able to get the value of the array by using the for [i] loop.

答:
define it like:

```<code>let locations = [
    { location_id: 1, location_name: 'Main office'},
    { location_id: 2, location_name: 'any name' },
];

locations.forEach(location => {
    alert(location.location_id);
});
</code>```

Or if your data is in json format:

```<code>let json = '{ "locations": [ { "location_id": 3, "location_name": "Name" } ]}';

const data = JSON.parse(json);

data.locations.forEach(location => {
    console.log(location.location_id);
});
</code>```

ContentLicense: CC BY-SA 4.0

Body:
I have an array, locations:

{
   "locations":[
      "{\"location_id\":\"1\",\"location_name\":\"Main Office\"}",
      "{\"location_id\":\"6\",\"location_name\":\"Secondary\"}"
   ]
}

I am trying to loop through this array to display the location id/name, but keep getting undefined errors.

for (var i = 0; i < locations.length; ++i) {
    alert(locations[i].location_id);
}

If I do alert(locations[i]), I can see the individual array contents for that index, but seemingly have no way go any further.

I feel like I'm missing something incredibly simple and would appreciate any help. Everything I've read suggests I should just be able to get the value of the array by using the for [i] loop.

Body:
define it like:

let locations = [
    { location_id: 1, location_name: 'Main office'},
    { location_id: 2, location_name: 'any name' },
];

locations.forEach(location => {
    alert(location.location_id);
});

Or if your data is in json format:

let json = '{ "locations": [ { "location_id": 3, "location_name": "Name" } ]}';

const data = JSON.parse(json);

data.locations.forEach(location => {
    console.log(location.location_id);
});


答:
The best way forward IMO is to create a custom type that contains the values from both json collections and then use this type throughout your app.

```<code>struct Currency {
    let currencyCode: String
    let name: String
    var price: Double
}
</code>```

One option here is to make the type Codable and decode it using a custom init(from:) and while this is a good approach here I will leave the decoding as it is and create the Currency objects from CurrencyNameModel instead,

```<code>let currencies = values.currencies.map { Currency(currencyCode: $0.key, name: $0.value, price: 0) }
</code>```

then update it with the prices from CurrencyModel

```<code>for (index, value) in currencies.enumerated() {
    if let model = values.results.first(where: { $0.key == value.currencyCode }) {
        currencies[index].price = model.value
    }
}
</code>```

This would all be done in the CurrencyViewModel so it would be changed to

```<code>class CurrencyViewModel: ObservableObject {
    @Published var currencies: [Currency] = []

    init() {
        fetchNewData { (currency) in
            switch currency {
            case .success(let names):
                self.currencies = names.currencies.map {
                    Currency(currencyCode: $0.key, name: $0.value, price: 0)
                }
                fetchData { result in
                    switch result {
                    case .success(let prices):
                        for (index, value) in currencies.enumerated() {
                            if let price = prices.results.first(where: { $0.key == value.currencyCode }) {
                                currencies[index].price = price.value
                            }
                        }
                    case .failure(let error):
                        print(error)
                    }
                }
            case .failure(let error):
                print("Error", error)
            }
        }
    }
}
</code>```

Title: How to maintain order while fetching the JSON data?

Body:
The best way forward IMO is to create a custom type that contains the values from both json collections and then use this type throughout your app.

struct Currency {
    let currencyCode: String
    let name: String
    var price: Double
}

One option here is to make the type Codable and decode it using a custom init(from:) and while this is a good approach here I will leave the decoding as it is and create the Currency objects from CurrencyNameModel instead,

let currencies = values.currencies.map { Currency(currencyCode: $0.key, name: $0.value, price: 0) }

then update it with the prices from CurrencyModel

for (index, value) in currencies.enumerated() {
    if let model = values.results.first(where: { $0.key == value.currencyCode }) {
        currencies[index].price = model.value
    }
}

This would all be done in the CurrencyViewModel so it would be changed to

class CurrencyViewModel: ObservableObject {
    @Published var currencies: [Currency] = []

    init() {
        fetchNewData { (currency) in
            switch currency {
            case .success(let names):
                self.currencies = names.currencies.map {
                    Currency(currencyCode: $0.key, name: $0.value, price: 0)
                }
                fetchData { result in
                    switch result {
                    case .success(let prices):
                        for (index, value) in currencies.enumerated() {
                            if let price = prices.results.first(where: { $0.key == value.currencyCode }) {
                                currencies[index].price = price.value
                            }
                        }
                    case .failure(let error):
                        print(error)
                    }
                }
            case .failure(let error):
                print("Error", error)
            }
        }
    }
}


问:
findDOMNode is deprecated in StrictMode
I am using antd and I am seeing this error

findDOMNode is deprecated in StrictMode. findDOMNode was passed an instance of DOMWrap which is inside StrictMode. Instead, add a ref directly to the element you want to reference

I have realized that it is because of mode="horizontal".
I have tried using other components as well and I see this error a lot in antd. Is there any way to fix this issue?
This is my current code

```<code>import React from 'react'
import { connect } from 'react-redux';
import { Layout, Menu  } from 'antd';

const { Header, Footer, Content } = Layout;

  const AddForm = () => {
    return (
    <div>
        {/* // Menu Starts from here */}

        <Layout className="layout">
            <Header>
            <div className="logo" />
            <Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']}>
                <Menu.Item key="1">nav 1</Menu.Item>
                <Menu.Item key="2">nav 2</Menu.Item>
                <Menu.Item key="3">nav 3</Menu.Item>
            </Menu>
            </Header>
            <Content style={{ padding: '0 50px' }}>
            <div className="site-layout-content">Content</div>
            </Content>
            <Footer style={{ textAlign: 'center' }}>Ant Design ©2018 Created by Ant UED</Footer>
        </Layout>
    </div>
    )

  };
</code>```

答:
The semantic team has issued that they are fixing the issue:

See here https://github.com/Semantic-Org/Semantic-UI-React/issues/4050

The best work around I presume is using plain semantic-ui instead of hacking react.

```<code><button className="ui button large primary">click me</button>
</code>```

Title: findDOMNode is deprecated in StrictMode

Body:
I am using antd and I am seeing this error

findDOMNode is deprecated in StrictMode. findDOMNode was passed an instance of DOMWrap which is inside StrictMode. Instead, add a ref directly to the element you want to reference

I have realized that it is because of mode="horizontal".
I have tried using other components as well and I see this error a lot in antd. Is there any way to fix this issue?
This is my current code

import React from 'react'
import { connect } from 'react-redux';
import { Layout, Menu  } from 'antd';

const { Header, Footer, Content } = Layout;

  const AddForm = () => {
    return (

        {/* // Menu Starts from here */}

        <Layout className="layout">

            <Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']}>
                <Menu.Item key="1">nav 1</Menu.Item>
                <Menu.Item key="2">nav 2</Menu.Item>
                <Menu.Item key="3">nav 3</Menu.Item>
            </Menu>

            <Content style={{ padding: '0 50px' }}>

Content

            </Content>
            Ant Design ©2018 Created by Ant UED
        </Layout>

    )

  };

Body:
The semantic team has issued that they are fixing the issue:

See here https://github.com/Semantic-Org/Semantic-UI-React/issues/4050

The best work around I presume is using plain semantic-ui instead of hacking react.

<button className="ui button large primary">click me</button>


问:
When I click tiktok like butten with selenium, it reverts after a few seconds
After a few seconds, when I click tiktok, it automatically reverts to the previous state

After a few seconds, when I click tiktok, it automatically reverts to the previous state

```<code>from selenium import webdriver
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager
from textwrap import wrap
import time
import warnings
warnings.filterwarnings('ignore')
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

options = webdriver.ChromeOptions()
options.add_argument('--ignore-certificate-errors-spki-list')
options.add_argument('--ignore-ssl-errors')
options.add_experimental_option('excludeSwitches', ['enable-logging'])
options.add_argument('--profile-directory=Profile 4')
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_argument("window-size=810,1080")
options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36")
options.add_argument('--no-sandbox')
options.add_argument('--start-maximized')
# options.add_argument('--start-fullscreen')
# options.add_argument('--single-process')
options.add_argument('--disable-dev-shm-usage')
# options.add_argument("--incognito")
options.add_argument('--disable-blink-features=AutomationControlled')
# options.add_argument('--disable-blink-features=AutomationControlled')
options.add_experimental_option('useAutomationExtension', False)
options.add_argument("disable-infobars")
options.add_argument("user-data-dir=C:\\Users\\DELL\\AppData\\Local\\Google\\Chrome\\User Data\\")
driver = webdriver.Chrome(executable_path=ChromeDriverManager().install(), options=options)
driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
    "source":
        "const newProto = navigator.__proto__;"
        "delete newProto.webdriver;"
        "navigator.__proto__ = newProto;"
})

driver.get("https://www.tiktok.com/@googlemapsfun/video/7062048347451870469?is_copy_url=1&is_from_webapp=v1")

like = driver.find_element(By.XPATH, '(//*[@data-e2e="feed-video"])')

actions = ActionChains(driver)
actions.move_to_element(like)
actions.double_click()
actions.perform()

time.sleep(150)
</code>```

After a few seconds, when I click tiktok, it automatically reverts to the previous state

答:
I have no reputation that would write to you in the comment, so I wrote here.
Hey! Did you get the desired? I did even this way, and still fail. He also puts like, and then tiktok removes him</p>
```<code># find element

like = DRIVER.find_element_by_tag_name('video')

# find height browser navigation panel

browser_navigation_panel_height = DRIVER.execute_script('return window.outerHeight - window.innerHeight;')

# find x and y for click on like

x = like.location["x"]
y = DRIVER.find_element_by_tag_name('video').location["y"] + browser_navigation_panel_height

# generation random coords

coord = random.randint(x, y)

# Performs mouse move action onto the element

actions = ActionChains(driver)

actions.move_by_offset(coord, coord)
actions.click()
actions.move_by_offset(coord, coord)
actions.click()
actions.perform()
</code>```

Body:
After a few seconds, when I click tiktok, it automatically reverts to the previous state

After a few seconds, when I click tiktok, it automatically reverts to the previous state

from selenium import webdriver
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager
from textwrap import wrap
import time
import warnings
warnings.filterwarnings('ignore')
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

options = webdriver.ChromeOptions()
options.add_argument('--ignore-certificate-errors-spki-list')
options.add_argument('--ignore-ssl-errors')
options.add_experimental_option('excludeSwitches', ['enable-logging'])
options.add_argument('--profile-directory=Profile 4')
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_argument("window-size=810,1080")
options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36")
options.add_argument('--no-sandbox')
options.add_argument('--start-maximized')
# options.add_argument('--start-fullscreen')
# options.add_argument('--single-process')
options.add_argument('--disable-dev-shm-usage')
# options.add_argument("--incognito")
options.add_argument('--disable-blink-features=AutomationControlled')
# options.add_argument('--disable-blink-features=AutomationControlled')
options.add_experimental_option('useAutomationExtension', False)
options.add_argument("disable-infobars")
options.add_argument("user-data-dir=C:\\Users\\DELL\\AppData\\Local\\Google\\Chrome\\User Data\\")
driver = webdriver.Chrome(executable_path=ChromeDriverManager().install(), options=options)
driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
    "source":
        "const newProto = navigator.__proto__;"
        "delete newProto.webdriver;"
        "navigator.__proto__ = newProto;"
})

driver.get("https://www.tiktok.com/@googlemapsfun/video/7062048347451870469?is_copy_url=1&is_from_webapp=v1")

like = driver.find_element(By.XPATH, '(//*[@data-e2e="feed-video"])')

actions = ActionChains(driver)
actions.move_to_element(like)
actions.double_click()
actions.perform()

time.sleep(150)

After a few seconds, when I click tiktok, it automatically reverts to the previous state

Body:
I have no reputation that would write to you in the comment, so I wrote here.
Hey! Did you get the desired? I did even this way, and still fail. He also puts like, and then tiktok removes him

# find element

like = DRIVER.find_element_by_tag_name('video')

# find height browser navigation panel

browser_navigation_panel_height = DRIVER.execute_script('return window.outerHeight - window.innerHeight;')

# find x and y for click on like

x = like.location["x"]
y = DRIVER.find_element_by_tag_name('video').location["y"] + browser_navigation_panel_height

# generation random coords

coord = random.randint(x, y)

# Performs mouse move action onto the element

actions = ActionChains(driver)

actions.move_by_offset(coord, coord)
actions.click()
actions.move_by_offset(coord, coord)
actions.click()
actions.perform()


问:
Django template syntax error: could not parse remainder % 2
I am getting a TemplateSyntaxError: "could not parse remainder % 2 from num%2":

```<code>{% if num%2 ==0 %}
   {{"Even"}}
{% else %}
   {{"Odd"}}
{% endif %}
</code>```

答:
You can't use arbitrary Python expressions in Django templates. You should create a custom filter for them.

However, for your expression there is a built-in tag divisibleby. From its example:

```<code>{{ value|divisibleby:"2" }}
</code>```

If value is 4, the output would be True. So the final answer looks like (untested):

```<code>{% if num|divisibleby:"2" %}
    Even
{% else %}
    Odd
{% endif %}
</code>```

Body:
I am getting a TemplateSyntaxError: "could not parse remainder % 2 from num%2":

{% if num%2 ==0 %}
   {{"Even"}}
{% else %}
   {{"Odd"}}
{% endif %}

Body:
You can't use arbitrary Python expressions in Django templates. You should create a custom filter for them.

However, for your expression there is a built-in tag divisibleby. From its example:

{{ value|divisibleby:"2" }}

If value is 4, the output would be True. So the final answer looks like (untested):

{% if num|divisibleby:"2" %}
    Even
{% else %}
    Odd
{% endif %}


问:
Is it possible to use an array value as a switch case value?
I am trying to create a working Java code. I created an encryption function that takes any symbol in a string and replaces it with a value from an array.

The problem is very simple. Decryption function must take any value written in an array and use it to decrypt. The code describes it better than I do.

```<code>   case "1" -> output += n_encryptions[0];
// Then in decrypt():
   case n_encryptions[0] -> output += "1";
// Sadly, this creates an error
</code>```

My goal is to make an easily changeable encryption and decryption system, since I am planning to change these values in the future.

I need a way to use an array value (n_encryptions[0] in the example) as a case parameter.

Edit: I guess an if statement is the best option. Thanks!

答:
Is it possible to use an array value as a switch case value?

No, it is not.

Switch labels (to the right of the word case) must be compile-time constant expressions.

I need a way to use an array value (n_encryptions[0] in the example)
as a case parameter.

Why do you 'need' this?  It surely can be expressed another way,for example by using if.

Body:
I am trying to create a working Java code. I created an encryption function that takes any symbol in a string and replaces it with a value from an array.

The problem is very simple. Decryption function must take any value written in an array and use it to decrypt. The code describes it better than I do.

   case "1" -> output += n_encryptions[0];
// Then in decrypt():
   case n_encryptions[0] -> output += "1";
// Sadly, this creates an error

My goal is to make an easily changeable encryption and decryption system, since I am planning to change these values in the future.

I need a way to use an array value (n_encryptions[0] in the example) as a case parameter.

Edit: I guess an if statement is the best option. Thanks!


问:
C# Organising and structuring of the code
I am quite new to c# and Visual studio and am not sure how to best structure the code so I  would very much apreciate tips and guidance so that I am not start to build something on a weak foundation.I am trying to create an application that:

Read data from a WebSocket

Store the data in a DataTable, and do calculations with the data that will be stored in new DataTables

Present the data + calculations in a Chart

This is how I have structured it so far:

```<code>    private Data data;
    private WebSocket ws;

private void Form1_Load(object sender, EventArgs e)
{
    // Class data that holds dataset with datatables, and that have access to the chart
    data = new Data(chart);

    // WebSocket class that retrieves data and stores it in a private object "Dataobject" and calls the data class on an onChange event. The data class then stores the data in the DataTable/DataSet
    ws = new WebSocket(data);

    // Method that binds the DataTable(s) to the chart
    data.print();
}
</code>```

Since the WebSocket works in a different thread the call to the data class from the WebSocket class is made like this:

```<code>    private void Dataobject_ValueChanged(bool value)
    {
        threadsafe();
    }
    public void threadsafe()
    {
        if (data.InvokeRequired)
        {
            Action safeWrite = delegate { threadsafe(); };
            data.Invoke(safeWrite);
        }
        else
        {
            data.AddRow(dataobject);
        }
    }
</code>```

Am I on the correct path or are there better ways? Thx!

答:
Disclaimer: A lot of this falls down to preference of course, but in general you should always follow the rule that you should do everything to make the code self explanatory and boring. "The quality of code is measured in the amount of 'WTF moments' that you experience while reading it"

Comments

The comments that you used for the properties should be shortened very much. They are too wordy and even if you have to use long comments, I would recommend you spread them over multiple lines.

If you comment fields of a class you should use the documentation comment syntax to make the IDE detect the comment and display it with the field / property when you use it later in the code.

///
/// Some text to better understand the use of this field.
///
private int someField;
```
<p>Although in general I would recommend making your code speak and not use comments for that. So e.g. if you have a variable which is used as a flag to indicate whether the object x is active, you should call that variable something like <code>isActive</code> and not have a comment explaining that, because the variable speaks for itself.</p>
<p><strong>Indentation</strong></p>
<p>I'm not sure if it's just a copy-paste mistake, but in your first code snippet you have uneven indentation which is not ideal. Inside a block you should always have the same indent level, expect maybe if some line of code is too long and you split it up into two lines.</p>
<p><strong>Spaces / Empty lines</strong></p>
<p>In your second code snippet, there's no space between the two methods. I would always recommend adding an empty newline after a closing bracket, expect for <code>if { } else { }</code> statements or a few other rare cases. But e.g. directly after an if statement I would add an empty newline and definitely between methods.</p>
<p><strong>Naming</strong></p>
<p>You should also name variables, fields, methods, etc. consistently. Your method <code>threadsafe</code> is all lower-case, but other methods before start with an upper-case letter. In C# you normally use pascal case for your methods and also for properties, so starting with an upper-case letter and then separating each word with an upper-case letter. Other things like variables will normally be camel-cased (starting with a lower-case letter, the rest same as pascal-case).</p>
<p><strong>Inline Delegates</strong></p>
<p>Often it is unnecessary to have code spread over multiple lines. Your <code>safeWrite</code> delegate is an example of that. In this case your delegate only does one thing and is not very complex. It doesn't need further explanation through a name, etc. You could therefore instead just use an inline delegate like this:</p>
<pre class="lang-cs prettyprint-override"><code>data.Invoke(() => threadsafe());
</code>```

There's many other things to be said about code formatting and styling. There's also many opinions on how to structure your code, but as I mentioned in the disclaimer: As long as you reduce confusion and reduce the complexity of your program, you're on a good track.

As a ending note, I think you should inform yourself about 'clean code'. I can recommend Uncle Bob's videos and talks on that topic, they can help you significantly with improving the way you write you're code.

Body:
I am quite new to c# and Visual studio and am not sure how to best structure the code so I  would very much apreciate tips and guidance so that I am not start to build something on a weak foundation.I am trying to create an application that:

Read data from a WebSocket

Store the data in a DataTable, and do calculations with the data that will be stored in new DataTables

Present the data + calculations in a Chart

This is how I have structured it so far:

    private Data data;
    private WebSocket ws;

private void Form1_Load(object sender, EventArgs e)
{
    // Class data that holds dataset with datatables, and that have access to the chart
    data = new Data(chart);

    // WebSocket class that retrieves data and stores it in a private object "Dataobject" and calls the data class on an onChange event. The data class then stores the data in the DataTable/DataSet
    ws = new WebSocket(data);

    // Method that binds the DataTable(s) to the chart
    data.print();
}

Since the WebSocket works in a different thread the call to the data class from the WebSocket class is made like this:

    private void Dataobject_ValueChanged(bool value)
    {
        threadsafe();
    }
    public void threadsafe()
    {
        if (data.InvokeRequired)
        {
            Action safeWrite = delegate { threadsafe(); };
            data.Invoke(safeWrite);
        }
        else
        {
            data.AddRow(dataobject);
        }
    }

Am I on the correct path or are there better ways? Thx!

Body:
Disclaimer: A lot of this falls down to preference of course, but in general you should always follow the rule that you should do everything to make the code self explanatory and boring. "The quality of code is measured in the amount of 'WTF moments' that you experience while reading it"

Comments

The comments that you used for the properties should be shortened very much. They are too wordy and even if you have to use long comments, I would recommend you spread them over multiple lines.

If you comment fields of a class you should use the documentation comment syntax to make the IDE detect the comment and display it with the field / property when you use it later in the code.

/// <summary>
/// Some text to better understand the use of this field.
/// </summary>
private int someField;

Although in general I would recommend making your code speak and not use comments for that. So e.g. if you have a variable which is used as a flag to indicate whether the object x is active, you should call that variable something like isActive and not have a comment explaining that, because the variable speaks for itself.

Indentation

I'm not sure if it's just a copy-paste mistake, but in your first code snippet you have uneven indentation which is not ideal. Inside a block you should always have the same indent level, expect maybe if some line of code is too long and you split it up into two lines.

Spaces / Empty lines

In your second code snippet, there's no space between the two methods. I would always recommend adding an empty newline after a closing bracket, expect for if { } else { } statements or a few other rare cases. But e.g. directly after an if statement I would add an empty newline and definitely between methods.

Naming

You should also name variables, fields, methods, etc. consistently. Your method threadsafe is all lower-case, but other methods before start with an upper-case letter. In C# you normally use pascal case for your methods and also for properties, so starting with an upper-case letter and then separating each word with an upper-case letter. Other things like variables will normally be camel-cased (starting with a lower-case letter, the rest same as pascal-case).

Inline Delegates

Often it is unnecessary to have code spread over multiple lines. Your safeWrite delegate is an example of that. In this case your delegate only does one thing and is not very complex. It doesn't need further explanation through a name, etc. You could therefore instead just use an inline delegate like this:

data.Invoke(() => threadsafe());

There's many other things to be said about code formatting and styling. There's also many opinions on how to structure your code, but as I mentioned in the disclaimer: As long as you reduce confusion and reduce the complexity of your program, you're on a good track.

As a ending note, I think you should inform yourself about 'clean code'. I can recommend Uncle Bob's videos and talks on that topic, they can help you significantly with improving the way you write you're code.


问:
Cannot group data by a column in R
I want to get a count of how many times each Player's name appears in my data frame ph1. My code is showing how many times each name is in the dataset, but I cannot group it by nso I can see how many times each Player's name is in the dataset.

I would prefer a dplyr solution but am open to others.

For example:

```<code>n Number_Players
1  21
2  2
</code>```

Code

```<code>ph1 %>%
     filter(!is.na(Player)) %>%
     group_by(Player) %>%
     mutate(n= n()) %>%
     relocate(n, .after=Player)
</code>```

Sample of how my output is appearing

```<code>Player              n   Year    PA  AB
Peavy, Jake         1   2008    58  49
Gallardo, Yovani    1   2014    59  53
Stratton, Chris     1   2018    50  43
Cashner, Andrew     1   2015    61  60
Anderson, Chase     1   2016    52  45
Burnes, Corbin      1   2021    59  52
Wolf, Randy         1   2009    80  67
Davies, Zach        2   2016    61  53
Senzatela, Antonio  1   2021    51  39
Syndergaard, Noah   2   2015    50  43
</code>```

Sample data

```<code>structure(list(Player = c("Peavy, Jake", "Gallardo, Yovani",
"Stratton, Chris", "Cashner, Andrew", "Anderson, Chase", "Burnes, Corbin",
"Wolf, Randy", "Davies, Zach", "Senzatela, Antonio", "Syndergaard, Noah",
"Syndergaard, Noah", "Davies, Zach", "Sánchez, Aníbal", "Hudson, Dakota",
"Leake, Mike", "De La Rosa, Jorge", "Cueto, Johnny", "González, Gio",
"Peralta, Wily", "Vólquez, Edinson", "Ryu, Hyun Jin", "Dempster, Ryan",
"Holland, Derek", "Wheeler, Zack", "Sabathia, CC"), Year = c(2008,
2014, 2018, 2015, 2016, 2021, 2009, 2016, 2021, 2015, 2016, 2019,
2019, 2019, 2016, 2015, 2008, 2015, 2014, 2014, 2014, 2009, 2018,
2014, 2008), PA = c(58, 59, 50, 61, 52, 59, 80, 61, 51, 50, 67,
54, 56, 59, 55, 50, 56, 56, 68, 64, 56, 75, 56, 62, 50), AB = c(49,
53, 43, 60, 45, 52, 67, 53, 39, 43, 58, 51, 52, 51, 49, 48, 45,
43, 57, 53, 47, 64, 53, 50, 48)), row.names = c(NA, -25L), class = c("tbl_df",
"tbl", "data.frame"))
</code>```

I checked the existing stackoverflow solutions, but did not see one that matches my need. If one exists, I would appreciate it if you could provide its link.

答:
```<code>ph %>%
  filter(!is.na(Player)) %>%
  group_by(Player) %>% count() %>%
  group_by(n) %>%
  count(name="Number_Players")

# A tibble: 2 x 2
# Groups:   n [2]
      n Number_Players
  <int>          <int>
1     1             21
2     2              2
</code>```

Title: Cannot group data by a column in R

Body:
I want to get a count of how many times each Player's name appears in my data frame ph1. My code is showing how many times each name is in the dataset, but I cannot group it by nso I can see how many times each Player's name is in the dataset.

I would prefer a dplyr solution but am open to others.

For example:

n Number_Players
1  21
2  2

Code

ph1 %>%
     filter(!is.na(Player)) %>%
     group_by(Player) %>%
     mutate(n= n()) %>%
     relocate(n, .after=Player)

Sample of how my output is appearing

Player              n   Year    PA  AB
Peavy, Jake         1   2008    58  49
Gallardo, Yovani    1   2014    59  53
Stratton, Chris     1   2018    50  43
Cashner, Andrew     1   2015    61  60
Anderson, Chase     1   2016    52  45
Burnes, Corbin      1   2021    59  52
Wolf, Randy         1   2009    80  67
Davies, Zach        2   2016    61  53
Senzatela, Antonio  1   2021    51  39
Syndergaard, Noah   2   2015    50  43

Sample data

structure(list(Player = c("Peavy, Jake", "Gallardo, Yovani",
"Stratton, Chris", "Cashner, Andrew", "Anderson, Chase", "Burnes, Corbin",
"Wolf, Randy", "Davies, Zach", "Senzatela, Antonio", "Syndergaard, Noah",
"Syndergaard, Noah", "Davies, Zach", "Sánchez, Aníbal", "Hudson, Dakota",
"Leake, Mike", "De La Rosa, Jorge", "Cueto, Johnny", "González, Gio",
"Peralta, Wily", "Vólquez, Edinson", "Ryu, Hyun Jin", "Dempster, Ryan",
"Holland, Derek", "Wheeler, Zack", "Sabathia, CC"), Year = c(2008,
2014, 2018, 2015, 2016, 2021, 2009, 2016, 2021, 2015, 2016, 2019,
2019, 2019, 2016, 2015, 2008, 2015, 2014, 2014, 2014, 2009, 2018,
2014, 2008), PA = c(58, 59, 50, 61, 52, 59, 80, 61, 51, 50, 67,
54, 56, 59, 55, 50, 56, 56, 68, 64, 56, 75, 56, 62, 50), AB = c(49,
53, 43, 60, 45, 52, 67, 53, 39, 43, 58, 51, 52, 51, 49, 48, 45,
43, 57, 53, 47, 64, 53, 50, 48)), row.names = c(NA, -25L), class = c("tbl_df",
"tbl", "data.frame"))

I checked the existing stackoverflow solutions, but did not see one that matches my need. If one exists, I would appreciate it if you could provide its link.


问:
React Select's short input box component width causes cursor position problem
I don't fully understand the ins and outs of react-select, but this seems to be a problem.

If I put the cursor somewhere other than the right end of the text in the box, say after the second of five characters, and then blur away from the component, then click in the box at a point to the right of the end of the text, the cursor will still be where it was, rather than at the right end of the text where it should be. If I click at a point within the text, then the cursor goes there. If I want to put the cursor at the far right of the text, I need to click within the very narrow space of a couple pixels to the right of the rightmost character.

This is happening because the width of the <input> box changes to the width of its contents, so clicks within the container to the right of the <input> are received by the container. The containing
 has these styles that seem to matter. I'm not familiar with inline-grids.

```<code>display: inline-grid;
grid-area: 1 1 2 3;
grid-template-columns: 0 min-content;
width: 100%;
</code>```

The <input> has this:

```<code>grid-area: 1 2 auto auto;
width: 100%;
min-width: 2px;
</code>```

Judging by the examples, it seems that input text in a react-select is meant to go away when you blur. Or maybe not. I want the text to stay there. My application is a search box.

I tried these:

```<code>autosize={false}
</code>```
```<code>.Select-control {
    table-layout: fixed;
}

.Select-input {
    overflow: hidden;
    max-width: 100%;
}
</code>```

They didn't help

What's the best way to make this work?

答:
Fixed it by using grid-template-columns: 0fr. You can see it here https://codesandbox.io/s/eloquent-hypatia-87f02b Now you can select anywhere you want and it'll behave as a regular input.

Original Answer

Problem is the min-content in the grid-template-columns so try this:

const customStyles = {
  control: () => ({
    gridTemplateColumns: '0px max-content'
  })
}

<Select styles={customStyles} options={...} />
```

Note that even with this you still get max of 1 since grid-area is 1 / 1 / 2 / 3 so you can also configure those if you need to.

More info on styles here

Body:
I don't fully understand the ins and outs of react-select, but this seems to be a problem.

If I put the cursor somewhere other than the right end of the text in the box, say after the second of five characters, and then blur away from the component, then click in the box at a point to the right of the end of the text, the cursor will still be where it was, rather than at the right end of the text where it should be. If I click at a point within the text, then the cursor goes there. If I want to put the cursor at the far right of the text, I need to click within the very narrow space of a couple pixels to the right of the rightmost character.

This is happening because the width of the <input> box changes to the width of its contents, so clicks within the container to the right of the <input> are received by the container. The containing
 has these styles that seem to matter. I'm not familiar with inline-grids.

display: inline-grid;
grid-area: 1 1 2 3;
grid-template-columns: 0 min-content;
width: 100%;

The <input> has this:

grid-area: 1 2 auto auto;
width: 100%;
min-width: 2px;

Judging by the examples, it seems that input text in a react-select is meant to go away when you blur. Or maybe not. I want the text to stay there. My application is a search box.

I tried these:

autosize={false}

.Select-control {
    table-layout: fixed;
}

.Select-input {
    overflow: hidden;
    max-width: 100%;
}

They didn't help

What's the best way to make this work?

Body:
Fixed it by using grid-template-columns: 0fr. You can see it here https://codesandbox.io/s/eloquent-hypatia-87f02b Now you can select anywhere you want and it'll behave as a regular input.

Original Answer

Problem is the min-content in the grid-template-columns so try this:

const customStyles = {
  control: () => ({
    gridTemplateColumns: '0px max-content'
  })
}

<Select styles={customStyles} options={...} />

Note that even with this you still get max of 1 since grid-area is 1 / 1 / 2 / 3 so you can also configure those if you need to.

More info on styles here


问:
Why use Celery instead of RabbitMQ?
From my understanding, Celery is a distributed task queue, which means the only thing that it should do is dispatching tasks/jobs to others servers and get the result back. RabbitMQ is a message queue, and nothing more. However, a worker could just listen to the MQ and execute the task when a message is received. This achieves exactly what Celery offers, so why need Celery at all?</p>

答:
In my opinion, it's easy to integrate celery with flower and other monitoring packages than RabbitMQ.

It all depends on the use case anyways...

If you don't need other functionalities celery provides, RabbitMQ would be an easy way out. Weighing out your options wouldn't be a bad idea...

ContentLicense: CC BY-SA 3.0

Title: Why use Celery instead of RabbitMQ?


问:
firebaseAppDistribution - No signature of method: build.android() is applicable for argument types: (build_run_closure1) values: [build_run_closure1@x
I have a capacitor app and I'm trying to implement the Firebase Distribution with Gradle (https://firebase.google.com/docs/app-distribution/android/distribute-gradle?authuser=1&apptype=aab) but I'm stuck at this error:

```<code>No signature of method: build_clqfykx9rkn9m9ygw4eh6w1bu.android() is applicable for argument types: (build_clqfykx9rkn9m9ygw4eh6w1bu$_run_closure1) values: [build_clqfykx9rkn9m9ygw4eh6w1bu$_run_closure1@60526ded]
</code>```

I've did all the steps of the process and my build.gradle files look like this:

build.gradle:

```<code>// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {

    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.2.1'
        classpath 'com.google.gms:google-services:4.3.5'

        // Add the App Distribution Gradle plugin
        classpath 'com.google.firebase:firebase-appdistribution-gradle:2.2.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

apply from: "variables.gradle"

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

</code>```

app/build.gradle:

```<code>apply plugin: 'com.android.application'

// Apply the App Distribution Gradle plugin
apply plugin: 'com.google.firebase.appdistribution'

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    defaultConfig {
        applicationId "com.some.app"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 1
        versionName project.hasProperty('version') ? version : '1.0.0'
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        aaptOptions {
             // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
             // Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
            ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
        }
    }
    flavorDimensions "environment"
    productFlavors {
        appA {
            dimension "environment"
            manifestPlaceholders = [displayName:"App A"]
        }
        appB {
            dimension "environment"
            applicationIdSuffix ".amigdala"
            manifestPlaceholders = [displayName:"App B"]
        }
    }
    signingConfigs {
        release {
            storeFile file("app-keystore.jks")
            storePassword System.getenv("KSTOREPWD")
            keyAlias "mykey"
            keyPassword System.getenv("KEYPWD")
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
            // https://firebase.google.com/docs/app-distribution/android/distribute-gradle?authuser=1&apptype=aab
            firebaseAppDistribution {
                serviceCredentialsFile "./service-account-key-distribution.json"
                artifactType "AAB"
                archivePath System.getenv("ARCHIVE_PATH")
                releaseNotes "Change this before releasing in production!"
            }
        }
    }
}

repositories {
    flatDir{
        dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
    }
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
    implementation project(':capacitor-android')
    testImplementation "junit:junit:$junitVersion"
    androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
    androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
    implementation project(':capacitor-cordova-android-plugins')
}

apply from: 'capacitor.build.gradle'

try {
    def servicesJSON = file('google-services.json')
    if (servicesJSON.text) {
        apply plugin: 'com.google.gms.google-services'
    }
} catch(Exception e) {
    logger.warn("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
}
</code>```

of course, everything worked until I added this part:

```<code> // https://firebase.google.com/docs/app-distribution/android/distribute-gradle?authuser=1&apptype=aab
            firebaseAppDistribution {
                serviceCredentialsFile "./service-account-key-distribution.json"
                artifactType "AAB"
                archivePath System.getenv("ARCHIVE_PATH")
                releaseNotes "Change this before releasing in production!"
            }
</code>```

I'm very new at modifying build.gradle files so I guess is sometihng syntax related but I can't figure it out. Even if I make small changes like artifactType "AAB" -> artifactType="AAB" I keep bouncing from this error to this one: Task 'appDistributionUploadRelease' not found in root project 'android'.

Any help or leads will be apreciated, thank you.

答: No signature for method : build.android... Seams to appear when there's something wrong with you Gradle configuration, like missing properties in the firebaseAppDistribution property or wrong file paths. Once I fixed that i had the Task 'appDistributionUploadRelease' not found in root project 'android' problem, which I solved (by pure luck) changing the appDistributionUploadRelease command for appDistributionUploadAppARelease. It seems the task doesn't have a generic command and the flavour must be specified.</p>

Body:
I have a capacitor app and I'm trying to implement the Firebase Distribution with Gradle (https://firebase.google.com/docs/app-distribution/android/distribute-gradle?authuser=1&apptype=aab) but I'm stuck at this error:

No signature of method: build_clqfykx9rkn9m9ygw4eh6w1bu.android() is applicable for argument types: (build_clqfykx9rkn9m9ygw4eh6w1bu$_run_closure1) values: [build_clqfykx9rkn9m9ygw4eh6w1bu$_run_closure1@60526ded]

I've did all the steps of the process and my build.gradle files look like this:

build.gradle:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {

    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.2.1'
        classpath 'com.google.gms:google-services:4.3.5'

        // Add the App Distribution Gradle plugin
        classpath 'com.google.firebase:firebase-appdistribution-gradle:2.2.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

apply from: "variables.gradle"

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

app/build.gradle:

apply plugin: 'com.android.application'

// Apply the App Distribution Gradle plugin
apply plugin: 'com.google.firebase.appdistribution'

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    defaultConfig {
        applicationId "com.some.app"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 1
        versionName project.hasProperty('version') ? version : '1.0.0'
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        aaptOptions {
             // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
             // Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
            ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
        }
    }
    flavorDimensions "environment"
    productFlavors {
        appA {
            dimension "environment"
            manifestPlaceholders = [displayName:"App A"]
        }
        appB {
            dimension "environment"
            applicationIdSuffix ".amigdala"
            manifestPlaceholders = [displayName:"App B"]
        }
    }
    signingConfigs {
        release {
            storeFile file("app-keystore.jks")
            storePassword System.getenv("KSTOREPWD")
            keyAlias "mykey"
            keyPassword System.getenv("KEYPWD")
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
            // https://firebase.google.com/docs/app-distribution/android/distribute-gradle?authuser=1&apptype=aab
            firebaseAppDistribution {
                serviceCredentialsFile "./service-account-key-distribution.json"
                artifactType "AAB"
                archivePath System.getenv("ARCHIVE_PATH")
                releaseNotes "Change this before releasing in production!"
            }
        }
    }
}

repositories {
    flatDir{
        dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
    }
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
    implementation project(':capacitor-android')
    testImplementation "junit:junit:$junitVersion"
    androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
    androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
    implementation project(':capacitor-cordova-android-plugins')
}

apply from: 'capacitor.build.gradle'

try {
    def servicesJSON = file('google-services.json')
    if (servicesJSON.text) {
        apply plugin: 'com.google.gms.google-services'
    }
} catch(Exception e) {
    logger.warn("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
}

of course, everything worked until I added this part:

 // https://firebase.google.com/docs/app-distribution/android/distribute-gradle?authuser=1&apptype=aab
            firebaseAppDistribution {
                serviceCredentialsFile "./service-account-key-distribution.json"
                artifactType "AAB"
                archivePath System.getenv("ARCHIVE_PATH")
                releaseNotes "Change this before releasing in production!"
            }

I'm very new at modifying build.gradle files so I guess is sometihng syntax related but I can't figure it out. Even if I make small changes like artifactType "AAB" -> artifactType="AAB" I keep bouncing from this error to this one: Task 'appDistributionUploadRelease' not found in root project 'android'.

Any help or leads will be apreciated, thank you.


问:
Java not found error when loading Apache Netbeans 9.0 or 10
I downloaded the archive for the program, unzipped it to C drive on Windows, then when I try to run either executable (32bit/64bit) in the bin folder I get the error message:

Cannot find JAVA 1.8 or higher.

in spite of Java 10 (JRE) being already installed. I also tried Installing Java 9 but was stuck with the same message.

I appreciate your help with this, Thanks.

答:
I experienced the issue after I updated Java and the version changed but the netbean.conf had the older version which is invalid.

The remedy is go into that file via notepad, or any text editor and then update the path with the correct version number, i.e. netbeans_jdkhome="C:\Program Files\Java\jre1.8.0_311".

You would go determined your latest Java edition, by pulling up the Java control panel and then hit the middle "Java" tab, hit "View" to see the current version you have installed.


问:
Joomla 1.6 Upload file field in article manager
I wanted to add pdf file in my articles. I have added a custom form field with type="file" in the article manager by hacking the xml and artical.php file in administrator/component/com_content directory.

But I am not able to save the uploaded files on server. What causes this?

Also I used the field type="Media" but it does not display pdf files?

答:
I had a requirement a while back where with every articles they wanted to be able to attach files for download. The trouble was that the end user had to be able to do this and they were not very tech savvy. I used this Joomla attachment extension and it has worked like a charm. I would recommend it.

In your case I would check the directory where the files are being uploaded, see if it has permissions that would allow files to be uploaded. Can you upload images fine and attach them in an article?

Update
This attachment does not work with Joomla 1.6+, the developers do have a plugin that is in Release Candidate stage that you can use.


答:
I will list all the noticeable problems in your query

"locations" array seems to be a part of another object

All elements of "locations" array are of type String hence the locations[i].location_id would not work as the "dot" operator expects an object

Suggestions

Make sure "locations" is an array of objects which is properly formatted for eg:

```<code>let locations = [
    { location_id: 1, location_name: 'Main office'},
    { location_id: 2, location_name: 'any name' },
];
</code>```

Title: Javascript - Error when accessing an associative array value

Body:
I will list all the noticeable problems in your query

"locations" array seems to be a part of another object

All elements of "locations" array are of type String hence the locations[i].location_id would not work as the "dot" operator expects an object

Suggestions

Make sure "locations" is an array of objects which is properly formatted for eg:

let locations = [
    { location_id: 1, location_name: 'Main office'},
    { location_id: 2, location_name: 'any name' },
];


问:
Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value - ASP.NET
How to properly deserialize POST method "Update" while developing Telegram bot in ASP.NET Core Web API by using Telegram.Bot package?
I used DeserializeObject(string) method to do so, but it keeps returning the error: Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value

Code:

```<code>using Microsoft.AspNetCore.Mvc;
using Telegram.Bot;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using Telegram.Bot.Types.ReplyMarkups;
using Newtonsoft.Json;

namespace OfficeBooking.TelegramApi.Controllers
{
    [ApiController]
    [Route(template: "api/message")]
    public class TelegramBotController : ControllerBase
    {
        private readonly TelegramBotClient _telegramBotClient;

        public TelegramBotController(TelegramBot telegramBot)
        {
            _telegramBotClient = telegramBot.GetBot().Result;
        }

        [HttpPost]
        public async Task <IActionResult> Update([FromBody]object update)
        {
            var upd = JsonConvert.DeserializeObject<Update>(update.ToString());
            var chat = upd.Message?.Chat;

            if (chat == null)
            {
                return Ok();
            }

            await _telegramBotClient.SendTextMessageAsync(
                    chatId: chat.Id,
                    text: "Testing sendMessage method",
                    parseMode: ParseMode.MarkdownV2,
                    disableNotification: false,
                    replyMarkup: new InlineKeyboardMarkup(
                        InlineKeyboardButton.WithUrl(
                            "Check sendMessage method",
                            "https://core.telegram.org/bots/api#sendmessage")));

            return Ok();
        }
    }
}
</code>```

答:
I think you should try to lean on ASP.NET Core to parse your json input. You can simply specify type Update instead of object and it will do the rest for you. You just need to use ready object with type Update:

        [HttpPost]
        public async Task <IActionResult> Update([FromBody]Update update)
        {
            var chat = update.Message?.Chat;

            if (chat == null)
            {
                return Ok();
            }

            await _telegramBotClient.SendTextMessageAsync(
                    chatId: chat.Id,
                    text: "Testing sendMessage method",
                    parseMode: ParseMode.MarkdownV2,
                    disableNotification: false,
                    replyMarkup: new InlineKeyboardMarkup(
                        InlineKeyboardButton.WithUrl(
                            "Check sendMessage method",
                            "https://core.telegram.org/bots/api#sendmessage")));

            return Ok();
        }
```

If you want framework to use NewtonsoftJson instead of default Json Utility (which is not necessary in your case), please follow this instructions https://dotnetcoretutorials.com/2019/12/19/using-newtonsoft-json-in-net-core-3-projects/

Body:
How to properly deserialize POST method "Update" while developing Telegram bot in ASP.NET Core Web API by using Telegram.Bot package?
I used DeserializeObject(string) method to do so, but it keeps returning the error: Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value

Code:

using Microsoft.AspNetCore.Mvc;
using Telegram.Bot;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using Telegram.Bot.Types.ReplyMarkups;
using Newtonsoft.Json;

namespace OfficeBooking.TelegramApi.Controllers
{
    [ApiController]
    [Route(template: "api/message")]
    public class TelegramBotController : ControllerBase
    {
        private readonly TelegramBotClient _telegramBotClient;

        public TelegramBotController(TelegramBot telegramBot)
        {
            _telegramBotClient = telegramBot.GetBot().Result;
        }

        [HttpPost]
        public async Task <IActionResult> Update([FromBody]object update)
        {
            var upd = JsonConvert.DeserializeObject<Update>(update.ToString());
            var chat = upd.Message?.Chat;

            if (chat == null)
            {
                return Ok();
            }

            await _telegramBotClient.SendTextMessageAsync(
                    chatId: chat.Id,
                    text: "Testing sendMessage method",
                    parseMode: ParseMode.MarkdownV2,
                    disableNotification: false,
                    replyMarkup: new InlineKeyboardMarkup(
                        InlineKeyboardButton.WithUrl(
                            "Check sendMessage method",
                            "https://core.telegram.org/bots/api#sendmessage")));

            return Ok();
        }
    }
}

Body:
I think you should try to lean on ASP.NET Core to parse your json input. You can simply specify type Update instead of object and it will do the rest for you. You just need to use ready object with type Update:

        [HttpPost]
        public async Task <IActionResult> Update([FromBody]Update update)
        {
            var chat = update.Message?.Chat;

            if (chat == null)
            {
                return Ok();
            }

            await _telegramBotClient.SendTextMessageAsync(
                    chatId: chat.Id,
                    text: "Testing sendMessage method",
                    parseMode: ParseMode.MarkdownV2,
                    disableNotification: false,
                    replyMarkup: new InlineKeyboardMarkup(
                        InlineKeyboardButton.WithUrl(
                            "Check sendMessage method",
                            "https://core.telegram.org/bots/api#sendmessage")));

            return Ok();
        }

If you want framework to use NewtonsoftJson instead of default Json Utility (which is not necessary in your case), please follow this instructions https://dotnetcoretutorials.com/2019/12/19/using-newtonsoft-json-in-net-core-3-projects/


问:
Working with difficult AM/PM formats and REGEX with lubridate in R
Hello guys I hope everyone is having a good one, I am trying to work with some AM/PM formats in lubridate on R but I cant seem to come up with a proper solution I hope you guys can correct meand help me out please!

I have a HUGE dataset that has date_time formats in a very rare way the format goes as follow:

First a number that represents the day, second an abbreviation of the month OR even the month fully spelled out a 12H time format and the strings " a. m." OR "p. m." or even a combination of more spaces between or missing "dots" then such as "a.  m"  to set an example please take a look at this vector:

```<code>dates<-c("02 dec 05:47 a. m",
"7 November 09:47 p. m.",
"3  jul 12:28 a.m.",
"23 sept 08:53 a m.",
"7 may 09:05 PM")
</code>```

These make up for more than 95% of the rare formats of datetime in the data set I have been trying to use lubridate on R I am trying to use the function

```<code>ydm_hm(paste(2021,dates))
</code>```

this is because all dates are form 2021 but I get always:

```<code>[1] NA                        NA                        NA
[4] NA                        "2021-05-07 21:05:00 UTC"
Warning message:
 4 failed to parse.
</code>```

the 4 that fail to parse give me NAS and the only one that parses is correct I do notice that this one has PM or AM as uppercase letters without dots but most of the time my formats will be like this:

```<code>ydm_hm("7 may 09:05 p.m.")
</code>```

and this gives me NAS...

So I feel as though the only way to get this dates to workout is to change the structure and using REGEX so convert all "a. m." combinations into "AM" and "PM" only after analyzing the data I realized all "p.m" or "a. m." strings come after ONE or TWO spaces after the 12H time format that always have a length of 5 characters and so what should be considered to come up with the patter of the REGEX is the following

the string will begins with one or two numbers then spaces and then letters (for the month abbreviated or fully spelled out after that will have spaces and then 5 characters (that's the 12H time format) and then will have letters spaces and dots for all possible a.m and p.m formats but I have tried with no luck to convert the structure of the date.. if you guys could help me I will be so freaking thankful I dont know if there is a way or another package in R that will even resolve this issue without using regex so thank you everyone for your help !

my desired output will be:

```<code>"2021-12-02 05;47:00 UTC"
"2021-11-07 09:47:00 UTC"
"2021-07-03 12:28:00 UTC"
"2021-09-23 08:53:00 UTC"
"2021-05-07 21:05:00 UTC"
</code>```

Body:
Hello guys I hope everyone is having a good one, I am trying to work with some AM/PM formats in lubridate on R but I cant seem to come up with a proper solution I hope you guys can correct meand help me out please!

I have a HUGE dataset that has date_time formats in a very rare way the format goes as follow:

First a number that represents the day, second an abbreviation of the month OR even the month fully spelled out a 12H time format and the strings " a. m." OR "p. m." or even a combination of more spaces between or missing "dots" then such as "a.  m"  to set an example please take a look at this vector:

dates<-c("02 dec 05:47 a. m",
"7 November 09:47 p. m.",
"3  jul 12:28 a.m.",
"23 sept 08:53 a m.",
"7 may 09:05 PM")

These make up for more than 95% of the rare formats of datetime in the data set I have been trying to use lubridate on R I am trying to use the function

ydm_hm(paste(2021,dates))

this is because all dates are form 2021 but I get always:

[1] NA                        NA                        NA
[4] NA                        "2021-05-07 21:05:00 UTC"
Warning message:
 4 failed to parse.

the 4 that fail to parse give me NAS and the only one that parses is correct I do notice that this one has PM or AM as uppercase letters without dots but most of the time my formats will be like this:

ydm_hm("7 may 09:05 p.m.")

and this gives me NAS...

So I feel as though the only way to get this dates to workout is to change the structure and using REGEX so convert all "a. m." combinations into "AM" and "PM" only after analyzing the data I realized all "p.m" or "a. m." strings come after ONE or TWO spaces after the 12H time format that always have a length of 5 characters and so what should be considered to come up with the patter of the REGEX is the following

the string will begins with one or two numbers then spaces and then letters (for the month abbreviated or fully spelled out after that will have spaces and then 5 characters (that's the 12H time format) and then will have letters spaces and dots for all possible a.m and p.m formats but I have tried with no luck to convert the structure of the date.. if you guys could help me I will be so freaking thankful I dont know if there is a way or another package in R that will even resolve this issue without using regex so thank you everyone for your help !

my desired output will be:

"2021-12-02 05;47:00 UTC"
"2021-11-07 09:47:00 UTC"
"2021-07-03 12:28:00 UTC"
"2021-09-23 08:53:00 UTC"
"2021-05-07 21:05:00 UTC"

Body:
In this case, parse_date from parsedate works

library(parsedate)
parse_date(paste(2021, dates))

-output

[1] "2021-12-02 05:47:00 UTC"
[2] "2021-11-07 09:47:00 UTC"
[3] "2021-07-03 12:28:00 UTC"
[4] "2021-09-23 08:53:00 UTC"
[5] "2021-05-07 21:05:00 UTC"

Or if the second value should be PM, use str_remove to remove the space

library(stringr)
parse_date(paste(2021, str_remove_all(dates,
    "(?<=[A-Za-z])[. ]+(?=[A-Za-z])")))
[1] "2021-12-02 05:47:00 UTC"
[2] "2021-11-07 21:47:00 UTC"
[3] "2021-07-03 00:28:00 UTC"
[4] "2021-09-23 08:53:00 UTC"
[5] "2021-05-07 21:05:00 UTC"

With ydm_hm, the issue is that one of the am/pm format showed spaces without the . and this may not get parsed.  We could change the format by removing the spaces

library(lubridate)
library(stringr)
ydm_hm(paste(2021, str_remove_all(dates,
    "(?<=[A-Za-z])[. ]+(?=[A-Za-z])")))
[1] "2021-12-02 05:47:00 UTC"
[2] "2021-11-07 21:47:00 UTC"
[3] "2021-07-03 00:28:00 UTC"
[4] "2021-09-23 08:53:00 UTC"
[5] "2021-05-07 21:05:00 UTC"


问:
exception handling attempt in pandas
I am having difficulty creating two columns, "Home Score" and "Away Score", in the wikipedia table I am trying to parse.

I tried the following script with two try-except-else statements to see if that would work.

```<code>test_matches = pd.read_html('https://en.wikipedia.org/wiki/List_of_Wales_national_rugby_union_team_results')

test_matches = test_matches[1]

test_matches['Year'] = test_matches['Date'].str[-4:].apply(pd.to_numeric)
test_matches_worst = test_matches[(test_matches['Winner'] != 'Wales') & (test_matches['Year'] >= 2007) & (test_matches['Competition'].str.contains('Nations'))]

try:
  test_matches_worst['Home Score'] = test_matches_worst['Score'].str.split("–").str[0].apply(pd.to_numeric)
except:
  print("let's try again")
else:
  test_matches_worst['Home Score'] = test_matches_worst['Score'].str.split("-").str[0].apply(pd.to_numeric)

try:
  test_matches_worst['Away Score'] = test_matches_worst['Score'].str.split("–").str[1].apply(pd.to_numeric)
except:
  print("let's try again")
else:
  test_matches_worst['Away Score'] = test_matches_worst['Score'].str.split("-").str[1].apply(pd.to_numeric)

test_matches_worst['Margin'] = (test_matches_worst['Home Score'] - test_matches_worst['Away Score']).abs()

test_matches_worst.sort_values('Margin', ascending=False).reset_index(drop = True)#.head(20)
</code>```

However, I would receive a Key error message and the "Home Score" is not displayed in the dataframe when shortening the code. What is the best way to handle this particular table and to generate the columns that I want? Any assistance on this would be greatly appreciated. Thanks in advance.

答:
The problem of the data you collect is the hyphen or dash. Except the last row, all score separator are the 'En Dash' (U+2013) and not the 'Hyphen' (U+002D):

```<code>sep = r'[-\u2013]'

# df is test_matches_worst
df[['Home Score','Away Score']] = df['Score'].str.split(sep, expand=True).astype(int)
df['Margin'] = df['Home Score'].sub(df['Away Score']).abs
</code>```

Output:

```<code>>>> df[['Score', 'Home Score', 'Away Score', 'Margin']]
     Score  Home Score  Away Score  Margin
565   9–19           9          19      10
566   21–9          21           9      12
567  32–21          32          21      11
568  23–20          23          20       3
593  21–16          21          16       5
595  15–17          15          17       2
602  30–17          30          17      13
604  20–26          20          26       6
605  27–12          27          12      15
614  19–26          19          26       7
618   28–9          28           9      19
644  22–30          22          30       8
656   26–3          26           3      23
658  29–18          29          18      11
666  16–21          16          21       5
679  16–16          16          16       0
682  25–21          25          21       4
693  16–21          16          21       5
694  29–13          29          13      16
696  20–18          20          18       2
704   12–6          12           6       6
705  37–27          37          27      10
732  24–14          24          14      10
733  23–27          23          27       4
734  33–30          33          30       3
736  10–14          10          14       4
737   32–9          32           9      23
739  13–24          13          24      11
745  32–30          32          30       2
753   29-7          29           7      22
</code>```

Note: you will probably receive a SettingWithCopyWarning

To solve it, use test_matches = test_matches[1].copy()

Bonus

Pandas function like to_datetime, to_timedelta or to_numeric can take a Series as parameter so you can avoid apply:

```<code>test_matches['Year'] = pd.to_numeric(test_matches['Date'].str[-4:])
</code>```

Title: exception handling attempt in pandas

Body:
I am having difficulty creating two columns, "Home Score" and "Away Score", in the wikipedia table I am trying to parse.

I tried the following script with two try-except-else statements to see if that would work.

test_matches = pd.read_html('https://en.wikipedia.org/wiki/List_of_Wales_national_rugby_union_team_results')

test_matches = test_matches[1]

test_matches['Year'] = test_matches['Date'].str[-4:].apply(pd.to_numeric)
test_matches_worst = test_matches[(test_matches['Winner'] != 'Wales') & (test_matches['Year'] >= 2007) & (test_matches['Competition'].str.contains('Nations'))]

try:
  test_matches_worst['Home Score'] = test_matches_worst['Score'].str.split("–").str[0].apply(pd.to_numeric)
except:
  print("let's try again")
else:
  test_matches_worst['Home Score'] = test_matches_worst['Score'].str.split("-").str[0].apply(pd.to_numeric)

try:
  test_matches_worst['Away Score'] = test_matches_worst['Score'].str.split("–").str[1].apply(pd.to_numeric)
except:
  print("let's try again")
else:
  test_matches_worst['Away Score'] = test_matches_worst['Score'].str.split("-").str[1].apply(pd.to_numeric)

test_matches_worst['Margin'] = (test_matches_worst['Home Score'] - test_matches_worst['Away Score']).abs()

test_matches_worst.sort_values('Margin', ascending=False).reset_index(drop = True)#.head(20)

However, I would receive a Key error message and the "Home Score" is not displayed in the dataframe when shortening the code. What is the best way to handle this particular table and to generate the columns that I want? Any assistance on this would be greatly appreciated. Thanks in advance.

Body:
The problem of the data you collect is the hyphen or dash. Except the last row, all score separator are the 'En Dash' (U+2013) and not the 'Hyphen' (U+002D):

sep = r'[-\u2013]'

# df is test_matches_worst
df[['Home Score','Away Score']] = df['Score'].str.split(sep, expand=True).astype(int)
df['Margin'] = df['Home Score'].sub(df['Away Score']).abs

Output:

>>> df[['Score', 'Home Score', 'Away Score', 'Margin']]
     Score  Home Score  Away Score  Margin
565   9–19           9          19      10
566   21–9          21           9      12
567  32–21          32          21      11
568  23–20          23          20       3
593  21–16          21          16       5
595  15–17          15          17       2
602  30–17          30          17      13
604  20–26          20          26       6
605  27–12          27          12      15
614  19–26          19          26       7
618   28–9          28           9      19
644  22–30          22          30       8
656   26–3          26           3      23
658  29–18          29          18      11
666  16–21          16          21       5
679  16–16          16          16       0
682  25–21          25          21       4
693  16–21          16          21       5
694  29–13          29          13      16
696  20–18          20          18       2
704   12–6          12           6       6
705  37–27          37          27      10
732  24–14          24          14      10
733  23–27          23          27       4
734  33–30          33          30       3
736  10–14          10          14       4
737   32–9          32           9      23
739  13–24          13          24      11
745  32–30          32          30       2
753   29-7          29           7      22

Note: you will probably receive a SettingWithCopyWarning

To solve it, use test_matches = test_matches[1].copy()

Bonus

Pandas function like to_datetime, to_timedelta or to_numeric can take a Series as parameter so you can avoid apply:

test_matches['Year'] = pd.to_numeric(test_matches['Date'].str[-4:])