
Olin tänään (eilen) Microsoftin DevDays2007 -härdellissä. Oli siinä 1000kpl ohjelmointisuuntautunutta setää ja tätiä Tennispalatsissa kuuntelemassa MS-henkisten ihmisten jutteluita.
Oikeastaan laitanpa satunnaista päähän jäänyttä juttua.
No olkootkin typerä otsikko. Yhdessä edellisessä jutussa ihmettelin
että eikö kukaan muu koe hiiren väliaikaisen siirtämisen ylös
helpompana kuin alas. Sitten rupesi kiinnostamaan että missä se
hiiri ylipäätään käy päivän aikana ja kuinka usein.
Koodasin sitten C#.NET:llä
pienen ohjelman, 'hotscreen', joka pitää kirjaa näistä
liikkeistä. Käytännössä tallessa on ruudun resoluution kokoinen
taulukko laskureita joita sitten suurennetaan aina kun saadaan
ns. MouseMove -eventti. On myös toinen taulukko, sen laskureita
suurennetaan silloin kun painetaan näppäimiä (hiiren viimeisimmän
olinpaikan koordinaattien laskuria suurennetaan, tällöin voi nähdä
missä hiiri on kun kirjoitetaan). Tuossa ylemmässä kuvassa nämä
näkyvät keltaisina ja punaisina pisteinä koska kuvaksi tallennettaessa
se taulukko muunnetaan punaiseksi kanavaksi. Hiiren liikkeet ovat
vihreässä kanavassa.
Tuon ohjelman teossa hankalimmaksi vaiheeksi osoittautui taulukon kuvaksi tallentaminen, jostain syystä kaikki mahdolliset '.SetPixel(rgb)' -funktiot ovat tajuttoman hitaita (10-20 minuuttia 3GHz koneella 1600x1200 -resoluution kuvalle). Lopulta oikotie löytyi siitä että käytti Bitmap:n LockBits -funktiota ja käsitteli pikselidataa suoraan.
Analyysistä sen verran että minulla on windowsin Start-palkki
ylhäällä (kyllä, sen voi raahata sinne) ja käytän sen 'ääretöntä'
pinta-alaa nähtävästi paljon. Muuten kävi niin kuin ajattelin ja
ruudun alaosa on melko pienellä käytöllä. Tuon kuvan tietoja kerännyt
versio oli vielä vähän raakile ja sammui (ts. painoin punaista raksia,
enkä ollut -- vielä silloin -- koodannut kysymystä että haluanko
varmasti hukata puoli päivää dataa) juuri ennen kuin olin menossa
kotiin; kuva itse on siis suunnilleen puolesta välistä päivää.
Kaipasin windowsiin kunnollista grep:iä. Saatavilla olisi kyllä natiivi versio gnugrep:stä, mutta kun windowsin komentorivi on niin kankea käyttää, enkä muutenkaan ole koskaan komentorivillä projektihakemiston lähellä niin sitä ei tulisi käytettyä.
Netin nurkasta löytyi sitten sellainen kuin AstroGrep. On lyhyen käytön
perusteella vakuuttanut, sisältää myös regexp -haut, näyttää kontekstin ja
on muutenkin ihan järkevä. Uutisten mukaan olisi porttautumassa Mono:lla
toimivaksi, mutta Unix -pohjaisissa kilpailu onkin jo astetta kovempi.
Minulla on kotikoneella päivittäisessä käytössä suunnilleen kuusi työpöytää (joista 3-4 jatkuvasti), ja niillä melko iso kasa terminaaleja (eli niitä ikkunoita joihin voi kirjoittaa tekstiä ja jotka herjaa 'invalid command' takaisin).
Kyllästyin siihen että nämä näkyvät ikkunapalkissa pelkkinä 'rxvt-unicode':ina, ja kirjoitin pätkän skriptiä joka muuttaa tätä tekstiä. Lopputuloksena 'topic' -ohjelma.
Käyttö: 'topic joku teksti tähän'.
Koodi:
#!/usr/bin/env python import sys topic = " ".join(sys.argv[1:]) print "Setting title to '%s'.\033]0;%s\007" % (topic, topic)
Nykyään kun törmään johonkin KieliA vs. KieliB -vertailuun, tekee minun mieli lähinnä kääntää lehden sivua/käyttää 'takaisin' -nappulaa selaimessa. Tämä johtunee siitä että olen itse syyllistynyt yhteen jos toiseenkin 'vertailuun', erinäisissä yhteyksissä. Kun miettii niitä jälkeenpäin, tulee vain nolo olo, 'voiko kieltä ymmärtää näin väärin'.
Kun olen nyt kääntänyt yhtä pientä peliä python/GTK -ympäristöstä Java/MIDP:hen, niin näiden kahden kielen ja näyttökitin erot ovat tulleet hyvin selkeiksi. Etenkin kun alunperin ohjelma on kirjoitettu noin vuosi sitten, niin en silloin tajunnut pythonia lähellekään niin hyvin kuin nyt. Vieläkään en tajua sitä niin hyvin kuin haluaisin.
Mutta otetaan esimerkkien kautta. Konteksti on siis peli jossa on kaksiulotteinen kenttä (miinaharava). Kentällä käytetään usein funktioita joita varten pitää käydä jonkun ruudun koko ympäristö läpi, kuitenkin niin ettei keskellä olevaa ruutua oteta huomioon. Perustoteutus on tällainen:
class Board {
...
public void addToBoard (int x, int y, int value) {
for (int dy = -1; dy <= 1; dy++)
for (int dx = -1; dx <= 1; dx++)
if (! (dx == 0 && dy == 0))
addSingle (x + dx, y + dy, value);
}
...
}
Python -toteutus tuosta on melko lailla identtinen. Nuo for:t ja if:t
toistuvat siis jokaisessa ympäristöä läpikäyvässä funktiossa. Rumaa.
Python on kuitenkin tietorakenteiltaan joustavampi ja tarjoaa ueamman tavan tehdä asia ymmärrettävämmin:
NEAR_DELTA = [-1, 0, 1]
class Board:
...
def add_to_board (self, x, y, value):
for dy in NEAR_DELTA:
for dx in NEAR_DELTA:
if not (dx == 0 and dy == 0):
self.add_single (x + dx, y + dy, value)
...
Mutta miksi tehdä tuota testiä kun voidaan yksinkertaisesti sanoa:
NEAR_DELTAS = [[-1, -1], [-1, 0], [-1, 1], [0, -1],
[0, 1], [1, -1], [1, 0], [1, 1]]
# huomaa että [0, 0] ei kuulu joukkoon, testi siis turha.
class Board:
...
def add_to_board (self, x, y, value):
for dx, dy in NEAR_DELTAS:
self.add_single (x + dx, y + dy, value)
...
ja toisaalta, tuo looppi on oikeasti monessa paikassa, olisi hyvä jos
voisi sanoa 'tee tällaista tälle ympäristölle':
NEAR_DELTAS = ...
class Board:
def traverse_neighbours (x, y, cb_function):
for dx, dy in NEAR_DELTAS:
cb_function (x + dx, y + dy)
def add_to_board_alternative (self, x, y, value):
self.traverse_neighbours (x, y, lambda nx, ny: self.add_single(nx, ny, value))
def add_to_board (self, x, y, value):
def add_internal (nx, ny):
self.add_single (nx, ny, value)
self.traverse_neighbours (x, y, add_internal)
...
Tuossa 'alternative' käyttää perinteisempää lambda-muotoa. Jälkimmäinen
muoto voi näyttää pidemmältä kirjoittaa, mutta tuossa on jätetty sen
verran toteutusteknisiä yksityiskohtia pois että se ei kerro
oikeastaan mitään, pythonin lambda on myös muutenkin rajoitettu ja
sitä ehdotetaankin korvattavaksi sisäkkäisillä funktioilla.
Tuo ei ole tietääkseni ollenkaan mahdollista Java:ssa sellaisena
kuin se on MIDP 2.0 -koneissa. Se on ehkä hyväkin asia, Java kun
sellaisena vaatii vähemmän tehoa/muistia, mutta vuosi on 2006 ja
ohjelmointikieleltä voisi haluta sekä luettavuutta että mukavuutta.
Sovittelin tässä yhdessä välissä pyblosxomia toimimaan apache/1.3 mod_python:n alla. Valmiiksi apache/2.0:n alla toimiva skriptiä piti vähän puukottaa että se toimisi vanhemmalla versiolla, mutta nyt se näytti ihan oikeastikin toimivan.
Käänsin sitten pari pluginia perl:stä pythonille ja tutustuin paremmin pyblosxomin arkkitehtuuriin. Vaikka se onkin blosxomin johdannainen, yhteyksiä ei ole ehkä niin paljon kuin voisi olla.
Koska en tunne pyblosxomin rakennetta kovin hyvin (ja dokkarit näyttävät kuvaavan vain 'toivetilaa'), tein tällaisen pbinfo -skriptin. Sitä pystyy kutsumaan käytännössä vain pbifancy:n (interpolate_fancy -käännökseni pyblosxomille) kautta ja silloin annettaessa parametrina minkä tahansa objektin, se tulostaa sen sisäisen rakenteen HTML:nä. Tämä helpottaa tiettyjen tietojen esiinkaivamista ja siten hyödyntämistä.
Esim:
In [1]:import pbinfo In [2]:print pbinfo.showinfo(pbinfo, None, None)
Objekti joka sille annetaan on tosiaankin melko lailla mitä tahansa, olio, instanssi oliosta, funktio, dict, stringi, numero. ipythonilla kun tarpeeksi leikkii niin oppii pythonin ulkoisesta rakenteesta paljon.
En olisi uskonut että itse 'hurahdan' johonkin kieleen, mutta pythonin kanssa se on tällaista. Oikeastaan innostuttaa 'päästä irjoittamaan' sillä jotain.
Itse koodista ei kannata niin hirveästi välittää, se korkeintaan
osoittaa että vaikka olisi kuinka hyvä syntaksi, aina löytyy joku joka
käyttää sitä rumalla tavalla. Voisin melkein sanoa että funktionaalisuuden ja
imperatiivisuuden sekoitus pythonissa on sen ainoa kauneusvirhe, niitä on
niin helppo käyttää - kuten juurikin tein - rumasti.
Eilen tuntui ekan kerran pitkään aikaan koodaaminen tuskalliselta. Itse rakenteen päässä muodostamisella ei tässä ollut mitään osuutta, tehtävä oli yksinkertainen ja monesti aiemmin tehty. Työkalu oli vaan totaalinen turn-off tälle pullamössöpojalle.
TTY:n Käyttöjärjestelmät -kurssilla käytetään jostain syystä Modula-3 -kieltä (itseasiassa syy on luultavasti se että joku kulutti työaikaansa tuohon kesän tai pari ja asiasta oli ihan pakko saada jotain 'käytännön' tulosta aikaiseksi). Kielen avainsanat KIRJOITETAAN ISOLLA, joten se tuntuu huutavan. Peruskirjasto on avuton, ja emacs -moodi on yksinkertaisesti paska (sulut päättyvät vääriin kohtiin, viiveitä siellä sun täällä eikä minkäänlaista koodin luokittelu-väritystä).
Mutta kun on leetwannabe niin sitä koodia väännetään vaikka /bin/ed:lla. Harkkatyö on testausmoduulin osalta valmis. Vasara.m3:ssa (testimoduulimme) on noin kolmanneksen verran enemmän rivejä kuin 'valmiiksi' kirjoittamassamme varsinaisessa harkkatyöratkaisussa. Päälle tulevat vielä testisyötteet, mutta niitä ei enää tarvitse varsinaisesti koodata (muuta kuin bugien korjauksina harkkatyöhön).
Edellinen vähän samanlainen kokemukseni oli muistaakseni VisualBasic
yhdistettynä Excelin taulukoihin. Siitä purkasta ei ehkä onneksi tullut
koskaan mitään.
Heti nähtyäni lyhyet aikaleimat ja inhimillistetyt päivämäärät Googlen Gmailissa tiesin haluavani samanlaiset käyttöön. Kyse on siis siitä että kun saa Gmailiin mailia, siinä näkyy jonkin aikaa esim '1 day ago', tai '8 minutes ago'. Samoin varsinaiseen päivämäärään ei laiteta ylimääräistä dataa. Jos maili on tämän vuoden puolelta, siitä näkyy vain kuukauden nimi ja pävämäärä.
Periaatteena on siis järkeistäminen, koska kuka oikeasti välittää mihin kellonaikaan, sekunnilleen, noin puoli vuotta sitten tipahtanut maili tuli.
Eilen ja tänään koodailin sitten blosxomiin (tähän blogihärveliin) pluginin joka ottaa sisään päivämäärän (tai ottaa sen jutusta) ja muokkaa siitä söpömmän. Koska halusin siitä mahdollisimman monikäyttöisen, lisäsin myös säädettävän kielen ja lyhenteiden käytön, onhan tässä samassa sivustossa myös englanninkielinen osio.
Käytännössä ajat ovat muotoa "12:34", "Eilen 12:34", "Maanantai 11", "Lokakuu 14" ja "Lokakuu 14, 2004". Aikaleimat ovat muotoa "55 minuuttia sitten", "1½ tuntia sitten", "3¾ päivää sitten", "1 kuukausi sitten" ja "1¼ vuotta sitten". Näitä näkee sitten nykyään tällä sivustolla. Alkuperäisen ajan näkee heiluttamalla hiirtä päivämäärän päällä, jos käyttöliittymä tukee title -attribuuttia.
Koodi (toistaiseksi kommentoimaton ja ohjeistamaton blosxom -plugin, ja siis perliä) löytyy tiedostona tästä: fluffydate.
Päivitys: Eipä ole tuotakaan nimellä kaunistettu, mutta minkäs voi. Piti sanoman että tämä on tullut jo ennen vastaan, nimellä FuzzyClock, joka näyttää ajan todellakin 'ihmisten tapaan'.
Päivitys: Ei jaksanut tuota nimeä, se on nyt fluffydate (ent.
humandate).
Joskus ajatukset kulkevat omia polkujaan. Jo pitkän aikaa olin ajatellut että kommenttispämmiin liittyen minulla olisi joku ajatus, mutta en vain koskaan saanut siitä kunnon tuntumaa. Pari päivää sitten välähtikin ja sain ajatuksesta kiinni, tiesin mitä alitajunta oli keittänyt kasaan.
Käytän figletiä tuottamaan 'ASCII -kuvan' satunnaisesti arvotusta tekstistä (CAPTCHA). Tämä teksti sitten naputellaan pieneen lootaan ja painetaan 'lähetä' -namiskaa kun kommentoidaan jotain juttua. Esimerkin voi nähdä yksittäisessä jutussa painamalla 'Lisää kommentti' -nappia.
Koodi löytyy (dokumentoituna ja esimerkkeistettynä) tästä: wbcaptcha. Sanokaapa tuo nimi nopeasti
kolme kertaa peräkkäin.
Tänään algebran tunnilla Jarno kertoi että kuulemma jos korttipakan jakaa tasan kahtia, sekoittaa kahdeksan kertaa niin että joka toinen kortti on toisesta pinosta niin lopputuloksena tulee pakka siinä alkuperäisessä järjestyksessä.
Siinä istuttiin hetken miettimässä asiaa, kokeellisestihan se piti todistaa. Oma python -kielinen viritykseni olisi tässä pakka.py.
Tässä esimerkkituloste tapauksella 'pakassa 16 korttia':
$ ./pakka.py 16 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 8 1 9 2 a 3 b 4 c 5 d 6 e 7 f 0 4 8 c 1 5 9 d 2 6 a e 3 7 b f 0 2 4 6 8 a c e 1 3 5 7 9 b d f 0 1 2 3 4 5 6 7 8 9 a b c d e fJos tuntee yhtään heksoja niin voi huomata että tuo näyttää keräävän parilliset/parittomat luvut aina toiselle puolelle (pakan puolikas on tässä 0-7 ja 8-f). Esim. Joka iteraatiolla sekoittaminen kaksinkertaistaa perättäisten parillisten lukujen lukumäärän vasemmalla puolella.
Tällä hetkellä en bonobon keskisttymiskyvyllä oikein kykene tekemään
mitään f: iN, nN -> N funktota joka kertoisi millä
paikalla kortti i olisi n:nnellä sekoituksella.
Pitihän se eilinen uhkaus toteuttaa. Tein skriptin joka parsii Samin top -listan ja generoi dataa joka sopii mrtg:lle. Tämä siis tarkoittaa käppyröitä.
Koska IRC:ssä joku oli jo tekemässä 'samaan kuvaan' sijoittuvia käppyröitä, tuli mieleeni 'Blogmatch' -idea. Ja tässä se sitten on: Blogmatch.
Näyttää tyhjältä, mutta pikkuhiljaa ne statistiikat sinne kertyy. Samilla
olisi jokaiselle päivälle sijoitus, ja olenkin miettinyt miten ne tiedot
tuohon nyt lisäisi..
Kuten tässä viereisessä käppyrässä näkyy, koneen kuormitus on kova, vaikka päivitys
tapahtuu (pinserin listan tavoin) vain kerran tunnissa. Se sitten kestääkin
noin 3min.
Voinen rehellisesti sanoa että olen käppyrähullu. Melkein kaikki
kuviteltavissa olevat jutut parista koneestani on jollain lailla käppyröity.
Joten ketään ei varmaan yllätä se että menin ja suostuttelin (ei ollut edes
vaikeata)
Pinserin Samin tekemään
top
-listaan yksittäisen blogin tietojen näytön. Se toimii niin että
top-listasta katsot 'go' -linkistä numeron jolla blogisi on top-listassa
listattuna (jotakuinkin 'kuinka monentena' se on sinne lisätty), ja laitat
sen 'http://www.pinseri.com/bloglist/top-single.cgi?id=' -linkin perään.
Jotakuinkin näin: http://www.pinseri.com/bloglist/top-single.cgi?id=293
Tiedot ovat rivivaihdolla erotettuja, ja samassa järjestyksessä kuin itse listassa. Virittämäni ohjelma tekee niistä sitten mrtg:lle sopivia, lopputuloksena esim. käppyrä listasijoituksestani (ei ole vielä ollut pitkään päällä..).
Periaatteessa Mikko Saaren BlogTop:n voisi yhdistää tähän
samaan juttuun (olenkin jo kirjoittanut pätkän perliä joka parsii
tarvittavat tiedot). Silloin jokaiselle blogille voisi heittää tuollaisen
käppyrän, mutta tunneittain päivittyvänä. Jännää..
Viritin itselleni RSS -feedin hesarin tuoreisiin. Jonkin aikaa sitä väkertäessä meni. Suoraan sanoen ruminta hötömölöä mitä olen ikinä nähnyt.
Jonkinlaisen parsimisen onnistumisen jatkuvuuden tosin takaakin se että asiat näyttävät siellä olevan niin 'järkevästi' tehty, että muutoksia tuskin tulee.
Lähdekoodin alussa on muutamia muuttujia mitä
kannattaa säätää oman koneen mukaan (hsrss.py). Vielä en ole jaksanut
säätää vanhojen cache -tiedostojen poistoa. 30:n jutun päivävauhdilla se
levy tuskin täyttyy, etenkin kun tallennetaan vain pieni osa (itse juttu).
Aloittaminen on minulle hankalin asia. Sen jälkeen hankalinta on lopettaa. Sitä vain jatkaa ja jatkaa. Etenkin jos tekee jotain mistä näkyy pienenkin muutoksen jälkeen mitä ja millaiseksi se tulee. Siinä mielessä jos tehdään sellainen pieni (!) poikkeutus että hyväksytään HTML/CSS koodaamiseksi, niin siinä on se erittäin ikävä puoli että vaikka se näyttäisi toimivan ihan hyvin, niin koskaan ei tiedä mikä ihmeversio selaimesta nyt yhtäkkiä meni rikki. Hyvänä esimerkkinä vaikkapa tämä saitti jonka toimivuutta esim. IE:llä olen vain vmwren alla katsellut. Ei kiinnosta niin paljon että jaksan säätää ulkonäön 'sinnepäin'.
Mutta sellainen koodi mistä ei näe 'heti suoraan' mitä siitä tulee, niin sellaista on pirun ikävää kirjoittaa. Nautin suunnattomasti siitä kun saa pistää python+pygtk+glade -koodia pystyyn. Yhteen ikkunaan python -tulkki jossa kokeilee syntaksia, toiseen koodi ja jonnekin työpöydälle glade editoimaan liittymää. Ja tuloksen näkee heti kun vain sanoo './ohjelma'. Hyvinkin paljon erilaista siihen verrattuna mitä esim. C++:lla työskennellessa kokee. Suurin osa ajasta kuluu selvitellessä että 'mistäs tällainen tuli'. Ei ihan mutta lähelle.
Hyvin paljon helpottaa kun hajottaa työnsä pieniin palasiin ja tekee ne. Siinä mielessä XP on oikeassa, pitää tehdä lyhyttä koodia ja tehdä sille testin. Siinä näkee että 'hoplaa', se toimii -> motivaatio++.
Tosiaan kuulostaa järkyttävän naiivilta että saan kicksiä siitä että 'se
toimii', mutta enpä ole paremminkaan ole osannut asian muotoilla. Siinä
vaiheessa kun asiasta ei oikein näe että toimiiko se vai ei, niin ei sillä
oikeastaan niin väliäkään. Todella loistavia feedback -systeemejä ovatkin
olleet sellaiset jotka ovat saaneet sisäänsä aivan satunnaista
käyttäjäsyötettä, sellaista mitä en ole pystynyt kontrolloimaan. Lähiaikoina
tulee tosiaan mieleen enimmäkseen cgi-skriptit.
Koinpa käteväksi pienen palan koodia, nimittäin sellaisen joka tekee aina päivämäärän mukaan yksilöllisen ja aina uuden tiedoston / hakemiston. Pätkä on nyt perliä, mutta vastaavan yksinkertaisesti käännettävissä vaikkapa shell-skriptiksi, jolloin ei ole perl:n käynnistämisen 'overheadia'.
Pätkä:
$notedir = '/home/pvsavola/blog/laiffi'
my $dtstr = date +%y%m%d;
chop $dtstr;
while (-e "$notedir/${dtstr}-$i.txt") {
print "${dtstr}-$i on olemassa, hyppy yli..\n";
$i++;
};
Itse käytän sitä ainakin omassa 'getpics' -skriptissa joka a) liittää kortin tiedostojärjestelmään, b) tekee hakemiston sen päiväisille kuville (tässä se pätkä käytetään) ja c) siirtää ne kuvat sinne. Lopuksi se tulostaa komennon jolla saan selattua suoraan ne tiedostot gqview:lla, jolloin ei tarvitse kuin valita se komento, painaa hiiren keskinappia ja -enter-.
Toinen käyttö (lyhyen ajan sisällä) on tämä login satunnaisheiton lisäys,
niille kun ei blosxomin
alla jaksa aina keksiä eritystä nimeä, niin menevät
päivämäärän mukaan. Ja kun saman päivän ajana tulee monta heittoa niin..
Tossa se on kuitenkin alla, se skripti, että näkyy mistä on kyse.
#!/usr/bin/perl -w
my $notedir = '/home/pvsavola/blog/laiffi';
my $i = 0;
my $dtstr = date +%y%m%d;
chop $dtstr;
while (-e "$notedir/${dtstr}-$i.txt") {
print "${dtstr}-$i on olemassa, hyppy yli..\n";
$i++;
};
$dayfile = "$notedir/${dtstr}-$i.txt";
exec("jed $dayfile");
Anselista oikealle
Tiivistelmästä sen verran että oli siellä hyviäkin juttuja, ne vaan on hankalampaa muistaa jälkikäteen :)
Tietyllä tavalla ehdottomasti paras anti oli ihan vaan se että työporukan kanssa mentiin yöjunalla takaisin ja kälätettiin jutuista.