Lukeminen verkosta

Tässä osiossa tutkitaan, miten Solana-verkosta luetaan dataa hakemalla erilaisia tilejä Solana-tilin rakenteen ymmärtämiseksi.

Solanassa kaikki data on olemassa "tileissä". Voit ajatella Solanan dataa julkisena tietokantana, jossa on yksi "Tilit"-taulu, jossa jokainen merkintä on tili samalla perus Tili-tyypillä.

Base Account Type
#[derive(PartialEq, Eq, Clone, Default)]
pub struct Account {
/// lamports in the account
pub lamports: u64,
/// data held in this account
#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
pub data: Vec<u8>,
/// the program that owns this account. If executable, the program that loads this account.
pub owner: Pubkey,
/// this account's data contains a loaded program (and is now read-only)
pub executable: bool,
/// the epoch at which this account will next owe rent
pub rent_epoch: Epoch,
}

TilitTilit

Solana-tilit voivat tallentaa "tilaa" tai "suoritettavia" ohjelmia. Jokaisella tilillä on "osoite" (julkinen avain), joka toimii sen yksilöllisenä tunnuksena, jota käytetään sen vastaavan lohkoketjudatan paikantamiseen.

Solana-tilit sisältävät joko:

  • Tila: Dataa, jota on tarkoitus lukea ja säilyttää. Esimerkiksi tietoa tokeneista, käyttäjädataa tai muuta ohjelmassa määriteltyä dataa.
  • Suoritettavat ohjelmat: Tilejä, jotka sisältävät Solana-ohjelmien varsinaisen koodin. Nämä tilit tallentavat ohjeita, joita käyttäjät voivat kutsua.

Tämä ohjelmakoodin ja ohjelman tilan erottaminen on keskeinen ominaisuus Solanan Tilimallissa. Lisätietoja löydät Solana-tilimalli -sivulta.

Hae lompakkotili

Tämä esimerkki näyttää, miten:

  1. Luodaan uusi keypair (julkinen/yksityinen avainpari).
  2. Pyydetään SOL-airdrop uuden osoitteen rahoittamiseksi.
  3. Haetaan tilitiedot rahoitetusta osoitteesta.

Solanassa uuden osoitteen rahoittaminen SOL:lla luo automaattisesti System Program -ohjelman omistaman tilin. Kaikki "lompakko"-tilit ovat yksinkertaisesti System Program -ohjelman omistamia tilejä, jotka sisältävät SOL:ia ja voivat allekirjoittaa transaktioita.

Fetch Account
import { Keypair, Connection, LAMPORTS_PER_SOL } from "@solana/web3.js";
const keypair = Keypair.generate();
console.log(`Public Key: ${keypair.publicKey}`);
const connection = new Connection("http://localhost:8899", "confirmed");
// Funding an address with SOL automatically creates an account
const signature = await connection.requestAirdrop(
keypair.publicKey,
LAMPORTS_PER_SOL
);
await connection.confirmTransaction(signature, "confirmed");
const accountInfo = await connection.getAccountInfo(keypair.publicKey);
console.log(JSON.stringify(accountInfo, null, 2));
Console
Click to execute the code.

"Lompakko" Solanassa on järjestelmäohjelman omistama tili, joka on yksi Solanan sisäänrakennetuista ohjelmista. Lompakkotilejä käytetään pääasiassa SOL-varojen säilyttämiseen (seurataan lamports -kentässä) ja transaktioiden allekirjoittamiseen.

Kun haet lompakkotilin tiedot, vastaus sisältää esimerkkitulostuksessa näkyvät kentät.

Example Output
{
"data": {
"type": "Buffer",
"data": []
},
"executable": false,
"lamports": 1000000000,
"owner": "11111111111111111111111111111111",
"rentEpoch": 0,
"space": 0
}

data -kenttä sisältää tilin datan tallennettuna tavuina.

Lompakkotileillä tämä kenttä on tyhjä (0 tavua). Muut tilit käyttävät tätä kenttää joko ohjelman tilan tai suoritettavan ohjelmakoodin tallentamiseen.

Example Output
{
"data": {
"type": "Buffer",
"data": []
},
"executable": false,
"lamports": 1000000000,
"owner": "11111111111111111111111111111111",
"rentEpoch": 0,
"space": 0
}

executable -kenttä osoittaa, sisältääkö tilin data -kenttä suoritettavaa ohjelmakoodia.

Lompakoille ja ohjelman tilaa tallentaville tileille tämän kentän arvo on false.

