Bild, leninartig
26. Feb 2019

phpmyadmin remote server and config files

remote login with phpmyadmin

for phpmyadmin to be able to log in to a remote db, the remote server needs to be added to the config file (says stackoverflow ;)) like so:

$i++;
$cfg['Servers'][$i]['host'] = 'HostName:port'; //provide hostname and port if other than default
$cfg['Servers'][$i]['user'] = 'userName';   //user name for your remote server
$cfg['Servers'][$i]['password'] = 'Password';  //password
$cfg['Servers'][$i]['auth_type'] = 'config';       // keep it as config

and of course the official phpmyadmin doc says the same, if in a slightly more verbose manner.
I guess there are ways to do this without having the password in the file in plaintext, but for now...

config file location (gentoo)

the above stackoverflow solution doesn't state exactly which file to edit as far as the path is concerned. a comment there says that /etc/phpmyadmin/config.inc.php would be the location.
which is true for most systems, I guess, but didn't work for me (that dir did not exist - manually creating dir and file didn't change anything).
google search for the filepath did not turn up much apart from the above.

gentoo paths

so after some more reading, I found out that (assuming a plain installation via '''emerge phpmyadmin''') the default config path would be:

/var/www/localhost/htdocs/phpmyadmin/

it might differ, according to your http server config. every file that ends on inc.php is considered a config filed and parsed by phpmyadmin

more...
09. Jan 2019

printmargins

besides the css settings, firefox will need to be adjusted if one wants to use the full area of an A4 paper sheet.

this mozilla blog post is in the right direction, but there's a third configuration options for the margins called print.print_edge, see screenshot: ff printmargins of course, the same options shown here for bottom can be set for top, left and right as well.

it seems like the relevant options are the print.print_unwriteable_margin_ options, but that may depend on which printer you select for the print preview. There seems to be no well-structured mozilla authorized manual for this stuff and I'm too lazy to dig deeper into it right now. setting all of those to zero will give you the full page for printing, but will also remove the page count in the formerly "unwriteable" top right corner.

more mozilla on this topic

since I don't want the page counter removed just for the one use case that I'm fiddling with, I set the top margin to 20. The numbers seem to refer to the percenteage of an inch (see link above). I checked manually, the counter won't appear below a top margin of 20, which seems stupid, because it will respect that margin, leaving blank margin to the page edge...

Also, I changed the A4 width + height settings in my css to a value slightly lower than standard (200mm instead of 210mm width, 290mm instead of 297mm height). The "real" standard measurements seem to cause a page break even with all margins set to zero. Using these slightly smaller values however works ok.

more...
20. Dec 2018

playlist-converter

this script will read the file locations from a playlist and

  • create a new timestamp-named folder either in a specified location or the users $HOME path
  • copy the mp3 files to the newly created folder
  • set all files to the same volume level
  • write a new playlist of relative pathnames to the directory

setting the volume is done by way of mp3gain's "-r" and "-d" flag. Afaics the default base value would be 89db, so

mp3gain -r -d6

would be equal to 89db +6db = 95db

script

#!/bin/bash
OLDIFS=$IFS
IFS='
'

printf "looking for mp3gain... "
command -v mp3gain || (printf "this script depends on mp3gain, which is not present on this computer. exiting\n" && exit 0)


if [[ -z $@ ]]; then
echo "usage: pass a playlist as first parameter and a destination basepath as optional second parameter" && exit 1
fi

defaultdir=$HOME
arg1=$(file -b $1)
arg2=$(file -b ${2:-$HOME})
colr='\033[0;34m'
off='\033[0m'


if [[ ( ${arg1,,} != *playlist* ) || ( ${arg1,,} == error* ) ]]; then
echo "please pass a valid playlist as first argument"
exit 1
fi

if [[ -z $2 ]]; then
echo "you can specify a destination path as second parameter... defaulting to ${HOME}" 
fi

