Updates from July, 2011 Toggle Comment Threads | Keyboard Shortcuts

  • Urban 23:54 on 11 Jul. 2011 Permalink |  

    Server status via SMS 

    Stormy weather makes me worried about my electronic equipment, especially servers. A summer storm can take out power, corrupt a HDD in the process, or in the worst case, fry absolutely everything by a strategically placed lightning strike.

    But even on a quiet winter day, hard disk can quietly fill with logs, one byte at a time, finally causing a bunch of services to die (I’m looking at you, Mysql).

    The point is, anything can happen and you have to check often to prevent an unplanned downtime, which can sometimes extend significantly because no-one checked1. And checking gets more tedious the more stuff you have. So this post describes a quick&dirty method, tailored to my needs, on the cheap.

    A quick disclaimer: I do know about Pingdom and similar services, as well as Nagios. However, I wanted a simple lightweight script, which runs on my home server behind a firewall, and queries my public servers over HTTP. Then it sends me a text, once daily.

    This is how it works:

    • my home server acts as an agent and tries to contact all the public servers
    • each server performs a quick and dirty on-demand self-test, responding with a message that reports the available disk space, mysql status, etc.
    • python script on the home server aggregates all the responses into a concise form, suitable for texting
    • and sends it, once a day.

    To test the public servers, I created a simple PHP script which performs some basic tasks a healthy server should be able to do, and returns a response. This is the version 1:

        /*A stands for Apache.
          If only "A" gets served,
          the web server is alive, but PHP doesn't work. */
        /*print P (short for PHP OK),
          followed by GBs of free disk space */
        echo "P[" . floor(disk_free_space("/") / 1024 / 1024 / 1024) . "G]";
        /*try connecting to MySQL */
        mysql_connect("server", "user", "pass")
            or die("db_down");
            or die("db_err");
        /*Print a short string ("My") through the
          database to prove it works.*/
        $res = mysql_query("select 'My' as my from user");
        $row = mysql_fetch_assoc($res);
        echo $row["my"];
        /*if everything works ok, this should
          return something like AP[10G]My
          which simply means apache works ok,
          php interpreter is fine,
          there's 10G of free disk
          and mysql is fine. */

    I wanted to get this summary delivered as a SMS notification. Twillio looked promising, but in the end wouldn’t take my CC, so I used this awesome hack to send free text in the form of a Google Calendar reminder.

    I extended the provided Python script to also get the free disk space of my home server and wrap everything up as a single SMS. The result looks something like this:

    Reminder: srv1_ok! c:1018M d:709054M srv2:AP[10G]My srv3:AP[2G]My

    This was at first meant to be just a form of “infrastructure unit test”, returning true if everything checks out OK, and false otherwise. But since there was room for additional info, I added more to fill the message.

    I’ve been somewhat reluctant to set up different notifications in the past, because that basically means more spam. But since I did it once at work (via e-mail), it’s been quite satisfying. An e-mail with the subject “Everything ok!” makes my day, and that’s what I get most of the time anyway.

    1. It’s just recently happened to me 🙂 []
  • Urban 22:31 on 19 Jan. 2011 Permalink |  

    Beyond gravity 

    With Gravity Lab, I’ve built what I think is a decent particle simulation framework. Which brings me to my hidden agenda: something I’ve wanted to do for a long time, but could only do incrementally, since the complexity of the entire task was just too overwhelming. So I present to you another particle simulator, codenamed Charges.

    It was a no-brainer, really. Ok, sure — there’s no money in educational apps. There’s that. But the thing was practically already done. Electric forces are just like gravitational forces: obeying inverse square law (read more here, or here). There’s just a matter of inverting the polarity, i.e., introducing “negative masses”. And change some constants.

    Or so I thought.

    It turns out a charged particle simulator is pretty useless by itself: particles always recombine (i.e., neutralize each other), or fly far away from each other until they get garbage-collected.

    What I needed were solid (metallic) objects, which could trap the particles — so I could observe the forces, make capacitors, simulate cathode ray tubes (CRT), and generally bring the “static” into “electrostatic”. So I decided to implement objects. And this is an epic journey of a developer, struggling with an interesting problem and generating much flow™ in the process. 🙂

    Simple enough, I decided to support rectangles and circles only. Why? Because this way, it can be quite easily checked whether a particle has hit the wall. When you tap the screen, I simply loop through an array of all objects and check if you tapped inside a body. If I find that to be true, I set the parent of the particle to the ID of the body. Then, when calculating the motion of the particle (which is done by summing all the forces of all the other particles), I only need to check if the particle has hit the parent object’s wall. If parent object is a rectangle, it’s really simple, like this:

    if rectangle
        if parent.left_wall.x < particle.x < parent.right_wall.x
            move freely (left or right)
            dont move along x axis
        if parent.bottom_wall.y < particle.y < parent.top_wall.y
            move freely (up or down)
            dont move along y axis

    With circles, I’ve already hit the first obstacle. You can’t separate x and y coordinate checking into separate conditions, because they are dependent. I tried many options without real success and particles always got stuck in some kind of deadlocked state. What finally proved to be the most efficient solution, was checking if the particle’s future position is too far away from the circle center (more than circle radius away), and projecting it back onto the circle boundary. Like this:

    if circle
        if (x^2 + y^2 < circle.radius^2)   
            move freely along x and y
            phi = atan2(y,x)
            x = circle.radius * cos(phi)
            y = circle.radius * cos(phi)

    It worked like a charm. But I faced a more dire problem, one that could not be solved in my limited particle-has-a-single-parent model. Namely, my particles couldn’t migrate from one parent to the next. Which would, of course, happen in nature: if you bring together a charged metallic object and an uncharged metallic object, some of the charge from the first one will be forced out into the second one.

    I wanted that, and it obviously couldn’t be done. Indeed, the composite objects made of circles and rectangles can become quite complex; how could one force the particles to stay within an object in such simple terms as shown above?

    I slept on it, and slept some more. And for the first time I can remember, the solution suddenly blinded me one morning. Yesterday’s morning, that is. And it goes like this.


    Let me explain. If a particle happens to be inside an overlap of two or more metallic objects (i.e, inside two or more objects at the same time), cycle through all of them every n frames of the animation. Let them all be parents, but not at the same time. And let the electrostatic forces that drive the particles away from each other do all the work.

    The bottom right particle in the picture above desperately wants to break away, to the South-East direction (down and to the right). If we bring in another body, the particle now has 2 parents (overlap). We iterate through both of them and let the particle just savor the moment for a while. And the moment it is assigned to object 2 above, it is propelled towards South-East, no longer bound by the first object. When there’s no more overlap, the time-sharing doesn’t happen any more. Voila.

    So hopefully, a new and amazing simulator will soon hit the App store. Stay tuned.

    • Bozo 19:44 on 20 Jan. 2011 Permalink

      ne ne ne… nisi še končal z gravitacijo :))) včeri zvečer sem neki vidu v enem dokumentarcu pa moraš to sprogramirat!!!… drugač pa enkrat pridem, pa da mi to vse pokažeš!

    • Urban 23:27 on 20 Jan. 2011 Permalink

      Dej posharej kej na deliciousu :p

  • Urban 03:24 on 10 Nov. 2010 Permalink |  

    OpenGL in njega nasledniki 

    Čez prvonovembrske praznike sem se lotil nepojmljivega: skodiral sem svojo prvo OpenGL aplikacijo. Moram reči, da sem navdušen nad preprostostjo vmesnika (OpenGL je nizkonivojski API za 2D in 3D grafiko); vedno sem imel občutek da gre za nekaj zelo kompliciranega1, ampak dejanska uporaba je zelo podobna konceptom iz 3D paketov (3DSmax, Blender,..).

    Definiraš točke v 3D koordinatnem sistemu, potem nanje napneš trikotnike, črte ali druge primitive, in zadeva že kar nekako izgleda. Če točkam določiš še barvo, bo renderer sam interpoliral barvo ploskev. Ko je objekt pripravljen, ga lahko premakneš po (x,y,z) ali poljubno rotiraš, tako da je v resnici najmanjši problem narisati vrtečo se kocko:

    Na posnetku sta 2 vrteča se ikozaedra2 (dvanajsterca oz. telesi z 12 ogljišči) in kocka, ki se premika po Lissajousovi krivulji (frekvenca po osi y je točno dvakratnik frekvence po osi x).

    Pri učenju sem si pomagal z naravnost odličnim tutorialom Jeffa LaMarcha, ki sicer opisuje uporabo na iPhonu, se pa tematike res loti pri osnovah. Priporočam! Zadeva pa je zaradi abstrakcijske narave OpenGL-a aplikabilna na praktično vsa okolja.

    In prav to me je pri vsem tem najbolj fasciniralo: totalna abstrakcija. OpenGL definira celo svoje podatkovne tipe (GLint, GLfloat, ipd.), s katerimi jamči, da se bo zadeva prevedla na praktično vsaki arhitekturi, ne glede na uporabljano velikost (sizeof) tipov. Zadeva si zato lahko brez težav sposodi moto Jave “napiši enkrat, poganjaj povsod”.

    In povsod pomeni tudi na spletu, v obliki WebGL. Ta je trenutno sicer še v postopku standardizacije3, gre pa za razširitev HTML canvasa z API-ji na osnovi OpenGL ES (= OpenGL for Embedded Systems), ki predstavlja podmnožico funkcionalnosti polnega OpenGL. OpenGL ES je podprt tudi na vseh iOS napravah (iPhone, iPad), Androidu, Symbianu in WebOS-u.

    Ta prenosljivost pa tudi razjasni, kako so lahko Googlovci tako hitro sportali Quake v HTML5: koda za quake 3 je pod GPL, tako da jo je bilo treba najbrž samo prestavit.

    1. kriva je seveda prva izkušnja, ko sem kot froc, še preden sem poznal sinus in kosinus, brez uspeha poskušal reverse-engineerati demo vrteče se kocke v Delphiju. Pa tudi OpenGL še ni bil ravno polnoleten takrat 🙂 []
    2. koordinate ogljišč mnogih teles lahko dobimo na Wolfram Alphi, takole: dodekaeder []
    3. za poganjanje rabiš zaenkrat še development build Firefoxa, Chroma ali Safarija []
    • božo 15:43 on 10 Nov. 2010 Permalink

      oj če bi na mesto na TK šel na smer PA, bi že v 3 letniku lahko obračal kocke v 3d prostoru kar na papirju :))) – no vsaj matrike. Ko bi prišu v 4 letnik bi ti blo pa dovoljeno še v Matlabu al pa Matemaci obračat kocke :)) – malo zajebancije :))

    • Urban 18:47 on 10 Nov. 2010 Permalink

      Hehe, na papirju smo jih tud mi obračal 🙂 ampak eno je domača naloga v 3. letniku, drugo pa ipad app ki ga boš vidu v naslednjem postu 🙂

  • Urban 20:35 on 1 Sep. 2010 Permalink |  

    iPhone GPS logger 

    V prejšnjem postu sem se razburjal nad odsotnostjo GPS-ov v fotoaparatih. Pa sem razmišljal naprej: imam telefon, ki je izjemna lokacijska naprava — združuje vsaj 3 lokacijske tehnologije:

    • Triangulacijo z uporabo baznih postaj (natančno na 1-5 km).
    • Zna uporabljat WiFi lokacijo1 (na kakih 50 m natančno).
    • Z obojim lahko pomaga pravemu GPS-u, omrežni A-GPS od mobilnega operaterja pa mu postreže še z almanahi in točno uro. Z vsem tem se GPS dobro ogreje za štart in res hitro najde točno lokacijo.

    Kombinacija vseh tehnik pa, poleg hitre določitve lokacije, z omejeno natančnostjo dela celo v zaprtih prostorih. Velika hitrost lociranja in dodatna podatkovna povezava za nalaganje podatkov na strežnik pa za saboj brez problema pustita Garmine in razne namenske loggerje.

    Edini problem predstavlja moja želja, da naj taka aplikacija teče v ozadju in me locira periodično na par minut, česar pa Steve Jobs, logično, ne pusti.

    Na jailbreakanem telefonu to ne bi smelo biti tak problem. Pa je kar. 🙂 Tule bom podokumentiral korake na poti k uspehu, ki sem jih mukoma prehodil v zadnjem tednu.

    Najprej sem našel pripomoček findme. Gre za konzolno aplikacijo, napisano za iPhone OS še pred časom SDK. Uporablja Skyhook API za WiFi geolokacijo in ne dela dobro. Izgleda, da locira samo po IP-ju, in kaže isto točko za celo Ljubljano. To sem seveda ugotovil šele, ko sem napisal bash skripto, ki je klicala curl za posredovanje podatkov na strežnik, in potuhtal kako skonfigurirati LaunchDaemona, ki je skripto periodično poganjal. Dodaten problem: LaunchDaemon opravil ne izvaja med spanjem, si pa zapomni da jih je zgrešil in jih izvede ko se naprava zbudi. Na žalost še vedno precej neuporabno.

    Seveda je iPhone SDK postregel s CoreLocation API-jem. Ta omogoča, da dobimo točno lokacijo na osnovi vseh treh tehnologij (Cell ID, WiFi, GPS), se pa pojavijo drugi problemi. Najde se sicer primer kode, prevajanje konzolne aplikacije, ki uporablja nedokumentirane apije za zbujanje telefona, pa je jama brez dna2. Končno aplikacijo z gornjega linka sem našel tudi na Cydii, in se je razsula še preden se je zagnala. Z zgornjo kodo se zato nisem več trudil.

    Naslednja postaja: iLocalis. Kar dodelana zadeva, ki omogoča spremljanje lokacije, podobno kot Mobile Me, zraven pa še zaklepanje telefona, snemanje avdia na daljavo, nastavitev preusmeritev, pošiljanje SMS in klicanje, ter brisanje podatkov s telefona — vse na daljavo. Aplikacija dela presenetljivo dobro (trudi se ne izprazniti baterije, dobro lovi exceptione in tudi v logih od telefona lepo izpisuje stanje), in spisal sem že tudi skripto, ki iz strani pobere koordinate in jih zloži v mojo bazo3.

    Ampak imel sem pa zelo neprijeten občutek; zadovoljstvo, ki sem ga pridobil z arhivom svojih koordinat, me je minilo, če sem pomislil, kaj vse lahko avtor iLocalisa naredi z mojim telefonom (pobriše ali ukrade popolnoma vse podatke, pošilja SMS-e ali naredi kakšen klic na 090 in se malo pofinancira). Zato sem bil praktično prisiljen njegov server zamenjati s svojim. 🙂

    Kako? Aplikacija je zaprta in podpisana, tako da popravljanje binarne datoteke (na windowsih silno uporabna tehnika) odpade.

    Problem sem rešil tako, da sem domeno, na katero daemon pošilja podatke, v iPhonovem /etc/hosts preusmeril na svoj IP naslov. Potem sem z vzvratnim inženiringom spisal nekaj svojih PHP skript, ki dovolj dobro imitirajo originalen strežnik, da se aplikacija ne pritoži. Problem pa se je pojavil, ker je edina povezava, ki me je zanimala — to je tista, ki je pošiljala podatke na strežnik — delovala preko HTTPS. Moj samopodpisani certifikat pa je povzročil napako v povezavi in prenos se ni izvršil.

    No, izkazalo se je, da je za delovanje dovolj že, če izdelaš svoj CA (Certificate Authority), z njim podpišeš certifikat za strežnik, potem pa certifikat od CA registriraš na telefonu (enostavno ga odpreš iz maila ali s spletne povezave). In zadeva končno deluje. GPS logger, ki ga vsak dan nosim s sabo in mu redno polnim baterije. 🙂

    Vas že slišim, kako pravite: “kaj pa boš s tem?” Ne vem še. Kaj pa bo Stephen Wolfram z dvajsetimi leti podatkov iz keyloggerja? Za nekaj bodo že uporabni, če ne za kaj drugega, pa za označevat fotografije glede na uro.

    1. MAC naslovi WiFi dostopnih točk so globalno unikatni in če enkrat prevoziš cel svet in si zapišeš, kje se kakšna dostopna točka nahaja, lahko že s tem, katere MAC-e vidiš, približno veš kje si; firma Skyhook je naredila točno to. []
    2. Dependency hell pri prevajanju toolchaina, različne verzije iPhone OS-a, Applovo podpisovanje, joj, prejoj []
    3. če koga zanima: na strani iLocalis.com moraš sharati svoj zemljevid, ta pa preko AJAX-a vleče podatke iz enega URL-ja v XML formatu. Potrebno je samo narediti cron job ki vsake pol ure poparsa ta XML []
    • dare 09:53 on 2 Sep. 2010 Permalink

      zvito, ni kaj 🙂

  • Urban 21:51 on 19 Aug. 2010 Permalink |  

    Lifestream in content stream 

    Vedno težje spremljam kje vse puščam svoj content — sprobal sem že 101 platformo za shranjevanje, deljenje ali organiziranje informacij, kak ducat pa jih tudi redno uporabljam.

    Poglejte kaj mislim: imam blog za resne poste, fotoblog za izbrane slike, Picaso za malo manj izbrane slike, še kakšen blog za čačke, Google reader shared feed, spam blog na Tumblrju, Twitter za mini statuse, Delicious za bookmarke, Youtube za favoritanje posnetkov, Instapaper za daljše članke, Evernote za zapiske, Dropbox za fajle, pa še par platform ki jih ne uporabljam zares za posredovanje vsebin (Facebook, Flickr, LinkedIn), itd., itd.

    Večina od teh storitev je pri meni zapolnila kakšno res specifično nišo. Spam postov nočem objavljati na glavnem blogu, hkrati pa jih ne morem sharati na Google Readerju (vsaj dokler niso napisani). Sharanih postov na Google Readerju — skupaj z duhovitim komentarjem, za katerega porabim več časa kot upam priznati in včasih naraste že skoraj v svoj post — pa tudi ne morem nikomur poslati kot link, ker pač nimajo permalinka (fail).

    Ta vedno večja množica opcij, ki se vse bolj prekrivajo, mi počasi že začenja iti na živce (paradoks izbire: sedaj se moram pred vsakim sharanjem še odločati, kaj bi bila najprimernejša platforma 🙂 ).

    Zares grdo pa postane, ko hočem kaj najti. Kje sem zadevo napisal, sharal ali komentiral? Dostikrat stvari hitreje na novo najdem na Googlu, kot da se prebijem čez vse svoje storitve in eno po eno preiskujem oz. ugibam ključne besede.

    In nenazadnje: storitve crkujejo1; dogajajo se zlorabe, zapirajo se accounti, in hitro lahko ostaneš brez podatkov2. Podatki pa so vredni toliko, kot je bil vreden čas, ki si ga porabil, ko si jih ustvarjal.

    Zaradi vseh naštetih razlogov sem čutil silno potrebo po tem, da ves svoj content stream nekako zberem vkup. Pa sem ga (večino).

    Najprej disclaimer: lahko bi izbral lažjo pot in inštaliral WP lifestream. Tako bi dobil strašno fin lifestream, z lepimi ikonami. (Sicer precej bolj namenjen agregaciji statusov, manj pa arhiviranju pravega contenta).

    Ker pa ga seveda nisem našel na prvi strani prvega searcha, sem se odločil za agregiranje RSS-ov z WP-o-Matic-om. Ta omogoča, da vse svoje smetenje po raznih platformah potegnem v svoj posebej za to narejen WordPress kot polnokrvne poste. S tem dobim tudi zastonj search in arhiv celotne zgodovine (in ja — WP-o-Matic zna cachirati tudi slike).

    Glede na to, da je vsa dosedanja vrednost v preteklih objavah, je bilo nujno poskrbeti za kompleten izvoz vseh starih vsebin. S tem pa je bilo več dela kot sem mislil.

    Štartal sem z Delicious.com, kjer imam 3000+ javnih bookmarkov (privatnim se zaenkrat odpovem). Delicious preko RSS daje na voljo samo največ 100 objav, lahko pa jih dobiš v celoti na spodnjem linku.


    Seveda so v delicious XMLu in ne v RSS, zato sem jih s spodnjo quick’n’dirty Ruby skripto prepisal v RSS ter nato z WP-o-Maticom importal kot file s svojega strežnika. (Skripta z if-om v 18. vrstici tudi izloči vse privatne bookmarke).

    require 'rexml/document'
    include REXML
    data = open('all.xml')
    xml = Document.new(data)
    root = xml.root
    puts '<?xml version="1.0" encoding="UTF-8"?>
    <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://web.resource.org/cc/">
        <description>Delicious bookmarks</description>
        <atom:link rel="self" type="application/rss+xml" href="http://feeds.delicious.com/v2/rss/urbans?count=15"/>'
    root.each_element do |e|
    	if e.attributes["shared"].to_s != "no"
    		desc = "<description>" + e.attributes["description"].to_s + "</description>"
    		puts "<item>
          <guid isPermaLink=\"false\">http://delicious.com/url/#{e.attributes["hash"].to_s}#urbans</guid>
          <source url=\"http://feeds.delicious.com/v2/rss/urbans\">urbans's bookmarks</source>
    puts '</channel></rss>'

    Naslednji je na vrsti Google Reader. Z malo brskanja najdemo tale URL:


    Zamenjati je treba {USER_ID_HERE} z našim Google Reader user idjem. Naj vas ne zavede tako kot mene — to ni ime vašega accounta. Dejansko se rabiš zlogirat v Reader, kliknit Sharing settings in skopirat numeričen user id (slika).

    Potem lahko številko n nastavimo na poljubno visoko in importamo celotno zgodovino (Yay, Google). Samo ne pozabit zbrisat potem tega joba in narediti enega, ki vleče samo 10 itemov, da ne bo WP-o-Matic vsakič nalagal vseh itemov.

    Za WordPress je bilo najhitreje, da sem začasno povečal output RSSa na dovolj veliko številko (Settings / Reading / Syndication feeds show the most recent n items).

    Pri Twitterju lahko potegnemo preko RSS-a do 200 updatov, če na konec RSS URL-ja dodamo ?count=n. Za več bi bilo treba kodirat in uporabit API.

    Pri parih zadevah pa sem imel tudi srečo, da še ni prav veliko objav in sem vse potegnil kar preko običajnega RSS-a.

    Saga še ni končana, precej je še storitev, ampak nekako po Paretovem pravilu sem podelal tistih 20% za 80% izkupička, tako da iskanje in permalinkanje delata zelo zadovoljivo — zadeve pa imam zdaj seveda na svojem serverju in jih lahko v prihodnje uporabim tudi za trening kakšnega bayesovega filtra (recimo za rangiranje blogpostov, ki jih pregledujem).

    Update (15.9.2010): WP-o-matic mi vsake toliko povsem naključno podvaja objave. Izgleda, da gre za nek long-standing bug, delno odpravljen, v enih primerih pa še vedno nagaja. Na hitro sem pogledal kodo in plugin res preverja unikatnost objave glede na hash, nisem pa naprej debugiral kje se zalomi, ker je napaka preveč sporadična. Kot rešitev sem zato inštaliral plugin Duplicate Post Eraser.

    1. Sajt Ma.gno.lia je tekel na enem ne-backupiranem Macu mini, in ko je ta izdihnil, so vsi uporabniki ostali brez bookmarkov []
    2. da ne omenjamo, da tudi linki umirajo; zanimiv eksperiment bo, ko enkrat preverim, koliko od mojih 3000 bookmarkov na Deliciousu še kaže na žive linke. []
    • dare 15:04 on 24 Aug. 2010 Permalink

      “Podatki pa so vredni toliko, kot je bil vreden čas, ki si ga porabil, ko si jih ustvarjal.”

      Love this.

    • dare 15:06 on 24 Aug. 2010 Permalink

      Drugač pa super, tole si bom tut jaz zrihtal. Nisi pa nič elaboriral kaj je narobe z WP-Lifestreamom?

      Naslednja naloga: na enem mestu zberi vse komentarje na vse sharane zadeve 🙂

    • Urban 17:32 on 24 Aug. 2010 Permalink

      WP Lifestream je super. Samo da sem štartal s temle, pa kasneje tud nisem več probaval, če bi se dalo zrihtat search, shranjevanje celotnih postov, import zgodovine in cachiranje slik.

      Drugače pa za commente še najbližje pride Disqus, ampak za sajte ki ga nimajo (recimo tale), to odpade :s .. Drugače pa nimam ideje kako bi sploh iskal commente; pri WP se načeloma lahko naročiš tud na commente na posameznem postu, ampak to niso samo tvoji.

    • dare 23:24 on 31 Aug. 2010 Permalink

      evo, zdele sem se cist slucajno spomnil, da sem ti pustil komentar in da si mogoce kaj odgovoril 🙂

      dost neucinkovita komunikacija, ce mene prasaste

Compose new post
Next post/Next comment
Previous post/Previous comment
Show/Hide comments
Go to top
Go to login
Show/Hide help
shift + esc