LTD

From ICO wiki

Meeskond

  • Eve Ormisson
  • Carlos Kirtsi

Analüüs

Mõte autokoolide veebiteenuse tegemiseks tuli sellest, et olen kuulunud ühe konkreetse autokooli sõiduõpetajatelt, kuidas nende tundide haldamise süsteem on väga ebamugav. Õpilaste poole pealt ei paistagi see niiväga välja (olen ka ise nimetatud koolis õppinud) - tunde ja õppejõude saab valida ja broneerida ning tundide eest saab maksta. Õppejõudude ja kooli halduse poolt vaadates töövooga aga ei toimi: õppejõud peavad oma sooritatud tunnid lisaks rakenduses kirja panemisele eraldi paberile ümber kirjutama, mis omakorda läheb raamatupidamisse. Raamatupidaja arvestab õpetajate tasusid käsikirjaliselt koostaud paberi alusel, mis on ajakulukas ja veaohtlik. Raamatupidamine võiks vajalikud andmed saada otse ühisest andmebaasist, mis säästaks nii õpetajate kui raamatupidajate aega ning vähendaks inimlike vigade ohtu tundide arvu ja toimumisaegade kopeerimisel.

Plaanis on luua andmebaas, kuhu saab sisestada sõiduõpetajate andmeid ja neile sobivaid tundide aegu. Samuti saab andmebaasi salvestada sõidukoolis õppijate andmeid, kui palju tunde nad on läbinud ja kas nad on tundide eest maksnud. Sõidutunde peaks saama broneerida saama ainult juhul, kui on tasutud ettemaks või vähemalt ei ole kasutajal võlgnevusi. Süsteem sisaldab teavet ka kooli(de) kohta ning õpilaste jaoks infot selle kohta, millis(te) auto(de)ga see õpetaja sõidab ning kust tunnid algavad.

Veebiteenusest saab pärida, kui mitu tundi ja millal on mingi õpetaja on läbi viinud. Info alusel saab kool korraldada raamatupidamist ja muud aruandlust. Samuti saab pärida üldist statistilist infot õpilaste tulemuste kohta, mille alusel saab võrrelda erinevaid autokoole, sõiduõpetajaid või uurida üldisi tendentse. Näiteks seda, kui mitme sõidutunniga õpilased tavaliselt autokooli lõpetavad? Kui suur osa õpilasi läbib autokooli minimaalsete sõidutundide (40 tundi) arvuga? Kas on mingid tähelepanuväärsed erinevused sõiduõpetajate või kooldie lõikes?

Veebiteenusele saab ehitada erinevaid klientrakendusi autokooldie broneerimissüsteemide näol, kus on erinevad vaated õpilaste, õpetajate ja administraatori jaoks. Süsteem võib toetada ka ühe õpetaja liikumist erinevate autokoolide vahel - näiteks saab õpetaja selle läbi hallata oma tunde mitmes erinevas autokoolis, mis annab talle võimaluse erinevatel päevadel erinevate autokoolide jaoks töötada. Veebiteenust saab liidestada raamatupidamissüsteemidega, et raamatupidaja ja autokooli juhatus saaksid läbi selle ülevaate oma kooli õpetajate ja õpilaste sõidutundidest.

Antud aine raames loodava kllientrakenduse vahendusel saavad õpilased valida õpetajaid, näha nende vabu sõiduaegu ja sõiduaegu broneerida. Õpetajad saavad sõiduaegu sisestada ja hallata.

Lühikirjeldus

Autokoolidele sõidutundide haldamiseks mõeldud teenus, mis oleks abiks nii sõiduõpetajatele kui kooli juhatusele ja raamatupidajatele. Samuti võimaldavad teenusele loodud kilentrakendused autokooli(de) õpilastel oma sõidutunde broneerida ja hallata.

Andmemudel

LTDerd.jpg

Idee funktsionaalsus

Versioonihaldus

https://eluonlill.visualstudio.com/LearnToDriveSolution/LTDTeam/_git/LearnToDriveSolution