pllist=$(/usr/bin/basename $1)
tstamp=$(date +%Y_%j_%H%M%S)
destpth=${2:-$HOME}
destin=${destpth%/}/00_playlists_normalized/"${pllist%.*}"-"${tstamp}"

read -n 1 -p $'normalize \e[34m'"${1}"$'\e[0m'" in "$'\e[34m'"${destin}"$'\e[0m'" [y/n]" yn
    case "$yn" in
        [Yy] ) printf "\n";;
        * ) printf "\n" && exit 0;;
    esac

printf "creating a destination directory at ${colr}${destin}${off}... "
mkdir -p $destin && printf "ok\n"

printf "copying files to ${colr}${destin}${off}..."
for mp3_file in $(grep "^[^#]" $1 | sed 's/\r$//'); do cp $mp3_file $destin; done && printf "ok\n"

printf "${colr}applying uniform gain${off}\n"
mp3gain -r -c -k ${destin}/*mp3

printf "rewriting playlist for normalized directory to${colr}${destin}/playlist_${tstamp}.m3u${off}...\n"
for i in $(grep "^[^#]" $1); do echo ${i##/*/} >> $destin/playlist_${tstamp}.m3u; done && printf "ok \n"

IFS=$OLDIFS

save as

more...
21. Aug 2018

E-Liquid Calculator

Hier ist ein E-Liquid-Rechner
So was gibt's anderswo schon fast genausogut ;), aber der hiesige ist für meine Bedürfnisse angepasst.

more...
30. Jun 2018

matplotlib stat generator

This is a production notebook. It uses data gathered from a PBX and internal routing and will generate reports for TT, ACW and so on.
It is meant to be customizeable, so one can easily adjust

  • the time range that should be evaluated
  • different plots are available for
    • hotline data
    • agent data
    • call distribution

The script can also easily iterate time ranges over the whole dataset and produce plots for each

This script makes little sense to use from a CLI, it's meant to run in an IPython Environment

script code

a markdown dump straight out of the notebook:

%load_ext autoreload
%autoreload 2

## Import necessary modules
import os,sys
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.dates import date2num, AutoDateFormatter, AutoDateLocator, WeekdayLocator, MonthLocator, DayLocator, DateLocator, DateFormatter
from matplotlib.dates import MO, TU, WE, TH, FR, SA, SU
from matplotlib.ticker import AutoMinorLocator, AutoLocator, FormatStrFormatter, ScalarFormatter
import numpy as np
import datetime, calendar
from datetime import timedelta
import matplotlib.patches as mpatches
from itertools import tee
from traitlets import traitlets

sys.path.append(os.path.abspath('/home/keuch/gits/keuch/code_box/pyt/spreadsheetparsing/entwuerfe/xls_testruns/lib/'))
from ce_funclib import determine_kernzeit as dtkz
from ce_funclib import continuity_check


from ipywidgets import widgets, interact, interactive, fixed, interact_manual, Layout
from IPython.display import display
#%matplotlib inline
%matplotlib tk


## Import data frome pickle generated from muß ein file mit agentenstats sein
arcpth='/home/keuch/gits/keuch/code_box/pyt/spreadsheetparsing/test_stats/archiv/'

######## GET A LIST OF MATCHING .xls FILES FROM THE GIVEN DIRECTORY

def collectxlfiles(arcpath):
    xlfilelist=list()

    for xlfile in os.listdir(arcpath):
        if xlfile.startswith('CE_alle_Ag'):
            xlfileabs=os.path.join(arcpath,xlfile)
            xlfilelist.append(xlfileabs)
    return sorted(xlfilelist)

xlfilelist=collectxlfiles(arcpth)
#xlfilelist
#examplefile=xlfilelist[233]
###### TEST FOR DATA IN FILE, SORT OUT EMPTY FILES

## good dataframes do per definition not contain any zero values
## fill bad DFs with nan?

