[vastaus aiempaan viestiin]
Kirjoittaja: | Kimmo Vehkalahti |
---|---|
Sähköposti: | - |
Päiväys: | 5.4.2006 23:44 |
Laivaseminaarissa Tukholmassa pitämäni esitelmän otsikkona oli "Survo-keskeinen työskentelytapa muiden ohjelmien hyödyntämisessä". Kävin melko ripeässä tahdissa läpi seitsemän esimerkkiä, joista ohessa käsittelen toista: 2) Kurssipalautteiden massa-Survonta 200-sivuiseksi Word-raportiksi Helsingin yliopiston matematiikan ja tilastotieteen laitoksella kerätään opiskelijoilta palautetta kaikista kursseista nettilomakkeella. Anonyymit vastaukset saapuvat palautejärjestelmän vastuuhenkilölle sähköpostitse. Niistä kootaan raportti kahdesti vuodessa. Tämän vuoden alusta lähtien raportti on tehty lähes automaattisesti Survolla. Tulin tehneeksi noin 10 sukroa ja C-modulin, joilla aiempi raskas "copy-paste" -urakka hoituu aivan hetkessä. Kokonaan työtä ei ole haluttu automatisoida, sillä on havaittu että mm. harjoitusten pitäjien nimet saadaan luotettavammin selville avokysymyksinä kuin valmiista listasta valittuna. Jälleen hyödynnetään sitä, että Word osaa lukea HTML-tiedostoja. Tässä tosin HTML-tiedostot luodaan Survossa C-modulilla eikä PRINT-operaatiolla kuten esimerkeissäni 1) ja 7). Lähtökohtana ovat kurssikohtaiset tekstitiedostot, joissa on peräkkäin seuraavannäköisiä viestejä (tässä esimerkkinä hieman peitelty näyte 'linmalsov'-nimisestä tiedostosta): From helinfo@cc.helsinki.fi Mon Jan 16 14:21:46 2006 Date: Mon, 16 Jan 2006 15:29:22 +0200 (EET) From: WWW-manageri <helinfo@cc.helsinki.fi> To: xxxxxxxx@solmu.math.helsinki.fi Subject: Mail from WWW (http://mathstat.helsinki.fi/kurssit/kysely/) Reply-to: helinfo+postitalomake@cc.helsinki.fi Sender: helinfo+postitalomake@cc.helsinki.fi X-Sender: http://www.helsinki.fi/bin/postitalomake Message-Id: <200601161529.1b9e43cb9fb209432@www.helsinki.fi MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit Status: RO X-Status: X-Keywords: This is a form sent to you by the WWW-server: Kurssin_nimi = Lineaaristen mallien sovellutukset Harjoitusten_pitäjä = Kimmo Vehkalahti Ohjausten_pitäjä = 1_Vaatimustaso = Melko vaikea 2_Opiskeluilmapiiri = Melko hyvä 3_Kurssimateriaali = Erittäin hyvä 4_Luennoijan_selkeys = Olen täysin samaa mieltä. 5_Kommentit_sisaltö_luennoija = Luentomoniste oli hyvä ja [...] 6_Tehtävien_taso = Sopivia 7_Harjoitusten_pitäjä_onnistui = Olen täysin samaa mieltä. 7b_Ohjausten_pitäjä_onnistui = Valitse tästä 8_Harjoituksista_apua = Erittäin paljon 9_Harjoitusten_paras_muoto = Mielestäni käytäntö oli hyvä. [...] 10_Harjoituskommentit = 11_Kokeiden_taso = Valitse tästä 12_Kokeiden_onnituminen = Valitse tästä 13_Koekommentit = 14_Osallistumisaktiivisuus = Jonkin verran (työskentelin pari kertaa viikossa) 15_Syy_kurssi_kesken = 16_Kommentit_itsestänsä = Kiire oli aikamoinen [...] 17_Tyytyväisyys = Olen erittäin tyytyväinen. 18_Parasta_kurssissa = Käytännön harjoitukset, asioiden looginen [...] 19_Huonointa_kurssissa = 20_Kehitystarpeet = REMOTE-HOST: xxxxxxxxx.xxxxxxxxx.helsinki.fi (128.214.xxx.xxx) HTTP-REFERER: http://mathstat.helsinki.fi/kurssit/kysely/ FORM-ID: 1234567890 Osa vastauksista on valintoja annetuista vaihtoehdoista (kuten nrot 1-4), osa avovastauksia (kuten nrot 5 ja 9), jotka saattavat olla pituudeltaan tuhansia merkkejä. Lomakesysteemi katkoo ne n. 1000 merkin pituisiksi, mutta tietyistä yksityiskohdista voi päätellä onko kyseessä jatkorivi. Tällaisten tiedostojen kimppuun sukrot käyvät ja alkavat muokata dataa hieman systemaattisempaan muotoon. En voi tässä mennä yksityiskohtiin, mutta koetan poimia joitain hauskoja kohtia esiin. Kokonaisuudessaan raportointi koostuu 10 vaiheesta (allaoleva on karkea dokumentaationi jonka perusteella olen myöhemmin tekemässä tarkempaa selostetta; "MK" viittaa palautejärjestelmän vastuuhenkilöön; teemme työtä vaiheittain ja vuorotellen vaihtaen tiedostoja laitoksen serverin kautta): 0. /MUUNNA -> tekee kaikista .txt .txt = eräitä teknisiä muunnoksia sekä merkkimuunnoksia 1. /HAR1 -> tekee kaikista .har1 (käyttää .txt) .har1= harjoitustenpitäjät lomakkeilla annetuissa muodoissa, 1. rivi: kurssin nimi, 2. rivi: luennoijan nimi 2. /OHJ1 <anal1|anal2|anal1sv|anal2sv> -> tekee yksitellen jokaisesta .ohj1 (käyttää .txt) .ohj1= ohjaustenpitäjät lomakkeilla annetuissa muodoissa 3. MK muodostaa käsin *.har2 ja *.ohj2 -tiedostot .har2= lomakkeella annetut ja korjatut nimet peräkkäisillä riveillä, 1. ja 2. rivi: korjatut kurssin ja luennoijan nimet .ohj2= muuten kuin .har2 mutta ei kurssin ja luennoijan nimiä 4. /SVEN -> muuntaa sv ja en -vastausvaihtoehdot suomeksi, .txt -> .dat .dat = kanonisoitu numeeristen vastausvaihtoehtojen kielen osalta 5. /HAR2 -> tekee kaikista .har ja .nam (käyttää .har1 ja .dat) .har = aakkostettu harjoitusten pitäjien lista .dat = kanonisoitu harjoitusten pitäjien osalta .nam = kurssin ja luennoijan nimet (1. ja 2. rivi) 6. /OHJ2 <anal1|anal2|anal1sv|anal2sv> -> tekee yksitellen .ohj (käyttää .ohj2 ja .dat) .ohj = aakkostettu ohjausten pitäjien lista .dat = kanonisoitu ohjausten pitäjien osalta 7. /HTML -> tekee kaikista .out (PALAUTE-modulilla: käyttää .dat, .har, .nam, .ohj) .out = html-muotoinen kooste palautteista -> tekee kaikista .html .html= kuten .out mutta eräitä merkkimuunnoksia 8. /NAM -> yhdistää .html-tiedostot yhdeksi raportti.html-tiedostoksi kurssien nimien mukaiseen aakkosjärjestykseen (käyttää .nam) 9. MK muodostaa lopullisen raportin Wordillä raportti.html-tiedostosta - sisällysluettelo automaattisesti Wordin toiminnolla Insert - Reference - Index and Tables - Table of Contents - kansi ja esipuhe + pari liitettä Tiedostoja syntyy pilvin pimein. Tammikuussa tehdyn ensimmäisen ns. "tuotantoajon" alkutilanteessa oli 40 tiedostoa; survonnan tauottua tiedostoja oli 380. :) Suurin osa niistä on apusälää (.har, .nam jne.). Varsinainen lopputulos, raportti.html, on kooltaan n. 500 KB. * * * Seuraavaksi esittelen joitakin poimintoja sukrojen toteutuksesta: /HAR1-sukro kaivaa jokaisesta kurssitiedostosta harjoitusten pitäjien nimet (jotka on siis annettu avovastauksina) ja muokkaa näin saadusta listasta helposti luettavan ja tarkistettavan. Oheisessa kohtaa koodia on sukromuistipaikassa W1 ao. kurssin koodinimi, tässä tapauksessa "anal1" (Analyysi I). SEARCH:illä saadaan sekä haetut tiedot kenttään että niiden lukumäärä sukromuistiin: / def Wlkm=W3 Wx=W4 *FILES={print W1}.txt RUN=1 SHOW=0 TUTSTACK=1{R}{save stack} *SEARCH HPIT ={home}{act}{erase} *REPLACE "HPIT = ","",C{act}{home}{erase} *{d5}{u5}{ins line}{ins line}{ins line}{ins line}{u3} Lukumäärä poimitaan sukromuistista ja pystytetään sen kokoinen data yhtä muuttujaa (Nimi) varten: *TUTSTACK{act}{R}{find @}{erase}{line start}{del stack}{load stack} *{save word Wlkm}{erase} *DATA A A+1,A+{print Wlkm},A,A-1{R} *A{copy}{R}{line start}{r80}{erase}{line start}{R} *Nimi{home}{l4}A{r} *{pre}{search}TUTSTACK{R}{erase}A+{print Wlkm}+2={act}{l} {save word Wx} *{jump END-10,Wx,1}{R} Dataa muokataan FILE-operaatioilla ja otetaan lopuksi kenttään (nimet A, AA, AAA jne. vaikuttavat syystäkin vähän kiireessä keksityiltä): *FILE COPY A TO NEW AA{act}{R} *FILE SORT AA BY Nimi TO AAA{act}{R} *FILE AGGR AAA BY Nimi TO AAAA{ref set 3}{R} *VARIABLES:{R} *N N -{R} *Nimi FIRST Nimi{R} *END{R}{ref jump 3}{act}{jump END-10,END+1,1} *FILE SORT AAAA BY -N TO AAAAA / SAVE=1{act}{R} *FILE STATUS AAAAA{act}{ref set 3} *{search}FIELDS:{R}{R} *{next word}{next word}{next word}{next word} *{r9}(###){ref jump 3}{line start}FILE UPDATE{act} *{jump END-10,END+1,1} /{tempo 2} *FILE LOAD -AAAAA CUR+2 / DELIMITER=|{act}{R} *SAVEW {print W1}.har1{act} Tässä on näkymä siitä, kun sukro on tehnyt em. vaiheet (olen vähän muutellut ihmisten nimiä tässä muuten oikeassa tilanteessa): *FILES=anal1.txt RUN=1 SHOW=0 TUTSTACK=1 * *A+20+2 75 *DATA A A+1,A+20,A,A-1 *AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ANimi *Riina Vehanen *Mikko Vihko *Juha Saavalainen *Mikko Vihko *useita, tapio verälä *Mikko Vihko *Juha Saavalainen *Tapio Verälä *Seppo Linden *Tapio Verälä *Mikko Vihko *en muista *Osmo Kalteva *Osmo Kalteva *Osmo Kalteva *Tapio Verälä *Markku Rantalainen *Timo Vuori *Seppo Linden *Osmo Kalteva * * *FILE COPY A TO NEW AA *FILE SORT AA BY Nimi TO AAA *FILE AGGR AAA BY Nimi TO AAAA *VARIABLES: *N N - *Nimi FIRST Nimi *END *FILE SORT AAAA BY -N TO AAAAA / SAVE=1 *FILE UPDATE AAAAA *Aggregated from data AAA by variable Nimi *FIELDS: (active) * 1 NA_ 2 N (###) * 2 SA_ 80 Nimi *END *Survo data file AAAAA: record=114 bytes, M1=6 L=64 M=2 N=10 *FILE LOAD -AAAAA CUR+2 / DELIMITER=| *SAVEW anal1.har1 * 4|Mikko Vihko * 4|Osmo Kalteva * 3|Tapio Verälä * 2|Seppo Linden * 2|Juha Saavalainen * 1|en muista * 1|Markku Rantalainen * 1|Riina Vehanen * 1|Timo Vuori * 1|useita, tapio verälä Tästä on helppo tarkistaa oikeat ja virheelliset tiedot. Useimmiten alkupään tiedot ovat oikein (kuten tässäkin heti viisi ensimmäistä). Ne voi tarkistaja vain poistaa; epämääräiset korvataan tietyllä merkkiyhdistelmällä (ne niputetaan raportissa yhteen luokkaan). Samalla tekniikalla sukro hakee kurssin nimen (myös avovastaus) ja valitsee jakauman moodiluokan edustajan ehdolle (tarkistettavaksi). Näin sitäkään ei tarvitse yleensä erikseen kirjoittaa missään vaiheessa. * * * /SVEN-sukro ("SVenskaENglish", nimet ovat mitä ovat...) muuttelee muunkieliset datat suomenkielisiksi, jotta jatkokäsittely olisi yksinkertaisempaa. Tässä rakennetaan TXTCONV-asetelmaa, jossa pitää ottaa huomioon sellainen yksityiskohta, että merkkijonoja korvattaessa uuden merkkijonon on oltava vähintään vanhan pituinen, muuten jäljelle jää "roippeita" vanhasta. Conversions-kentän rakennuskomentoja (huomaa tyhjät {} rivin aluissa; estävät tehokkaasti vahinkoaktivoinnit sukroa kirjoittaessa!): *{}SET CUR+1,END,CUR-1{act}{home}{erase} *{}PUTEND CUR+1,END .txt{act}{home}{erase} *{R}{r30}{block}{block}{block}{block}{u}{line start} *{}PUTEND CUR+1,END .dat{act}{home}{erase}{R}{ref set 1} *{jump END-2,END+2,1} *CONVERSIONS:{R} Yksityiskohta kaaviosta (kysymyksen 7a vaihtoehdot ruotsista suomeksi): / 7a. *t "Välj här# "Valitse tästä#{R} *t "Jag är nog helt av annan åsikt.# "Olen täysin eri mieltä.#{R} *t "Jag är delvis av annan åsikt.# "Olen jonkin verran eri mieltä.#{R} *t "Kan inte säga någonting om det.# "En osaa sanoa.#{R} *t "Jag är delvis av samma åsikt.# "Olen melko samaa mieltä.#{R} *t "Jag instämmer helt.# "Olen täysin samaa mieltä.#{R} Risuaidat (#) selittyvät sillä, että sukro täydentää nämä lopuksi siten että merkkijonot ovat samanmittaiset (lisäämällä blankkoja): + B0: {R}{line start}{save word W2} - if W2 '=' END then goto B10 *{r3}{find #}{save cursor W2,Wc0}{Wc0=Wc0-4}{next word}{Wc1=0} + B1: {r}{save char W2} - if W2 '=' # then goto B2 *{Wc1=Wc1+1} - if Wc1 >= Wc0 then goto B9 else goto B1 + B2: {ins} {ins}{Wc1=Wc1+1} - if Wc1 >= Wc0 then goto B9 else goto B2 + B9: {goto B0} + B10: {ref jump 1} *{u}{ins line} *REPLACE "#","char(10)#" C{act}{home}{erase} *REPLACE # " C{act}{home}{erase} *{R} Nuo "char(10)":t varmistavat, että konversiot koskevat vain rivin loppuun päättyviä, ei esimerkiksi keskellä avovastausta mahdollisesti olevia muuten samoja merkkijonoja. * * * /HAR2 muokkaa edellä käsin korjatuista harjoitustenpitäjien luetteloista siistimmät listat käyttäen samantapaista tekniikka kuin /HAR1, nyt vain tarvitaan vähän lisää viilailuja. Systemaattinen haku SEARCH:illä on aivan sama kuin edellä, mutta viilailuja on kenttään rakennettavan datan survomisessa: *FILE COPY A TO NEW AA{act}{R} *FILE EXPAND AA{act}{R} *VAR Sukunimi:S35=MISSING TO AA{act}{R} *FILE EXPAND AA{act}{R} *VAR Etunimi:S35=MISSING TO AA{act}{R} *väli=pos(Nimi,sp){R} *VAR str(Sukunimi)=str(Nimi,väli+1) TO AA{act}{R} *VAR str(Etunimi)=str(Nimi,1,väli) TO AA{act}{R} *..........{R} *VAR str(Sukunimi)=str(Etunimi) TO AA / CASES=Sukunimi,MISSING{act}{R} *..........{R} *FILE SORT AA BY Sukunimi,Etunimi TO AAA / SAVE=1{act}{R} *FILE AGGR AAA BY Sukunimi TO AAAA{ref set 3}{R} *VARIABLES:{R} /N N - *Nimi FIRST Nimi{R} *END{R}{ref jump 3}{act}{jump END-10,END+1,1} *FILE LOAD -AAAA CUR+2{act}{R} *DELETE{home}{act}{erase} *SAVEP {print W1}.har{act} Lopputulos em. pseudonimillä näyttää tältä (XYZ on em. kaatoluokan symboli): Osmo Kalteva Seppo Linden Juha Saavalainen Riina Vehanen Tapio Verälä Mikko Vihko Timo Vuori XYZ * * * /NAM-sukro järjestää loppuvaiheessa kurssikohtaiset HTML-tiedostot aakkosjärjestykseen kurssin nimen mukaan. Kurssin nimi löytyy /HAR2:n jäljiltä .nam-tiedoston ensimmäiseltä riviltä. Tässä pieni luuppi, jossa toimitaan rivi riviltä tiedostonimien listassa: *{ref set 1}{ref set 2} + A: {ref jump 2}{R}{save word W1}{erase} - if W1 '=' {sp} then goto B *{ref set 2} *LOADW {print W1}.nam,1,1,CUR{act}{line start} *{ins} {ins}{home} *{print W1} *{goto A} + B: {ref jump 1}{r30} *AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA{u}{line start} Tässä on listan alkua luupin jäljiltä: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA aksjoukko Aksiomaattinen joukko-oppi anal1 Analyysi I anal1sv Analys I anper Analyysin peruskurssi data Data-analyysi I design Design and analysis of experiments diffyht1 Differentiaaliyhtälöt I diffyht2 Differentiaaliyhtälöt II diskr Johdatus diskreettiin matematiikkaan funkt1 Funktioteoria I gradusem Gradu-seminaari laskint Laskentaintensiiviset tilastolliset menetelmät linmal Yleistetyt lineaariset mallit linmalsov Lineaaristen mallien sovellukset ... Lajitteluavain ("AAAA...") on siis jo paikoillaan, nyt vain järjestetään, sitten pyyhitään kurssien nimet pois ja muokataan tiedostojen nimistä valmis rimpsu käyttöjärjestelmän COPY-komentoa varten, joka lopulta (binäärikopiointina) yhdistää tiedostot peräkkäin oikeaan järjestykseen: *SORT CUR+2,END,CUR+1{act}{R}{erase} / *CLEAR CUR+1,END{home}{r30}{act}{home}{erase} / *INSERT 6{home}{act}{erase} / *PUTEND CUR+1,END .html+&{act}{home}{erase} / *REPLACE "+&"," + &",C{act}{home}{erase} / *>copy _alku_.html + &{R} *{jump END-5,END,1}{find +}{erase} + _loppu_.html raportti.html /B *{ref jump 1}{act} Tilanne näyttää siis käytännössä tällaiselta: *>copy _alku_.html + & * aksjoukko.html + & * anal1sv.html + & * anal1.html + & * anper.html + & * data.html + & * design.html + & * ... * vektan.html + & * linmal.html + _loppu_.html raportti.html /B Tässähän käytetään hyväksi Survon melko uutta ominaisuutta, siis sitä että käyttöjärjestelmäkomennot voi jakaa usealle riville &-merkin avulla (aika kätevää tässä; komento on kaikkiaan yli 40 riviä pitkä!). C-modulissa on järjestetty niin, että HTML-tiedostot talletetaan ilman alku- ja loppukoristeita; ne tulevat mukaan vasta tuossa kopioinnissa yhteisesti koko raportille. Niissä ei ole sinänsä mitään ihmeellistä: _alku_.html: <HTML> <HEAD> <TITLE>Kurssipalaute / Matematiikan ja tilastotieteen laitos</TITLE> <!-- Created with SURVO MM --> </HEAD> <BODY> _loppu_.html: </BODY> </HTML> * * * Tämä oli ihan hauska ohjelmointitehtävä! Paljon sottaisia yksityiskohtia, mutta kaikista selvisi mukavasti. Raskaimman työn tekee Survon C-moduli, joka muodostaa sukrojen siistimästä datasta HTML-tiedostot. Tuon vaiheen koodaus sukrona olisi ollut mitä luultavimmin turhan sotkuista hommaa, mutta C:llä se sujui hyvin. Esivalmistelut puolestaan olivat ilman muuta paremmin sukrojen kuin C-modulin heiniä. Alkukesästä palauteraportointi pyörähtänee jälleen. Saa nähdä löytyykö ohjelmista korjattavaa vai pääsenkö pelkillä nappien painalluksilla. ;) - Kimmo
Vastaukset: |
---|
Survo-keskustelupalstan (2001-2013) viestit arkistoitiin aika ajoin sukrolla, joka automaattisesti rakensi viesteistä (yli 1600 kpl) HTML-muotoisen sivukokonaisuuden. Vuoden 2013 alusta Survo-keskustelua on jatkettu entistäkin aktiivisemmin osoitteessa forum.survo.fi. Tervetuloa mukaan!