Example Output
{
"data": {
"type": "Buffer",
"data": []
},
"executable": false,
"lamports": 1000000000,
"owner": "11111111111111111111111111111111",
"rentEpoch": 0,
"space": 0
}

lamports -kenttä sisältää tilin SOL-saldon lamporteina ilmaistuna.

Lamportit ovat SOL:n pienin yksikkö. 1 SOL = 1 000 000 000 lamportia.

Example Output
{
"data": {
"type": "Buffer",
"data": []
},
"executable": false,
"lamports": 1000000000,
"owner": "11111111111111111111111111111111",
"rentEpoch": 0,
"space": 0
}

owner -kenttä näyttää ohjelman, joka omistaa tilin.

Lompakkojen kohdalla omistaja on aina System Program, osoitteella 11111111111111111111111111111111.

Example Output
{
"data": {
"type": "Buffer",
"data": []
},
"executable": false,
"lamports": 1000000000,
"owner": "11111111111111111111111111111111",
"rentEpoch": 0,
"space": 0
}

rentEpoch -kenttä on jäänne vanhentuneesta mekanismista, jossa tileiltä veloitettiin "rent"-maksua (lamporteina) niiden tietojen säilyttämisestä verkossa.

Tätä kenttää ei nykyään käytetä, mutta se on mukana taaksepäin yhteensopivuuden vuoksi.

Example Output
{
"data": {
"type": "Buffer",
"data": []
},
"executable": false,
"lamports": 1000000000,
"owner": "11111111111111111111111111111111",
"rentEpoch": 0,
"space": 0
}

space -kenttä näyttää tavujen määrän data -kentässä. Tämä ei ole kenttä itse Account -tyypissä, vaan se on sisällytetty vastaukseen.

Tässä esimerkissä space -kenttä on 0, koska data -kenttä sisältää 0 tavua dataa.

Example Output
{
"data": {
"type": "Buffer",
"data": []
},
"executable": false,
"lamports": 1000000000,
"owner": "11111111111111111111111111111111",
"rentEpoch": 0,
"space": 0
}

"Lompakko" Solanassa on järjestelmäohjelman omistama tili, joka on yksi Solanan sisäänrakennetuista ohjelmista. Lompakkotilejä käytetään pääasiassa SOL-varojen säilyttämiseen (seurataan lamports -kentässä) ja transaktioiden allekirjoittamiseen.

Kun haet lompakkotilin tiedot, vastaus sisältää esimerkkitulostuksessa näkyvät kentät.

data -kenttä sisältää tilin datan tallennettuna tavuina.

Lompakkotileillä tämä kenttä on tyhjä (0 tavua). Muut tilit käyttävät tätä kenttää joko ohjelman tilan tai suoritettavan ohjelmakoodin tallentamiseen.

executable -kenttä osoittaa, sisältääkö tilin data -kenttä suoritettavaa ohjelmakoodia.

Lompakoille ja ohjelman tilaa tallentaville tileille tämän kentän arvo on false.

lamports -kenttä sisältää tilin SOL-saldon lamporteina ilmaistuna.

Lamportit ovat SOL:n pienin yksikkö. 1 SOL = 1 000 000 000 lamportia.

owner -kenttä näyttää ohjelman, joka omistaa tilin.

Lompakkojen kohdalla omistaja on aina System Program, osoitteella 11111111111111111111111111111111.

rentEpoch -kenttä on jäänne vanhentuneesta mekanismista, jossa tileiltä veloitettiin "rent"-maksua (lamporteina) niiden tietojen säilyttämisestä verkossa.

Tätä kenttää ei nykyään käytetä, mutta se on mukana taaksepäin yhteensopivuuden vuoksi.

space -kenttä näyttää tavujen määrän data -kentässä. Tämä ei ole kenttä itse Account -tyypissä, vaan se on sisällytetty vastaukseen.

Tässä esimerkissä space -kenttä on 0, koska data -kenttä sisältää 0 tavua dataa.

Example Output
{
"data": {
"type": "Buffer",
"data": []
},
"executable": false,
"lamports": 1000000000,
"owner": "11111111111111111111111111111111",
"rentEpoch": 0,
"space": 0
}

Token Program -ohjelman hakeminen

Tämä esimerkki hakee Token Program -ohjelman havainnollistaakseen eroa lompakko- ja ohjelmatilien välillä.