def filetoframe(exfile):
    exframe=pd.read_excel(exfile) # this is a regular pd.DataFrame
    datecell=exframe.iloc[0,1]
    sheet_datetime=pd.to_datetime(datecell,format='%d.%m %Y : %H')
    sheet_date=sheet_datetime.date()

    integritycheck=exframe.iloc[2,1] # files with data have "agenten" here, files with no calls have a 'nan'

    if integritycheck != 'Agenten':
        # if it's empty, keep date for filling it later
        print('Exception: ', end='')
        except_status='ex'

        usefulcols={0:'tstamp',1:'agent',3:'an',4:'be',22:'vl',24:'ht_float',29:'tt_float'} # map cols to decent names
        exframe=exframe.reindex(columns=sorted(usefulcols.keys()))
        exframe.rename(columns=usefulcols,inplace=True)        
        exframe=exframe[0:1] # strip text rows and the mangled sum row
        print(sheet_datetime)

        exframe['tstamp']=sheet_datetime
        exframe['date']=sheet_date
        exframe['agent']='nocalls_datum'
        exframe[['wd','ww','mm','yy']]=exframe['tstamp'].dt.strftime('%a,%W,%m,%Y').str.split(',',expand=True) # make ww,yy,mm,wd columns
        exframe['bz']=exframe['tstamp'].apply(dtkz)
        exframe['ort']=exframe['agent'].str[0] # split the identifier into useable columns
        exframe['id']='foobar' # split the identifier into useable columns

        # integers should be of appropriate datatype, we received them as strings
        # exframe[['vl','an','be','ww','mm','yy']]=exframe[['vl','an','be','ww','mm','yy']].astype(np.int64) #just for the beauty of it
        exframe.fillna(0, inplace=True) 
        exframe[['ww','mm','yy']]=exframe[['ww','mm','yy']].astype(np.int64) #just for the beauty of it
        #exframe.fillna(0, inplace=True) 
        return exframe,except_status

    else:
        except_status='reg'

        exframe.columns=range(0,30) # rename columns to a temporarily more readable format, fancy rename later
        usefulcols={0:'tstamp',1:'agent',3:'an',4:'be',22:'vl',24:'ht_float',29:'tt_float'} # map cols to decent names
        exframe=exframe[sorted(usefulcols.keys())] # skip cols and keep the ones we need
        exframe.rename(columns=usefulcols,inplace=True) # rename cols
        exframe=exframe[3:-1] # strip text rows and the mangled sum row
        exframe['tstamp']=pd.to_datetime(exframe['tstamp'],format=' %d.%m.%Y %H:%M ')
        exframe['date']=exframe['tstamp'].dt.date
        exframe[['wd','ww','mm','yy']]=exframe['tstamp'].dt.strftime('%a,%W,%m,%Y').str.split(',',expand=True) # make ww,yy,mm,wd columns
        exframe['bz']=exframe['tstamp'].apply(dtkz)

        exframe['ort']=exframe['agent'].str[0] # split the identifier into useable columns
        exframe['id']=exframe['agent'].str[-6:] # split the identifier into useable columns
        exframe['agent']=exframe['agent'].str[2:-7] # split the identifier into useable columns

        # integers should be of appropriate datatype, we received them as strings
        exframe[['vl','an','be','ww','mm','yy']]=exframe[['vl','an','be','ww','mm','yy']].astype(np.int64) #just for the beauty of it

        return exframe,except_status
framelist=list()
exceptionlist=list()
for xfile in xlfilelist:
    frame_from_file,except_status=filetoframe(xfile)
    if except_status=='ex':
        exceptionlist.append(xfile)
    framelist.append(frame_from_file)