Blogi

  • Märts 2018 - ideede pakkumine
  • 01.04.2018 - idee valimine, wiki lehe tegemine
  • 02.04.2018 - idee analüüs
  • 13.04.2018 - versioonihaldusesse projekti tegemine
  • 15.04.2018 - algas töö veebiteenusega
  • 21.05.2018 - veebiteenus sai valmis
  • 22.05.2018 - klientrakenduse loomine
  • 23.05.2018 - viimased parandused veebiteenusele
  • 28.05.2018 - lahkhelide tekkimise tõttu teise klientrakenduse loomine
  • 02.06.2018 - XML osa valmimine
  • 03.06.2018 - Retsensioonide alustamine

Lisad

Erinevatest töökultuuridest põhjustatud lahkhelide tõttu võib juhuda, et antud veebiteenusele valmib aine raames kaks erinevat klientrakendust - kahe erineva autokooli tundide broneerimise rakendused lõppkasutajale (õpilasele). Kahe erineva rakenduse loomine sama veebiteenuse vastu peaks hästi illustreerima veebiteenuse võimalusi ja eeliseid.

Kood ise

Meie kood on leitav SIIT

XML osa

XML lähtekood

<?xml version="1.0" encoding="UTF-8"?>
<schools>
   <school>
      <lessons>
         <lesson id="1" hidden="false">
            <lessonId>1</lessonId>
            <lessonStart><![CDATA[31.05.2018 13:00]]></lessonStart>
            <lessonEnd><![CDATA[31.05.2018 14:00]]></lessonEnd>
            <lessonType><![CDATA[Truck driver training]]></lessonType>
            <vehicle id="1">
               <vehicleId>4</vehicleId>
            </vehicle>
            <person id="1">
               <personId>1</personId>
            </person>
            <person id="2">
               <personId>3</personId>
            </person>
         </lesson>
         <lesson id="2" hidden="false">
            <lessonId>2</lessonId>
            <lessonStart><![CDATA[27.05.2018 13:00]]></lessonStart>
            <lessonEnd><![CDATA[27.05.2018 14:00]]></lessonEnd>
            <lessonType><![CDATA[Beginner training]]></lessonType>
            <vehicle id="1">
               <vehicleId>1</vehicleId>
            </vehicle>
            <vehicle id="2">
               <vehicleId>2</vehicleId>
            </vehicle>
            <person id="1">
               <personId>2</personId>
            </person>
            <person id="2">
               <personId>4</personId>
            </person>
         </lesson>
         <lesson id="3" hidden="true">
            <lessonId>3</lessonId>
            <lessonStart><![CDATA[10.05.2018 10:00]]></lessonStart>
            <lessonEnd><![CDATA[15.05.2018 18:00]]></lessonEnd>
            <lessonType><![CDATA[Security driving training]]></lessonType>
            <vehicle id="1">
               <vehicleId>3</vehicleId>
            </vehicle>
            <person id="1">
               <personId>2</personId>
            </person>
            <person id="2">
               <personId>5</personId>
            </person>
         </lesson>
      </lessons>
      <personsInLesson>
         <person id="1" type="teacher">
            <firstname><![CDATA[Urmo]]></firstname>
            <lastname><![CDATA[Segisti]]></lastname>
            <mail><![CDATA[urmo@segisti.ee]]></mail>
            <phone><![CDATA[+372 53806309]]></phone>
            <hidden>false</hidden>
         </person>
         <person id="2" type="teacher">
            <firstname><![CDATA[Marko]]></firstname>
            <lastname><![CDATA[Martin]]></lastname>
            <mail><![CDATA[marko@martin.ee]]></mail>
            <phone><![CDATA[+372 547 3321]]></phone>
            <hidden>false</hidden>
         </person>
         <person id="3" type="student">
            <firstname><![CDATA[Anti]]></firstname>
            <lastname><![CDATA[Nuga]]></lastname>
            <mail><![CDATA[anti@nuga.ee]]></mail>
            <phone><![CDATA[+372 574 2333]]></phone>
            <hidden>false</hidden>
         </person>
         <person id="4" type="student">
            <firstname><![CDATA[Aia]]></firstname>
            <lastname><![CDATA[Auk]]></lastname>
            <mail><![CDATA[aia@auk.ee]]></mail>
            <phone><![CDATA[+372 506 4759]]></phone>
            <hidden>false</hidden>
         </person>
         <person id="5" type="student">
            <firstname><![CDATA[Turva]]></firstname>
            <lastname><![CDATA[Mees]]></lastname>
            <mail><![CDATA[turva@mees.ee]]></mail>
            <phone><![CDATA[+372 561 4759]]></phone>
            <hidden>false</hidden>
         </person>
      </personsInLesson>
      <vehicles>
         <vehicle id="1">
            <make><![CDATA[Skoda]]></make>
            <model><![CDATA[Octavia]]></model>
            <year>2016</year>
            <fuel>gas</fuel>
            <hidden>false</hidden>
         </vehicle>
         <vehicle id="2">
            <make><![CDATA[Toyota]]></make>
            <model><![CDATA[Avensis]]></model>
            <year>2017</year>
            <fuel>diesel</fuel>
            <hidden>false</hidden>
         </vehicle>
         <vehicle id="3">
            <make><![CDATA[Skoda]]></make>
            <model><![CDATA[Suberb]]></model>
            <year>2017</year>
            <fuel>gas</fuel>
            <hidden>false</hidden>
         </vehicle>
         <vehicle id="4">
            <make><![CDATA[Scania]]></make>
            <model><![CDATA[R450]]></model>
            <year>2018</year>
            <fuel>diesel</fuel>
            <hidden>false</hidden>
         </vehicle>
      </vehicles>
   </school>
