Arra gondoltam, hogy ha pénzes private cloud-ot fejlesztenék (mint ahogy valójában, csak az ingyen van/support szerződéses), akkor csinálnék egy olyan licenszelési módot, hogy power-saving license. Ez azt jelentené, hogy amennyi áramot megtakarít neked a cluster azzal, hogy a felesleges kapacitást kikapcsolja, na annak a felét kérnénk el licenszdíjként. Nyilán a másik fele az ügyfélé maradna.
Szerintem egész attraktív licenszelési mód, hogy azt mondjuk hogy csak a megspórolt villanyszámládból kérünk egy kicsit. Ugyanakkor valójában nem hozna keveset. Egy PC jellegű gép ha folyamatosan működik, akkor 5-10000 forintnyi villanyszámlát csinál. Akár csak egy kis cég szerverszobájában is pörög ilyenből néhány tucatnyi. Sok múlik azon persze, hogy mennyire van overcommit-olva a szerverfarmod, de kicsit okosan, megtakaríthatod az üzemidő jónéhány százalékát, ebből szerverenként havonta pár-ezer forintnyi zseton jönne, ami nem sok, de sok szerverrel felszorozva már szép. Menj be a szerverszobába és számold meg a dobozokat :)
Szóval a dolog szépsége az lenne, hogy nagyon olcsónak tűnik, de nem az, és ennek ellenére amikor kifizetted akkor még mindig nagyon olcsónak tűnik :-)
2012. december 19., szerda
2012. december 18., kedd
elszállt ötletek: ami a tömörítésből még hiányzik
Van egy mondás, miszerint egy rendszerben egy adott pillanatban csak egy komponens a bottleneck. Ezt megfigyelheted akkor is, amikor egyik gépről nagyobb mennyiségű adatot pumpálsz át etherneten: vagy a merevlemez, vagy a hálózat lesz teljesen leterhelve, a processzor meg közben vakarja a tökeit.
Arra gondoltam, hogy ezen kicsit megpróbálok segíteni, de ha egyszerűen csak bedobok egy tetszőleges tömörítő algoritmust a sorba, akkor könnyen lehet, hogy a CPU-t rúgom agyon és ezzel azt nevezem ki új bottleneck-nek, míg innentől a hálózat forgalom lesz alacsony. Minden vason külön ki kellene találnom hogy mennyire jó ötlet egy tömörítést közbedobni, és nem akarom, mert már a másodiknál is nagyon unnám.
Egy olyan InputStream/OutputStream párosra gondoltam, ami egy kellően nagy bufferrel rendelkezik. Az output része az írásra itélt adatokat csomagokra bontaná és egy szálon figyelné hogy melyik mennyi idő tellik el a beérkezés és a bufferből távozás között. Ha úgy becsülné meg, indítana egy szálat, ami a buffer egy részét egy tömörítő algoritmussal betömörítené és hozzátenne egy nagyon rövid headert (pl 1 byte) ami jelezné hogy tömörítve van-e és ha igen milyen algoritmussal. Az input része csak csekkolná ezt a headert és szükség esetén kitömörítené a csomagot. Nyilván ez egy kicsi overhead.
Így a viszonylag gyenge hálózati kapcsolatot kicsit felgyógyíthatnám egy processzorral, de annélkül, hogy esetleg bizonyos esetekben nagyon durván kiszúrjak magammal.
Egy másik kapcsolódó ötlet az az lenne, hogy egy olyan tömörítő input/output streameket próbálnék ki, amelyek ellenőrzik (lehetőleg csak egyszer) hogy az adott rendszeren létezik-e az adott tömörítő algoritmusnak natív változata. Ha van akkor azon átpipe-olva tömörítené az adatokat, ha pedig nincs, akkor egy java implementációra terhelné. A natív implementációk általában véve gyorsabbak, még azzal együtt is, hogy context-switch ésatöbbi.
Szóval ez csak szimpla tuning. Nincs autóm, úgyhogy azt nem tudom brümmögtetni :-) Ja és nem is szeretnék, mert nem szeretem a brümmögést :-D
Hát ennyi lenne az ötlet, jöhetnek a kövek.
Arra gondoltam, hogy ezen kicsit megpróbálok segíteni, de ha egyszerűen csak bedobok egy tetszőleges tömörítő algoritmust a sorba, akkor könnyen lehet, hogy a CPU-t rúgom agyon és ezzel azt nevezem ki új bottleneck-nek, míg innentől a hálózat forgalom lesz alacsony. Minden vason külön ki kellene találnom hogy mennyire jó ötlet egy tömörítést közbedobni, és nem akarom, mert már a másodiknál is nagyon unnám.
Egy olyan InputStream/OutputStream párosra gondoltam, ami egy kellően nagy bufferrel rendelkezik. Az output része az írásra itélt adatokat csomagokra bontaná és egy szálon figyelné hogy melyik mennyi idő tellik el a beérkezés és a bufferből távozás között. Ha úgy becsülné meg, indítana egy szálat, ami a buffer egy részét egy tömörítő algoritmussal betömörítené és hozzátenne egy nagyon rövid headert (pl 1 byte) ami jelezné hogy tömörítve van-e és ha igen milyen algoritmussal. Az input része csak csekkolná ezt a headert és szükség esetén kitömörítené a csomagot. Nyilván ez egy kicsi overhead.
Így a viszonylag gyenge hálózati kapcsolatot kicsit felgyógyíthatnám egy processzorral, de annélkül, hogy esetleg bizonyos esetekben nagyon durván kiszúrjak magammal.
Egy másik kapcsolódó ötlet az az lenne, hogy egy olyan tömörítő input/output streameket próbálnék ki, amelyek ellenőrzik (lehetőleg csak egyszer) hogy az adott rendszeren létezik-e az adott tömörítő algoritmusnak natív változata. Ha van akkor azon átpipe-olva tömörítené az adatokat, ha pedig nincs, akkor egy java implementációra terhelné. A natív implementációk általában véve gyorsabbak, még azzal együtt is, hogy context-switch ésatöbbi.
Szóval ez csak szimpla tuning. Nincs autóm, úgyhogy azt nem tudom brümmögtetni :-) Ja és nem is szeretnék, mert nem szeretem a brümmögést :-D
Hát ennyi lenne az ötlet, jöhetnek a kövek.
2012. december 17., hétfő
BS szótár: upstream és downstream
Egyes open source szoftverek esetében (pl ovirt) gyakran kerül szóba az upstream és downstream verzió, majdnem minden esetben amikor felhasználókkal beszélünk akkor a felhasználó visszakérdez hogy "Az up/downstream vajon mi?"
Cefet egyszerű: az upstream az a "community edition" megfelelője, a downstream meg a pénzes cók. Csak ezt így nem illik mondani :-)
Cefet egyszerű: az upstream az a "community edition" megfelelője, a downstream meg a pénzes cók. Csak ezt így nem illik mondani :-)
2012. november 11., vasárnap
oVirt lecke
Pár dolog, amit az eheti oVirt Workshop-on nyilvánvalóvá vált (legalábbis nekem):
Egyébként a ("rivális") cloudstack forráskódját olvasgatom, próbálgatom. Egyes dolgok marhára tetszenek, például hogy elmegy egy jetty-n, de van egy csomó dolog, ami tiszta marhaság. Pl a saját "IoC" rendszer, a belehegesztett mysql, stb.
- Az olyan környezetfüggőségek, mint a PostgreSQL és a JBoss nem hozzák közelebb az oVirt-et a felhasználókhoz. Sokan akarnák ez egészet egy kicsi környezetben futtatni, például tomcat-en vagy akár jetty-n. Akárcsak az appszerverből, adatbázisból sem szeretne a felhasználó hat félét a rendszerében. Meg tudom érteni...
Söt a fejlesztők is így akarják. - Tavaly ilyenkor még nem volt komoly verseny a nyílt forráskódú cloud management szoftverek között. Az oVirt is éppen publikálás elött állt. Azóta akkora szoftver-ajánlat jött létre, hogy az nagyon megnehezíti a felhasználók döntéseit. oVirt, Openstack, CloudStack, OpenNebula, satöbbi satöbbi. Nem hiszem, hogy ennyi szoftver túlélheti a versenyt, valaki rá fog faragni.
- Az OVirt UI nem rossz elsőre, de néhány helyen kicsit lehetne fejleszteni. A régi design-tól el kellene szakadni.
- A hibaüzenetek nem csak hogy nem elég jók, de néha kifejezetten gebasz. pl "Nem sikerült elindítani a virtuális gépet" - és vajon miért?
- Feature-szinten azért minden kritikus és bomlasztó hozzáállásom ellenére szerintem egészen jól állunk, de az architektúrát ki kell pofozni, a ganajt ki kell hordani. Csökkenteni kell a fejlesztők extra terheit, különben a kutya sem akar majd beszállni buherálni.
Egyébként a ("rivális") cloudstack forráskódját olvasgatom, próbálgatom. Egyes dolgok marhára tetszenek, például hogy elmegy egy jetty-n, de van egy csomó dolog, ami tiszta marhaság. Pl a saját "IoC" rendszer, a belehegesztett mysql, stb.
2012. október 28., vasárnap
subhub @ googlecode
Gondoltam egyet és megosztottam a subhub nevű pubsubhubbub kliensemet a google code-on. Ez a cucc két JMS sorral elintéz mindent. Egy JMS sorban küldöd fel, hogy mire íratkozzon fel, a másikon pedig kapod az feed updateket. Kicsit kezdetleges, de biztosan használható, mert én használom :-)
https://code.google.com/p/subhub/
https://code.google.com/p/subhub/
2012. október 17., szerda
Kotlin tesztkör
Néhány hónapja a Jetbrains orosz csapata bejelentette hogy új JVM nyelvet fejlesztenek Kotlin néven. Próbálgatom, gondoltam pár dolgot mesélek, hátha érdekes. Nem lesz teljes leírás, csak kedvcsináló. Ha megjött a kedved hozzá, látogass el a kotlin weboldalára! Türelmetleneknek a végén összefoglaló.
Meséltem neketek a beteges final-ozásomról. Nos a magamfajta elvetemülteknek alighanem üdítő feature a kotlin nyelvben az, hogy a változó deklarációjánál meg kell mondani, hogy változhat-e vagy sem. Ami változhat, az var (variable), ami nem, az val (value).
Ez semmi új, a scala is hasonló koncepcióval jött.
A változók deklarációjánál még tréfi az is, hogy nem kell kétszer elmondanod a típust. Kitalálja. Példa:
val kakukk = "kakukk" //nyilván string
val map = HashMap<String, String>()
Azt gondolom észrevetted, hogy new sincs. Nincsen. Mondjuk a melóhelyi projectemen, hogy a metódusok fele nagybetűvel kezdődik többnyire nem érteném, hogy ez most új objektum vagy csak hívás... desebaj, az úgyse nem lesz kotlinban.
Természetesen property-k definiálása is kapott egy szebb és kompaktabb szintaxist. Elösször is, minden amit var-ként definiál az ember, az egyből property, getterrel, setterrel, tokkal vonóval.
A null értékektől való para mindig is itt volt, mióta java platform létezik, meg még elötte is, csak szegény emberek elötte egy segmentaiton fault-ot kaptak, nem pedig NPE-t. Azért ha a kettő közül kell választani, akkor én még mindig inkáb a NPE-t választanám, az nem feltétlenül halálos.
Míg a java nyelv esetében erőtlen próbálkozásokat látunk annotációk bevezetésére, az új JRE nyelvek mind valamilyen mehanizmussal jönnek a null értékek kezelésére. A kotlin megkülönbözteti tipusonként, hogy lehet-e null. Például egy funkció, ami esetleg null-t ad vissza, azt így deklarálod:
fun talánNull() : String?
Na ez nagyon kedves, de a sima java-ban nincs ilyen, ezért minden java API minden visszaadott értéke a kotlin szempontjából esetleg null lehet. Na most például a slf4j LoggerFactory.getLogger(akármi.class) soha nem ad vissza null értéket, de a kotlin ezt nem érti, viszont néhány kényelmes operátort ad az esetleges null-támadás kivédésére. Az egyik a !! operátor. Ez a "Hidd el nekem hogy nem null, dögöljek meg itt azonnal ha null!!" operátor :) A log4j esetében például így nézne ki:
LoggerFactory.getLogger(akármi.class)!!
A másik lehetőség, az úgynevezett Elvis operátor. Elvis-szel azokat a helyzeteket tudod röviden megfogalmazni, amikor null értéket valami mással helyettesítenél. Pl ha getFoo() null-t ad vissza, akkor helyettesítsük le inkáb foo-ra:
val foo : String = getFoo() ?: "foo";
Ez a (x == null) ? null : x.getFoo() típusú műveletekre használatos. Így néz ki a fenti példa esetében fél szemű Elvis-szel.
x?.getFoo()
Ez null lesz, ha x null, és a getFoo() értéke, ha x nem null. Egész kompakt.
Ez a dolog nekem már scala-ban is nehezen esett le, de nincsen statikus változó. Első felmerülő kérdés egyből az, hogy akkor hogy a túróba fogok loggert deklarálni. Valahogy így
class object {
private val logger : Logger = LoggerFactory.getLogger(akármi.class)!!
}
Innetől ugyanúgy használhatod, mintha egy sima statikus logger lenne.
Minden új JVM nyelv lehetőséget ad closure-ök használatára (különben az érdeklődés hiányával kell szembenéznie), a kotlin sem kivétel. Nézzünk egy gyors példát:
fun kickntimes(int cnt, fn : () - > Unit) {
for(i in 0 .. cnt) {
fn();
}
}
...
kickntimes(100, {print("bla")});
Ez sem új, a groovy is és a scala is mindenféle extrákkal cicomázza fel a java osztályait. Így lesz a java.io.File osztálynak olyan metódusa, aminek például átpasszolsz egy closure-t és minden sorára meghívja. Valahogy így:
val myFile = File("bla");
myFile.forEachLine({ print(it); });
Mivel Jetbrains, nyilván idea plugin van hozzá. Azért annyira sokat azért ne várj tőle, épp úgy fejlesztés alatt áll, mint a nyelv maga. Szinez, pár helyen kisegíti a szintaxist, kódformáz. Refaktorálni többnyire nem tud, csak az alapokat (osztály átnevezés).
Szóval egészen sok új dolga van a kotlinnak, érdekes koncepciók vannak benne és van. (Ellenben a scala IDE mindig elavult eclipse-re epül, amellett hogy nem is tud sokat) kotlint használni kicsit olyan érzés, mintha délután négykor érkeznél a házibuliba: nagyon korai. Majd meglátjuk mi sül ki belőle.
var vagy val
Meséltem neketek a beteges final-ozásomról. Nos a magamfajta elvetemülteknek alighanem üdítő feature a kotlin nyelvben az, hogy a változó deklarációjánál meg kell mondani, hogy változhat-e vagy sem. Ami változhat, az var (variable), ami nem, az val (value).
Ez semmi új, a scala is hasonló koncepcióval jött.
A változók deklarációjánál még tréfi az is, hogy nem kell kétszer elmondanod a típust. Kitalálja. Példa:
val kakukk = "kakukk" //nyilván string
val map = HashMap<String, String>()
Azt gondolom észrevetted, hogy new sincs. Nincsen. Mondjuk a melóhelyi projectemen, hogy a metódusok fele nagybetűvel kezdődik többnyire nem érteném, hogy ez most új objektum vagy csak hívás... desebaj, az úgyse nem lesz kotlinban.
Mr Bean
Természetesen property-k definiálása is kapott egy szebb és kompaktabb szintaxist. Elösször is, minden amit var-ként definiál az ember, az egyből property, getterrel, setterrel, tokkal vonóval.
var name : String? = null;
Ennyi, ha nem akarod felüldefiniálni a getter tartalmát. Nagyon ajánlanám, hogy ne akard, vicces dolgokat lehet vele elkövetni. Pl ha a getterből a property-re hivatkozol, akkor simán a kód meghívja önmagát. Ezt gondolom majd kijavítják :)
Null-safety
A null értékektől való para mindig is itt volt, mióta java platform létezik, meg még elötte is, csak szegény emberek elötte egy segmentaiton fault-ot kaptak, nem pedig NPE-t. Azért ha a kettő közül kell választani, akkor én még mindig inkáb a NPE-t választanám, az nem feltétlenül halálos.
Míg a java nyelv esetében erőtlen próbálkozásokat látunk annotációk bevezetésére, az új JRE nyelvek mind valamilyen mehanizmussal jönnek a null értékek kezelésére. A kotlin megkülönbözteti tipusonként, hogy lehet-e null. Például egy funkció, ami esetleg null-t ad vissza, azt így deklarálod:
fun talánNull() : String?
Na ez nagyon kedves, de a sima java-ban nincs ilyen, ezért minden java API minden visszaadott értéke a kotlin szempontjából esetleg null lehet. Na most például a slf4j LoggerFactory.getLogger(akármi.class) soha nem ad vissza null értéket, de a kotlin ezt nem érti, viszont néhány kényelmes operátort ad az esetleges null-támadás kivédésére. Az egyik a !! operátor. Ez a "Hidd el nekem hogy nem null, dögöljek meg itt azonnal ha null!!" operátor :) A log4j esetében például így nézne ki:
LoggerFactory.getLogger(akármi.class)!!
A másik lehetőség, az úgynevezett Elvis operátor. Elvis-szel azokat a helyzeteket tudod röviden megfogalmazni, amikor null értéket valami mással helyettesítenél. Pl ha getFoo() null-t ad vissza, akkor helyettesítsük le inkáb foo-ra:
val foo : String = getFoo() ?: "foo";
Ez a (x == null) ? null : x.getFoo() típusú műveletekre használatos. Így néz ki a fenti példa esetében fél szemű Elvis-szel.
x?.getFoo()
Ez null lesz, ha x null, és a getFoo() értéke, ha x nem null. Egész kompakt.
Nincs static
Ez a dolog nekem már scala-ban is nehezen esett le, de nincsen statikus változó. Első felmerülő kérdés egyből az, hogy akkor hogy a túróba fogok loggert deklarálni. Valahogy így
class object {
private val logger : Logger = LoggerFactory.getLogger(akármi.class)!!
}
Innetől ugyanúgy használhatod, mintha egy sima statikus logger lenne.
Closure
Minden új JVM nyelv lehetőséget ad closure-ök használatára (különben az érdeklődés hiányával kell szembenéznie), a kotlin sem kivétel. Nézzünk egy gyors példát:
fun kickntimes(int cnt, fn : () - > Unit) {
for(i in 0 .. cnt) {
fn();
}
}
...
kickntimes(100, {print("bla")});
Extension functions
Ez sem új, a groovy is és a scala is mindenféle extrákkal cicomázza fel a java osztályait. Így lesz a java.io.File osztálynak olyan metódusa, aminek például átpasszolsz egy closure-t és minden sorára meghívja. Valahogy így:
val myFile = File("bla");
myFile.forEachLine({ print(it); });
IDE
Mivel Jetbrains, nyilván idea plugin van hozzá. Azért annyira sokat azért ne várj tőle, épp úgy fejlesztés alatt áll, mint a nyelv maga. Szinez, pár helyen kisegíti a szintaxist, kódformáz. Refaktorálni többnyire nem tud, csak az alapokat (osztály átnevezés).
Összevisszafoglaló
Szóval egészen sok új dolga van a kotlinnak, érdekes koncepciók vannak benne és van. (Ellenben a scala IDE mindig elavult eclipse-re epül, amellett hogy nem is tud sokat) kotlint használni kicsit olyan érzés, mintha délután négykor érkeznél a házibuliba: nagyon korai. Majd meglátjuk mi sül ki belőle.
2012. október 3., szerda
script kalandok
Ha a saját python tudásomat értékelnem kellene 1-10-ig akkor szégyenkezés nélkül 1-est adnék magamnak. A CV-ből is kihagyom, ugyanis nem karrier-cél. Ennek ellenére melóban mostanában az időm túlnyomó részét python gubancolás köti le sajnos, bugfixek, apróbb featurek, takarítgatás. Sokan csinálnák nálam jobban, talán akárki lelkesebben.
Első mese: egy python szál egy félórás tökéletes működés után (valami aszinkron taszkot vezérelt) egyszerűen csak meghalt. Vagy egy napon keresztül néztem azt a pár sor kódot és nem fogtam fel, hogy mi a baja. Aztán leesett: egy ponton a loggert hívta meg a script logging metódus nélkül. Valahogy így:
self._log('szopás')
Erre a python (helyesen) azt mondta ezen a ponton a végrehajtásban, hogy az pedig nem metódus, hanem ojjektum, és dobott egy hibát amit senki sehol nem kapott el. A szál elszakadt, a taszk meg beakadt és azt hiszem van valami timeout valahol 12 óra után, de nekem már ehhez is alig volt türelmem.
Egy szép példa arról, hogy logolás nélkül még elvben jó volt a rendszer, de logolással már nem.
Második mese: valamikor már írtam a pythonos srácok tab vs space, illetőleg 2 space vs 3 space vs 4 space vs N space vitájáról. Persze már akkor is találtam olyat, hogy valahol 13 space volt egy parancs elött. Erre a sonar hívta fel a figyelmemet, amúgy én se számolom. Szóval a 13 hogy jöhetett ki? Azt 2 db 4-spaces, egy 2-spaces és egy 3 spaces pythonos írta együtt? Mindegy, mert valahogy a python egészen idáig tolerálta a dolgot, legalábbis azt hiszem. Ma történt az, hogy megintcsak egy pythonban írt szálban keletkező hibát kellett kutatnom. Az __init__ metódus egy pár feltétel után meghívta a start() metódust, párszáz sorral lejjebb ott volt a start metódus ami elsőre nézve valami értelmes dolgot csinált. (van abban is kis gebasz amúgy, még vita trágya) Okénak tűnt, és mégsem volt az, a start ugyanis soha nem kapta meg a vezérlést. Mintha valami tréfás manó elvarázsolta volna.
Egy csomó lapozgatás után esett csak le: el volt szúrva a spacelés, így a start nem a szál osztály egy metódusa volt, hanem csak egy random funkció ott a levegőben, akit a fene se hív meg. Amúgy a szál meg frankón elindult, de nem csinált semmit se.
Tessék, space-nácik :-)
Az odáig oké, hogy én elcseszem, nyilván mert béna vagyok pythonban, de ezeket az elcseszéseket a project maintainerei csinálták, akik nyilván jobbak nálam, és még ők is ilyen alap dolgokat szúrnak el. Amúgy cefetjó, hogy dynamikus, modern, light, ésatöbbi, leszarom, csak menjen.
Első mese: egy python szál egy félórás tökéletes működés után (valami aszinkron taszkot vezérelt) egyszerűen csak meghalt. Vagy egy napon keresztül néztem azt a pár sor kódot és nem fogtam fel, hogy mi a baja. Aztán leesett: egy ponton a loggert hívta meg a script logging metódus nélkül. Valahogy így:
self._log('szopás')
Erre a python (helyesen) azt mondta ezen a ponton a végrehajtásban, hogy az pedig nem metódus, hanem ojjektum, és dobott egy hibát amit senki sehol nem kapott el. A szál elszakadt, a taszk meg beakadt és azt hiszem van valami timeout valahol 12 óra után, de nekem már ehhez is alig volt türelmem.
Egy szép példa arról, hogy logolás nélkül még elvben jó volt a rendszer, de logolással már nem.
Második mese: valamikor már írtam a pythonos srácok tab vs space, illetőleg 2 space vs 3 space vs 4 space vs N space vitájáról. Persze már akkor is találtam olyat, hogy valahol 13 space volt egy parancs elött. Erre a sonar hívta fel a figyelmemet, amúgy én se számolom. Szóval a 13 hogy jöhetett ki? Azt 2 db 4-spaces, egy 2-spaces és egy 3 spaces pythonos írta együtt? Mindegy, mert valahogy a python egészen idáig tolerálta a dolgot, legalábbis azt hiszem. Ma történt az, hogy megintcsak egy pythonban írt szálban keletkező hibát kellett kutatnom. Az __init__ metódus egy pár feltétel után meghívta a start() metódust, párszáz sorral lejjebb ott volt a start metódus ami elsőre nézve valami értelmes dolgot csinált. (van abban is kis gebasz amúgy, még vita trágya) Okénak tűnt, és mégsem volt az, a start ugyanis soha nem kapta meg a vezérlést. Mintha valami tréfás manó elvarázsolta volna.
Egy csomó lapozgatás után esett csak le: el volt szúrva a spacelés, így a start nem a szál osztály egy metódusa volt, hanem csak egy random funkció ott a levegőben, akit a fene se hív meg. Amúgy a szál meg frankón elindult, de nem csinált semmit se.
Tessék, space-nácik :-)
Az odáig oké, hogy én elcseszem, nyilván mert béna vagyok pythonban, de ezeket az elcseszéseket a project maintainerei csinálták, akik nyilván jobbak nálam, és még ők is ilyen alap dolgokat szúrnak el. Amúgy cefetjó, hogy dynamikus, modern, light, ésatöbbi, leszarom, csak menjen.
Feliratkozás:
Bejegyzések (Atom)