Virtuaalikassa

TKO-wiki
Loikkaa: valikkoon, hakuun

PHP: statistiikkaa vepistä

http://db.cs.helsinki.fi/~mcrantan/rv/rv.php. Tuolla on kehityspuu joka elää silloin tällöin, toimii best-effort -periaatteella.
[Statistiikkaa tsohana ].
Eikö päivity? Tarkista RV-koneelta että tunneli on pystyssä (tix.tko-aly.fi:ssä 127.0.0.1:3305 ohjattu RV-koneen (bogrund-2 toistaiseksi as of 20100204) 127.0.0.1:3306:een; RV-koneessa on ssh-avain tixille ja sitten vaan sopivat -L/-R -vivut jos ei itsestään buutissa nouse).

Jos tunneli on kuitenkin pystyssä, katso tixillä MySQLstä
SHOW SLAVE STATUS
. Joskus voi olla kummallisia tilanteita, kuten että toukokuun 2008 jälkeen on muutettu logiikkaa tai että on käsin säädetty jonkin tuotteen ominaisuuksia jolloin logiikka hajoaa ja replikointi voi pysähtyä kuten seuraavassa:
mysql> SHOW SLAVE STATUS;
+----------------------------------+-------------+-------------+-------------+---------------+------------------+---------------------+--------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+
| Slave_IO_State                   | Master_Host | Master_User | Master_Port | Connect_Retry | Master_Log_File  | Read_Master_Log_Pos | Relay_Log_File     | Relay_Log_Pos | Relay_Master_Log_File | Slave_IO_Running | Slave_SQL_Running | Replicate_Do_DB | Replicate_Ignore_DB | Replicate_Do_Table | Replicate_Ignore_Table | Replicate_Wild_Do_Table | Replicate_Wild_Ignore_Table | Last_Errno | Last_Error                                                                                                                                                                                                                                                    | Skip_Counter | Exec_Master_Log_Pos | Relay_Log_Space | Until_Condition | Until_Log_File | Until_Log_Pos | Master_SSL_Allowed | Master_SSL_CA_File | Master_SSL_CA_Path | Master_SSL_Cert | Master_SSL_Cipher | Master_SSL_Key | Seconds_Behind_Master |
+----------------------------------+-------------+-------------+-------------+---------------+------------------+---------------------+--------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+
| Waiting for master to send event | 127.0.0.1   | rv-replica  |        3305 |            60 | mysql-bin.000703 |              242979 | slave-relay.010000 |        184300 | mysql-bin.000693      | Yes              | No                | RV              |                     |                    |                        |                         |                             |       1048 | Error 'Column 'priceid1' cannot be null' on query. Default database: 'RV'. Query: 'INSERT INTO ITEMHISTORY(time, count, itemid, userid, actionid, priceid1) VALUES(NOW(), 6, 426, 404 , 8, (SELECT priceid FROM PRICE WHERE itemid=426 AND endtime IS NULL))' |            0 |              184163 |         2924015 | None            |                |             0 | No                 |                    |                    |                 |                   |                |                  NULL |
+----------------------------------+-------------+-------------+-------------+---------------+------------------+---------------------+--------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+
1 row in set (0.00 sec)

Tämä siis korjautuu tutkimalla kantaa ja huomaamalla että 'kappas, hinta, joka liittyy itemid 426:een, on merkitty käytetyksi (kuten jos tuote poistuisi valikoimasta), mutta logiikka ei tunne tällaista mahdollisuutta':

mysql> SELECT * FROM PRICE WHERE itemid=426;
+---------+---------------+-------+----------+-----------+--------+--------+---------------------+---------------------+
| priceid | barcode       | count | buyprice | sellprice | itemid | userid | starttime           | endtime             |
+---------+---------------+-------+----------+-----------+--------+--------+---------------------+---------------------+
|     213 | 6415600503068 |     0 |      115 |       150 |    426 |    404 | 2008-02-26 15:46:57 | 2008-05-13 10:03:42 |
+---------+---------------+-------+----------+-----------+--------+--------+---------------------+---------------------+
1 row in set (0.00 sec)