</schools>

XSD

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="schools">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="school">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="lessons">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element maxOccurs="unbounded" name="lesson">
                      <xs:complexType>
                        <xs:sequence>
                          <xs:element name="lessonId" type="xs:int" />
                          <xs:element name="lessonStart" type="xs:string" />
                          <xs:element name="lessonEnd" type="xs:string" />
                          <xs:element name="lessonType" type="xs:string" />
                          <xs:element maxOccurs="unbounded" name="vehicle">
                            <xs:complexType>
                              <xs:all>
                                <xs:element name="vehicleId" type="xs:int" />
                              </xs:all>
                              <xs:attribute name="id" type="xs:int" use="required" />
                            </xs:complexType>
                          </xs:element>
                          <xs:element maxOccurs="unbounded" name="person">
                            <xs:complexType>
                              <xs:sequence>
                                <xs:element name="personId" type="xs:int" />
                              </xs:sequence>
                              <xs:attribute name="id" type="xs:int" use="required" />
                            </xs:complexType>
                          </xs:element>
                        </xs:sequence>
                        <xs:attribute name="id" type="xs:int" use="required" />
                        <xs:attribute name="hidden" type="xs:boolean" use="required" />
                      </xs:complexType>
                    </xs:element>
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
              <xs:element name="personsInLesson">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element maxOccurs="unbounded" name="person">
                      <xs:complexType>
                        <xs:all>
                          <xs:element name="firstname" type="xs:string" />
                          <xs:element name="lastname" type="xs:string" />
                          <xs:element name="mail" type="xs:string" />
                          <xs:element name="phone" type="xs:string" />
                          <xs:element name="hidden" type="xs:boolean" />
                        </xs:all>
                        <xs:attribute name="id" type="xs:int" use="required" />
                        <xs:attribute name="type" type="xs:string" use="required" />
                      </xs:complexType>
                    </xs:element>
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
              <xs:element name="vehicles">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element maxOccurs="unbounded" name="vehicle">
                      <xs:complexType>
                        <xs:all>
                          <xs:element name="make" type="xs:string" />
                          <xs:element name="model" type="xs:string" />
                          <xs:element name="year" type="xs:unsignedShort" />
                          <xs:element name="fuel" type="xs:string" />
                          <xs:element name="hidden" type="xs:boolean" />
                        </xs:all>
                        <xs:attribute name="id" type="xs:int" use="required" />
                      </xs:complexType>
                    </xs:element>
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