Ohjelmatili tallentaa käännetyn tavukoodin Token Program -ohjelman lähdekoodista. Voit tarkastella tätä ohjelmatiliä Solana Explorerissa.

Fetch Program Account
import { Connection, PublicKey } from "@solana/web3.js";
const connection = new Connection(
"https://api.mainnet-beta.solana.com",
"confirmed"
);
const address = new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
const accountInfo = await connection.getAccountInfo(address);
Console
Click to execute the code.

Token Program on suoritettava ohjelmatili Solanassa. Kuten lompakkotileillä, ohjelmilla on sama perustana oleva Account tietorakenne, mutta merkittävillä eroilla kentissään.

executable -kenttä on asetettu arvoon true, mikä osoittaa, että tämän tilin data -kenttä sisältää suoritettavaa ohjelmakoodia.

Ohjelmatileillä data -kenttä tallentaa ohjelman suoritettavan koodin. Lompakkotileillä puolestaan on tyhjä datakenttä.

Kun otat Solana-ohjelman käyttöön, ohjelman suoritettava koodi tallennetaan tilin data -kenttään.

Suoritettavilla ohjelmatileillä on myös ohjelma, joka on määritetty tilin owner -ohjelmaksi.

Kaikki ohjelmatilit omistaa Loader-ohjelma, joka on Solanan sisäänrakennettujen ohjelmien kategoria, joka omistaa suoritettavia ohjelmatilejä Solanassa.

Token Program -ohjelman kohdalla owner on BPFLoader2-ohjelma.

Token Program on suoritettava ohjelmatili Solanassa. Kuten lompakkotileillä, ohjelmilla on sama perustana oleva Account tietorakenne, mutta merkittävillä eroilla kentissään.

executable -kenttä on asetettu arvoon true, mikä osoittaa, että tämän tilin data -kenttä sisältää suoritettavaa ohjelmakoodia.

Ohjelmatileillä data -kenttä tallentaa ohjelman suoritettavan koodin. Lompakkotileillä puolestaan on tyhjä datakenttä.

Kun otat Solana-ohjelman käyttöön, ohjelman suoritettava koodi tallennetaan tilin data -kenttään.

Suoritettavilla ohjelmatileillä on myös ohjelma, joka on määritetty tilin owner -ohjelmaksi.

Kaikki ohjelmatilit omistaa Loader-ohjelma, joka on Solanan sisäänrakennettujen ohjelmien kategoria, joka omistaa suoritettavia ohjelmatilejä Solanassa.

Token Program -ohjelman kohdalla owner on BPFLoader2-ohjelma.

Token Program Account
{
"data": {
"type": "Buffer",
"data": [127, "...truncated, total bytes: 134080...", 0]
},
"executable": true,
"lamports": 4522329612,
"owner": "BPFLoader2111111111111111111111111111111111",
"rentEpoch": 18446744073709552000,
"space": 134080
}

Hae mint account

Tämä esimerkki hakee USD Coin (USDC) mint account -tilin osoittaakseen, miten ohjelmat Solanassa tallentavat tilan erillisiin tileihin.

Mint account on Token Program -ohjelman omistama tili. Se tallentaa tietyn tokenin globaalit metatiedot, mukaan lukien kokonaistarjonnan, desimaalien määrän ja tilit, joilla on valtuudet luoda tai jäädyttää tokeneita. Mint account -tilin osoite yksilöi tokenin Solana-verkossa.

Fetch Program Account
import { Connection, PublicKey } from "@solana/web3.js";
const connection = new Connection(
"https://api.mainnet-beta.solana.com",
"confirmed"
);
const address = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
const accountInfo = await connection.getAccountInfo(address);
Console
Click to execute the code.

Tässä esimerkissä keskeinen huomioitava asia on, että Mint-tili tallentaa tilaa, ei suoritettavaa koodia.

Mint-tilit ovat Token Program -ohjelman omistamia, joka sisältää ohjeet Mint-tilien luomiseen ja päivittämiseen.

Mint Account
{
"data": {
"type": "Buffer",
"data": [1, "...truncated, total bytes: 82...", 103]
},
"executable": false,
"lamports": 407438077149,
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"rentEpoch": 18446744073709552000,
"space": 82
}

executable -kenttä on false, koska mint account -tilin data -kenttä tallentaa tilaa, ei suoritettavaa koodia.

Token Program määrittelee Mint -datatyypin, joka tallennetaan mint account -tilin data -kenttään.