Huolimatta siitä että tällä kertaa SHOW SLAVE STATUS näytti virheilmoituksen jonka ilmoitus oli juurikin oikein ja jonka korjaus korjasi asiat, on syytä aina tutkia asiaa hieman pintaa syvemmältä ja miettiä, miten Smurffilimpparin endtime oli tullut asetetuksi. Ongelma nyt kuitenkin korjataan asettamalla tuotteen hinta voimassaolevaksi (eli endtime NULLiksi) ja käynnistämällä slave uudestaan:

mysql> UPDATE PRICE SET endtime=NULL WHERE priceid=213;
Query OK, 1 row affected (0.05 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SLAVE STOP;
Query OK, 0 rows affected (0.00 sec)

mysql> SLAVE START;
Query OK, 0 rows affected (0.00 sec)

mysql>

Jos tilanne on ollu päällä jo pitkään, DAYHISTORY-taulu ei päivity. Lisäksi voi käydä (jos nyt olet vaikka loganneena sisään) niin, että logiikka korjaa viimeiset kaksi päivää mutta jättää NULLia väliin:


mysql> SELECT * FROM DAYHISTORY WHERE date > '2010-01-20';
+------------+--------+-------+-------+--------+
| date       | rvarvo | depo  | buy   | invest |
+------------+--------+-------+-------+--------+
| 2010-01-21 | 125942 | 38215 | 13769 |  10525 |
| 2010-01-22 | 112009 | 24240 | 18567 |  14082 |
| 2010-01-23 | 111224 |  NULL |  1080 |    815 |
| 2010-01-24 | 110953 |  NULL |   345 |    281 |
| 2010-01-25 |  99436 | 15560 | 15443 |  11637 |
| 2010-01-26 | 156694 | 10940 |  9689 |   7388 |
| 2010-01-27 | 156694 |  NULL |  NULL |   NULL |
| 2010-01-28 | 156694 |  NULL |  NULL |   NULL |
| 2010-01-29 | 156694 |  NULL |  NULL |   NULL |
| 2010-01-30 | 156694 |  NULL |  NULL |   NULL |
| 2010-01-31 | 156694 |  NULL |  NULL |   NULL |
| 2010-02-01 | 156694 |  NULL |  NULL |   NULL |
| 2010-02-02 | 156694 |  NULL |  NULL |   NULL |
| 2010-02-03 | 156694 |  NULL |  NULL |   NULL |
| 2010-02-04 | 117703 | 18830 | 17404 |  13433 |
| 2010-02-05 | 109783 |  7770 | 13151 |   9956 |
+------------+--------+-------+-------+--------+
16 rows in set (0.00 sec)

mysql>

Tämä korjataan poistamalla (DELETE) DAYHISTORY-taulusta rivit jotka halutaan luoda uudestaan, esimerkiksi vaikka 20. päivän jälkeiset:

mysql> DELETE FROM DAYHISTORY WHERE date > '2010-01-20';
Query OK, 16 rows affected (0.05 sec)

Kirjaudu sen jälkeen veppikäliin sisään ja mene sivulle 'Item Management'. Tällöin PHP ajaa kannassa stored proceduren, joka etsii viimeisen päivän (MAX(date)) jolloin tieto on aggregoitu ja generoi päiväkohtaiset historiat sen jälkeisille päiville uudestaan. Hommassa menee 10-20 sekuntia per päivä, joten muutaman minuutin päästä pitäisi näkyä lisää päiviä:

mysql> SELECT * FROM DAYHISTORY WHERE date > '2010-01-20';
+------------+--------+-------+-------+--------+
| date       | rvarvo | depo  | buy   | invest |
+------------+--------+-------+-------+--------+
| 2010-01-21 | 125942 | 38215 | 13769 |  10525 |
| 2010-01-22 | 112009 | 24240 | 18567 |  14082 |
| 2010-01-23 | 111224 |  NULL |  1080 |    815 |
| 2010-01-24 | 110953 |  NULL |   345 |    281 |
| 2010-01-25 |  99436 | 15560 | 15443 |  11637 |
| 2010-01-26 | 153199 | 25400 | 19316 |  14928 |
| 2010-01-27 | 140893 | 15870 | 16592 |  12516 |
| 2010-01-28 | 127451 |  6965 | 17837 |  13587 |
| 2010-01-29 | 116337 |  3840 | 14434 |  11204 |
| 2010-01-30 | 114697 |  3160 |  2051 |   1660 |
| 2010-01-31 | 113857 | 12605 |  1308 |    962 |
| 2010-02-01 | 104040 | 27810 | 14704 |  11134 |
| 2010-02-02 | 140616 | 20430 | 22375 |  17443 |
| 2010-02-03 | 129587 | 22095 | 18400 |  13798 |
+------------+--------+-------+-------+--------+
14 rows in set (0.01 sec)

Muutoksia

  • Kehitysversioon (nyt jo tuotannossa) on skoodattu lisää juttuja:
    • TUOTANNOSSA: Summerituki commapilla: Sunin commapi sarja- ja rinnakkaisporttien käsittelyyn tarvitaan,
    • TUOTANNOSSA: käynnistys ja määrittelytiedosto: nyt 'LD_LIBRARY_PATH=<paikka jossa commapi:n kirjasto on> java -jar ./RV.jar [valinnainen asetustiedosto]' . Määrittelytiedostoa haetaan oletusarvoisesti paikoista /etc/rv/rv.conf, /etc/rv.conf ja ./rv.conf. Mallitiedosto on RV.jar -paketissa
    • TUOTANNOSSA: LDAP: kirjoitin RVLDAP.java:n jota voi käyttää käyttäjän antaman käyttäjätunnuksen tai sähköpostiosoitteen tarkistukseen laitoksen LDAPista (ldap://ldap.helsinki.fi:389/o=hy , esim:
 ldapsearch -L -u -x -H ldap://ldap.helsinki.fi:389 -b o=hy -z 10 "(&(givenName=Mikko) (sn=Rantanen))".
    • TUOTANNOSSA: Vaikuttaa siltä, että JNDI/LDAPissa odotetaan (jos LDAP-palvelin ei vastaakaan) kunnes joko tapahtuu verkkokerroksen timeout (aikakatkaisu) tai yhteys muodostuu. Tämähän nyt ei käy, joten panen lähipäivinä kolmen (3) sekunnin timeout-koodin ajoon (joka myös kertoo että venaillaan LDAP-yhteyttä kun käyttäjä kirjautuu sisään jottei tule huolia).
    • TUOTANNOSSA: Lisätty tuoteryhmät. Tuoteryhmät on määritelty seuraavasti:
 0    DEFAULT GROUP, NO DEFINITION
 1    Drinks, soda with bottle return
 2    Drinks, soda with can return
 3    Drinks, juices
 4    Drinks, soda without can return
 10   Sweets, chocolate
 11   Sweets, other
 12   Sweets, ice creams
 20   Food, pizzas
 21   Food, noodles
 22   Food, dairy
 23   Food, salty snacks (beef jerky, potato chips etc.)
 24   Food, other (meat pies etc.)
 30   Hot liquids, coffee
 31   Hot liquids, tea
 32   Hot liquids, hot chocolate
 80   Bottle return (negative price)
 81   Can return (negative price)
 90   Seasonal products (kinder-eggs, chocolate Santa Claus etc.)
    • TUOTANNOSSA: Lisätty MySQL-tuki: MySQL:n Connector/J tarvitaan (mysql-connector-java-5.1.5 nyt ajossa). Nyt RV-koneessa pyörii MySQL, joka replikoi minun (dogo) kotikoneelle, joka replikoi alkokrunnille. Harkka-tsohani jatkokehitysversiosta http://db.cs.helsinki.fi/~mcrantan/rv/ voi katsella reaaliaikaisia statistiikkoja niin kauan, kuin yhteydet pysyvät auki ja alkokrunnia ei buutata ja muistan pystyttää tunnelit ja käynnistää kannat uudestaan jne. Löytyy tuotekohtaiset graafit (päiväostot + keskiarvo) ja ajantasainen RV-arvo sekä graafi RV-arvosta ja päivittäisistä depositeista.
      • MUUTOS: ei replikoi mun kotikoneelle vaan suoraan tix.tko-aly.fi:hin. Graafien lisäksi on piirakkagrammi varaston nykytilasta tuoteryhmittäin (yleensä limuja on >50 prossaa varastoarvosta)
    • TUOTANNOSSA: Lisätty uusi käyttäjätyyppi 'INACTIVE', joka voi kirjautua sisään mutta RV-kone huutaa ~15 sekuntia ennenkuin voi tehdä mitään. INACTIVE-käyttäjien negat eivät näy shamelistillä (jotta pikku fuksipalleroiset eivät opi huonoille tavoille). Varsinaisen käyttäjähallinnan puutteessa statusta muutetaan editoimalla /usr/local/rv/gurula/rvpasswd -tiedostoa ja sitten sanomalla kannassa UPDATE RVPERSON SET roleid=<haluttu rooli> WHERE userid=<käyttäjän ID, voi luntata rvpasswd:stä myös>

SVN

Toiveita & Ehdotuksia

  • Kirjautumisessa vois olla infoa siitä, miten luoda uus tili
    • Ehdotuksia uudeksi login-promptiksi?
    • Eiks pelkkää teksti tyyliin "syötä uusi tunnus rekiteröityäksesi rv:n käyttäjäksi" tjsp riitä? -TKa
  • Pieni nillitys: nyt kirjudutaan ulos yhdellä enterillä. Ennen se ekalla painalluksella tyhjensi ruudun ja tokalla vasta kirjas ulos. Makukysymys.
    • Eiks tämä ollut toisinpäin, ensin kirjas ulos ja tokalla painalluksella tyhjensi ruudun? X-) Sini 12:36, 3 September 2007 (EEST)
  • Kauneusvirhe (ei kriittinen toiminnan kannalta): shamelist-tekstit voisivat alkaa ruudun yläreunasta jos ne saa jotenkin. Muistelisin että javalla konsolitekstin asemointi ei ole kovin helppoa.
    • Joo ei oo. Sitä JCursesia ootellessa, vähän niinku luotan että on 24 riviä tai enemmän. En äkkiseltään edes tiedä miten sitä kysyisi clientiltä; TELNETissä tietty voi muistaakseni kysästä mitä telnet-clientti valehtelee terminaaliemulaatiostaan mutta sieltähän nyt voi tulla mitä vain ja joka emulaatiolla on oma tapa kertoa ruudun geometriasta (jos on).

Hölmöjä ideoita

  • Teksti vihreäksi, loginin tilalle ">:" ja vilkkuva kursori perään
    • Tarttis jonkun JCursesin tai vastaavan. Voi sen tehä kylmästi ANSI-koodia puskemalla mutta ei tekis mieli.
    • Todellaki tollanen feature tarvitaan! Vaikka sitten ANSIa. Tarvitaan myös aikalaskuri gurulan seinälle!

Bugeja

  • Olisi ehkä hyvä, ettei salasanaksi kävisi kahvin tai muun tuotteen viivakoodi (jotkut jo innostuivat)
    • Entäs tyhjät salasanat? Siellä on vaikka kuinka monella. Minusta tätä ei pitäisi änkyröidä, kohta joku ehdottaa että salasana pitää vaihtaa kerran kuussa, 15 viimeistä muistetaan, pituus pitää olla 11 merkkiä ja siinä pitää olla isoja ja pieniä kirjaimia, numeroita ja erikoismerkkejä :)


  • Komento 'rvarvo' jää piiloon.
    • Kiertotie: shift-pageup näyttää tulosteen tty:n scrollbackista

