2012. júl. 21.

OTP egyenleget naponta Google Docs-ba automatikusan

Update: Téma erről a posztról HUP-on: http://hup.hu/node/120903

Előzmény

Egy szép nyáron napon volt pár e-mail a Gmail fiókomban, amikkel csak 1 hét múlva kellett volna valamit kezdenem, és zavart, hogy ennek ellenére minden nap ott néznek rám. Egy kis guglizással rátaláltam erre:
http://lifehacker.com/5825634/how-to-add-a-snooze-button-to-gmail-no-extensions-required
Már a cikk címe felkeltette a érdeklődésem, mert elképzelésem nem volt, hogy hogyan lehetséges ez bármiféle kiterjesztés vagy harmadik félnek történő jelszókiadás nélkül.
Lehetséges, és a varázslat része a dolognak a Google Scripts, ami lehetővé teszi számunkra, hogy minden nap megadott időben lefutó javascript nyelvű felhőben tárolt scripteket írjunk, amik nagyon kényelmes javascriptes api-n hozzáférhetnek Google szolgáltatásainkhoz, mint például a Gmailhez vagy a Docs-hoz.
Ennek a scriptnek a kódjáról nem fogok beszélni. Ha érdekel, akkor megtalálod az eredeti linken.

 

Kényszer

Aztán jött a kényszer, hogy valamire használnom kell ezt a Google Script-et a Gmail Snooze-on felül.. Itt jött az ötlet, hogy milyen király(?) lenne, ha láthatnám a banki egyenlegem alakulását egy grafikonon Google Docsban.

 

Kérés

Az OTP biztosít egy a normál netbanktól független felületet, ahol a telekóddal és kártyaszámmal le lehet kérdezni az aktuális egyenleget. A telekód alapból a számlaszám utolsó 3 számjegye. Ez a felület az OTPdirekt belépés gomb alatt található jelenleg:
OTP-egyenleg
Direkt link az OTP egyenleglekérdezés leírására

Itt a kártyaszám és a telekód megadása utána megkaphatjuk az aktuális egyenlegünk:
image[3]
Hm… Ezt a lekérdezést szeretnénk valahogy automatizálni.

Nézzük meg az űrlapot, ami beküldünk:
(Chrome-ban dolgozom.)
image
Katt az “Elem megtekintésére”.
Ekkor a Chrome feldobja az Elements Panel-t:
image
A method=”post”-ból láthatjuk, hogy ez egy POST kérés lesz. A kérésben a következő mezők fognak utazni:
muvelet
azonosito
telekod
honlapAzonosito
azonositoxx
telekodxx

Ezekből mi csak kettőnek állítjuk az értékét, és értelemszerűen ezek az azonositoxx és telekodxx. A többit alapértéken hagyjuk.
Valójában ha jobban megnézzük, akkor tévedtem, mert az azonositoxx  és a telekodxx az beküldéskor üres lesz az onsubmit eseménykezelő hatására, és a tartalmuk átíródik a rejtett azonosito es telekod mezőkbe. (Ezt azért csinálták, mert nem akarták, hogy a böngésző felajánlhassa a jelszó elmentését, valamint így a Vissza gomb megnyomása után a böngésző nem tudja visszaállítani a kitöltött állapotát az űrlapnak.)

Eddig feltételezésink helyességéről meggyőződhetünk, ha elkezdjük figyelni az oldal forgalmát a Network fülön, és beküldünk egy kérést.
Ehhez váltsunk át a Network fülre (Az Elements fültől 2-vel jobbra.), és aztán a szokványos módon küldjük be az űrlapot. Ezután kattintsuk rá a “bankkartyaEgyenlegLekerdezes” kérésre, és keressük a Form Data részt.
image
Úgy tűnik, hogy mindent helyesen láttunk.
Kipróbálhatjuk mondjuk wget-el (opcionális):
wget https://www.otpbankdirekt.hu/homebank/do/bankkartyaEgyenlegLekerdezes -O - --post-data "muvelet=login&azonosito=██████████&telekod=███&honlapAzonosito=Default.User&azonositoxx=&telekodxx="
(Ez a parancs egy sor.)


Ha minden jól sikerült, akkor a wget hatására láthatjuk a lekérdezés eredményét egy csomó html kód közt.

Megvan, hogy hogyan tudjuk lekérdezni. Akkor most ebből valahogy Google Script-et kéne csinálni.