Exception: 2017-04-17 00:00:00
Exception: 2017-05-14 00:00:00
Exception: 2017-11-19 00:00:00
Exception: 2017-12-03 00:00:00
Exception: 2017-12-10 00:00:00
Exception: 2018-03-04 00:00:00
Exception: 2018-03-11 00:00:00
Exception: 2018-04-08 00:00:00
#### produce a unified frame with all data and sort it by timstamp and agentname
bigframeii=pd.concat(framelist)
bigframeii.sort_values(['tstamp','agent'],inplace=True)
bigframeii.reset_index(drop=True,inplace=True) # there you go
# die exklusivlogins müssen zusammengelegt werden
unify_id={'gesinst':'995887','stanzju':'878457','papkeda':'891914'}
bigframeii.loc[bigframeii['id'] == unify_id['gesinst'],'agent'] = 'gesinst'
bigframeii.loc[bigframeii['id'] == unify_id['stanzju'],'agent'] = 'stanzju'
bigframeii.loc[bigframeii['id'] == unify_id['papkeda'],'agent'] = 'papkeda'
#### check, ob alle Daten(Tage) lückenlos sind
datenserie_uniq=bigframeii['date'].unique().tolist()
tage_bestand=len(datenserie_uniq)
tage_start=datenserie_uniq[0]
tage_ende=datenserie_uniq[-1:]

missing_dates=continuity_check(datenserie_uniq)
if not missing_dates:
    print('no dates are missing')
else:
    print('the following dates are not within the frame:')
    print(missing_dates)
no dates are missing
# get all agents available and create frames for kern and neben
allagents_list=sorted(bigframeii['agent'].unique())
allagents_list.extend(['Hagenow','Berlin','Alle'])
standorte=bigframeii.ort.unique().tolist()

we can't figure out individual calls anyway, since raw data calls have been grouped by hours already
so we can go on and group by days to figure out averages

bigframeii.head(2)
#Samstage = bigframeii.loc[(bigframeii['tstamp'].dt.dayofweek ==  5)
tstamp agent an be vl ht_float tt_float date wd ww mm yy bz ort id
0 2017-03-04 08:00:00 beckfra 1.0 1.0 0.0 2.3667 2.1333 2017-03-04 Sat 9 3 2017 n H 216694
1 2017-03-04 08:00:00 tetzlva 1.0 1.0 0.0 2.6833 2.6167 2017-03-04 Sat 9 3 2017 n B 613887
Datum_MIN = bigframeii.tstamp.dt.date.min()
Datum_MAX = bigframeii.tstamp.dt.date.max()

Datum_VON = datetime.date(2017,5,1)   # YY,MM,DD
Datum_BIS = datetime.date(2018,10,1)

Kernzeit = (bigframeii['bz'] ==  'k')
Nebnzeit = (bigframeii['bz'] ==  'n')

Berlin = (bigframeii['ort'] ==  'B')
Hagenow = (bigframeii['ort'] ==  'H')