Mint Account
{
"data": {
"type": "Buffer",
"data": [1, "...truncated, total bytes: 82...", 103]
},
"executable": false,
"lamports": 407438077149,
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"rentEpoch": 18446744073709552000,
"space": 82
}

data -kenttä sisältää serialisoidun Mint -tilatiedon, kuten mint authorityn, kokonaistarjonnan ja desimaalien määrän.

Lukeaksesi Mint-tilistä, sinun täytyy deserialisoida data -kenttä Mint -datatyyppiin. Tätä käsitellään seuraavassa vaiheessa.

Mint Account
{
"data": {
"type": "Buffer",
"data": [1, "...truncated, total bytes: 82...", 103]
},
"executable": false,
"lamports": 407438077149,
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"rentEpoch": 18446744073709552000,
"space": 82
}

Token Program (TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA) omistaa mint account -tilin.

Tämä tarkoittaa, että mint account -tilin data -kenttää voi muokata vain Token Program -ohjelmassa määriteltyjen ohjeiden avulla.

Mint Account
{
"data": {
"type": "Buffer",
"data": [1, "...truncated, total bytes: 82...", 103]
},
"executable": false,
"lamports": 407438077149,
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"rentEpoch": 18446744073709552000,
"space": 82
}

Tässä esimerkissä keskeinen huomioitava asia on, että Mint-tili tallentaa tilaa, ei suoritettavaa koodia.

Mint-tilit ovat Token Program -ohjelman omistamia, joka sisältää ohjeet Mint-tilien luomiseen ja päivittämiseen.

executable -kenttä on false, koska mint account -tilin data -kenttä tallentaa tilaa, ei suoritettavaa koodia.

Token Program määrittelee Mint -datatyypin, joka tallennetaan mint account -tilin data -kenttään.

data -kenttä sisältää serialisoidun Mint -tilatiedon, kuten mint authorityn, kokonaistarjonnan ja desimaalien määrän.

Lukeaksesi Mint-tilistä, sinun täytyy deserialisoida data -kenttä Mint -datatyyppiin. Tätä käsitellään seuraavassa vaiheessa.

Token Program (TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA) omistaa mint account -tilin.

Tämä tarkoittaa, että mint account -tilin data -kenttää voi muokata vain Token Program -ohjelmassa määriteltyjen ohjeiden avulla.

Mint Account
{
"data": {
"type": "Buffer",
"data": [1, "...truncated, total bytes: 82...", 103]
},
"executable": false,
"lamports": 407438077149,
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"rentEpoch": 18446744073709552000,
"space": 82
}

Mint Account -tilin deserialisointi

Solana-tilin data -kenttä sisältää raakadataa tavuina. Tulkitaksesi tätä dataa mielekkäästi, sinun täytyy deserialisoida se asianmukaiseen datatyyppiin, jonka tilin omistava ohjelma on määritellyt.

Useimmat Solana-ohjelmat tarjoavat asiakaskirjastoja, joissa on apufunktioita deserialisointiprosessin abstrahoimiseksi. Nämä funktiot muuntavat tilin raakatavut jäsennellyiksi datatyypeiksi, mikä helpottaa tilidatan käsittelyä.

Esimerkiksi @solana/spl-token sisältää getMint() -funktion, joka auttaa deserialisoimaan mint account -tilin data -kentän Mint -datatyyppiin.

Deserialize Mint Account Data
import { PublicKey, Connection } from "@solana/web3.js";
import { getMint } from "@solana/spl-token";
const connection = new Connection(
"https://api.mainnet-beta.solana.com",
"confirmed"
);
const address = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
const mintData = await getMint(connection, address, "confirmed");
Console
Click to execute the code.
Mint Account Type
pub struct Mint {
/// Optional authority used to mint new tokens. The mint authority may only
/// be provided during mint creation. If no mint authority is present
/// then the mint has a fixed supply and no further tokens may be
/// minted.
pub mint_authority: COption<Pubkey>,
/// Total supply of tokens.
pub supply: u64,
/// Number of base 10 digits to the right of the decimal place.
pub decimals: u8,
/// Is `true` if this structure has been initialized
pub is_initialized: bool,
/// Optional authority to freeze token accounts.
pub freeze_authority: COption<Pubkey>,
}

getMint() -funktio deserialisoi mint account -tilin data -kentän Token Program -ohjelman määrittelemään Mint -datatyyppiin.

Mint Account
{
"data": {
"type": "Buffer",
"data": [1, "...truncated, total bytes: 82...", 103]
},
"executable": false,
"lamports": 407438077149,
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"rentEpoch": 18446744073709552000,
"space": 82
}