XSLT to HTML

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
    <xsl:output method="html" indent="yes"/>

    <xsl:template match="/">
      <html>
        <body>
          <xsl:for-each select="schools/school/personsInLesson/person">
            <xsl:if test="@type ='student'">
              <h2>
                <xsl:value-of select="firstname" />
                <xsl:text> </xsl:text>
                <xsl:value-of select="lastname" />
              </h2>
              <table border="1">
                <tr>
                  <th>Email</th>
                  <th>
                    <xsl:value-of select="mail"/>
                  </th>
                </tr>
                <tr>
                  <th>Phone</th>
                  <th>
                    <xsl:value-of select="phone"/>
                  </th>
                </tr>
              </table>
            </xsl:if>
          </xsl:for-each>
        </body>
      </html>
    </xsl:template>
</xsl:stylesheet>

XSLT to XML

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">
      <xsl:element name="schools">
        <xsl:element name="school">
          <xsl:element name="lessons">
        <xsl:for-each select="schools/school/lessons">
          <xsl:element name="lesson">
            <xsl:attribute name="id">
              <xsl:value-of select="@id"/>
            </xsl:attribute>
            <xsl:attribute name="hidden">
              <xsl:value-of select="@hidden"/>
            </xsl:attribute>
            <xsl:element name="lessonId">
              <xsl:value-of select="@lessonId"/>
            </xsl:element>
            <xsl:element name="lessonStart">
              <xsl:value-of select="@lessonStart"/>
            </xsl:element>
            <xsl:element name="lessonEnd">
              <xsl:value-of select="@lessonEnd"/>
            </xsl:element>
            <xsl:element name="lessonType">
              <xsl:value-of select="@lessonType"/>
            </xsl:element>
            <xsl:element name="vehicle">
              <xsl:attribute name="id">
                <xsl:value-of select="@id"/>
              </xsl:attribute>
              <xsl:element name="vehicleId">
                <xsl:value-of select="@vehicleId"/>
              </xsl:element>
            </xsl:element>
            <xsl:element name="person">
              <xsl:attribute name="id">
                <xsl:value-of select="@id"/>
              </xsl:attribute>
              <xsl:element name="personId">
                <xsl:value-of select="@personId"/>
              </xsl:element>
            </xsl:element>
          </xsl:element>
        </xsl:for-each>
          </xsl:element>
        </xsl:element>
      </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Projekti retsensioon

Retsenseerisime projekti puhul meeskonda Maagikud

Üldiselt Maagikute ideest ja projektianalüüsist

Maagikute projektiidee on hea ja üsna põhjalikult lahti analüüsitud. Analüüsi juures on tore, et meeskond on muuhulgas ära toonud hinnangu oma tööle, koostöö toimisele ja projekti käigus saavutatule.

Teenusele valminud andmebaasiskeem on tehtud AB-aluste vaimus ja toob mälestusi Raspeli ülesannetet. EDR tundub korralik - kuigi ise oleks mõne koha peal ehk katsunud lihtsamalt hakkama saada.

Üleüldiseks kommentaariks tahaksime kohe öelda, et klientrakendus ja veebiteenus võiksid olla eraldi projektides. Hetkel on ainuke käivitatav projekt Solutionis “Airport_angular”, kus asuvad nii klientrakenduse kui veebiteenuse failid. Kokku jätab see veidi hübriidlahenduse mulje, sest raske on eraldada, kus üks lõpeb ja teine algab. Kui keegi sooviks sama teenuse vastu mõnda muud kilentrakendust kirjutada, oleks selline kliendi ja teenuse liitmine ebaloogiline.

Kuigi jah, peab tõdema, et koolitöö raames on ühes projekti asuvat lahendust mugavam käivitada - käivitamise liigutust tuleb kahe korra asemel teha ainult korra.

Veebiteenuse retsensioon

Järgenvad mõtted on järjestatud rakenduse ja selle uurimise reaalses järjekorras ning võivad olla seega veidi hüplikud:

Kood on ilusti liigendatud ja organiseeritud, Unit-of-Work muster on implementeeritud.

