Nach den angekündigten Preiserhöhungen bei o2 (Golem) habe ich meinen (im Sommer auslaufenden) Vertrag mit einem entsprechend erbostem Schreiben gekündigt. Um nun einen guten neuen Vertrag zu finden wollte ich genauer wissen wieviel Minuten/SMS ich denn so brauche…

Da ich schon seit Langem immer fleißig die .csv files zu den Rechnungen herunterladen hab ich schnell folgendes Python Script geschrieben das mir die Zählarbeit erleichtert (und Schreikrämpfe in Excel verhindert).

Als kleinen Bonus zählt es auch (etwas inexakt fürchte ich) die Homezone Minuten, daraus kann man ablesen was das Verlieren von Genion für Auswirkungen hat.

# parses .csv files from o2 germany billing
# counts talked minutes ('sprache' in 'ART') and sms sent ('sms' in 'TARIFGRUPPE')
# ignores international minutes/sms
import csv
import glob
import string

# <CONFIG>
mypath = '*.csv' # e.g. './mybills/*.csv'
mydelimiter = '|' # '|' aka "pipe" is default with o2
# </CONFIG>

if __name__ == "__main__":
    files = glob.glob(mypath)
    assert len(files) > 0, "Error! No Files found (check path)"

    totalminutes = 0
    totalsms = 0
    totalhomezone = 0
    for file in files:
        csvfile = open(file)
        reader = csv.DictReader(csvfile,delimiter=mydelimiter)
        smscount = 0
        timecount = dict(hours=0,minutes=0,seconds=0)
        homezonecount = 0
        for row in reader:
            if 'sprache' in string.lower(row['ART']):
                (h,m,s) = string.split(row['DAUER'], ':')
                timecount['hours'] += int(h)
                timecount['minutes'] += int(m)
                timecount['seconds'] += int(s)
                if 'homezone' in string.lower(row['TARIFGRUPPE']):
                    homezonecount += int(m) + (int(h)*60) + (int(s)/60)
            if 'sms' in string.lower(row['TARIFGRUPPE']):
                smscount = smscount + 1
        minutes = timecount['minutes'] + (timecount['hours']*60) + (timecount['seconds']/60)
        totalminutes += minutes
        totalsms += smscount
        totalhomezone += homezonecount
        print(file+' '+str(minutes)+' Minutes '+str(smscount)+' SMS ('+str(homezonecount)+' Minutes in Homezone)')
        assert minutes >= homezonecount, "Error! More minutes in homezone than total?"
    # the cool .format prints only work in python 2.6 ...
    #print('Total  :{0:4} Minutes and {1:4} SMS in {2} Months ({3:4} Minutes in Homezone)'.format(totalminutes,totalsms,len(files),totalhomezone))
    #print('Average:{0:4} Minutes and {1:4} SMS per Month'.format(totalminutes/len(files),totalsms/len(files)))
    # ... and since that isn't in debian stable yet... i added "old" prints
    print('Total   '+str(totalminutes)+' Minutes '+str(totalsms)+' SMS in '+str(len(files))+' Months ('+str(totalhomezone)+' Minutes in Homezone)')
    print('Average '+str(totalminutes/len(files))+' Minutes '+str(totalsms/len(files))+' SMS per Month')

Comments No Comments »

Must see, really cool take on the topic. Complete with disturbing images of a north-european distopian, snowcovered town ;)

Far better than the twilight movie, which sucked (i liked the book though, i read all four).

Comments No Comments »

Currently learning for an exam and freshing up my XSLT knowledge … ;)

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!--
    ! Small XSLT prog that calculates the faculty of one or more
    ! numbers by recursively calling a named template
    ! numbers are expected to be in a tree:
    ! <nums><num>1</num><num>2</num>...</nums>
   -->

  <xsl:output method="text"/>

  <xsl:template match="num">
      <xsl:text>fak(</xsl:text>
      <xsl:value-of select="."/>
      <xsl:text>) is </xsl:text>
      <xsl:call-template name="fak">
          <xsl:with-param name="number" select="."/>
      </xsl:call-template>
  </xsl:template>

  <xsl:template name="fak">
      <xsl:param name="number"/>
      <xsl:choose>
          <xsl:when test="$number = 1">
              <xsl:value-of select="$number"/>
          </xsl:when>
          <xsl:otherwise>
              <xsl:variable name="recursefak">
                  <xsl:call-template name="fak">
                      <xsl:with-param name="number" select="$number - 1"/>
                  </xsl:call-template>
              </xsl:variable>
              <xsl:value-of select="$number * $recursefak"/>
          </xsl:otherwise>
      </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

Expected XML looks like this (with DTD even! ;P):

<?xml version="1.0" ?>
<!DOCTYPE numbers [
  <!ELEMENT nums (num+)>
  <!ELEMENT num (#PCDATA)>
]>
<nums>
  <num>3</num>
  <num>12</num>
</nums>

Comments No Comments »

i seldomly laugh out loud when reading something … but this made my day ;)

Windows 7
XKCD 528 <img alt=“Disclaimer: I have not actually tried the beta yet. I hear it’s quite pleasant and hardly Hitler-y at all.”>

ps) i saw the (leaked) beta in vmware and it actually was quite nice ;)
pps) the horde on webspace (no shell) guide will be delayed until my host decides to fix his PHP installation (imap_open() is broken…)

Comments No Comments »

After uploading the (now smaller) Horde with our FTP client we can continue with

Part 2 The Database
Since without shell access we can’t use Horde’s setup (./scripts/setup.php) to do this for us we have to manually set up the database for Horde.

This step depends on your webhosters so i’ll just make it quick:
First create a database with your webhost, then find: hostname (often locahost), username, password, type (often tcp) and databasename for that database.

Now your webhoster probably offers some kind of management frontend (mostly phpmyadmin). There you navigate to your database and select the “SQL” tab.

In the editbox you will find there you have to paste some of the lines from the .sql file provided with Horde that matches your database. I use mysql so i used ./scripts/sql/create.mysql.sql.

Out host already created the database, the user etc. so we only need lines that create tables. In my file this would be lines 52 -> end (look for the first CREATE TABLE statement). Copy&Paste and press Submit. This should have given you no errors and created ~18 tables in your database.

In the next step we will create a basic configuration that allows Horde to run so we can do the rest of the setup from within it.

Comments 1 Comment »