Korjatut

  • Jos syöttää vääriä salasanoja ja tunnuksia, ruutu täyttyy vain bad password-teksteillä ja shamelist jää kokonaan piiloon
    • Fiksattu. Lähtökohtaisesti tuon oli tarkoitus olla kertomatta telnetin takaa tulevalle mitään käyttäjiin liittyvä tietoa kunnes on logattu sisään, mutta muutinpa tuon nyt niin että siihen tulee listat ja login.
  • Kun syöttää väärän viivakoodin, kassa sanoo "please enter old style d<amount> to buy". Tuossa on väärin d(eposit), sitähän ei käytetä kun ostetaan. Lisäksi tuo old-style-buy on nykyään disabloitu".
    • fiksattu koodissa, panen tuotantoon RSN
  • UNIVERSITY ACCOUNTIN pyytämisestä pitäisi olla selitys, että mihin sitä tarvitaan. Sitä ei kukaan ymmärrä.
    • Runoilin jotain, panen tuotantoon RSN. Teksti:
 Please enter your UNIVERSITY ACCOUNT (such as 'mcrantan' or 'jkolanki').
   This is required because we need accountability for purchases. Your 'handle'
   or 'RV account' name can be anything. Please, support RV and trust us - tell
   us who is using this service and enter your faculty-issued account or e-mail
   address. We will never reveal it to anyone:
  • Voisi tsiigata (en tiie onko jo) et käyttäjä voi syöttää vain [A-Za-z0-9] -merkkejä tunnuksekseen ja salasansakseen. Siellä listassa kun joku oli syöttänyt nimekseen "\n\n\n"
    • fiksattu: vain [a-zA-Z] on nyt sallittu.
  • tuotteen tieojen muuttaminen: pelkkä enter potkaisee pihalle
    • fiksattu
  • kun rekisteröityy, se sanoo "bad login or password" ennen ku voi ees syöttää niitä ekaa kertaa.
    • fiksattu
  • Viivakoodittoman tuotteen maksaminen, ts. rahan nostaminen tililtä, ei onnistu ilman kahta desimaalia
    • fiksattu; nyt toimii nolla, yksi tai kaksi desimaalia depositissa tai nostossa.
  • Uloskirjaus esim. enterillä (kuten ennenkin), kun nyt en keksi, miten voi lopettaa ostamatta mitään (hups, tää olikin jo täällä - Jesse :)
    • fiksattu
  • Joku varmistuskysymys uuden tunnuksen luontiin, jos esim. typottaa oman tunnuksen
    • fiksattu
  • Takaperoisen yhteensopivuuden vuoksi voisi olla hyvä, että parilla enter-napin painalluksella pääsee sulkemaan ostosruutunsa. Tämä on tosin vain mielipide.
    • fiksattu
  •  ?-merkki ja enter antaa syntilistan ja potkaisee ulos. Olisin kaivannut helppiä.
    • huomasin tuon joku aika sitten, liittynee siihen miten regexpit handlaa kysärin, tutkitaan
    • fiksattu
  • toi potkasee heti ulos kun ostaa jotain. koitin äsken palauttaa pulloa, ja sit se vähens multa 20snt ja potkas ulos. tiedän kyl et se kysy että haluanko ostaa pullon palautuksen mut silti. ja se et se potkasee ulos ei oo hyvä
    • fiksattu
  • voisko toi pullon palautus olla -0.2e?
    • Häh, pullopalautushan voi olla mitä vaan?
    • Tarkoitin sitä, että kun "ostaa" pullonpalautuksen, ts. näppäilee sinne koodin 335353, niin saldo laskeekin vaikka 1.0e:stä 0.8e:hen, vaikka IMO sen pitäs nousta 1.2e:hen
    • ahaa, ymmärrän, lienenköhän varmistellut että negatiivisia ostoja ei voi tapahtua, tutkitaan
    • Fiksattu: tämäpä olikin kiusallinen, oli monessa paikassa tarkisteluja negatiivisen hinnan suhteen, muutin vähän muutakin sivussa. Jos tuotteesta saa rahaa, sen hinnaksi pitää sitten tietty antaa esim. '-0.15'...
  • Kirjautumisen aikakatkaisu (tällainen oli muistaakseni ennenkin), jotta seuraava RV:n käyttäjä ei voi tehdä ostoksiaan edellisen tililtä
    • hyvä idis, tutkin asiaa, joku taimeri siihen pitää luoda jne.
    • Timer+TimerTask ei pelannu, tein tuommoisen Thread.sleep(100) -loopin; muita ehdotuksia otetaan vastaan, joskin tuo on varmaan kevyin tapa.