Voit tarkastella täysin deserialisoitua Mint Account -dataa Solana Explorerissa.

address -kenttä sisältää Mint account -tilin osoitteen.

Mint account -tilin osoitetta käytetään tunnistamaan token Solana-verkossa.

mintAuthority -kenttä näyttää auktoriteetin, jolla on oikeus luoda uusia tokeneita.

Tämä on ainoa tili, joka voi luoda uusia yksiköitä tokenista.

supply -kenttä näyttää luotujen tokenien kokonaismäärän.

Tämä arvo on tokenin pienimmässä yksikössä. Saadaksesi kokonaistarjonnan standardiyksiköissä, mukauta supply -kentän arvoa decimals -arvolla.

Deserialized Mint Data
{
"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG",
"supply": "8985397351591790",
"decimals": 6,
"isInitialized": true,
"freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar",
"tlvData": {
"type": "Buffer",
"data": []
}
}

Kenttä decimals näyttää tokenin desimaalipaikkojen määrän.

Deserialized Mint Data
{
"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG",
"supply": "8985397351591790",
"decimals": 6,
"isInitialized": true,
"freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar",
"tlvData": {
"type": "Buffer",
"data": []
}
}

Kenttä isInitialized osoittaa, onko mint account alustettu. Tätä kenttää käytetään turvallisuustarkistuksena Token Programissa.

Deserialized Mint Data
{
"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG",
"supply": "8985397351591790",
"decimals": 6,
"isInitialized": true,
"freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar",
"tlvData": {
"type": "Buffer",
"data": []
}
}

Kenttä freezeAuthority näyttää auktoriteetin, jolla on oikeus jäädyttää token accounteja.

Jäädytetystä token accountista ei voi siirtää tai polttaa tokenia.

Deserialized Mint Data
{
"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG",
"supply": "8985397351591790",
"decimals": 6,
"isInitialized": true,
"freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar",
"tlvData": {
"type": "Buffer",
"data": []
}
}

Kenttä tlvData sisältää lisätietoja Token Extensionsille (vaatii lisädeserialisointia).

Tämä kenttä on merkityksellinen vain Token Extension Programin (Token2022) luomille tileille.

Deserialized Mint Data
{
"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG",
"supply": "8985397351591790",
"decimals": 6,
"isInitialized": true,
"freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar",
"tlvData": {
"type": "Buffer",
"data": []
}
}

getMint() -funktio deserialisoi mint account -tilin data -kentän Token Program -ohjelman määrittelemään Mint -datatyyppiin.

Mint Account
{
"data": {
"type": "Buffer",
"data": [1, "...truncated, total bytes: 82...", 103]
},
"executable": false,
"lamports": 407438077149,
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"rentEpoch": 18446744073709552000,
"space": 82
}

Voit tarkastella täysin deserialisoitua Mint Account -dataa Solana Explorerissa.

address -kenttä sisältää Mint account -tilin osoitteen.

Mint account -tilin osoitetta käytetään tunnistamaan token Solana-verkossa.

mintAuthority -kenttä näyttää auktoriteetin, jolla on oikeus luoda uusia tokeneita.

Tämä on ainoa tili, joka voi luoda uusia yksiköitä tokenista.

supply -kenttä näyttää luotujen tokenien kokonaismäärän.

Tämä arvo on tokenin pienimmässä yksikössä. Saadaksesi kokonaistarjonnan standardiyksiköissä, mukauta supply -kentän arvoa decimals -arvolla.

Kenttä decimals näyttää tokenin desimaalipaikkojen määrän.

Kenttä isInitialized osoittaa, onko mint account alustettu. Tätä kenttää käytetään turvallisuustarkistuksena Token Programissa.

Kenttä freezeAuthority näyttää auktoriteetin, jolla on oikeus jäädyttää token accounteja.

Jäädytetystä token accountista ei voi siirtää tai polttaa tokenia.

Kenttä tlvData sisältää lisätietoja Token Extensionsille (vaatii lisädeserialisointia).

Tämä kenttä on merkityksellinen vain Token Extension Programin (Token2022) luomille tileille.

Deserialized Mint Data
{
"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG",
"supply": "8985397351591790",
"decimals": 6,
"isInitialized": true,
"freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar",
"tlvData": {
"type": "Buffer",
"data": []
}
}

Is this page helpful?

Sisällysluettelo

Muokkaa sivua