Script

Hozzunk létre egy új Google Táblázatot, nyissuk meg, és az Eszközök menüből válasszuk ki a Script szerkesztőt. Ekkor kapunk egy nagyon segítőkész ablakot, amit csukjunk is be.

Ekkor ezt kell látnunk:
image
A kis “Play” gombbal lefuttathatjuk a myFuncton-t, ami jelenleg nem csinál semmit. (Ekkor el kell mentenünk a Project-et. Mentsük tetszőleges néven.)

Csináljunk valami extravangásabbat:
image

Mikor ezt lefuttatjuk, akkor első pillantásra nem történik semmi, pedig valójában megjelent egy üzenetablak, de nem ott ahol vártuk, hanem az eredeti dokumentumban:

image

Az elérhető API-kat itt találod: https://developers.google.com/apps-script/defaultservices

Például megtalálhatjuk a UrlFetchApp.fetch metódust, ami jó szolgálatot fog nekünk tenni. Ezzel fogjuk lekérni az egyenlegünket.
A korábban összehozott lekérés és a dokumentáció alapján a következő kódot állítjuk elő:
image

Ez ugyanaz a lekérés, ami korábban kipróbáltunk. Próbáljuk ki itt is:
image

… és az eredmény:
image
A lekérés a title alapján működni látszik….. Már csak valahogy ki kéne nyerni belőle a lényeget. Html-ből infót kinyerni nem szép, de hasznos.

A következő buta, de működő megoldást választottam: Az első <span class="value"><strong> és </strong> közötti cucc érdekel minket:
var egyenleg = response.getContentText().split('<span class="value"><strong>')[1].split("</strong>")[0];

Valamint még a pontot is kéne kapni belőle, mert számot szeretnénk:
var egyenleg = response.getContentText().split('<span class="value"><strong>')[1].split("</strong>")[0].replace(".","");

Így a következő tesztelhető kódhoz jutunk:
image

… amit ha lefuttatunk, akkor most már ténylegesen az egyenlegünket kapjuk a dobozba:
image

Ez szép és jó, de mi grafikont szeretnénk.

A grafikonhoz először meg lennie az adatnak táblázatosan. Mondjuk így:
image

Ezután kijelöljük az A és B oszlopot egyszerre, és hozzáadunk a dokumentumhoz egy vonaldiagramot. Azon kicsit állítgatunk, és akkor valami ilyesmit kaphatunk:
image
Azért volt fontos az egész A és B oszlopot kijelölni, mert így ha egy új sorba beleírunk valamit, akkor így az is felkerül a diagramra, és így akkor most már tényleg csak az a magic kell, ami minden nap hozzáad egy új sort ehhez a táblázathoz a megfelelő értékekkel.

Az eddig elkészült függvényünket alakítsuk át egy segédfüggvénnyé, ami az egyenleggel tér vissza visszatérési értékként. Ehhez egyszerűen cseréljük le az msgBox-os sort erre:
return egyenleg;

Ezután írjuk meg a következő függvényt, ami hozzáadja a megfelelő értékekkel rendelkező új sort:
image

Láthatjuk, hogy ez felhasználja korábban megírt getOtpEgyenleg függvényünket.
Az “otp-egyenleg” a munkalap neve. Ez neked lehet, hogy más.
A dátumot azért ilyenre formázom, mert (többek közt?) ezt ismeri fel a Docs dátumnak.

Ha ezt a függvényt lefuttatjuk a kis Play gombbal, akkor láthatjuk, hogy hozzáadódik egy új sor a táblázathoz, és a diagram is frissül.

Egyetlen lépés van már csak hátra: Beállítani, hogy minden este automatikusan lekérje az aktuális egyenleget:
Resources menü → Current script’s triggers → és ott adjuk hozzá a következő sort:
image

Mentsük, és ezzel készen is vagyunk. Minden éjjel magától frissülni fog a táblázatunk. :)

Yéy!

 

A kód másolható formában

function getOtpEgyenleg() {
  
  var url  = "https://www.otpbankdirekt.hu/homebank/do/bankkartyaEgyenlegLekerdezes";
  var payload = 
    {
      "muvelet" : "login",
      "azonosito" : "██████████",
      "telekod" : "███",
      "honlapAzonosito" : "Default.User",
      "azonositoxx" : "",
      "telekodxx" : ""
    };
  var options =
    {
      "method" : "post",
      "payload" : payload
    };

  var response = UrlFetchApp.fetch(url, options);
  
  var egyenleg = response.getContentText().split('<span class="value"><strong>')[1].split("</strong>")[0].replace(".","");
  return egyenleg;
}