Statistiikat rvitem.conffista ja rv.logista

Seuraa tämmöinen awkkiskripti. Toimii sanomalla cat rvitem.conf rv.log | awk -f <tiedostojossatämätekstion> ja se sitten päällekirjoittaa mahdollisesti siinä hakemistossa olevan myynnit.csv -tiedoston. Käppyrät piirtää vaikka eskelisessä tai openofficessa. Pitäisi vielä toteuttaa tuotteiden lajittelu niin että olisi helppo valita juomat yhtenä alueena, pizzat ja nuudelit toisena jne.

# First, establish written month relation to number
# and x-y direction pointer in buys[n, m] to 1,1 and
# then initialize the order in which we want the
# products to be listed. Some products such as Marlboro
# Red (Estonia) and beers will be skipped.

BEGIN {
    FS="|"
    mon["Jan"]=1
    mon["Feb"]=2
    mon["Mar"]=3
    mon["Apr"]=4
    mon["May"]=5
    mon["Jun"]=6
    mon["Jul"]=7
    mon["Aug"]=8
    mon["Sep"]=9
    mon["Oct"]=10
    mon["Nov"]=11
    mon["Dec"]=12

# Defined product classes (may be used later)

#    split("6 8 24 10 22 68 12 70 62 14 16 18 20 130 66 64 60 140 142 176 178", sodas, " ")
#    split("26 28 30 32 76 42 44 90 92 94 124 126 168 170 172", foods, " ")
#    split("52 50 58 56 54", hots, " ")
#    split("96 98 100 106 102 88 86 82 74 72 110 114 84 134 148 194", chocolates, " ")
#    split("136 138 104 108 112 36 38 40 46 78 80 144 146 152 200", sweets, " ")
#    split("4 116 118 120 122 34 150 196 198", juices, " ")
#    split("156 158 160 180 182 184 186 192", dairy, " ")


# ..set the order in which the products are put out

    foo = split("6 8 24 10 22 68 12 70 62 14 16 18 20 130 202 204 66 64 60 140 142 176 178 26 28 30 32 76 42 44 90 92 94 124 126 168 170 172 52 50 58 56 54 96 98 100 106 102 88 86 82 74 72 110 114 84 134 148 194 136 138 164 166 174 188 190 104 108 112 36 38 40 46 78 80 144 146 152 200 4 116 118 120 122 34 150 196 198 154 156 158 160 180 182 184 186 192", order, " ")

# Some variables for later use and first columns
# m effectively means how many lines are reserved
# from top (sellprice, stock value/buy and stock value/sell)

    buyevents=0
#    n=1
    m=5

    buys[0, 0] = "\"Sellprice (cents)\""
    buys[0, 1] = "\"Buyprice  (cents)\""
    buys[0, 4] = " "

    arrlen = 0
    for (i in order)
    {
        arrlen++
    }

}

