ááŒá¿áá¬áá áºáá¯ááŸáááẠ- áááá¯áá»á¯ááºááá¯ááºááŸá¯áá»áŸá±á¬á·áá»áá¬ážáá±á¬ááœááºáááºáá áºáá¯ááœáẠáá»áááºážáá¶áá«ááºáá áºáá¯áá¯ááºáá±ážááẠáááºáá²áááºá blockchains á¡á¬ážáá¯á¶ážáá®ážáá«ážá áá«ááᯠááŒá¯á¶áá°ážááŒá®ážáá¬ážáá«á á¡ááŸááºááááºáááºá áá¯á¶ážá áœá²áá°áá»á¬ážá¡ááŒá¬áž áá¯á¶ááŒááºááŸá¯áááŸááá±á¬ ááœááºáááºáá»á¬ážááœáẠááŒááºážááá¯á·ááááá¯ááºáá±á¬ áá»áááºážáá¶áá«ááºáá áºáᯠáááºáá®ážááŒááºážá ááŒá¿áá¬áá»á¬ážá áœá¬ááᯠááŒá±ááŸááºážáá±ážáá«áááºá
á€áá±á¬ááºážáá«ážááœáẠá¥ááá¬áá
áºáá¯á¡áá±ááŒáá·áº ááááºážáá»á¬ážááá¯á¡áá¯á¶ážááŒá¯á ááŒá¿áá¬ááá¯ááŒá±ááŸááºážááá¯ááºáá¯á¶ááᯠááŒá±á¬ááŒáá«áááºá áá°ááá¯á·áá²á ááááá¯á¶ážááŒá
áºáá²á·áááºá
á¡á
ááá¯ááºážááœááºá áá»áœááºá¯ááºááá¯á·ááẠblockchain ááŸá¡áá»ááºá¡áááºáá»á¬ážá¡áá±á«áºá¡ááŒá±áá¶á áá¶áá«ááºáá
áºáá¯ááá¯áá¯ááºáá¯ááºáááºá
á®á
ááºáá²á·áááºá ááá¯á·áá±á¬áºá ááá¯á·áá±á¬ááºááœáẠááŸááºážááŸááºážáááºážáááºážááŒá
áºáá¬áááº- á¡áá±á¡ááœááºááᯠááŒááºááŸááºááá¯ááºáááºá ááá¯ááá¯áááºááŸá¬ ááŒá±ááŸááºážáá»ááºááẠáááá·áºáá»á±á¬áºáá±á
áá»áœááºá¯ááºááá¯á·ááẠááŒá±ááŸááºážáá»ááºáá
áºáᯠááœááºáá±á«áºáá¬áááº- commit-expand á¡á
á®á¡á
ááºááᯠá¡áá¯á¶ážááŒá¯áá«á áá¬áá¬ááẠáá¶áá«ááºáá
áºáá¯ááᯠ1 á០5 á¡áá ááá·áºááŸááºážááŒá®áž áá¬ážáá
áºáá¯ááá·áºáᬠááááºááᯠá¡áá¯á¶ážááŒá¯á áááºááºáá¯ááºáááºá
áá á¬ážááá¬ážááẠá¡áá±á¬ááºážá¡á á¬ážáá áºáá¯ááŒá¯áá¯ááºááŒá®áž áá¬áá¬á០áá»áŸáá¯á·ááŸááºáá¶áá«ááºááŸáá·áº âáá¬ážâ ááᯠá áááºá á¬áá»á¯ááºááá¯á· áá±ážááá¯á·áá²á·áááºá ááá¯ážááá¯ážááŸááºážááŸááºážááŒá±á¬áááẠáá°á áááºááœá±ááᯠáá¯ááºááŒáááºá ááá¯á·áá±á¬áẠáá¬áá¬ááẠáá¶áá«ááºáá»á¬ážááᯠá á áºáá±ážááŒá®áž á¡áá¯á¶ážááŒá¯áá° á¡ááá¯ááºáááẠááá¯á·ááá¯áẠááŸá¯á¶ážááŒááºážááŸááááŸá áá¯á¶ážááŒááºáá²á·áááºá
á¡áááºá áá¬áá¬ááẠáá¶áá«áẠááá¯á·ááá¯áẠ"áá¬áž" ááᯠá¡áááºááŒá¯ááẠááá±ážááá¯á·áá«áá á¡áá¯á¶ážááŒá¯áá° á¡ááá¯ááºááá²á·áááºá á€ááá á¹á ááœááºá ááááºážáá áºáá¯á á®á¡ááœáẠá áááºá á¬áá»á¯ááºáá áºáá¯ááᯠááŒáá¯áááºááá·áºááœááºážáá¬ážáááºááŸáá·áº áááºážááœáẠááŒá áºááá¯ááºáá»á±ááŸááá±á¬ á¡ááá¯ááºáááŸá¯áá»á¬ážááᯠááá·áºááœááºážááẠááá¯á¡ááºáá«áááºá á¡áááºáááŒá±á á¡áá»áááºáá¯ááºááŒá®áž á á»á±ážááŒá®ážáᬠááŒá áºááœá¬ážáááºá á¡á²áá®áá¯ááºážá áááŒá¬áž áá±ážáááºážáá²á· ááŒá±ááŸááºážáá»áẠáááŸááá°ážá
áááŒá¬áá±ážáá®áá Tradisys á¡ááœá²á·ááẠWaves áááá¯ááá¯áá±á¬ááœáẠáá¯ááºáá±á¬ááºáá»ááºáá áºáá¯ááᯠááá·áºááœááºážááẠá¡ááá¯ááŒá¯áá²á·áááºá rsaVerify(). áááºážááẠá¡áá»á¬ážáá°ááŸá¬ááŸáá·áº áá¯áá¹áááááá±á¬á·á¡áá±á«áºá¡ááŒá±áá¶á RSA áááºááŸááºáááá¬ážáááºááŸá¯ááᯠá á áºáá±ážáááºá ááááºá¡áá±ááŒáá·áº feature ááá¯ááá·áºááœááºážáá²á·áááºá
áá»áœááºá¯ááºááá¯á·ááẠááááºážáá¯á¶ážáá¯ááᯠáá®ááœááºáá²á·áááºá
á¥ááá¬áá
áºáá¯á¡áá±áá²á· Ride on Waves ááá¯áá¯á¶ážááŒá®áž áá»áááºážáá¶áá«ááºáá
áºáá¯áá¯ááºáá±ážáá¬ááᯠááŒáá·áºááŒáá¡á±á¬ááºá áááºááŒááºáá±á¬ á
á¬áá»á¯ááºááᯠááœá±á·ááŸáááá¯ááºáááºá
á¡ááá¯áá« tab ááá¯ááœá¬ážááŒá®áž script ááŸáá·áºááœá±ážáá»ááºáá« ááŒáá¯ááœá²ááœá¬ážáááºá. á áááºá á¬áá»á¯ááºáá¯áẠ(aka script) ááᯠáááºááœá±á·ááá«áááºá
á
áááºá
á¬áá»á¯ááºáá¯ááºááœáẠáá¯ááºáá±á¬ááºáá»ááºá¡á
á¯á¶áá«ááŸááááºá @Callable á¡ááŒá
Ạá¡ááŸááºá¡áá¬ážááŒá¯áá¬ážááá·áºá¡áá¬áá»á¬ážááᯠá¡áá¯á¶ážááŒá¯á á
áááºááá¯ááºáá«áááºá ááááºáá±á«áºááŸá¯ á¡áá±á¬ááºážá¡áááºáá»á¬áž. áá»áœááºá¯ááºááá¯á·ááẠáá¯ááºáá±á¬ááºáá»ááºááŸá
áºáá¯ááᯠá
áááºáááºá
á¬ážáá«áááºá áá±á¬ááºážáá
á¬áž О áá¯ááºááááºážáá±ážáááº:
- func á¡áá±á¬ááºážá¡á á¬áž (playerChoice)
- func áá¯ááºááááºážááŒááºáž(gameIdársaSign)
1. á¡áá¯á¶ážááŒá¯áá°ááẠá¡ááá¯ááºážáá¡ááŸááºááŸáá·áº á¡áá±á¬ááºážá¡á á¬ážá¡ááœááºá¡á á¬ážááᯠááœá±ážáá»ááºáááºá
2. client ááẠá¡áá±á¬ááºážá¡á
á¬ážáá¯ááºáá±á¬ááºáá»ááºááᯠáááºáá®ážáááºá á¡áá±á«áºááá¯á¶áá±ážá¡ááœááºááá±á¬á· ááŒá
áºááŸá¬áá«á á¡áá±á¬ááºážá¡á
á¬áž ("50").
3. áá±á¬ááºáááºááẠá áááºá á¬áá»á¯ááºááááºá ᬠ(á¡áá¶ááœáŸáá·áº InvocationTx) ááá¯á· Invocation ááœáŸá²ááŒá±á¬ááºážáá±ážáááºá ááœá±áá±ážááœá±áá°ááœáẠáá±á«áºááá¯ááŸá¯ááá·áºáááºáá»ááºáá áºáá¯á¡ááŒá Ạá¡áá±á¬ááºážá¡á á¬ážáá¯ááºáá±á¬ááºáá»ááºáá«ááŸááááºá ááá¯ááá¯áááºááŸá¬ Invocation ááœá±áá±ážááœá±áá°ááẠá áááºáááºáááá¯ááºááœáẠá¡áá±á¬ááºážá¡á á¬ážáá¯ááºáá±á¬ááºáá»áẠ(ááœá±ážáá»ááºááŸá¯- á á¬áááºáž) ááᯠá áááºáá¯ááºáá±á¬ááºá á±áááºá
4. á¡áá±á¬ááºážá¡á
á¬ážáá¯ááºáá±á¬ááºáá»ááºááᯠááá·áºááœááºážá
ááºážá
á¬ážáá«-
@Callable(i)
func bet (playerChoice) = {
let newGameNum = IncrementGameNum()
let gameId = toBase58String(i.transactionId)
let pmt = extract(i.payment)
let betNotInWaves = isDefined(pmt.assetId)
let feeNotInWaves = isDefined(pmt.assetId)
let winAmt = ValidateBetAndDefineWinAmt(pmt.amount, playerChoice)
let txIdUsed = isDefined(getString(this, gameId))
if (betNotInWaves)
then throw ("Bet amount must be in Waves")
else if (feeNotInWaves)
then throw ("Transaction's fee must be in Waves")
else if (txIdUsed)
then throw ("Passed txId had been used before. Game aborted.")
else {
let playerPubKey58 = toBase58String(i.callerPublicKey)
let gameDataStr = FormatGameDataStr(STATESUBMITTED, playerChoice, playerPubKey58, height, winAmt, "")
ScriptResult(WriteSet(cons(DataEntry(RESERVATIONKEY, ValidateAndIncreaseReservedAmt(winAmt)), cons(DataEntry(GAMESCOUNTERKEY, newGameNum), cons(DataEntry(gameId, gameDataStr), nil)))), TransferSet(cons(ScriptTransfer(SERVER, COMMISSION, unit), nil)))
}
}
áá¯ááºáá±á¬ááºáá»ááºááẠá áááºáááºáááá¯ááºá¡ááŒá±á¡áá±ááá¯á· ááááºážá¡áá áºáá áºáá¯ááᯠáá±ážáá¬ážáááºá ááá¯ááá¯áááºááŸá¬-
- ááááºážá¡áá áºá¡ááœáẠáá®ážááá·áºá¡ááŸááºá¡áá¬áž (ááááºáž ID)
- ááááºážá¡ááŒá±á¡áá± = áááºááŒáá²á·áááºá
- áá á¬ážááá¬ážááœá±ážáá»ááºááŸá¯ (á¡ááá¯ááºážá¡ááŸáẠ50)
- á¡áá»á¬ážáá°ááŸá¬áá±á¬á·
- á¡áá¬ážá¡áá¬ááŸááá±á¬á¡ááá¯ááºáááŸá¯áá»á¬áž (áá á¬ážááá¬ážááá±á¬ááºážááŒá±ážá¡áá±á«áº áá°áááºá)
áááºážááẠblockchain ááŸá áá±áá¬ááŸááºáááºáž (áá±á¬á·áááºááá¯áž) ááŸáá·áºáá°áááºá
{
"type": "string",
"value": "03WON_0283_448t8Jn9P3717UnXFEVD5VWjfeGE5gBNeWg58H2aJeQEgJ_06574069_09116020000_0229",
"key": "2GKTX6NLTgUrE4iy9HtpSSHpZ3G8W4cMfdjyvvnc21dx"
}
"áá±á¬á·" (áá±á¬á·) â ááááºážá¡áá¯ááºáá® ááááºážá¡áá áºá áá»ááºáá±áá¬áá»á¬ážááᯠ"áááºááá¯áž" á¡ááœááºáááá¯ááºážááœáẠáá«ááŸááááºá á€á¡áá¬áá»á¬ážááᯠáááºááºááœáẠááááºážáááºážáá¬ážáááºá áá±áá¬áá»á¬áž á áááºá á¬áá»á¯ááº-
5. áá¬áá¬ááẠá
áááºá
á¬áá»á¯ááºááᯠâááŒáá·áºâ ááŒá®áž blockchain Api ááᯠá¡áá¯á¶ážááŒá¯á áá±ážááá¯á·áá¬ážáá±á¬ ááœá±áá±ážááœá±áá° (ááááºážá¡áá
áº) ááᯠááŸá¬ááœá±á·áááºá ááááºážá¡áá
áºá Game id ááᯠblockchain ááœáẠááŸááºáááºážáááºáá¬ážááŒá®ážááŒá
áºáááºá ááá¯ááá¯áááºááŸá¬ áááºážááẠááŒá±á¬ááºážáá²ááŒááºáž ááá¯á·ááá¯áẠááœáŸááºážááá¯ážááŸá¯áááŸááá±á¬á·áá«á
6. áá¬áá¬ááẠáá¯ááºááááºážááá·áºáá¯ááºáá±á¬ááºáá»áẠ(gameIdá rsaSign) ááá¯áá¯ááºáá±ážáááºá á¥ááá¬á á€áá²á·ááá¯á·áá±á¬á
withdraw ("FwsuaaShC6DMWdSWQ5osGWtYkVbTEZrsnxqDbVx5oUpq", "base64:Gy69dKdmXUEsAmUrpoWxDLTQOGj5/qO8COA+QjyPVYTAjxXYvEESJbSiCSBRRCOAliqCWwaS161nWqoTL/TltiIvw3nKyd4RJIBNSIgEWGM1tEtNwwnRwSVHs7ToNfZ2Dvk/GgPUqLFDSjnRQpTHdHUPj9mQ8erWw0r6cJXrzfcagKg3yY/0wJ6AyIrflR35mUCK4cO7KumdvC9Mx0hr/ojlHhN732nuG8ps4CUlRw3CkNjNIajBUlyKQwpBKmmiy3yJa/QM5PLxqdppmfFS9y0sxgSlfLOgZ51xRDYuS8NViOA7c1JssH48ZtDbBT5yqzRJXs3RnmZcMDr/q0x6Bg==")
7. áá¬áá¬ááẠá áááºá á¬áá»á¯áẠ(á¡áá¶ááœáŸáá·áº InvocationTx) ááá¯á· Invocation ááœáŸá²ááŒá±á¬ááºážááŸá¯áá áºáᯠáá±ážááá¯á·áááºá ááœá±áá±ážááœá±áá°ááœáẠááœá²á·á ááºážáá¬ážáá±á¬ áá¯ááºááááºážááá·áºáá¯ááºáá±á¬ááºáá»áẠ(gameIdá rsaSign) ááá¯á· áá±á«áºááá¯ááŸá¯áá«ááŸááááºá
áá¯ááºáá±á¬ááºáá»ááºáá«ááŸááááºá ááááºážá¡áá¯ááºáá® ááááºážá¡áá
áºááŸáá·áº RSA áá®ážááá·áºáá±á¬á·ááŒáá·áº áá°ážááŒá¬ážáá±á¬ identifier ááᯠáááºááŸááºááá¯ážááŒááºážá ááááºá áááºááŸááºááááºááẠáááŒá±á¬ááºážáá²áá«á
áá«áá¬áá¬ááá¯ááá¯ááá¯ááá²
áá»áœááºá¯ááºááá¯á·ááẠáá°áá®áá±á¬áááºááá¯áž (ááááºáž ID) ááá¯áá°á áááºážá¡ááœáẠRSA áááºááŸááºáááºážáááºážááᯠá¡áá¯á¶ážááŒá¯áá«á áá°áá®áá±á¬ááááºááᯠáá»áœááºá¯ááºááá¯á·á¡ááŒá²áááŸááááºááŒá áºáááºá áá«á RSA algorithm á¡áá¯ááºáá¯ááºáá¯á¶áá«á ááááºáž id ááŸáá·áº RSA áá»áŸá±á¬ááºáá¬ážááŒááºážáááááºááᯠááááá±á¬ááŒá±á¬áá·áº áá±á¬ááºáá¯á¶ážáá¶áá«ááºááᯠááŒááºááŸááºááááá«á áá¶áá«ááºáá áºáá¯ááœá±ážáá»ááºááŒááºážáááºáááºáž á¡áááá¹áá«ááºáááŸááá±á
8. Blockchain ááẠááœá±áá±ážááœá±áá°ááᯠáááºáá¶áááºá áááºážááẠáá¯ááºááááºážááá·áºáá¯ááºáá±á¬ááºáá»áẠ(gameIdá rsaSign) ááᯠáá¯ááºáá±á¬ááºáááºá
9. áá¯ááºááááºážááá·áºáá¯ááºáá±á¬ááºáá»ááºá¡ááœááºážááœááºá áá¯ááºááœá¬ááŸá¯ááŒá áºáá±á«áºáááºá RandInt áá¯ááºáá±á¬ááºáá»ááºáá»á¬ážááᯠáá¯ááºáá¯ááºáá«á (gameIdá rsaSign)á áááºážááẠáá»áááºážáá¶áá«áẠáá®ážá ááºáá áºáá¯ááŒá áºáááºá
# @return 1 ... 100
func GenerateRandInt (gameId,rsaSign) = {
# verify RSA signature to proof random
let rsaSigValid = rsaVerify (SHA256, toBytes(gameId), rsaSign, RSAPUBLIC)
if (rsaSigValid)
then {
let rand = (toInt(sha256(rsaSign)) % 100)
if ((0 > rand))
then ((-1 * rand) + 1)
else (rand + 1)
}
else throw ("Invalid RSA signature")
}
áá»áááºáž - áá»áááºážáá¶áá«ááºáá áºáá¯ááŸááá«áááºá
áááá RSA áááºááŸááºáááááºááŒá áºááá·áº string ááá¯áá°áááºá ááááºážá¡áá¯ááºáá® áá®ážááá·áºáá±á¬á· (rsaSign) ááá¯á·áá±á¬áẠSHA-256 (sha256(rsaSign)).
áááºááŸááºááŸáá·áº áá±á¬ááºáááºááœá² áááºááŒááºážá ááááºááᯠáá»áœááºá¯ááºááá¯á· áááá·áºááŸááºážááá¯ááºáá«á ááá¯á·ááŒá±á¬áá·áº áá»áááºážáá¶áá«ááºáá
áºáá¯á áá»áá¯ážáááºááᯠááœáŸááºážááá¯ážááẠáááŒá
áºááá¯ááºáá±á á¡áá»áá¯á·áá±á¬á¡ááœá¬á¡áá±ážáá
áºáá¯ááœáẠáá¶áá«ááºáá
áºáá¯áááŸáááẠ(á¥ááá¬á 1 á០100)á toInt ááŒá±á¬ááºážáá²ááŒááºážáá¯ááºáá±á¬ááºáá»ááºááŸáá·áº %100 (áááºáá°áááº) ááá¯áá¯á¶ážáá«á
áá±á¬ááºážáá«ážáá¡á ááœááºáá»áœááºá¯ááºááá¯á·ááẠfunction ááá¯áá±á¬áºááŒáá²á·áááºá rsaVerify()á¡áá»á¬ážáá°ááŸá¬ áá±á¬á·ááá¯á¡áá¯á¶ážááŒá¯á RSA áááºááŸááºáááá¬ážáááºááŸá¯ááᯠá á áºáá±ážááá¯ááºá á±ááá·áºá á€áááºááŸá¬ GenerateRandInt(gameIdársaSign) á¡ááá¯ááºážááŒá áºáááºá
rsaVerify (SHA256, toBytes(gameId), rsaSign, RSAPUBLIC)
á¡áá»á¬ážáá°ááŸá¬áá±á¬á· RSAPUBLIC ááŸáá·áº rsaSign string ááᯠinput ááá¯á·áá±ážááá¯á·áááºá áááºááŸááºááẠááá¬ážáááºááŸá¯ááŸááááŸá á á áºáá±ážáá¬ážáááºá á á áºáá±ážááŸá¯á¡á±á¬ááºááŒááºáá«á áá¶áá«ááºáá¯ááºáá±ážáááºááŒá áºáááºá ááá¯ááºáá«áá áááºááŸááºááẠáááŸááºáááºááŒá±á¬ááºáž (Invalid RSA áááºááŸááº) ááᯠá áá áºá áá°ááááºá
áá¬áá¬ááẠááááºážá¡áá¯ááºáá®ááᯠáá®ážááá·áºáá±á¬á·ááŒáá·áº áááºááŸááºáá±ážááá¯ážááŒá®áž áááá áá¯ááºááœááºá¡ááœááºáž ááá¬ážááẠRsa áááºááŸááºááᯠáá±ážááá¯á·ááááºááŒá áºáááºá á áááºá á¬áá»á¯ááºááᯠááŒáá·áºáá»ááºááá·áºá¡áá« ááá·áºáááºáá±á¬ááºááᯠááŒááºáááºáááºááŸááºáá¬ážáááºá áááºááŸááºáá¬ážáá±á¬á¡áá»áááºá¡ááœááºáž áá¬ááŸáááŒá áºáá«áá á¡áá¯á¶ážááŒá¯áá°á á¡ááá¯ááºááááºá á€ááá á¹á ááœááºá áá¯áááºáá±á¬ááºááᯠááá·áºááááºá á¬ááá¯á· ááá¯ááºááá¯ááºáá±ážááá¯á·ááá«áááºá áááºážááẠáá¯á¶ážááŸá¯á¶ážááŸá¯ááᯠááŒá áºá á±áá±á¬ááŒá±á¬áá·áº áááºážááẠ"áá¬áá¬ááᯠááááºáááºááŒááºážá¡ááœáẠá¡áá»áá¯ážáááŸáááá¯ááº" áá°á ááœááºáá±á«áºáá¬áááºá á¡á±á¬ááºááŸá¬ á¥ááá¬áá áºáá¯ááŒáá¬ážáá«áááºá
á¡áá¯á¶ážááŒá¯áá°ááẠáá
á¬ážáá±áááºá
ááááºážáá»á¬ážááœáẠáá¶áá«ááºáá»á¬ážáá¯ááºáá¯ááºáááºá áá»áœááºá¯ááºááá¯á·ááẠááŒááºáá blockchain ááá¯ááºáá±á¬ á áá áºáá áºáá¯ááŒá áºáá±á¬ oracle ááᯠá¡áá¯á¶ážááŒá¯áá«áááºá áá¬áá¬ááẠááááºáž ID á RSA áááºááŸááºááᯠáá¯ááºáá±á¬ááºáááºá á áááºá á¬áá»á¯ááºááẠáááºááŸááºáááá¬ážáááºááŸá¯ááᯠá á áºáá±ážááŒá®áž á¡ááá¯ááºááá°ááᯠáá¯á¶ážááŒááºáááºá áá¬áá¬á០áá áºá á¯á¶áá áºáᬠááá±ážááá¯á·áá«á á¡áá¯á¶ážááŒá¯áá°ááẠá¡ááá¯á¡áá»á±á¬áẠá¡ááá¯ááºááááºá
ááŒááºááŸááºááŒááºážááẠáááºážááá¬á¡á áááŒá
áºááá¯ááºáá±á¬ááŒá±á¬áá·áº á€áááºááŸá¬ ááá¯ážáá¬ážáá±á¬áá»áá¯ážáááºáááºážáááºážáá
áºáá¯ááŒá
áºáááºá Tradisys ááááºážáá»á¬ážá¡á¬ážáá¯á¶ážááẠáá±á¬áºááŒáá¬ážáá±á¬ á¡ááºáááá¯áá®áááºáá±á«áºááœáẠá¡ááŒá±áá¶á á¡áá¯ááºáá¯ááºáá«áááºá á€áááºááŸá¬ blockchain ááááºážáá»á¬ážá¡áá¯ááºáá¯ááºáá¯á¶ááŒá
áºáááºá á¡á¬ážáá¯á¶ážá ááœáá·áºáááºážááŒááºáá¬ááŒá®áž á
áá
á
áºááá¯á·ááááºá á¡ááŒá¬áž blockchain ááœááºááá¯áá²á·ááá¯á·áá±á¬á
áá
áºá analogues áááŸááá«á áá«á ááŒá¯á¶áá¬áá»áááºážáá«áá²á
source: www.habr.com