Kaukonäkömatka eli C++ tutti numero 3 ===================================== OSA III Satunnainen hetki ostoskeskuksessa voi olla puistattava. Löysin itseni läheisen elintarvikepakkaushyllyn viereltä tyhjyyteen tuijottamassa. Seisoin siinä hölmistyneenä, paikallani aivan. Ihmettelin, mitäkö tuokin aikoo, onkohan se jokin nisti? Liikahdus, juoksin itseäni karkuun. Mutta minä olin vain valvonut. Valvonut niin kauan etten edes muistakaan. Ei muista kuin kauniin maan siinä pakkauksen kyljessä. Sinne saahan matkustaa? Kaukomatkan maailmaan, mahdollisuuden näen uudestaan! Siis keltainen vuorineuvoksetar oli saanut vain maksatulehduksen nautittuaan liian vähän C-vitamiinia, siksi lääkäri määräsi hänelle kunnon annoksen C++ -vitamiinivalmistetta! Kolme pilleriä päivässä. Niin, tämän osan opetuspainotteisen materiaalin on sitten kirjoittanyt eräs tuttavani, monta vuotta C/C++ -kieltä harrastellut, sekä eräissä piireissä guruttunut henkilö, Heikki Höijäri. Siis minä (Joro) vastaan edelleen paskanpuhumisesta, mutta koodiesimerkit sekä järkevämmänpuoleisen tekstinmuotoiset ovat Heikin käsialaa. Annoin Heikille mahdollisuuden osallistua tutin tekemiseen hänen luettuaan kaksi edellistä osaa ja olleen kiinnostenuisemman puoleinen kyseenomaisenmuotoisesta asiasta. Oikeamman näköinen selitys lieneskelee, että Heikki tahtoi esimerkkien olevan edes tässä osassansa asiallisemman puoleinen. Suuressa epäviisaudessani menin sitten lupailemaan suurensuurta palstatilan näköistä tästä tutoriaaliputoriaalista. Tilanne lieneskelee väliaikaisempi, joten seuraavassa osassaan onpi taas vanha tuttu turpallinen tilanne ja minäpinä taas kirjoittelemassansa koodia! Niin, ja nyt kun kaikki melkein tuntevat itsensä vaivautuneeksi, niin aloittakaamma tämän tutin tutunhutunomaisella puheensolinaisella asiasta vanhaa. Disclaimer ---------- Tässäpä ei ole disclaimeria tai mitään muuta varoitusta, koska sellaiset on todettu täysin turhiksi. Tai no ei oikeasti ole, joten kaipa tähän pitää pieni sitten kirjata. Enpäs siis ota vastuuta esimerkkien toimivuudesta tai asioiden oikeellisuudesta. Eikö ota kukaan muukaan, kuten esimerkkihenkilömme Heikki. Sinä kyllä iteksesi saat ottaa vaikka mitä, kunhan et muita asiaan sotkeskele. Niin ja kun on puheentapaista ollut vaikka mistä, niin kerrompa jostain pelottavasta vaiheteheksi. No otetaan sitten itse pirua sarvista ja mietiskellään Ameriikaan yhdysvaltojensa presidenttismiehen valintasta. Siellähän kuuleman mukaan on nyt suuri pelastaja, sorrettujen kansojen vapauttaja, itse antikristus(ken teloittaja)! Tottahan tokiloinen, tällainen (anti-)sankari tulee toistamiseen valita johtoiseen, ja miksei sen jälkeen uudestaan, uudestaan! Ja teletappiloisuuskansa olisi mielissänsä! Vai olisivatkohan sittenkäistään? Kuitenkin suuttuloisivat tuollaiselle ja alkaisivat kapinoida. Siinä sitten vielä sisällissotaiseen ajautuisivat ja joku Venäjänmaa keksiikin, että tapetaahan kaikki kun eivät tajua mistään yhtikäisen mitään kun ovat toistensa kurkussansa. Pörörörmmpm. Entäpäs ovatkin toisenmilisiä he ja valitsevatten jonkun toisennäköisen ihmisolioisen valkeahkoon taloonsa hyppimään ja pomppimaan kunnes kuoleepi hän? Siellähän hän sitten pomppisi ja kaikki ois häpihäpi! Niin, mutta sittenkös joku ählämöidi sinne menis ja laittais sille jojon, jotta pysisi paikallansa hän. No siitäkös hyö suuttuisvat ja joku aivokuoallut varapersidentti pääsis sitten painelemaan ydinpomminappuloitansa vesivehmaan jenkkaisen tahdissa! Mites sitten suut asetellaan vinoon tahi hymiönmuotoon? Hä hä? Iso nou-nou... Ja kaikille tiedoksi vielä, että tätä saa levitellä vapaammanpuoleisesti, aivan kuten naapurin uranainen saa levitellä omia antejaan, kunhan ei ihan julkeasti mene levittelemään. Tai no kyllä tätä saa levittää kun ei sitä ole toistaiseksi laissakaan kielletty. Tai no on, sillä tämähän on teos ja tekijänoikeuden alainen, mutta kun näistä teoksista saa määrätä se tekijänoikeuden haltija, joka sattuu olemaan minä, niin minäpä päätänkin, että tätä saa levitellä. Ei kyllä menis läpi tämä selitys siinä naapurin uranaisen tapauksessa, vaan vankilaan pistäsivät tai ainakin sakkoja antasivat. On kyllä ihme touhua. Mutta enpä voi mitään, niin on joku minua viisahampi mennyt päättämään. Tosiaankin semmoinen lisäys vielä, että se paritus on kieällettyä niin eipä mennä sutenööriperkeleet perimään tämän levityksestä maksua elikkäs ilmahteeksi pitääpi siirrellä muille immeisille. Hei, maailma! ------------- Oho, jäi vanha otsikko tuohon. Voisko joku vaihtaa sen? Ai miksei vai? No voihan ihme... Tehdään sitten uusi otsake. Poikkeukset ----------- Koska aina ei voi olla kaikki ihan tervehiä ja toimia kuten tahdotaan tai olettaa saattaisi. Siksikös me heittelemme poikkeuksia ylt ympäriinstä, aivan kuin mätiä tomaatteja huonon puhujan päälle. Jotta oma nahka säästyy, niin otetaanpa poikkeus kiinni ja kutsutaan poikkeuksen päälle ymmärtävä taho hoitamaan tilanne taas normaalintapaiseksi tai sitten vaan kadotaan poies. Melkein kuin joo. Elikkäs pitäisi olla tiedossansa mahdollinen poikkeuksen heittävän koodipätkän puoleinen. Tällöin voidaan luoda try - catch -rakenne, jossa kokeilemme onnea lotossa, totossa ja eräässä kolmannessa asiassa. Eli siis try -osassa koetellaan mitä se mahtaapi tuoda tullessansa vaiko tuopiko se yhtikäs mitään, ja catch -osassa korjataan tilanne, kun kaikki, tai ainakin jotain sattuupi kaatumaan päällensä. ---[ poikkea.cpp ]--- #include using namespace std; int main() { try { // Tähän pahaa koodia int arvo; cout << "Anna numero väkiltä 1-9" << endl; cin >> arvo; if (arvo<1 || arvo>9) throw arvo; cout << "Antamasi numero oli " << arvo << endl; } catch (int virhe) { cout << "Antamasi numero, " << virhe << " on virheellinen" << endl; } return 0; } --------------------- Tuo heitettävä poikkeus voipi olla mitä tahansa tyyppiä. Edellisessä esimerkintapaisessa heitetiin int-tyyppinen poikkeus. Niin, ja noita poikkeuksia voidaan yrittää kopata hanskaloiseemme eri tyyppisiänsä: ---[ poikkea2.cpp ]--- #include #include #include using namespace std; class Poikkeus { public: string lue() { return "Poikkeus-luokka"; } }; class Dummy { public: virtual void b() {}; }; int main() { try { int arvo; cout << "Anna numero väkiltä 1-4" << endl; cin >> arvo; switch (arvo) { case 1: throw arvo; break; case 2: throw string("string"); break; case 3: throw new Poikkeus(); break; case 4: Dummy* tmp = NULL; typeid(*tmp); break; } } catch (int virhe) { cout << "Poikkeus: " << virhe << endl; } catch (string virhe) { cout << "Poikkeus: " << virhe << endl; } catch (Poikkeus* virhe) { cout << "Poikkeus: " << virhe->lue() << endl; } catch (std::exception& e) { cout << "Poikkeus: " << e.what() << endl; } return 0; } ---------------------- Elikkä näin hianoja esimerkkilöitä olimma saanehet. Tämä poikkeuksellinen tutti jatkaa matkaansa kohti seuraavanmuotoista aihetta, jossa viennellään vaikkapa pullaisesta pitkoisesta pullainen poikainen. Semmonen rusinainen pullainen poikainen, jolla on rusinaiset silmät, rusinainen suu, ja kolme rusinaista nappia. Anaam. Tyypinmuunnokset ---------------- Niin muunnetaanpas hieman tyyppiä, siis tehdäänkin tuosta tuollaisen toisenlainen. Siis ei tälläinen niinkuin se sattuu alkuisenperin olemaan. Niin ja mitens tää nyt oikeasti onnistuupi? Niin, joo oleppas hyvä (tahi paha valintaisesi mukaan, jos sellaiseen olet halukkaammanpuoleinen) Heikki! Hei, ja suoraan asiaan. Perinteinen C-kielessäkin oleva tyypinmuunnos: int a; double b; i = (int)b; //Vanha C-tyylinen muunnos i = int(b); //Tämä on C++ oma määritys, vastaa edellistä riviä Eli tuo on täysin pätevä myös täällä, mutta toimii vain perustyypeille. Esimerkiksi luokkien tyyppimuunnokset eivät onnistu. Tai no onnistuu kyllä, mutta tuon tavan käyttäminen luo mahdollisia virhetilanteita ja ovat muutenkin epäsuositeltavia. Tämän vuoksi C++:ssa on muutama muunnosoperaattori: reinterpret_cast (muunnettava) dynamic_cast (muunnettava) static_cast (muunnettava) const_cast (muunnettava) Nämä on tarkoitettu eri muunnoksia varten. Seuraavassa erittely ja tarkempi selostus. (Hiihihih (Joron lisäys)). reinterpret_cast Tarkoitettu muuntamaan osoitin toiseksi osoittimeksi. Osoittimen sisältö kopioidaan binäärisesti eli sisällölle ei tehdä tarkistuksia. Class A{}; Class B{}; A* a = new A; B* b = reinterpret_cast(a); dynamic_cast Käytetään osoittimien ja referenssien kanssa, joiden kohteena on olio. Tarkistaa, että muunnettava olio on oikeaa tyyppiä. Class A { virtual void a() {}; }; Class B : public A {}; A* a1 = new B(); A* a2 = new A(); B* b1 = dynamic_cast(a1); //Onnistuu B* b2 = dynamic_cast(a2); //Ei onnistu, arvona NULL static_cast Käytetään sellaisten tyyppien kanssa, joille voidaan tehdä myös päinvastainen muunnos. ---[ scast.cpp ]--- #include using namespace std; int main() { double a = 2.45; int b = static_cast(a); double c = static_cast(b); cout << a << endl; cout << b << endl; cout << c << endl; class A { public: virtual string nimi() { return "A"; } }; class B : public A { public: string nimi() { return "B"; } }; A* d = new A(); B* e = static_cast(d); A* f = static_cast(new B); cout << d->nimi() << endl; cout << e->nimi() << endl; cout << f->nimi() << endl; return 0; } ------------------- const_cast Tämä muunnos auttaa pääsemään eroon, tai saamaan takaisin, const -määreestä. class A{}; const A* a = new A; A* b = const_cast (a); Vielä mainittakoon typeid, jolla voidaan määrittää vermeiden (kuten Joro ehdotti noita kutsuttavan :-) tyyppi. #include class A{}; A a; A *b; cout << typeid(a).name() << endl; cout << typeid(b).name() << endl; Pörörör, pölskssald. Jääpi minulle aikaa sekoiluun ja itseni kidutukseen enempi. Laatuloisen puoleista ei tietenkään hulluilu ole, vaan pahempata! Sinä päivänä oli kaikki hyvin, kaikki hyvin, virtasi vesi hiljalleen, tuuli hönki puissa uutta aamuaan. Vain yksin ulkona julma maailma. Niin se on, ja niin sen pitikin olla. Vektorit ja hieman Äs Tee Ällää ------------------------------- Ottakaamme suunnaksi uusi tietoinen rakenne, vektori. Tuo ei ole semmottinen vektori niinkui on matemaatikoiden kirjoissansa opetattu (siis ei ole suuntavektori, jolla onpi suunta ja pituus) vaan tässä tapauksessansa tarkoitetaan vermehettä, joka mahdollistaa dynaamisen listan helpommanpuoleisesti. Niin tuo vektori perustuu tuohon sabluunamallivermeeseen, joten sen sisältöisenä voi olla vaikka mitä. Niinjoo, annanpa taas vaihteheksi viisahampien kertoa asioista. Ja, sattuipa viime viikolla niin, että viheriö lakkasi olemasta, kuopan tilalle rakensivat. Mutta minä voisin nukkua hieman ja antaa Heikin jatkaa parin kappaleen verran. Kirjoitan sitten myöhemmin näitä selityksiäpelityksiä. Näin teemmä joo, olen sitten pirteänä ja hyväisen tuulisena, yönraikkaana valmis selittämään teille, oi rakkahat lukijaiset, notta mitä tuo Heikki-setäinen on tänne kirjaillut. Niin ja selittänen myös suhteellisuusteorian. Ja suhteettomuusteorian kanssa. Niin ja tietenkin helikopterin propellien pyörimisnopeuden vaikutuksen nopeuteen, ohjattavuuteen, kopterin kaltevuuteen, kitkakertoimeen sekä pakkolaskun mahdollisuuteen kovassa tai myrskyisessä tuulessansa tahi muussa vastaavassa ilmavirtausilmiössänsä! Vektori on siis dynaaminen listarakenne, jonka alkioiden tyyppi voidaan määrittää, sillä vektori perustuu sabluunamalliin. Vektori ei siis ole C++:n "sisäänrakennettu" vaan se kuuluu STL:än (Standard Template Library), joka siis nimensä mukaisesti on joukko sabluunoita. Tuohon kuuluu useita eri luokkia, mutta nyt keskitymme lähinnä vector-luokkaan. Ja esimerkkiä heti alkuun: ---[ vektori.cpp ]--- #include #include using namespace std; int main() { // int-vektori vector i; // double-vektori, alustetaan 3 alkiota vector d(3); // string-vektori vector s; // Lisätään dataa vektorin loppuun i.push_back(1); i.push_back(3); i.push_back(9); i.push_back(4); i.push_back(11); d.push_back(4.3); d.push_back(2.1); d.push_back(5.8); d.push_back(3.4); s.push_back("yksi"); s.push_back("kaksi"); s.push_back("kolme"); s.push_back("neljä"); // Tulostaa: 1 3 9 4 11 for (unsigned int c=0; c::iterator si = s.begin(); while (si!=s.end()) { cout << *si << " "; si++; } cout << endl; // Poistaa ensimmäisen alkion s.erase(s.begin()); return 0; } --------------------- Esimerkissä on esitetty vektorin luonti, datan lisääminen, muuttaminen, poistaminen, arvojen saanti sekä iteraattori. Toki vektoreilla pystyy tekemään muutakin, mutta tällä pitäisi selvitä jo pidemmälle. Keltahainen mokomaisuus. Listarakennelma hajosi tuulessa! Vektori osoittikin kohti NULL:a! Tiedemiehet todistavat: /dev/null ei olekaan olemassa! Kuinka bittejä voidaan digitoida eli muuntaa biteiksi?! Lue lisää uudesta tietämystekniikanalan tiedelehdestä, Ho-bitistä! Mukana seitsensivuinen netin porno-opas! Saatavilla hyvinvarustetulta lehtimyyjältä puoltentoista litran colapullon hinnalla! String ------ String-luokka kuuluupi myöäs Äs Tee Ällään, joten semmottinen voitassii käydään tässä läpi nopeammanpuoleisesti. Maanantaikappalemonisteinen kirosana-aavikko odottaa ottajaansa. Niin, eli ei muuta kuin riisumaan stringejä noilta eräiltä olioilta... Merkkijonototeutus, jossa kätevästi tarvittavat metodit. Ei puskuriylivuotoa, helppo käytettävyys, ja mitä vielä. String-luokan myötä C++ toivottaa hyvästit char-arraylle ja -osoittimille. Ei nyt ihan kuitenkaan, mutta melkein. String:n dataan voi tarvittaessa saada osoittimen metordilla c_str(). Operaattorien ylilatauksen takia käsittely helpottuu entisestään. Mutta antaa mainospuheiden olla, itse asiaan (Joron huomautus: oikeasti toteutus edelleen merkkijonotaulukkoinen, mutta luokan rakennuksella estellään sen suuremmanpuoleinen väärinkäyttöinen): ---[ string.cpp ]--- #include #include using namespace std; int main() { string a = "a"; string b("b"); //string c = 'a'; //väärin! string::size_type l = b.length(); cout << a.length() << " " << l << endl; string d = "merkkijono"; cout << strlen(d.c_str()) << endl; d.insert(6,"nen"); cout << d << endl; d.erase(0,1); cout << d << endl; d.replace(5,3,"kö "); cout << d << endl; string::size_type p = d.find("o"); cout << p << " "; p = d.rfind("o"); cout << p << endl; cout << d.find("joo") << " == " << string::npos << ", int() == " << int(string::npos) << endl; cout << d.substr(5) << endl; cout << d.substr(5,4) << endl; return 0; } -------------------- Niin, tommonen! Haistelkaa nyt stringejä ekstaasiloisissanne! Kunhan tokenette, voikaamme jatkaa seuraavaan aiheenpuoleiseen... Muistanpa eräänpuoleisen tapahtuman konsulentti-Pentin luennolla, jossa ystäväisemme Pentti kertoleitsoi mielenkiintoisemman puoleisia yksityiskohtaloita juuri hänen konsulentointifirmaloisensa menestyvänpuoleisesta konsulentiloinnista. Kuunteloitsimme korvaiset tarkkaammanpuoleisina jokaikistä sanantapaista, jotka Pentti suustansa päästeli ulospäin. Tätä mahtavanpuoleista tilaisuutta en minkäännäköisestä tapausesta väliin jättäisi, sen verta oli hyvä puheloimaan ja mielenkiintoisenlaista asiaa puheli hän. Lopussa saimme oikein palautetta hänelle antaa! Mutta näen kauheudessa maailman, takapenkissä salin hämärän, pimeässä eläjän, erään palautelapun repijän! Tästäkös kauhistuin niin, että tulin ja menin repimään oman lappuloiseni vahinkoloisessa myös. Pentti kun näki tämän, hän alkoi husteerisena kirkuloimaan ja juoksemaan luokse, ja lausahtelemaan: "mitä sinä hyvä lapsi menit tekemaan??!!". Mikään ei ole hirvittävämmän puoleista kuin husteerisenpuoleinen konsulentti, jonka palautepaperi on menty repimään. Sellainen tarinanpuoleinen siis kontsulentti-Pentistä. Nii! Eiköhän suurin osa ole nyt valmiina, jotan hus sika seuraavaan aiheeseen! Tiedostovirrat -------------- Koskas nyt ei ole varaa enää matkustella virran varrelle, niin menkäämme vain suihkuloimaan ja lämpimämmän vesimassanpuoleisen virtaloida alas ja kastelle kehokkaanne. Hyi hai sie! Mutta etpä haise enää kun suihkuvirrassansa olet pulikointia harrastellut. Saippuaa myös käytämmä! Tahdissansa mars! Ei viinaa puille! Lukiessani aiempia tutoriaaleja huomasin ettei virtojen yhteydessä käsitelty tarkemmin näiden metodeja. Ainakin tiedostojen käsittelyä tarvitaan useassa ohjelmassa joten kerron nyt hieman tiedostovirroista. Esimerkin turvin siis tarttukaamme tähänkin aiheeseen: ---[ tvirta.cpp ]--- #include #include using namespace std; int main() { //Avataan tiedostoa lukua varten fstream t1("tiedosto1",ios_base::in); if (t1.good()) cout << "Avaaminen onnistui" << endl; else cout << "Avaaminen epäonnistui" << endl; t1.close(); //Tekee saman asian kuin edellinen ifstream t2("tiedosto1"); if (t2.good()) cout << "Avaaminen onnistui" << endl; else cout << "Avaaminen epäonnistui" << endl; t2.close(); //Avataan tiedosto lukua sekä kirjoitusta varten, osoitin fstream* t = new fstream("tiedosto2",ios_base::in|ios_base::out); if (t->good()) cout << "Avaaminen onnistui" << endl; else cout << "Avaaminen epäonnistui" << endl; t->close(); //Kaikki new-operaattorilla varatut muistialueet tulisi vapauttaa //delete-operaattorilla. Muisti kyllä vapautetaan ohjelman päätyttyä, //mutta esimerkiksi pidempään ajettavassa ohjelmassa ei ole varaa //pitää turhia muistialueita varattuna. delete(t); //Luodaan uusi tyhjä tiedosto t = new fstream("tiedosto3",ios_base::in|ios_base::out|ios_base::trunc); if (t->good()) { cout << "Avaaminen onnistui" << endl; *t << "Tiedostoa voidaan kirjoittaa ja lukea" << endl; *t << "Jopa useampi rivi"; string tmp="- ja usealla tavalla\n"; t->write(tmp.c_str(),tmp.length()); //Etsitään tiedoston alku t->seekp(0); //Luetaan tiedostosta rivi, lukee koko rivin, oli se kuinka //pitkä tahansa (rivinvaihtomerkki \n) getline(*t,tmp); char tmp2[256]; //Luetaan tiedostosta rivi, tai niin monta merkkiä kuin //puskuriin mahtuu. Puskurin koko ilmoitetaan... t->getline(tmp2,256); cout << tmp << endl << tmp2 << endl; } else cout << "Avaaminen epäonnistui" << endl; t->close(); delete(t); return 0; } -------------------- Mistä suunnasta tahansa tuuli puhaltaa, antaa tuulen vain riepottaa. Näenkö selvemmin sen, naapurin kauniin pihakuusen? Viettohon joulun käy, ei kuusta enää pihalla näy. Repeää taivas ja alkaa sataa. Kuitenkin se tuuli puhaltaa... Niin, jouluisen puun voisimme rakennella viheroksistansa tai sitten hankkia semmottinen laillisemmanpuoleisesti rahaisella myyjäsetäisiltä. Tahi koristelkaamme konehemme C++ -koodillansa! Näin tehkääme! Joulukuusi EVP! Esikäsittelijä -------------- Tämä ei itseistä asiaa ole, mutta pakkohan tästä on maininnanmuotoinen laittaa tänne, joten minä sitten itse tästä kerroskelen nopeasti. Koskas lähdeskooditiedostoisia olisi hyvä olla enempi ja ois mukavaa, jos sinne voisi ehtoja laitella, notta ei välttämättänsä kaikkea viittis mukaan ottaa. Niin ja muuta hassua. Listalla eteenpäin kuljemma. #define x y Määritteleepi x:n arvoksi y. Arvoa ei ole pakko määrittää, jolloin x on vain määritelty ilman arvoa, se vaan siis on olemassa. #undef x Poistaa x:n määrityksen, jonkas jälkeen tuo voidaan esim-erkiksi uudelleen määritellänsä uudella arvollansa. #ifdef x #ifndef x Seuraavaan #else, #elif tai #endif -määreeseen asti oleva koodi otetaan mukaan / ei oteta mukaan, jos x määritetty / ei määritetty. Tai jotain. Valitse vain toisenmuotoinen vermes. #if x Jos x tosi, seuraavaan #else, #elif tai #endif -määreeseensä asti oleva koodi otetaan mukaan käännöstyöhön #elif x Else if, tätä pitää seurata ainakin yksi #if, #ifdef tai #ifndef. Toimii samoin kuin #if #endif Lopettaa ehdon. Elikkäs tämä noiden eräinen loppuhuiseen #else Jos edellinen ehto ei ole tosi, suoritetaan tämä #error x Tulostaa virheilmoituksen x ja keskeyttää kääntöprosessin #include #include "x" Näistä puheskeltiinkin jo ensimmäisessänsä osassa, mutta ideana on, että esikääntäjä ottaa tiedoston x mukaansa. Esikääntäjäinen, ainaskii Gnu-projektin vermehessä, on nimeltänsä cpp eli C preprocessor. Ja jos haluat nähräs, millaista koodia tuleepi tuon jäljiltä, kokeiles "cpp tiedosto.cpp > uloste.ii". Kun tuota ulostetiedostoa tarkastellaan, huomataan sinne tulleen kaikennäköistä hassua. Ja ei se mitään hassua ole, vaan siellä onpi mm. kaikki tarvittavat otsaketiedostot liitettynänsä mukaan. Oma koodisi voi ollansa vain murto-osainen tuosta koko vermehestä. Tämän voipi käännellänsä täysin samoin kuin tuon ei-käsitellyn tiedostonsa. Tuossa tuo ii-päätteinen kertoopi kääntäjällensä, notta ei tarvitsena enää esikäsittelöidä. Niin, se puistonpenkki... Loppusanat ---------- Jaa vielä lisää vai? No pakkohan sitä on kun vaaditta. Niin siis joskus. Tuskin enää tänä vuonna. Tosin ei sitä tiedä. No ei sillä väliä. Pyrhens. Seuraavassa osassa teemme ratsian baariin, jossa bailasin avaruusolion kanssa, imemme posket lommolla limettiä limetin imemisen maailmanmestaruuskisojen merkeissä, kikatamme kuin meriturskat, juomme päivän vanhaa Valion maitoa, mietimme vastausta kysymykseen "kumpi voittaa, karhu vai leijona?" sekä yleisöä viihdyttääksemme esitämme sirkustemppuja! Myös lapset on otettu huomioon ja heitä varten rakennamme tivolin. Tivolissa on mitä hurjempia laitteita, unohtamatta perinteisiä, rauhallisempia kohteita. Myös letku. Taivaanrannan taa, unien maailmaan, lehdistä lukemaan, aamuyöhön juhlimaan, satamaan kaatumaan, avaruuden sopukkaan, Meremoth-2 sua rakastaa. Copyright (c) kello 20:03 sininen savu ympäroi huoneen, vuoden uuden kuulen, vuoden suuren, onko 2003 vastauksesi siis, kerro! Tekijänoikeus hallussa: Esimerkit sekä osa tekstiosuuksista Heikki Höijäri. Muutoin Joro. (Tämän sarjan virallisemmanpuoleinen minähahmotelma eli Joro aka Jouni Roivas, http://roivas.org, emailia lähettää hän kohti jroivas@iki.fi, siis näin lyhyesti sanottuna, pidempi versio eksyi uumeniin, syvälle harmaisiin. Heikille voit lähettää postia osoitteeseen heikki@jepjep.org)