function updateSpreadSheetWithNewRow() {
  var egyenleg = getOtpEgyenleg();
  var date =  Utilities.formatDate(new Date(), "GMT", "yyyy-MM-dd");
  
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("otp-egyenleg");
  
  sheet.appendRow([date, egyenleg]);
}

Még egy kis kiegészítés (aktuális egyenleg)


Néha jó lenne rögtön itt látni az aktuális egyenleget (nem csak a tegnap estit).

Erre csináltam egy függvényt, ami beírja azt egy cellába, és létrehoztam egy trigger-t, ami a doksi megnyitásánál lefuttatja.
function updateSpreadWithCurrentBalance(){  
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("otp-egyenleg");
  sheet.getRange("E2").setValue("Updating...");
  SpreadsheetApp.flush();
  var egyenleg = getOtpEgyenleg();
  sheet.getRange("E2").setValue(egyenleg);
}

…és a trigger:

image

2012. jún. 20.

Trimage

Mindig azt mondják, hogy ha tanulni akarunk, akkor szálljunk be valami nyílt-forrású projektbe. Nekem a Trimage volt régen egy ilyen projekt. A Trimage alkalmazás Kilian egy aranyos kis Python projektje volt (és valoszleg még ma is az) egyszerű átlátható kóddal.
A Trimage alkalmazás jpeg és png képek veszteségmentes tömörítésére szolgál.
A projektben való részvétel az kb. annyiból állt, hogy commit-olgattam githubon, és Kilian meg lelkesen befogadta őket. Pár e-mailt is váltottunk. Feladatot meg vagy a TODO listáról válaszottam vagy pedig csak úgy találtam valami teendőt.
OOP-sítettem, kicsit átdolgoztam a gui-t, párhuzamosítottam, csináltam windows port-ot és jó pár egyéb apróságot csináltam, és Kilian egy idő után megtisztelt azzal, hogy a projekt weboldalához is hozzáadta a nevem(commit).  Ezt akkor nagy megtiszteltetésnek éltem meg.

Biztos vagyok benne, hogy ma is lehetne teendőt találni ezzel kapcsolatban.

2012. jún. 19.

Túl sok időm van labirintus

Egyszer el kellett mennem korábban egy szoftlab1 gyakorlatról. Azt akartam, hogy a gyakarlatvezető engedjen el hiányzás beírása nélkül, így hát megdumáltam, hogy következő alkalomra csinálok egy labirintusjátékot, és cserébe elenged hiányzás nélkül.

Ezen a félvételen épp játszom az alkotásommal:
Labirintus
forrás (fordítás: gcc -o maze maze.c -lncurses)

Mikor megmutattam neki következő alkalommal, akkor kiderült, hogy nem gondolta komolyan, hogy megcsinálom, és nem is várta el, és azt mondta, hogy túl sok időm van... És ezt negatívan mondta...

"Képernyőkímélősített" verzió: (Yep… Unatkoztam labon.)
"Képernyőkímélősített"labirintus
forrás (fordítás: gcc –lncurses animatedmaze.c)

A labirintust randomizált DFS-el generáltam, ami jól látszik is az animációban. A slow-motion animációban meg még jobban.
Ez egy backtracking algoritmus, ami itt azt jelenti, hogy addig megy a láthatatlan útcsináló mindig véletlen valamerre, amíg tud. Aztán ha elakad, mert már minden irányban út van a fal túloldalán (és két utat nem akarunk egymásba nyitni, mert köröket nem szeretnénk a labirintusba), akkor egész addig visszamegy, amíg már nem ilyen helyen jár, és ott folytatja útcsináló tevékenységét. Ennyi az egész.

Slow-motion:
"Képernyőkímélősített" slow-motion labirintus
Am egész baráti a korábban linkelt c kódom, és a 2 verzió csak pár sorban tér el.
Ui.: El nem tudjátok képzelni, hogy mennyit vacakoltam, mire ilyen csili-vili animált gif-eket tudtam csinálni ebből, szóval szeressétek.