Retsenseerija- ja testijasõbralikult on teostatud dataseeding. On meeldiv, et see töö on ära tehtud ning programmi käivitades on juba saadaval testandmed. Kuna see ei olnud kohustuslik osa projektist, kuid on tõeliselt kasutajasõbralik lsia, võiks Maagikute tiim siinkohal saada lisapunkti.

Andmebaas tundub korralik ja korrektselt tehtud. Sama võiks öelda domeenimudeli kohta. Kood on selge ja liiasuseta. Mõnes kohas, kus Linq-päringud lähevad väga pikaks, võiks see siiski olla ülevaatlikuse ja mugavama lugemise mõttes teisiti liigendatud. Pikki ridu on rakse lugeda, sest need ei mahu korraga ekraanile. Viimane märkus käib eelkõige DAL.App.EF projekti repositooriumite, aga ka BL projekti service´ite kohta.

Hea, et Swagger on teenusele lisatud - see annab hea kiire ülevaate teenuse meetodites ja parameetritet. Paraku annab Swaggeri laadminie hetkel info asemel veateate. Meie tiim oleks väga huvitatud jälile saama, millest on see veateade tingitud kuivõrd oleme täna hommikust peale oma projektis silmitsi sama probleemiga.

Komplimetidest ja kiitmistväärivatest kohtadest veel: api-kontrollerite meetodid on eeskujulikult kommenteeritud. Vaatemudelid on samuti kenasti varustatud (osaliselt) nii veateadete, kuvamisnimede (display) kui annotatsioonidega.

Kokkuvõtteks on vormistamise ja koodi mõttes võibolla vaid ette heita, et teenus võiks selguse huvides olla rakendusest eraldi projektis ja pikad Linq-päringud võiksid olla teisiti vormindatud - ka projektimeeskonna enda huvides. Muidu on kood pigem meelivalt askeetlik ja loetavalt vormistatud.

Veebiteenuse kohta ei oskagi hetkel midagi rohkem lisada - kõik mis vaja, tundub olemas olevat ja toimivat.

Klientrakenduse retsensioon

Klientrakenduse avalehekülg on sümpaatne, sest andmete valideerimine ja teated kasutajale on korralikult ja põhjalikult teostatud.

Sisselogimata kasutajana broneeringute tegemine töötab kenasti, kuid saadud info, et broneering on tehtud, jätab õhku küsimuse - mis saab edasi? Tellimus on lisatud, broneering on tehtud, aga edasine loogika on jäänud läbi mõtlemata. Sisselogimata kliendi kontaktandmeid ju ei küsita ning broneerigu lehelt ära liikudes (näiteks Login lehele minnes) kaob ka teade broneeringu tegemise kohta. Küllap on siin loogika arendus lihtsalt teiste pakiliste tööde tõttu pooleli jäänud.

Registreeritud kasutaja loogika on jõutud paremini läbi mõelda. Pileteid saab broneerida, broneeringuid saab vaadata ja tühistada. Pärast broneeringu tegemist peab uue broneeringu tegemoiseks korraks lehelt ära liikuma - see on väike ebamugavus, kuid ei midagi hullu. Proovisime ka järjest samale lennule ja samale kohale piletit broneerida - see ei ole võimalik, sest kontroll broneeritud istekohtadele on eeskujulikult teostatud.

Rakendust uurides tekkis mõte, et sisseloginud kasutajal võiks olla võimalus oma isikuandmeid näha ja muuta.

Rakenduses ei ole võimalik näha teiste kasutajate broneeringuid. Proovisime mitme kasutajaga broneeringuid lisada ja kustutada ning esialgsel testimisel tundub, et näha saab ainult oma infot - just nii nagu peakski olema. Eraldi komplimenti väärib, et teostada on jõutud ka lennundusega kokkusobival teemal kujundatud 404 lehekülg neile, kes urli käsitsi muuta üritavad (mida me loomulikult testisime).

Admini kasutajaga sisse logides (admin@eesti.ee, Foobar.foobar1), avaneb eelnevast huvitavam vaade, kus on nii infot kui tegevusi oluliselt rohkem.