Wunschzeitraum = ((bigframeii.tstamp.dt.date >= Datum_VON) & (bigframeii.tstamp.dt.date <= Datum_BIS))
#bigframeii.loc[Wunschzeitraum & Kernzeit & Hagenow]   # SUPER!
kzdata=bigframeii.loc[Wunschzeitraum & Kernzeit].copy()
kzdata_reindex=kzdata.set_index(['tstamp','ort']).copy() # timestamps und Standort als neue Indizes
kzdata_byday=kzdata_reindex.groupby([pd.TimeGrouper('D', level='tstamp'), pd.Grouper(level='ort')]).sum() # nach Tagen gruppiert und alle Zahlen summiert
def plotzi(frame):

    aht,aacw,att,nzb,bg ="#003873","#EE0042","#899EB2","#C7798F","#FEFFE2"
    sonntage=WeekdayLocator(byweekday=(6), interval=2)
    datevon=frame.index.get_level_values('tstamp').min().strftime('%d.%m.%y')
    datebis=frame.index.get_level_values('tstamp').max().strftime('%d.%m.%y')


    #### ------------------------------------ ####

    fig=plt.figure(figsize=(12,5))

    ax=fig.add_subplot(111)
    ax.margins(0,0)
    ax.set_facecolor(bg)
    ax.set_xlabel('Kernzeit / ceDis von '+datevon+' bis '+datebis)
    ax.xaxis.set_major_locator(sonntage)
    ax.xaxis.set_major_formatter(DateFormatter('%d.%m.%y'))
    ax.set_ylabel('Calls angenommen')


    ber=frame.xs('B', level=1, drop_level=True)['an']
    hgw=frame.xs('H', level=1, drop_level=True)['an']

    b=ax.bar(ber.index,ber.values, label='calls', color=nzb, width=1)
    h=ax.bar(hgw.index,hgw.values, label='calls', color=aht, width=0.6)

    plt.setp(ax.xaxis.get_majorticklabels(), rotation=45, horizontalalignment='right', size=6 )

    bercalls=int(ber.sum())
    hgwcalls=int(hgw.sum())
    allecalls=bercalls+hgwcalls
    anteilhgw=str(    format((hgwcalls/allecalls)*100,'.2f')   )  
    anteilber=str(    format((bercalls/allecalls)*100,'.2f')   )



    callsBH = mpatches.Patch(color='000000', label='Calls Ber+Hgw: '+str(allecalls))
    callsB = mpatches.Patch(color=nzb, label='Calls Ber: '+str(bercalls) +' ('+anteilber+'%)'        )
    callsH = mpatches.Patch(color=aht, label='Calls Hgw: '+str(hgwcalls) +' ('+anteilhgw+'%)'        )

    ax.legend(handles=[callsBH,callsB,callsH],fontsize=8,ncol=2,loc='upper right',borderaxespad=-2,framealpha=0.99)

    plt.subplots_adjust(bottom=0.25)
plotzi(kzdata_byday)

example plots:

agent data hotline data site related distribution

more...
01. Nov 2016

network printer client side config

Network cups server up and running, avahi-systemd client also detecting the printer and printing fine

on the gentoo client however, no networked printer is detected. Quic solution for now:

  • localhost:631 (attention: somehow I added a line to one of the numerous config files around that made me go directly to the print server address)
  • add printer. for the correct https uri I just visited the server's cups interface server:631 and copied the link to the printer in the admin section (just: copy link address. this seems to bet the valid resource format)
  • when given the choice for a ppd filter, NOT choosing a ppd is the important part. cups offers a "raw" ppd / queue. Ust this, assuming the correct ppd is already given on the server side.
  • -> works fine.
more...
15. May 2015

Mozilla Dekstop Download Directories

If you use Firefox or Iceweasel as I do, you may wonder about the "Desktop" and "Download" directories it creates every time you save anything to disk, even if you explicitly set ff to ask you where to save your stuff. This can be prevented by creating a ~/.config/user-dirs.dirs file, either with or without real content. This is according to http://www.kariliq.nl/misc/firefox-dirs.html and also this old arch forum post: https://bbs.archlinux.org/viewtopic.php?pid=997084#p997084

more...
07. May 2015

adjust cursor color for vim and urxvt

Whenever I used a dark colour scheme for vim (like the excellent muon or getafe, I find myself lost beacuse the usually black cursor of my urxvt wouldnt adjust to the dark colour theme. I found that this cant be tweaked in vim, but one can change the color of the urxvt terminal; so, for my needs, putting the following into $HOME/.Xresources:

URxvt*cursorColor:  #D6C0FB
URxvt*cursorBlink:  on

does the job pretty satisfyingly :-)
(for reloading the Xresources, use xrdb -load .Xresources. put the same command into ~/.xinitrc to have it loaded on X startup)

more...
04. May 2015

css completion in vim

:set omnifunc=csscomplete#CompleteCSS 

and the ctrl-x+ctrl-o will give the possible completions!

see here
and here

the first one explains it very nicely and has a screenshot, too :-)

more...