Modulo:Linganbi foresti
--[[
* Modulo che implementa il template Collegamenti esterni.
]]--
require('strict')
local getArgs = require('Modulo:Arguments').getArgs
local mWikidata = require('Modulo:Wikidata')
local mCitazione = require('Modulo:Citasion')
local mEditAtWikidata = require('Modulo:Modifega so Wikidata')
-- Permette di definire l'ordine di visualizzazione dei vari gruppi
local orderedGroupNames = {
'Ufisałi', 'Ençiclopedie', 'Biografie', 'Testi',
'Letaratura', 'Pułìtega', 'Rełijon', 'Architetura',
'Astronomia', 'Biołoxia', 'Editoria', 'Xiografia',
'Lenguìstega', 'MAB', 'Software', 'Bałon', 'Sci',
'Spor', 'Videoxughi', 'Muxica', 'Fumeti', 'Cine'
}
-- Soglie di attenzione sul numero elevato di collegamenti, per categorie di controllo
local MOLTI_LINK = 12
local MOLTI_LINK_2 = 15
-- Categorie di servizio
local catLetta = ' lexesta da Wikidata'
local catMultiSenzaQual = ' multepla, lexesta da Wikidata sensa cuałifegador'
local catMoltiLink = 'Voxe co modeło Linganbi foresti e racuanti ligaminti'
local catMoltiLink2 = 'Voxe co modeło Linganbi foresti e racuanti ligaminti (masa)'
local catEmpty = 'Voxe co modeło Linganbi foresti sensa dati da Wikidata'
local catUnknownQual = 'Voxe co modeło Linganbi foresti e cuałifegadori sconosesti'
local catExcessiveLoad = 'Voxe co modeło Linganbi foresti e on mùcio de entità Wikidata cargae'
local catDuplicates = 'Voxe co modeło Linganbi foresti e dopioni dexativai'
-- Tabella dei qualificatori riconosciuti
-- Qui vanno elencati solo quelli generali, validi per tutte le dichiarazioni
-- Ciascuno ha la sua configurazione che può essere lasciata vuota o compilata come di seguito:
-- "par" è il parametro del modulo Citazione da compilare col qualificatore
-- "fallback" è una sottotabella coi qualificatori di ripiego in ordine di priorità
-- "restricted" è true se il qualificatore impone una citazione diversa per url a stesso sito
local knownQualifiers = {
-- item o stringa dell'autore
P50 = { par = 'autore', fallback = { 'P2093' }, restricted = true },
P478 = { par = 'volume', restricted = true },
P304 = { par = 'pagina', restricted = true },
P577 = { par = 'data', restricted = true },
-- titolo o "indicato come" o "riferito come" o pseudonimo
P1476 = { par = 'titolo', fallback = { 'P1810', 'P1932', 'P742', 'P554' } },
-- url archiviato, solo per le proprietà di tipo URL
P1065 = { par = 'archivio' }, P2960 = { par = 'dataarch' }, P582 = { par = 'urlmorto' },
P407 = {}, P813 = {}
}
-- I qualificatori di ripiego sono automaticamente aggiunti con configurazione vuota
for _, t in pairs(knownQualifiers) do
if t.fallback then
for _, v in ipairs(t.fallback) do knownQualifiers[v] = {} end
end
end
-- =============================================================================
-- Funzioni di utilità
-- =============================================================================
-- Restituisce la configurazione delle sottopagine.
--
-- @return {table}
local function readConfig()
local ret = {}
for _, groupName in ipairs(orderedGroupNames) do
ret[groupName] = mw.loadData('Module:Linganbi foresti/' .. groupName)
end
return ret
end
-- Restituisce il titolo della pagina corrente rimuovendo eventuale testo tra parentesi.
-- Se l'etichetta dell'elemento Wikidata contiene delle parentesi,
-- non le rimuove perché significa che fanno parte del titolo.
-- Con il parametro "from" (elemento Wikidata arbitrario) usa sempre l'etichetta.
--
-- @param {string} from
-- @return {string}
local function getCurrentTitle(from)
local ret
local label = mWikidata._getLabel({ from })
if from then
ret = label
else
ret = mw.title.getCurrentTitle().text
if not (label and string.find(label, ' %(')) then
ret = mw.text.split(ret, ' %(')[1]
end
end
return ret
end
-- Restituisce il dominio dell'URL specificato.
--
-- @param {string} url
-- @return {string}
local function getDomain(url)
return mw.uri.new(url).host:gsub('^www.', '')
end
-- Restituisce true se l'elemento collegato alla pagina o quello specificato in from
-- ha tra i valori (o loro sottoclassi) della proprietà indicata uno degli elementi specificati.
-- Restituisce come secondo valore una tabella con gli ID delle entità caricate ai fini della ricerca.
-- @param {string} prop - codice della proprietà 'Pxxx'
-- @param {table} [entityIds] - array dei valori (strighe 'Qxxx') che può avere
-- @param {string} from
-- @return {boolean}
-- @return {table}
local function checkEntity(prop, entityIds, from)
local args = { from = from, recursion = 8 }
for _, entityId in ipairs(entityIds) do
table.insert(args, entityId)
end
return mWikidata._propertyHasEntity(prop, args)
end
-- Converte un parametro ricevuto come 'Xxx, yyy' in { 'Xxx'=true, 'Yyy'=true }
local function ParametroElenco(param)
local chiavi = {}
local valori = param and mw.text.split(param, ',')
if valori then
for _, str in ipairs(valori) do
chiavi[mw.getContentLanguage():ucfirst(mw.text.trim(str))] = true
end
end
return chiavi
end
-- =============================================================================
-- Classe ExtLink
-- =============================================================================
-- La classe ExtLink rappresenta un singolo collegamento esterno.
-- Al suo interno ha un riferimento alla propria configurazione (linkConf)
-- e nel caso la proprietà Wikidata abbia più valori li raccoglie tutti.
local ExtLink = {}
-- Costruttore della classe ExtLink.
--
-- @param {table} [url] - uno o più URL, quanti sono i valori della proprietà Wikidata
-- @param {table} linkConf - la configurazione fissa per questo collegamento esterno
-- @param {table} extraConf - altri elementi di configurazione ricavati dall'item
-- @param {string} from - entityId se diverso da quello collegato alla pagina corrente
-- @return {table} un nuovo oggetto ExtLink
function ExtLink:new(url, linkConf, extraConf, from)
local self = {}
setmetatable(self, { __index = ExtLink })
self.url = url
self.linkConf = linkConf
self.extraConf = extraConf
self.from = from
self.title = getCurrentTitle()
self.title = self.from and mWikidata._getLabel({ self.from }) or self.title
self.extraConf.medium = self.linkConf.medium or 'web'
return self
end
-- Restituisce il parametro titolo per il modulo Citazione.
--
-- @return {string}
function ExtLink:_getTitolo()
local titolo = self.extraConf.titolo[1] or self.title
if self.linkConf.titolo then
titolo = self.linkConf.titolo:gsub('$1', titolo)
end
if #self.url > 1 and self.extraConf.titolodis[1] then
return string.format('%s (%s)', titolo, self.extraConf.titolodis[1])
else
return titolo
end
end
-- Restituisce il parametro altrilink per il modulo Citazione.
-- Nel caso di valori multipli, genera quelli successivi al primo.
--
-- @return {table}
function ExtLink:_getAltriLink()
if self.extraConf.restrictedData then return end
local tbl = {}
local titolo, specifica
for i = 2, #self.url do
titolo = self.extraConf.titolo[i] or self.title
if self.extraConf.titolodis[i] then
specifica = self.extraConf.titolodis[i]
else
local ripetuto = false -- controllo se stesso titolo già usato
for j = 1, i - 1 do
if titolo == (self.extraConf.titolo[j] or self.title) then
ripetuto = true
break
end
end
if ripetuto then
specifica = 'altra versione'
else
specifica = nil -- se titoli diversi, va bene anche senza specificazione
end
end
if specifica then
titolo = string.format('%s (%s)', titolo, specifica)
end
table.insert(tbl, { self.url[i], titolo })
end
return tbl
end
-- Formatta il collegamento esterno quando la proprietà è di tipo URL.
--
-- @return {string}
function ExtLink:_formatPropertyURL()
local formattedLinks = {}
local currTitle = getCurrentTitle(self.from)
local claims = mWikidata._getClaims(self.linkConf.pid, { from = self.from }) or {}
for idx, claim in ipairs(claims) do
local langs = mWikidata._formatQualifiers(claim, 'P407', { formatting = 'raw' }, true)
langs = (#langs == 1 and langs[1] == 'Q652') and {} or langs
for i, lang in ipairs(langs) do
langs[i] = mw.wikibase.getLabel(lang) or lang
end
local formattedLink = mCitazione.cita_da_modulo(
self.extraConf.medium,
{
url = mWikidata._formatStatement(claim),
titolo = self.linkConf.titolo:gsub('$1', currTitle),
lingua = table.concat(langs, ','),
cid = self.linkConf.cid,
urlarchivio = self.extraConf.archivio[idx],
dataarchivio = self.extraConf.dataarch[idx],
urlmorto = self.extraConf.urlmorto[idx] and 'sì' or (self.extraConf.archivio[idx] and 'no')
})
table.insert(formattedLinks, '* ' .. formattedLink ..
mEditAtWikidata._showMessage({ pid = self.linkConf.pid, qid = self.from }))
end
return table.concat(formattedLinks, '\n')
end
-- Formatta il collegamento esterno come elemento di un elenco puntato.
--
-- @return {string}
function ExtLink:getListItem()
-- se è specificato l'URL di formattazione è una
-- proprietà di tipo "identificativo esterno" altrimenti di tipo URL
if not self.linkConf.url then
return self:_formatPropertyURL()
end
local formattedLinks = {}
for i = 1, self.extraConf.restrictedData and #self.url or 1 do
local formattedLink = mCitazione.cita_da_modulo(
self.extraConf.medium,
{
url = self.url[i],
titolo = self:_getTitolo(),
altrilink = self:_getAltriLink(),
sito = self.linkConf.opera and '' or self.extraConf.sito,
opera = self.linkConf.opera,
editore = self.linkConf.editore,
lingua = self.linkConf.lingua,
cid = self.extraConf.restrictedData and self.extraConf.cid[i] or self.linkConf.cid,
autore = self.linkConf.autore or self.extraConf.autore[i],
volume = self.extraConf.volume[i],
p = self.extraConf.pagina[i],
data = self.linkConf.data or self.extraConf.data[i],
tipo = self.linkConf.tipo or self.sitodis
})
table.insert(formattedLinks, '* ' .. formattedLink ..
mEditAtWikidata._showMessage({ pid = self.linkConf.pid, qid = self.from }))
end
return table.concat(formattedLinks, '\n')
end
-- =============================================================================
-- Classe LinksManager
-- =============================================================================
-- La classe LinksManager è la classe principale del modulo.
-- Al suo interno ha un riferimento a tutti collegamenti esterni (extLinks)
-- presenti in un dato elemento Wikidata e li può restituire tutti formattati
-- nel modo più appropriato.
local LinksManager = {}
-- Costruttore della classe LinksManager.
--
-- @param {table} args
-- @return {table} un nuovo oggetto LinksManager
function LinksManager:new(args)
local self = {}
setmetatable(self, { __index = LinksManager })
self.numExtLinks = 0
self.categories = {}
self.catColon = ''
self.from = args.from
self.escludi = ParametroElenco(args.escludi)
self.soloprop = ParametroElenco(args.prop)
self.sologruppi = ParametroElenco(args.gruppo)
self.solomedium = ParametroElenco(args.medium)
-- la pagina dei test utilizza uno stub del modulo Wikidata
if mw.title.getCurrentTitle().prefixedText ==
'Discussioni modulo:Collegamenti esterni/test' then
self:_setStubWikidata(args.stubwd)
end
self.extLinks = self:_getExtLinks()
return self
end
-- Formatta e carica una o più categorie di servizio.
function LinksManager:_addCategory(...)
for _, category in pairs({ ... }) do
if category then
category = string.format('[[%sCategoria:%s]]', self.catColon, category)
table.insert(self.categories, category)
end
end
end
-- Permette di specificare uno stub del modulo Wikidata
-- in modo da ottenere i valori delle proprietà in modo deterministico,
-- non dipendenti da modifiche utente a un elemento Wikidata.
--
-- @param {table} stubwd
function LinksManager:_setStubWikidata(stubwd)
mEditAtWikidata = { _showMessage = function(frame) return '' end }
mWikidata = stubwd
self.catColon = ':'
self.debug = true
end
-- Controlla se un elemento fa parte delle esclusioni richieste dall'utente
function LinksManager:_Escluso(elemento, inclusi)
return self.escludi[elemento] or (next(inclusi) and inclusi[elemento] ~= true)
end
-- Ottiene tutti i collegamenti esterni (configurati) presenti in un dato elemento Wikidata
-- suddivisi per gruppo.
--
-- @return {table}
function LinksManager:_getExtLinks()
local ret, groupSites = {}, {}
local cfg = readConfig()
local lang = mw.language.getContentLanguage()
local pageContent = mw.title.getCurrentTitle():getContent()
:gsub('<!%-%-.-%-%->', '')
:gsub('<[Rr][Ee][Ff]%s.-/>', '') -- facilita la ricerca successiva
:gsub('<[Rr][Ee][Ff].->.-</[Rr][Ee][Ff]%s*>', '')
local loadedEntities = setmetatable({}, {
__newindex = function(t1, key, t2)
if not t2 then return end
for k, v in pairs(t2) do rawset(t1, k, v) end
end })
local duplicates = false -- per categoria temporanea
for _, groupName in ipairs(orderedGroupNames) do -- per ogni gruppo tematico
groupSites[groupName] = {}
ret[groupName] = {}
-- controlla se è un gruppo escluso manualmente dall'utente
if self:_Escluso(groupName, self.sologruppi) then
cfg[groupName] = {}
end
for _, linkConf in ipairs(cfg[groupName]) do -- per ogni sito configurato
local claims, valido
-- se il sito non è escluso manualmente dall'utente, avviene la lettura da Wikidata
if not (self:_Escluso(linkConf.pid, self.soloprop) or
self:_Escluso(lang:ucfirst(linkConf.medium or 'web'), self.solomedium)) then
claims = mWikidata._getClaims(linkConf.pid, { from = self.from })
end
-- controlla se ci sono valori
if claims and #claims > 0 then
-- controlla se è un sito da escludere per soggetto non pertinente
if type(linkConf.vincolo) == 'table' then
local Nvincoli = 0
for _ in ipairs(linkConf.vincolo) do Nvincoli = Nvincoli + 1 end
for i = 2, Nvincoli, 2 do -- per ogni coppia 'proprietà', {valori}
valido, loadedEntities[i] = checkEntity(linkConf.vincolo[i - 1], linkConf.vincolo[i], self.from)
if valido then break end
end
else
valido = true
end
-- controlla che il link non sia generato da altri template in voce
if valido and linkConf.template then
for template in mw.text.gsplit(linkConf.template, ',') do
template = mw.text.trim(template):gsub(' +', ' +')
local first_char = template:match('^.')
first_char = string.format('[%s%s]', first_char:upper(), first_char:lower())
if pageContent:match('{{%s*' .. template:gsub('^.', first_char) .. '%s*[|}]') then
valido, duplicates = false, true
break
end
end
end
end
-- se il sito è abilitato, viene aggiunto a quelli da mostrare
if valido then
local url = {}
local extraConf = { cid = {}, titolodis = { count = 0 } }
-- per ogni dichiarazione
for i, claim in ipairs(claims) do
for k, t in pairs(knownQualifiers) do
if t.par then
extraConf[t.par] = extraConf[t.par] or { count = 0 }
local properties = { k, unpack(t.fallback or {}) }
-- ricava i qualificatori generali e ne tiene il conto
for _, v in ipairs(properties) do
extraConf[t.par][i] = mWikidata._formatQualifiers(claim, v) or
t.par == 'urlmorto' and
mWikidata._formatQualifiers(claim, v, { snaktype = 'somevalue' }) or nil
if extraConf[t.par][i] then
extraConf[t.par].count = extraConf[t.par].count + 1
if t.restricted then
extraConf.restrictedData = true
end
break
end
end
end
end
if claim.qualifiers then
knownQualifiers.multi = {}
-- cerca un disambiguante per il titolo di ogni url
for qualifierId in mw.text.gsplit(linkConf.multi or '', ',') do
if qualifierId == '' then break end
qualifierId = mw.text.trim(qualifierId):upper()
if extraConf.titolodis[i] == nil and claim.qualifiers[qualifierId] then
local args = { nq = '1', formatting = 'raw' }
local formattedQualifier = mWikidata._formatQualifiers(claim, qualifierId, args)
if formattedQualifier then
extraConf.titolodis[i] = mw.wikibase.getLabel(formattedQualifier)
if extraConf.titolodis[i] then
extraConf.titolodis.count = extraConf.titolodis.count + 1
end
end
end
knownQualifiers.multi[qualifierId] = true
end
-- categoria di servizio in presenza di qualificatori non riconosciuti
for qualifierId in pairs(claim.qualifiers) do
if not (knownQualifiers[qualifierId] or knownQualifiers.multi[qualifierId]) then
self:_addCategory(catUnknownQual)
break
end
end
end
-- crea l'url
claim = mWikidata._formatStatement(claim)
if linkConf.cid then
extraConf.cid[i] = i .. '_' .. linkConf.cid .. '_' .. (extraConf.data[i] or claim)
end
if linkConf.url then
-- se proprietà di tipo id, il valore viene sostituito a "$1"
claim = mw.message.newRawMessage(linkConf.url, claim):plain()
end
table.insert(url, (claim:gsub(' ', '%%20')))
end
-- nome sito, di default il dominio estratto dall'url
extraConf.sito = linkConf.sito or getDomain(linkConf.url)
-- creazione dell'oggetto collegamento esterno, con l'url (o gli url) e gli altri dati raccolti
table.insert(ret[groupName], ExtLink:new(url, linkConf, extraConf, self.from))
-- categoria per proprietà letta; se multipla e indistinguibile, usa categoria di avviso
local tail = #url > 1 and linkConf.url and
extraConf.titolodis.count ~= #url and
extraConf.titolo.count < #url - 1 and
catMultiSenzaQual or catLetta
self:_addCategory(linkConf.pid .. tail)
-- per verificare se un sito è ripetuto nel gruppo
groupSites[groupName][extraConf.sito] = (groupSites[groupName][extraConf.sito] or 0) + 1
-- conteggio complessivo dei collegamenti
self.numExtLinks = self.numExtLinks + 1
end
end
end
-- verifica se un sito è ripetuto nel gruppo
for _, groupName in ipairs(orderedGroupNames) do
for _, extLink in ipairs(ret[groupName]) do
-- necessaria la disambiguazione (più URL con lo stesso dominio nel gruppo),
-- se configurata tramite "sitodis" nella configurazione.
if groupSites[groupName][extLink.extraConf.sito] > 1 then
extLink.sitodis = extLink.linkConf.sitodis
end
end
end
-- categorie di servizio su numero di link/entità caricate e doppioni omessi
local catnumero = self.numExtLinks == 0 and catEmpty or
self.numExtLinks > MOLTI_LINK_2 and catMoltiLink2 or
self.numExtLinks > MOLTI_LINK and catMoltiLink
self:_addCategory(catnumero,
#loadedEntities > 100 and catExcessiveLoad,
duplicates and catDuplicates)
return ret
end
-- Formatta i collegamenti esterni come elenco puntato.
--
-- @param {table} [groupNames]
-- @return {string}
function LinksManager:_formatList(groupNames)
local formattedLinks = {}
for _, groupName in ipairs(groupNames) do
for _, extLink in ipairs(self.extLinks[groupName]) do
table.insert(formattedLinks, extLink:getListItem())
end
end
return table.concat(formattedLinks, '\n')
end
-- Restituisce tutti i collegamenti esterni formattandoli come elenco puntato
--
-- @return {string}
function LinksManager:getList()
local categories, links
-- categorie di servizio
categories = (mw.title.getCurrentTitle().namespace == 0 or self.debug) and
table.concat(self.categories) or ''
-- collegamenti
links = self:_formatList(orderedGroupNames)
return links .. categories
end
-- =============================================================================
-- Funzioni esportate
-- =============================================================================
local p = {}
-- Funzioni di utilità per il manuale, danno la soglia di attenzione sul n° di link.
function p.threshold(frame)
return MOLTI_LINK
end
function p.threshold2(frame)
return MOLTI_LINK_2
end
-- Funzione di utilità per il manuale, restituisce un elenco
-- delle proprietà supportate, divise per gruppo.
function p.properties(frame)
local res = {}
local cfg = readConfig()
table.sort(orderedGroupNames)
for _, groupName in ipairs(orderedGroupNames) do
local wdLinks = {}
for _, linkConf in ipairs(cfg[groupName]) do
local wdLink = string.format('<tr><td>[[d:Property:%s|%s (%s)]]</td><td>%s</td><td>%s</td><td>%s</td></tr>',
linkConf.pid, mWikidata._getLabel({ linkConf.pid }), linkConf.pid, linkConf.url or '', linkConf.cid or '', linkConf.template and ('[[t:'..linkConf.template..'|'..linkConf.template..']]') or '')
table.insert(wdLinks, wdLink)
end
local group = frame.args[1] == 'modulo' and
string.format('* [[Modulo:Collegamenti esterni/%s]] (%s)', groupName, #wdLinks) or
mw.getCurrentFrame():expandTemplate {
title = 'Cassetto',
args = {
titolo = string.format('[[Modulo:Collegamenti esterni/%s|%s]] (%s)', groupName, groupName, #wdLinks),
testo = '<table class="wikitable sortable plainlinks"><tr><th>Proprietà</th><th>Formato URL</th><th>cid</th><th>Template singolo</th></tr>' .. table.concat(wdLinks, '') .. '</table>'
}
}
table.insert(res, group)
end
return table.concat(res, '\n')
end
-- Funzione di utilità per il manuale, verifica l'assenza di proprietà duplicate.
function p.checkdup(frame)
local ids, res = {}, {}
local cfg = readConfig()
for _, groupName in ipairs(orderedGroupNames) do
for _, linkConf in ipairs(cfg[groupName]) do
if ids[linkConf.pid] then
table.insert(res, linkConf.pid)
else
ids[linkConf.pid] = true
end
end
end
return #res == 0 and 'nessun duplicato' or
string.format('<span class="error">%s</span>', table.concat(res, ', '))
end
-- Funzione per l'utilizzo da un altro modulo.
function p._main(args)
return LinksManager:new(args):getList()
end
-- Funzione per il template {{Collegamenti esterni}}.
function p.main(frame)
return p._main(getArgs(frame, { parentOnly = true }))
end
return p
Content Disclaimer
Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.
- The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
- There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
- It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
- Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
- Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.
Index:
pl ar de en es fr it arz nl ja pt ceb sv uk vi war zh ru af ast az bg zh-min-nan bn be ca cs cy da et el eo eu fa gl ko hi hr id he ka la lv lt hu mk ms min no nn ce uz kk ro simple sk sl sr sh fi ta tt th tg azb tr ur zh-yue hy my ace als am an hyw ban bjn map-bms ba be-tarask bcl bpy bar bs br cv nv eml hif fo fy ga gd gu hak ha hsb io ig ilo ia ie os is jv kn ht ku ckb ky mrj lb lij li lmo mai mg ml zh-classical mr xmf mzn cdo mn nap new ne frr oc mhr or as pa pnb ps pms nds crh qu sa sah sco sq scn si sd szl su sw tl shn te bug vec vo wa wuu yi yo diq bat-smg zu lad kbd ang smn ab roa-rup frp arc gn av ay bh bi bo bxr cbk-zam co za dag ary se pdc dv dsb myv ext fur gv gag inh ki glk gan guw xal haw rw kbp pam csb kw km kv koi kg gom ks gcr lo lbe ltg lez nia ln jbo lg mt mi tw mwl mdf mnw nqo fj nah na nds-nl nrm nov om pi pag pap pfl pcd krc kaa ksh rm rue sm sat sc trv stq nso sn cu so srn kab roa-tara tet tpi to chr tum tk tyv udm ug vep fiu-vro vls wo xh zea ty ak bm ch ny ee ff got iu ik kl mad cr pih ami pwn pnt dz rmy rn sg st tn ss ti din chy ts kcg ve