Admini alal on eriti toredaks funktsiooniks Statistika. Samuti töötab kõik kenasti Halduse lehel. Lisada ja kustutada saab nii lende, lennuliine kui lennukeid.

Natuke segaseks jääb antud juhul piletite vaade. Idee analüüsist jääb mulje, et Adminina sisselogides saab näha ja hallata kõiki broneeringud, kuid hetkel kuvatakse vaid kaks testbroneeringut ja mitte eelnevalt rakenduse praeguste uurijate poolt tehtud broneeringuid. Testbroneeringute all on ka väike bugi (mida rakenduse loojad ilmselt hästi teavad) - kehtiva arve juures asuvat “Tühista” nuppu vajutades visatakse kaustaja korraks Login vaatesse ja siis tagasi broneeringute juurde - kust vaatavad muutmata kujul vastu need samad kaks tesbroneeringut. Ilmselt jäi see osa funktsionaalsusest praegu ajapuudusel välja arendamata ning põhirõhk admin-ala läks halduse ja statistika vaadete peale.

Koodist: nagu juba eelnevalt mainitud sai, oleks ilmselt parem, kui klientrakendus oleks veebiteenusest eraldi projektis. Praegu on klientrakendus projekti sees eraldi kaustas, mis aitab olukorda selgust tuua. Klientrakenduse kausta siseselt on kood aga organiseeritud selgelt ja arusaadavalt. Kuna Angular on siinkirjutajate jaoks veidi võõras teema, ei oska me koodi kohta midagi väga põhjapanevat öelda. Kuid kood tunudb olevat loogilisteks tükkideks jagatud ja seetõttu suhteliselt hästi hallatav.

Kokkuvõte

Kokkuvõtteks võib öelda, et Maagikud on oma ülesandega VR II aine raames üsna kenasti hakkama saanud. Ilmselgelt on neil aega mingites kohtades napiks jäänud, mistõttu ei ole jõutud kõiki mõtteid lõpuni mõelda ja funktsionaalsusi lõpuni arendada. Aga selle eest on mõne teise funktsionaalususega (nt Admini Halduse vaate funktsionaalsused) kõvasti vaeva nähtud. Üldine mulje oli hea, väikesed märkused ja normised on juba eespool ära toodud.

Nagu juba enne mainitud sai, oli tööd meeldiv retsenseerida tänu tiimi poolt implementeeritud dataseedile ja meeskonna kirjutatud analüüsile, mis andis sissevaate nende plaanidesse ja töö käiku.



XML retsensioon

XML osa puhul retsenseerime tiimi RaamatuRiiul

Meeskonnal on XML fail andmete edastamiseks väga hästi koostatud ja kogu struktuur on loogiline ja hästi mõistetav. Ülesande miinimum maht on täidetud 4 loogilist dimensiooni luues ja ka ületatud, sest kokku on neid loogilisi dimensioone 7 ja seda on saavutatud jättes fail endiselt hästi loetavaks ja hästi mõistetavaks. XML failist saadud skeemifail ehk XSD on automaatselt genereeritud ja ise muutusi pole tehtud, mis ei ole ka problemaatiline, sest esialgne XML on põhjalikult valmistatud ja pole vajadusi muudatusteks. XLST fail andmete transformeerimiseks XMList HTMLi on ka hästi koostatud ja kogu info saab selgelt kätte, failist on näha kuidas kogu transformatsioon on selgelt läbimõeldud ja vaeva nähtud täpse info kuvamiseks. Boonuspunktid oskuste näitamise puhul tavahinna ja soodushinna kuvamisel. Selgelt on näha meeskonna oskust HTMLi ja XMLiga läbikäimisel. Lisaks on transformatsioon XLST XMLiks korralikult tehtud ja kogu info saab nii kätte täpselt nii nagu see on ette tehtud ilma mingisuguste probleemideta. Kokkuvõttes kiidame meeskonna Raamaturiiul tehtud töö väga kvaliteetseks ja kõrge hindega võimaluse korral. Selgelt on näha, kuidas on rahulikult aega võetud ja kõik XML osad selgelt ja loogiliselt kirja pandud.