Ohjelmoinnin peruskurssien laaja oppimäärä Esittelyluento Riku Saikkonen 28. 9. 2012
Sisältö 1 Laaja oppimäärä lyhyesti 2 Scheme-kieli ja SICP-kirja 3 Funktionaalinen ohjelmointi 4 Esimerkki rajapintojen analysoinnista 5 Skriptaus 6 Lopuksi
Mitä laajassa oppimäärässä on? vaihtoehtoinen suoritustapa ohjelmoinnin peruskursseille käydään läpi enemmän asioita ja mennään usein peruskursseja syvemmälle kokeillaan ohjelmointia ryhmässä syksyllä: peruskurssin tehtävät ja tehtäviä Scheme-kielellä keväällä mm. Python-tehtäviä, ohjelmointiprojekti ryhmässä, ohjelmointikilpailujen tehtäviä tarkemmin kurssiesitteessä: https://wiki.aalto.fi/display/laajaohj12/kurssiesite
Syksyn kurssin sisältö kurssiesitteestä: T-106.1210-peruskurssin sisältö Erilaisia tapoja tehdä abstraktioita ja ohjelmointirajapintoja Rekursio ongelmanratkaisumenetelmänä Funktionaalisen ohjelmoinnin perusteita Ohjelmointikielten tulkkien toteuttaminen Scheme-ohjelmointikieli käytännössä käydään pienten tehtävien avulla läpi noin 150 sivua kurssikirjasta ja hiukan muuta asiaa kirja löytyy netistä, ks. kohtaa Oppimateriaali kurssin sivuilla https://wiki.aalto.fi/display/laajaohj12
Kevään kurssien sisältöä kevään luennoilla ja kotitehtävissä on (tämänhetkisen suunnitelman mukaan) mm: skriptausta olio-ohjelmointia (tapoja käyttää olioita järkevästi) olioiden sisäistä toimintaa oikeiden Python-kirjastojen käyttöä oikeasti käytössä olevien (Python-)ohjelmien muokkaamista kotitehtäviin tulee jonkin verran valinnanvaraa: voi valita mitkä aiheet kiinnostavat lisäksi keväällä: ratkotaan ohjelmointikilpailujen tehtäviä (TRAK-kurssiin liittyen) harjoitellaan realistisia ryhmätyötapoja, (mm. versionhallintaa) vähän isompaa ohjelmaa tehdessä tarkennamme kevään sisältöä vielä syksyn kurssin aikana ja avulla
Sisältö 1 Laaja oppimäärä lyhyesti 2 Scheme-kieli ja SICP-kirja 3 Funktionaalinen ohjelmointi 4 Esimerkki rajapintojen analysoinnista 5 Skriptaus 6 Lopuksi
Scheme-kielen suunnitteluperiaate Programming languages should be designed not by piling feature on top of feature, but by removing the weaknesses and restrictions that make additional features appear necessary. Scheme demonstrates that a very small number of rules for forming expressions, with no restrictions on how they are composed, suce to form a practical and ecient programming language that is exible enough to support most of the major programming paradigms in use today. R 5 RS (Scheme-kielen määrittely)
Scheme lyhyesti 1/2 muuttujien tyyppejä ei tarvitse kertoa: Scheme on dynaamisesti tyypitetty, kuten esim. Python ja Ruby tyypit tarkistetaan kun koodia suoritetaan tulkattavissa oleva kieli (myös kääntäjiä on) automaattinen muistinhallinta (roskankeruu) omalaatuinen prex-syntaksi: kielen rakenteet ovat muotoa ( operaattori operandi operandi...) esim. (* 2 (+ 3 4)), vrt. Pythonissa 2 * (3 + 4) vaatii hieman totuttelua ohjelmoijalta helpottaa mm. makrojen tekemistä ja kielen laajentamista koodi on dataa: Scheme-ohjelman käsittely toisella ohjelmalla on helppoa
Esimerkkejä syntaksista Scheme-koodinpätkiä (+ 5 (* x 2)) (/ (+ x y) 2) (define (average x y) (/ (+ x y) 2)) (if (< (average x y) 3.0) (display "y") (display "n")) (define (f x y) (let ((avg (average x y)) (sum (+ x y))) (if (and (>= avg 0) (< (* avg avg) sum)) (* sum sum sum) (+ avg sum)) Vastaava Python-koodi 5 + x*2 (x+y) / 2 def average(x, y): return (x+y) / 2 if average(x, y) < 3.0: print "y" else: print "n" def f(x, y): avg = average(x, y) sum = x + y if (avg >= 0 and avg*avg < sum): return sum * sum * sum else: return avg + sum
Scheme lyhyesti 2/2 leksikaalinen skooppi (kuten esim. Javassa) paikalliset muuttujat näkyvät sen lohkon sisällä, jossa ne on määritelty ei eroa lauseilla ja lausekkeilla (melkein mitä tahansa voi laittaa minkä tahansa sisälle) jokaisella lausekkeella on (paluu)arvo (ei erillistä returnia) puolifunktionaalinen kieli: tukee funktionaalista ohjelmointityyliä, mutta ei pakota siihen ensimmäisen luokan funktiot Schemessä funktiot ovat kuin mitä tahansa muuttujia esim. funktio voi tehdä ja palauttaa toisen funktion Schemen erikoisuuksia: laiskat arvot, makrot, kontinuaatiot näitä käsitteitä käsitellään kurssilla tarkemmin...
Pieni esimerkki Schemen suunnitteluperiaatteesta edeltä: ei eroa lauseilla ja lausekkeilla (melkein mitä tahansa voi laittaa minkä tahansa sisälle) Javassa ja C:ssä on kaksi iä, lause ja lauseke: if (x == 3) b = 5; b = (x == 3)? 5 : 8; else b = 8; samoin Pythonissa (molemmissa on if, mutta eri syntaksi): if x == 3: b = 5 b = 5 if x == 3 else 8 else: b = 8 Schemessä sama if käy molempiin: (if (= x 3) (set! b (if (= x 3) 5 8)) (set! b 5) (set! b 8)) Miksei Javassa tai C:ssä voisi toimia esim: b = ({ if (x == 3) 5; else 8; }); (gcc:ssä melkein toimiikin, sen omalla C:n laajennuksella)
Miksi Scheme-kieltä käytetään kurssilla? Scheme on yksinkertainen kieli ja helppo oppia kurssi pyrkii keskittymään periaatteisiin, jotka ovat yhteisiä lähes kaikille kielille, eikä yksittäisten kielten yksityiskohtien opetteluun erilainen kuin Python, jotta saa laajemman kuvan ohjelmoinnista (ei tosin kovin erilainen) minkä tahansa uuden ohjelmointikielen opettelu on helpompaa, jos on nähnyt useita erilaisia kieliä rekursiivinen ajattelutapa ja funktionaalisen ohjelmoinnin perusteet ovat hyödyllisiä muussakin ohjelmoinnissa ohjelmointikielen tulkin tekeminen ja kielen muokkaaminen on helpompaa Schemellä (erityisesti ei tarvitse keskittyä kielen syntaksin käsittelyyn) hyvä kurssikirja
Syksyn kurssikirja SICP: alkuosa Abelson, H., Sussman, G. J., Sussman, J.: Structure and Interpretation of Computer Programs, 2nd edition, MIT Press tai McGraw-Hill 1996 käyttää Schemen R 5 RS-versiota ohjelmoinnin perusoppikirja, oli pitkään käytössä MIT:n ensimmäisellä ohjelmointikurssilla esittelee myös lyhyesti tietotekniikan osa-alueita miksi ohjelmointikielet ovat sellaisia kuin ovat? kantava teema: abstraktioiden tekeminen eri tavoilla menee asioihin syvemmälle kuin useimmat muut perusoppikirjat
Syksyn kurssikirja SICP: loppuosa kurssikirjan tulkkiosio (luku 4) opettaa: pienen ohjelmointikielen tulkin tekeminen ei ole vaikeaa kokeilemaan ja miettimään mitä tapahtuisi jos kielessä olisi... ja antaa esimerkkejä harvinaisemmista ohjelmointiparadigmoista (esim. logiikkaohjelmointi) kääntäjäosio (luku 5) esittelee pienen assembler-kielen ja kääntäjän perustoiminnot sekä käsittelee muistinhallintaa kurssilla jatketaan tulkeista hieman eri suuntaan kuin kirjassa, mm. katsotaan miten oliot voi toteuttaa ja kokeillaan makroja
Miksi tulkkeja? Schemen ja tulkkien avulla on helpompi ymmärtää muiden ohjelmointikielten toimintaa tulkki antaa konkreettisen ja tarkan kuvan siitä, miten ohjelmointikieli toimii (vaikka oikea kielen toteutus tekeekin enemmän optimointeja) Schemessä monien kielten perusominaisuudet ovat mahdollisimman siistissä muodossa yksinkertaistettuna: moni kieli = Scheme + yksityiskohtia + rajoituksia + muutama isompi lisäys kuten oliot lisäksi tulkilla voi kokeilla ohjelmointikielen muokkaamista ja oman kielen suunnittelua tulkin rakennetta voi käyttää pohjana muunlaiseen kielen käsittelyyn, esim. monimutkaisen asetustiedoston lukemiseen
Tulkki asetustiedoston lukemisessa monia (varsinkin Unix-)ohjelmia konguroidaan tekstimuotoisilla asetustiedostoilla usein asetuksina on aluksi vain avainarvo -pareja (esim. ikkunan oletusleveys = 500 pikseliä)... kunnes joku kaipaa muuttujia (50 % paperin koosta)... tai haluaa tehdä asetuksen joka on suhteessa johonkin toiseen (keskiarvo kahdesta muusta asetuksesta)... tai uuden toiminnon, joka muuttaa useampaa asetusta väliaikaisesti näin voi päätyä enemmän tai vähemmän ohjelmointikieltä muistuttavaan asetustiedostoon tällaista monimutkaisempaa asetustiedostoa käsittelevä koodi on yleensä rakenteeltaan yksinkertaisen ohjelmointikielen tulkki
Ohjelmointikieli asetustiedostossa asetuksiin voidaan käyttää myös oikeaa ohjelmointikieltä, jolloin asetustiedoston ja lisämoduulin raja hämärtyy esimerkki: suuri osa Emacs-tekstieditorista on tehty sitä varten tehdyllä kielellä, Emacs Lispillä Lisp-kielen murre, johon lisätty tekstieditorin erikoisuuksia (esim. buer ja window) samalla kielellä tehdään sekä omia asetuksia että monimutkaista lisätoiminnallisuutta myös graanen asetuskäyttöliittymä yksinkertaisille asetuksille Firefoxin asetukset ovat JavaScript-kieltä niissäkin on graanen editori (Preferences ja about:cong) JavaScriptiä käytetään Webissä, mutta paljon myös Firefoxin sisällä esimerkki lisämoduulista: Gnomen Hearts-korttipelin tietokonepelaajat on tehty Pythonilla (varsinainen peli C:llä)
Mihin Schemeä käytetään oikeasti? laajennus- tai skriptikielenä muulla kielellä kirjoitettuun ohjelmaan esim. Gimp-kuvankäsittelyohjelmaa voi laajentaa Schemellä pohjana omalle pienelle (tai isolle) ohjelmointikielelle, koska Scheme on siisti ja helposti laajennettava kieli esim. GNU R -tilasto-ohjelman ohjauskieli perustuu Schemeen esim. JavaScript on ottanut mallia Schemestä ohjelmointikielitutkimuksessa uusien ideoiden kokeilussa opetuskäytössä joskus ohjelmiinkin (mm. SSH on tehnyt tuotteita Schemellä) lisäksi muut Lisp-kielet (mm. Common Lisp ja Emacs Lisp) muistuttavat Schemeä
Sisältö 1 Laaja oppimäärä lyhyesti 2 Scheme-kieli ja SICP-kirja 3 Funktionaalinen ohjelmointi 4 Esimerkki rajapintojen analysoinnista 5 Skriptaus 6 Lopuksi
Ohjelmointiparadigmat yleisimmät ohjelmointiparadigmat: imperatiivinen eli lausekielinen ohjelmointi (imperatiivinen) olio-ohjelmointi funktionaalinen ohjelmointi logiikkaohjelmointi määritelmät eivät ole kovin tarkkarajaisia, ja muitakin paradigmoja on jotkin ohjelmointikielet tukevat lähinnä yhtä paradigmoista, esim. C, Java, Haskell, Prolog toiset (uudemmat?) tukevat ainakin jonkin verran useampaa, esim. Python, Ruby, Scala, JavaScript paradigmoja käytetään osin myös kielissä, jotka eivät tue niitä kunnolla (esim. olio-ohjelmointia C:ssä)
Miksi eri paradigmoja kannattaa opetella? erilaisten paradigmojen tunteminen antaa enemmän vaihtoehtoja ohjelman suunnitteluun vaikkei käyttäisikään erikoista ohjelmointikieltä jokainen paradigma on paras tunnettu työkalu johonkin asiaan uuden kielen opettelu on paljon helpompaa, jos on nähnyt monia erilaisia kieliä varsinkin jos paradigma on tuttu eri ohjelmointikielet lainaavat usein ominaisuuksia toisiltaan auttaa ymmärtämään myös abstraktioita esim. Javan ja Pythonin merkkijonot ovat funktionaalisia: merkkijonoja ei voi muuttaa (eikä niistä siksi tarvitse tehdä kopioita)
Funktionaalinen ohjelmointi funktionaalinen ohjelmointi tarjoaa tapoja jakaa ohjelma osiin abstraktioita, joilla ohjelman voi koota pienistä helposti ymmärrettävistä paloista usein pyritään siihen, että lopullinen koodi kertoo, mitä pitää tehdä eikä miten se tehdään (eli deklaratiiviseen ohjelmointiin), ja toteutus piilotetaan abstraktioihin perustuvat usein funktioiden käyttöön argumentteina ja paluuarvoina esim. sen sijaan että laskettaisiin jotain itse tehdyllä while-silmukalla, voidaan käyttää abstraktia funktiota joka on tehty juuri sen muotoisille silmukoille toisaalta funktionaalisuus on erilainen tapa ajatella ohjelman tilaa imperatiivisessa ohjelmoinnissa ohjelman käskyt muuttavat ohjelman senhetkistä tilaa funktionaalisessa useammin luodaan uusi versio tilasta, jolloin sekä vanhaa että uutta voi halutessaan käsitellä
Esimerkki funktioiden käytöstä (SICP 1.31.3.2) Halutaan arvioida π:n arvoa kaavalla π 8 = 1 1 3 + 1 5 7 + 1 9 11 +. Ratkaisu oman summa-abstraktion avulla { b 0, jos a > b f (n) = f (a) + b n=next(a) f (n) muuten. n=a (define (sum f a next b) def sum(f, a, next, b): (if (> a b) if a > b: 0 return 0 (+ (f a) else: (sum f (next a) next b)))) return f(a) + sum(f, next(a), next, b) (define (pi-f x) def pi_f(x): (/ 1.0 (* x (+ x 2)))) return 1.0 / (x*(x+2)) (define (pi-next x) def pi_next(x): (+ x 4)) return x + 4 (define (pi-sum a b) def pi_sum(a, b): (sum pi-f a pi-next b)) return sum(pi_f, a, pi_next, b) Testiajo: (* 8 (pi-sum 1 1000)) 3.139592655589783
Muita funktionaalisia ohjelmointikieliä Schemen lisäksi yleisiä funktionaalisia ohjelmointikieliä ovat mm. Haskell, Ocaml, Standard ML ja Erlang funktionaalinen ohjelmointitapa on viety näissä pidemmälle kuin Schemessä Schemen osaaminen helpottaa näiden kielten opettelua, vaikka kielet sinänsä eivät ole kovin lähellä Schemeä monet uudemmat ei-funktionaaliset kielet tukevat funktionaalista ohjelmointia ainakin jonkin verran: esim. Ruby, JavaScript, Scala, Python
Funktionaalista ohjelmointia Pythonilla Esimerkki: parittomien lukujen 199 neliöiden summa reduce(lambda x,y: x+y, map(lambda x: x*x, filter(lambda x: x%2==1, range(1, 100)))) 166650 sum([ x*x for x in range(1, 100) if x%2==1 ]) 166650 esimerkin kummankin version käyttämät listankäsittelyoperaatiot on lainattu Pythoniin funktionaalisesta ohjelmoinnista saman voisi toki tehdä ilmankin (esim. käsin silmukoilla), mutta koodi olisi pidempää ja virhealttiimpaa Python tukee funktionaalista ohjelmointia vain osittain: vain osa tarvittavista ominaisuuksista
Sisältö 1 Laaja oppimäärä lyhyesti 2 Scheme-kieli ja SICP-kirja 3 Funktionaalinen ohjelmointi 4 Esimerkki rajapintojen analysoinnista 5 Skriptaus 6 Lopuksi
Vähän rajapinnoista ja abstraktioista Ohjelmointirajapintoja voi tutkia eri näkökulmista: Miten käytän olemassaolevaa rajapintaa omasta ohjelmastani? (Esim. Miten käytän tietokantoja Pythonista?) Miten tekisin oman rajapinnan samaan tai saman tapaiseen tehtävään? Voiko tästä rajapinnasta oppia jotain? Sopiiko tämä rajapinta (tai jokin useista olemassaolevista) juuri omaan ohjelmaani? Kannattaisiko jokin asia tehdä muulla tavalla kuin rajapinnan kautta? Onko rajapinta yleisesti ottaen hyvin suunniteltu? Suosittelisinko sitä kaverilleni? Katsotaan muutamaa hyvin erilaista rajapintaa samaan tehtävään: ohjelma tuottaa jotain dataa (esim. taulukko numeroita), ja siitä pitäisi piirtää kuvaaja.
Kuvaaja tavallisella kirjastolla: JFreeChart Javalle tehty kuvaajanpiirtokirjasto (paljon muitakin samankaltaisia on sekä Javalle että muille kielille) luokkia datan talletukseen, eri tyyppisten kuvaajien tekemiseen, kuvaajan osien muokkaamiseen,... JFreeChart-koodiesimerkki XYSeries s = new XYSeries("data"); s.add(1.0, 2.8); s.add(2.0, 3.7);... XYDataset d = new XYSeriesCollection(s); JFreeChart c = ChartFactory.createXYLineChart("otsikko", "Aika (s)", "Matka (m)", d, PlotOrientation.VERTICAL, true, true, false); try { ChartUtilities.saveChartAsPNG(new File("kuva.png"), c, 700, 500); } catch (IOException e) {... }
Kuvaaja Gnuplot-komentoja kirjoittamalla Gnuplot on komentoriviohjelma, jolle lähetetään tekstinä komentoja, joiden perusteella se piirtää kuvaajan komentoja voi kirjoittaa käsin, mutta toki voi myös tehdä ohjelman, joka tuottaa Gnuplot-komentoja ja käsittelee Gnuplotin tuottamaa kuvaa samalla tavalla voisi käyttää esim. Matlabia Esimerkki Gnuplot-komennoista set xlabel "Aika (s)" set ylabel "Matka (m)" plot '-' with linespoints 1.0 2.8 2.0 3.7. e
Kuvaaja Pythonin Matplotlibillä Python-ohjelmointikielelle tehty kirjasto tarkoitettu sekä ohjelmien käyttöön että interaktiiviseen käyttöön (Gnuplot- tai Matlab-tyyliin, mutta komennot ovat Python-koodia eikä vain tähän tarkoitukseen tehtyä komentokieltä) oliopohjainen kirjasto, jonka käytöstä on pyritty tekemään mahdollisimman yksinkertaista Esimerkki Matplotlibin käytöstä (eräs käyttötapa) import matplotlib.pyplot as plt x = [1.0, 2.0,...]; y = [2.8, 3.7,...] plt.plot(x, y, marker='+', linestyle='-') plt.xlabel('aika (s)') plt.ylabel('matka (m)') plt.show()
Kuvaajaesimerkin analysointia edellä oli kolme tapaa: JFreeChart, Gnuplot, Matplotlib neljäs tapa olisi toki piirtää kuvaaja itse ilman näitä aputyökaluja mitä sitten pitäisi käyttää? vaikea kysymys; riippuu siitä mitä ohjelma muuten tekee kaikki vaihtoehdot ovat omalla tavallaan hyviä entä voisiko näistä tavoista oppia jotain? JFreeChart lienee ohjelmoijalle tutumpi tapa kuin muut Gnuplotissa on tehty oma komentokieli ja sille tulkki; Matplotlibissä tältä on vältytty rakentamalla kuvaajanpiirtokomennot Python-kielen sisään yksityiskohtia vertailemalla oppisi lisää kuvaajanpiirtokirjaston suunnittelemisesta
Rajapinta on kieli eräs tapa ajatella rajapintoja on, että rajapinta antaa käyttäjälleen uuden kielen, jolla puhua tietokoneelle myös yksinkertaista luokkaa voi ajatella tällaisena useimmiten nämä kielet muistuttavat luonnollisia kieliä (joskus esim. matemaattista notaatiota) niistä voi löytää esim. verbejä, substantiiveja ja adjektiiveja; tai subjektin, objektin, jne. esim. progressbar.update(200, 15.0): subjekti, verbi, tarkentavia sanoja esim. data.saveto("foo.txt"): subjekti, verbi, objekti esim. print("x"): verbi, objekti joskus rajapintakieli toimii paremmin omana pienenä ohjelmointikielenään (vrt. Gnuplot edellä)
Sisältö 1 Laaja oppimäärä lyhyesti 2 Scheme-kieli ja SICP-kirja 3 Funktionaalinen ohjelmointi 4 Esimerkki rajapintojen analysoinnista 5 Skriptaus 6 Lopuksi
Mikä skriptaus? skripti on lyhyehkö tiettyyn erikoistarkoitukseen tehty ohjelma yleensä nopeasti tehty (minuuteissa, yleensä enintään tunneissa) usein enimmäkseen yhdistelmä valmiita työkaluja ja/tai kirjastoja usein kertakäyttöinen usein vain tekijän omaan käyttöön tarkoitettu (ei esim. käyttöliittymää tai kunnollista dokumentointia) tyypillisesti ei kovin kaunista koodia skripteillä usein: muokataan tai tilastoidaan tekstimuotoista dataa konvertoidaan dataa toiseen muotoon tai automatisoidaan esim. komentorivityökalujen käyttöä esimerkkejä: laske tekstitiedoston yleisimmät sanat nimeä uudelleen kaikki tiedostot, jotka täyttävät tietyt ehdot konvertoi satoja kuvatiedostoja toiseen formaattiin (käyttäen työkalua, joka osaa konvertoida yhden tiedoston kerrallaan)
Esimerkki skriptistä: koneen yleisimmät prosessit Osa ps -ef -komennon tulostetta UID PID PPID C STIME TTY TIME CMD root 12502 576 0 Aug 29? 0:22 screen irssi root 17117 1612 0 Jul 07? 0:00 /usr/lib/ssh/sshd root 12077 1612 0 16:57:57? 0:00 /usr/lib/ssh/sshd Python-skripti import sys cmds = dict() hdr = sys.stdin.readline() ind = hdr.rfind(" CMD")+1 for l in sys.stdin: cmd = l[ind:].partition(" ")[0].strip() if cmd in cmds: cmds[cmd] += 1 else: cmds[cmd] = 1 Ajoesimerkki 500x ssh-agent 418x /bin/tcsh 416x screen 308x irssi 307x /usr/lib/ssh/ssh 123x -tcsh 96x ssh 65x /c/bin/zsh 40x pine 17x /c/bin/bash scmds = sorted(cmds.items(), key=lambda x: x[1], reverse=true) for c,v in scmds[:10]: print str(v)+"x "+c
Sisältö 1 Laaja oppimäärä lyhyesti 2 Scheme-kieli ja SICP-kirja 3 Funktionaalinen ohjelmointi 4 Esimerkki rajapintojen analysoinnista 5 Skriptaus 6 Lopuksi
Lopuksi tässä luennossa näkyi pieni osa Schemestä ja vain muutama esimerkki Scheme-kieltä ehtii opetella rauhassa kurssin aikana samoin muita edellä olevia käsitteitä ja kirjaa käsitellään tarkemmin ja rauhallisemmin kurssilla muutaman sanan yhteenveto: syksyllä Schemeä, tulkkeja ja funktionaalista ohjelmointia; keväällä mm. oikeita ohjelmia ja kirjastoja, skriptausta ja ohjelmointiprojekti
Seuraavaksi laajalla kurssilla Laajassa oppimäärässä tulossa: 14.10. Python-tehtävät tehtynä viimeistään 14.10. ilmoittautuminen viimeistään laajan ilmoittautuminen on Oodissa (auki 14.10. asti), ks. https://wiki.aalto.fi/display/laajaohj12 16.10. laajan ensimmäinen (ei-esittely-)luento 31.10. ensimmäiset Scheme-tehtävät tehtynä viimeistään tulossa kotisivuille ensi viikolla: muiden kolmen Scheme-tehtäväkierrosten deadlinet kahden ensimmäisen kierroksen tehtävät (automaattinen tarkistusjärjestelmä vasta ilmoittautumisten jälkeen)