# If second field (when separated by '|') is numbers
# and the line does not start with '#'-character, it is
# barcode and 3rd field contains product name. This relation
# is stored.
#
# When product information is encountered, sellprice and
# stock values (buy and sell) are stored on rows 2 and 3.
# The first column (totals) on both rows is updated every time
# to avoid complexity in the end when .CSV is printed.

{
    foo = match($2, /[0-9][0-9][0-9][0-9][0-9]+/)

    if ( (foo != 0) && ($0 !~ /^#/) && (NF > 4) )
    {

# Kludge: we'll set column to 999 which is not likely to contain
# product information. It is easy to 'weed out' when importing
# generated CSV.

        for (i in order)
        {
            n = 999
            if (order[i] == $1)
            {
                n = i

                buys[n, 0] = $6
                buys[n, 1] = $5
                buys[n, 2] = $5*$7
                buys[n, 3] = $6*$7
                buys[n, 4] = "\"" $1 ":" $3 "(" $7 ")\""
                buys[n, 5] = $7

                if ($5 > 0 && $7 >= 0) buyvals += buys[n, 2]
                if ($6 > 0 && $7 >= 0) selvals += buys[n, 3]
                buys[0, 2] = "\"Stock value  (BUY): " buyvals "\""
                buys[0, 3] = "\"Stock value (SELL): " selvals "\""
                buys[0, 5] = "\"Count on stock:     \""
                xdir[$2] = n
#        n++;

#                printf("buyvals: %d, selvals: %d, tuote: %s, n = %d\n", buyvals, selvals, $2, xdir[$2])
            }
        }

    }

# Note that when speaking of 'field 9' or similar, I mean
# the number that would be assigned to the field if FS=" " .
# Unfortunately, FS is previously set to |, so after setting
# year-string, we artificially increase NF to 9 and fill in
# blanks.
#
# If field 9 contains 'bought', this is buy-event.
# We can have multiple buys per day and we may need to establish
# new relation between day and the row it corresponds to.
# Associative array ydir is indexed through concatenation of
# day-mon-year (for example, string '02Mar2007.' including the
# dot in the end which really does not matter)
# When new date is seen, it is written to buys[n, m] as new
# row's first column.

    foo = substr($0, 21, 3)
    if (foo == "EES")
    {
        yearpos = 26
    }

    else
    {
        yearpos = 25
    }

    matches = match($0, /bought/)

    if (matches != 0)
    {
        buyevents++;
        NF=9
        $2 = substr($0, 5, 3)
        $3 = substr($0, 9, 2)
        $6 = substr($0, yearpos, 4)

        foo = match($0, /[0-9][0-9][0-9][0-9][0-9]+/, bitem)

        $9 = bitem[0]

# Check if we have row for this day. If not, create row
# and initialize its values to zero.

        if (! ($2$3+""$6+"" in ydir))
        {
             ydir[$2$3+""$6+""] = ++m
             buys[0, m] = $3+"" "/" mon[$2]+"" "/" $6

             for (initl=1; initl<=arrlen; initl++)
             {
                 buys[initl, m] = 0
             }
        }

        buys[xdir[$9], m] += 1

        strawb = match($0, /6415131402342/)
        if (strawb != 0)
        print($0)

    }

}

# In the end, print out .csv file.
# Creation is kludged by printf'ing a single space
# character.

END {

    printf(" ") > "myynnit.csv"

    for (j=0; j<=m; j++)
    {
        for (i=0; i<arrlen; i++)
        {
            printf("%s,", buys[i, j]) >> "myynnit.csv"
        }

# Last element: no trailing comma, just newline
        printf("%s\n", buys[arrlen, j]) >> "myynnit.csv"
    }

#    printf("Buy events total: %d, stock value (buy): %d, stock value (sell): %d.\n\n", buyevents, buyvals, selvals)
}

Hinnasto

Hinnasto on myös webissä, http://www.cs.helsinki.fi/u/mcrantan/rv/hinnasto/ löytyy aiemmin mainitusta tsoha-harkasta.

Hinnaston voi luoda hienolla skriptillä joka ottaa syötteekseen rvitem.conf-tiedoston:

#!/bin/bash

if [ $# = 0 ]
  then
    echo NEED CMDLINE ARGUMENT: WHERE IS rvitem.conf
    exit 1
fi

if [[ ! -e $1 ]]
  then 
    echo NEED CMDLINE ARGUMENT: WHERE IS rvitem.conf
    exit 1
fi

itemfile=$1

# 5 first lines are crap

x=`wc -l $itemfile  | awk '{print $1 - 5}'`
# ..so x is the number of lines we're interested in.
date=`date`
echo x = $x
echo itemfile = $itemfile
tail -$x $itemfile | awk 'BEGIN { FS = "|"}; { print $2}' | xargs -I XYZ barcode -e EAN -b XYZ -o XYZ.ps

for i in *.ps; do

  pstopnm -llx 0.1 -lly 0.2 -urx 1.6 -ury 1.3 -portrait -stdout $i | pnmtopng > `echo $i | sed 's/\.ps//'`.png
rm $i
done


cat <<EOF >hinnasto.html
<HTML>
<HEAD><TITLE>RV - hinnasto $date</TITLE></HEAD>
<BODY>
<TABLE><TR><TH>BARCODE</TH><TH>ITEM</TH><TH>PRICE</TH></TR>
<!-- tästä eteenpäin viivakoodi - tuote - hinta -->

EOF

# for line in `tail -$x $itemfile`; do

tail -$x $itemfile | awk 'BEGIN { FS = "|"}; { hinta=$6/100; i=$2; printf("<TR VALIGN=\"middle\"><TD><IMG SRC=\"./%s.png\" BORDER="0" WIDTH="130"></TD><TD>          %s</TD><TD>                %5.2f EUR</TD>\n", i, $3, hinta) >>"hinnasto.html" }';

cat <<EOF >>hinnasto.html
</TABLE>
</BODY>
</HTML>
EOF