Alle Beiträge von adlerweb

YouTube Watch Later als M3U-Playlist exportieren

Ein großer Teil meines Medienkonsums läuft über YouTube. Bastler, Podcasts, Vorträge – nahezu alles ist hier vorhanden und hat den Fernseher nahezu vollständig abgelöst. Eine der aufwändigsten Arbeiten für mich ist es meine „Wunschliste“ an Videos zu verwalten. Welche Videos möchte ich mir noch ansehen. Hierzu nutze ich bereits seit längerem einige Scripte um Posts diverser Channels zu sortieren und Interessantes in die „Watch Later“-Liste, also „Später ansehen“, zu verschieben. Diese kann ich dann einfach auf dem Tablet laufen lassen und so die Videos nach und nach ansehen.

Anders sieht es aus wenn ich am PC arbeite. Zwar kann man auch hier die Liste über die Webseite nutzen, jedoch ist hier ohne Klimmzübe kein Overlay („Immer im Vordergrund“) möglich. Als Abhilfe nutze ich hier üblicherweise VLC – dort kann man eine YouTube-URL eingeben und direkt abspielen. Leider gibt es keine direkte Unterstützung für Playlisten und die verfügbaren Plugins lassen nur öffentliche Listen abrufen.

Bild:

Natürlich könnte ich jetzt meine Scripte umschreiben und öffentliche (bzw. „Nicht gelistete“) Listen nutzen, jedoch ist das manuelle Hinzufügen zur Watch-Later-List dank des überall verfügbaren Buttons wesentlich einfacher als das Hinzufügen zu selbst angelegten Listen.

Bild: https://adlerweb.info/blog/wp-content/uploads/2015/04/wll.png

Da ich von LUA, welches in VLC zum Einsatz kommt, keine Ahnung habe und durch meine sonstigen YT-Automationen tonnenweise fertigen PHP-Code zur Verfügung habe ist entsprechend eine Webanwendung daraus geworden. Benötigt wird ein API-Key, welcher in der Dev-Console beantragt werden kann sowie die Installation des Google API PHP-Client. Auch sollte der Webserver die Berechtigung haben key.php im selben Verzeichnis zu beschreiben – dies kann z.B. über „touch key.php ; chmod ugo+w key.php“ erfolgen. Der erste Aufruf sollte über den Browser erfolgen, hierbei wird man aufgefordert das Script mit YouTube zu Paaren. Die so abgerufenen Schlüssel werden in den angesprochenen key.php gespeichert, sodass folgende Zugriffe ohne weitere Abfragen erfolgen. Die URL kann nun in VLC eingefügt werden – dieser sollte die so bereitgestellte Playlist laden und die Videos nacheinander abspielen – mit allen Features des VLC wie z.B. Always-on-Top, Abspielgeschwindigkeit, Videoeffekte, etc.

Bild: https://adlerweb.info/blog/wp-content/uploads/2015/04/playlist-300×266.png

Den Code zum selbst testen gibts anbei oder – ohne WordPress-Korrekturversuche – im Gist. Eventuell ließ sich das Ganze auch noch mit youtube-dl kombinieren um einen Podcast-kompatiblen Feed zu erstellen.

< ?php

/**
 * Youtube Watch Later List To Playlist Script
 * 
 * This script fetches your watch later list and outputs it as an M3U playlist
 *
 * Requirements:
 *   PHP enabled webserver
 *   Google PHP API (https://github.com/google/google-api-php-client)
 *   A YouTube API key (Oauth2, can be registered at https://console.developers.google.com/)
 *   Some kittens to sacrifice
 *
 * Initialization
 *   First ensure your webserver can write a file called "key.php" to the directory
 *   you put this file in. E.g. "touch key.php ; chmod ugo+w key.php"
 *   Next open the appropriate URL in your browser. You will be asked to pair
 *   this script with your YouTube-Account. If you configured everything correctly
 *   it will output the playlist and save your access codes in the key.php mentioned
 *   above. Successive requests do not require additional authentication. You may now
 *   put the URL in your YT-enabled media player like VLC.
 *
 * Based on examples by DomSammut (https://www.domsammut.com/code/php-server-side-youtube-v3-oauth-api-video-upload-guide)
 * 2015 Florian Knodt 
 */ 

// Set this to the directory of google api php client
set_include_path('./google-api-php-client/src/');

$OAUTH2_CLIENT_ID = 'YOURID.apps.googleusercontent.com';
$OAUTH2_CLIENT_SECRET = 'YOURSECRET';
$REDIRECT = 'http://localhost/yt/ytwll2m3u.php';
$APPNAME = 'YouTube WLL Import Test';

require_once 'Google/autoload.php';
session_start();

$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setApplicationName($APPNAME);
$client->setAccessType('offline');

if(file_exists('key.php')) {
    require_once 'key.php';
}

if(isset($key)) {
    $client->setAccessToken($key);
    $_SESSION['token'] = $key;
}else{
    $client->setScopes('https://www.googleapis.com/auth/youtube');
    $client->setRedirectUri($REDIRECT);
}

// Define an object that will be used to make all API requests.
$youtube = new Google_Service_YouTube($client);

if (isset($_GET['code'])) {
    if (strval($_SESSION['state']) !== strval($_GET['state'])) {
        die('The session state did not match.');
    }
 
    $client->authenticate($_GET['code']);
    $_SESSION['token'] = $client->getAccessToken();
 
}
 
if (isset($_SESSION['token'])) {
    $client->setAccessToken($_SESSION['token']);
    $keydata = '< ?php $key=\''.$_SESSION['token'].'\'; ?>';
    //echo '' . $_SESSION['token'] . '';
   
    if(!is_writable('key.php')) {
        die('key.php can not be written - please put this code into key.php: '.$keydata);
    }
    file_put_contents('key.php', $keydata);
}

// Check to ensure that the access token was successfully acquired.
if ($client->getAccessToken()) {
    try {
        // Call the channels.list method to retrieve information about the
        // currently authenticated user's channel.
        $channelsResponse = $youtube->channels->listChannels('contentDetails', array(
            'mine' => 'true',
        ));
 
        $playlist = '#EXTM3U'."\n";
        foreach ($channelsResponse['items'] as $channel) {
            // Extract the unique playlist ID that identifies the list of videos
            // uploaded to the channel, and then call the playlistItems.list method
            // to retrieve that list.
            $uploadsListId = $channel['contentDetails']['relatedPlaylists']['watchLater'];
 
            $playlistItemsResponse = $youtube->playlistItems->listPlaylistItems('snippet', array(
                'playlistId' => $uploadsListId,
                'maxResults' => 50
            ));
 
            foreach ($playlistItemsResponse['items'] as $playlistItem) {
                $playlist .= '#EXTINF:-1,'.$playlistItem['snippet']['title']."\n".'https://www.youtube.com/watch?v='.$playlistItem['snippet']['resourceId']['videoId']."\n";
            }
            
            while(isset($playlistItemsResponse['nextPageToken'])) {
                $playlistItemsResponse = $youtube->playlistItems->listPlaylistItems('snippet', array(
                    'playlistId' => $uploadsListId,
                    'maxResults' => 50,
                    'nextPageToken' => $playlistItemsResponse['nextPageToken'],
                ));
                foreach ($playlistItemsResponse['items'] as $playlistItem) {
                    //$htmlBody .= sprintf('
  • %s (%s)
  • ', $playlistItem['snippet']['title'], //$playlistItem['snippet']['resourceId']['videoId']); $playlist .= '#EXTINF:-1,'.$playlistItem['snippet']['title']."\n".'https://www.youtube.com/watch?v='.$playlistItem['snippet']['resourceId']['videoId']."\n"; } } } } catch (Google_ServiceException $e) { echo sprintf('

    A service error occurred: %s

    ', htmlspecialchars($e->getMessage())); } catch (Google_Exception $e) { echo sprintf('

    An client error occurred: %s

    ', htmlspecialchars($e->getMessage())); } $_SESSION['token'] = $client->getAccessToken(); } else { $state = mt_rand(); $client->setState($state); $_SESSION['state'] = $state; $authUrl = $client->createAuthUrl(); $htmlBody = < <Authorization Required

    You need to authorise access before proceeding.

    END; } if(isset($playlist)) die($playlist); ?> < !doctype html> My Uploads < ?php echo $htmlBody?>

    Logrotate für Windows-Webserver IIS

    Seriously, Microsoft? Der in Windows integrierte Webserver IIS kann problemlos vernünftige Log-Dateien erzeugen und besitzt auch eine Funktion diese bei Erreichen einer Zeitspanne oder eines Größenlimits zu schließen und eine neue beginnen. Was leider fehlt: Alte Dateien löschen. Es kommt was kommen musste: Auf einem Produktivserver durfte ich mehr als 100GB an logtechischen Textkauderwelsch finden. Platte voll.

    Zwar kann man hier mit der in NTFS verfügbaren Ordnerkompression gegensteuern, eine Dauerlösung ist das aber sicher nicht. Am Ende habe ich auf Basis eines Powershell-Scriptes von Daniel Schroeder aka deadlydog etwas passendes gebastelt um hier Abhilfe zu schaffen. Regelmäßig über die Aufgabenplanung aufgerufen bleibt so der Ordner auf einem erträglichen Maß.

    $limit = 15 #Delete Logs after 15 Days
    $path = "C:\inetpub\logs\LogFiles\W3SVC1"
    
    # Function to remove all files in the given Path that have not been modified after the given date.
    # original written by deadlydog / Daniel Schroeder, http://blog.danskingdom.com/powershell-functions-to-delete-old-files-and-empty-directories/
    # Requires Powershell >=2.0
    function Remove-FilesNotModifiedAfterDate([parameter(Mandatory)][ValidateScript({Test-Path $_})][string] $Path, [parameter(Mandatory)][DateTime] $DateTime)
    {
        Get-ChildItem -Path $Path -Recurse -Force -File | Where-Object { $_.LastWriteTime -lt $DateTime } | Remove-Item
        #Get-ChildItem -Path $Path -Recurse -Force -File | Where-Object { $_.LastWriteTime -lt $DateTime } | Format-List BaseName,LastWriteTime
    }
    
    Remove-FilesNotModifiedAfterDate -Path "$path" -DateTime ((Get-Date).AddDays(1-$limit))

    Zum Ausführen wird mindestens PowerShell 2.0 benötigt. Ältere Betriebssysteme wie z.B. 2008R2 bringen nur PowerShell 1 mit, hier muss manuell über das Windows Management Framework aktualisiert werden.

    SSH: Fingerprint-Algorithmus ändern

    Bild: https://adlerweb.info/blog/wp-content/uploads/2015/04/sshmd5-300×45.pngMit einem der letzten Updates scheint OpenSSH einen Schritt in Richtung Gegenwart getätigt zu haben. Nun werden Fingerprints nicht mehr als MD5 sondern mit SHA256 präsentiert. Was auf der einen Seite eine tolle Sache ist kann aber auch zum Problem werden: Eine hiesige Debian-Kiste kann mit dem dort als stable deklarierten OpenSSH 7.0 auch optional keinen SHA256-Hash herausrücken. Manueller Abgeleich mit dem neueren Client des ArchLinux-Systems unmöglich. Um hier wieder auf einen gemeinsamen Nenner zu kommen bleibt nur den neuen Client auf den älteren Hash-Algorithmus zurückzutrimmen. Das funktioniert über die SSH-Config (/etc/ssh/ssh_config or ~/.ssh/config) mit folgenden Zeilen – zum Glück auch für einzelne Hosts:

    Host oldserver.org
    FingerprintHash md5

    Schon erhält man beim Verbinden wieder den gewohnten MD5-Hash und kann sich – bis auch andere Distros sha256 herausrücken – behelfen.

    Internet Explorer und die Kompatibilitätsmodi

    Auch wenn Microsoft ihn quasi schon beerdigt hat: Immer wieder stößt man noch auf den Internet Explorer. Gerade in Firmen ist er kaum wegzudenken, denn viele Produkte der Industrie haben es auch 2015 noch nicht geschafft auf ActiveX zu verzichten bzw. halbwegs standardisierte Formate zu verwenden. Besonders tückisch hierbei: Während die neueren Versionen des Internet Explorer immerhin halbwegs mit den aktuellen Webstandards klar kommen sind viele Webanwendungen noch auf ältere Inkarnationen zugeschnitten. Um hier den Nutzern keine Angst vor einer Aktualisierung zu bescheren schaltet der Internet Explorer beim kleinsten Anzeichen für Probleme in einen Kompatibilitätsmodus und behandelt die Inhalte wie frühere Versionen. Auch ist es nicht unüblich, dass alle internen Adressen automatisch immer mit den damaligen Vorgaben behandelt werden.

    Wer als Webentwickler für Firmen unterwegs ist sollte hier gegensteuern. Natürlich ist es einfach den jeweiligen Administratoren eine Änderung der Einstellungen oder gar einen anderen Browser zu empfehlen, jedoch ist dies häufig nicht mit Policies vereinbar oder aber wird als Ausnahme gehandhabt. Letztere werden gerne auf Grund der Seltenheit nur schlecht gewartet oder gehen mit der Zeit in den Tiefen des Systemmanagements verloren und sogen dann für aufwändige Fehlersuchspiele.

    Wer sich sicher ist, dass seine Seite mit aktuellen IE-Versionen läuft kann jedoch auch ganz ohne Firmenadministrator die meisten Probleme vermeiden. Über einen propritären Meta-Tag lässt sich der IE anweisen eine bestimmte Rendering-Art zu verwenden – unabhängig von der globalen Vorlage.

    Um beispielsweise explizit als IE11 zu rendern kann folgender Eintrag im head der Seite ergänzt werden:

    Selbes geht natürlich auch für andere Versionen. Eine Sonderstellung bildet noch „edge“ – hiermit wird immer die neueste verfügbare Engine genutzt. Perfekt wenn mann möglichst viele aktuelle Funktionen verfügbar machen will. Identifiziert sich dennnoch ein älterer Browser kann man immernoch per Browserweiche o.Ä. einen abgespeckten Content servieren ohne befürchten zu müssen unbeabsichtigt auch neuere IE-Versionen einzuschränken.

    Mehr Infos gibt es in einem Technet-Artikel von Stephanus Schulte, welcher das Thema ausführlich erklärt. Wer sich lieber auf die Fakten beschränkt wird im MSDN fündig.

    Hak5 als ASCII-Video

    (was posted only on YT before)

    You can’t watch Hak5 on text consoles? Challenge accepted…

    Downloading Hak5 using lynx and watching as ASCII-Art using mplayer and aalib.
    Re for 1808: https://www.youtube.com/watch?v=3RPgd6U2oyc

    full command:
    mplayer -quiet -vo aa:driver=curses -monitorpixelaspect 0.5 yourfile.mp4

    Sorry for the audio, guess the mic-cable must be broken somewhere

    It is also possible to use vo=caca to get colored output

    Nvidia/X.org: OpenGL-Fehler bei einigen Spielen

    Vor kurzem mussten die mehr als 10 Jahre alten Grafikkarten meines Rechners einem neueren Modell weichen. Schneller, weniger Strom und – das Wichtigste – ich kann wieder die aktuelle Treibergeneration nutzen. Die Umrüstung ist unter Linux ja kein Problem: Umstecken, den alten Nvidia 340 „Legacy“-Treiber gegen einen aktuellen 346er ersetzen und fertig ist. Dank nvidia-settings sind die Monitore schnell sortiert und der 3D-Test glxgears zeigt trotz Rendering auf 4 Monitoren zugleich solide 60 Frames (aka vsync-Maximum). Auch Videobearbeitung und Co reagieren solide. Also schnell die Arbeit fertig gemacht und eine Runde zocken. Oder auch nicht.

    X Error of failed request: BadAlloc (insufficient resources for operation)
    Major opcode of failed request: 154 (GLX)
    Minor opcode of failed request: 3 (X_GLXCreateContext)

    so lautete die Meldung, welche ich beim Starten von RTCW:ET erhielt. Na gut, eventuell ja was daran kaputt, also graben wir mal UT99 aus. Nichts. UT2004? Nichts. $randomgame in wine? Nichts. WTH?

    Genervt klicke ich mich durch meinen Game-Ordner und bleibe bei OpenTTD und ArmagetronAD hängen. Beide funktionieren fehlerfrei und dürfen nun den Feierabend versüßen. Die nächsten Tage blieb keine Zeit für Spiele.

    Heute konnte ich mich dem Problem nochmal genauer annehmen und mein Kopf machte soeben Bekanntschaft mit der Tischkante. Wer aufgepasst hat wird feststellen: Nur binär vertriebene Spiele machten das Problem, Open-Source Games laufen. Kein Wunder, denn letztere werden – egal wie alt – passend zum System kompiliert. 64Bit. Die Binärspiele hingegen laufen – wie auch wine – im 32 Bit Modus und greifen entsprechend auf die Kompatibilitätslibraries zurück…die ich natürlich nicht aktualisiert hab. Also schnell die lib32-nvidia-340xx-libgl gegen die aktuelle lib32-nvidia-libgl getauscht und voilà: Auch die Binärblobs können auf wundersame Weise wieder 3D. Doh‘!

    Powershell über Aufgabenplanung (oder Batch) starten

    Bild: https://adlerweb.info/blog/wp-content/uploads/2015/03/logpurgetask-279×300.pngMit der Powershell hat Microsoft zwar keine angenehm zu verwendende, aber immerhin sehr mächtige Konsole geschaffen, welche es ermöglicht eine Vielzahl an Aufgaben unter Windows über Scripte zu steuern. Ein Wichtiger Punkt bei der Automatisierung ist natürlich auch das zeitgesteuerte Ausführen –  im Windows-Jargon „Aufgabenplanung“ bzw. früher „Geplanter Task“. Leider lassen sich Powershell-Scripte nicht direkt als Programm ausführen, daher muss man etwas tricksen: Als Programmname gibt man „C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe“ ein – ja, 1.0 ist korrekt, auch neuere Powershell-Versionen sind in diesem Ordner zu finden. Der Pfad zum eigentlichen Script wird als Argument „-File“ hinterlegt – Anführungszeichen bei Bedarf natürlich nicht vergessen. Schon können Scripte zeitgesteuert – oder durch einen der anderen möglichen Trigger – gestartet werden. Die „üblichen“ Fallstricke der Aufgabenplanung (Berechtigungen, lauf ohne Anmeldung, etc) sind natürlich wie immer zu beachten.

    "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -File "C:\Program Files (x86)\LogPurge\LogPurge.ps1"

    SSL-Zertifikate mit SHA256 erstellen

    Mit OpenSSL kann man sich schnell einen Zertifikatsantrag zusammenstellen – hat man mit diesem ein Zertifikat beantragt kann man so z.B. Webseiten per HTTPS ausliefern. Leider musste ich feststellen, dass auf einigen Systemen noch SHA1 für die Authentifizierung verwendet wird. Dies ist schon etwas länger auf der Abschlussliste, da sich Zweifel an der Sicherheit mehren. Besser ist es für diesen Message Authentication Code (MAC) einen neueren Hashfunktion wie z.B. den Nachfolger SHA-2 zu verwenden. Der Befehl zum Erstellen eines neuen Keys mit Request lautet:

    openssl req -sha256 -new -newkey rsa:4096 -nodes -keyout yourdomain.key -out yourdomain.csr

    Will man sein bestehendes Zertifikat ummodeln kann man auch

    openssl req -new -sha256 -key your-private.key -out your-domain.csr

    Automatische Kicad BZR-Builds unter Gentoo

    KiCad ist ein neuer, mächtiger Editor zum Entwurf von Schaltungen. Leider ist die letzte mehr-oder-weiniger-Stable, welche unter Gentoo im Portage-Tree verfügbar ist, von 2013 und lässt einige nette Funktionen vermissen. Wer mehr möchte greift üblicherweise direkt auf den Entwicklungszweig zurück, welcher in einem BZR-Repository bereitsteht. Für auf Debian und Redhat basierende Distributionen gibt es ein Installationsscript, welches sich um alle Voraussetzungen und den Build-Prozess kümmert. Für Gentoo stehen Ebuilds im Displacer-Overlay bereit. Da die Overlays bei mir nicht sauber funktionierten habe ich nebenbei™ das offizielle Script um die Gentoo-Deps erweitert. Nicht schön, aber macht das Leben leichter. Kompletter Code mit patchfile ist drüben bei gist verfügbar.

    #!/bin/bash -e
    # Install KiCad from source onto either:
    #  -> a Ubuntu/Debian/Mint or
    #  -> a Red Hat
    #  -> a Gentoo
    # compatible linux system.
    #
    # The "install_prerequisites" step is the only "distro dependent" one.  That step could be modified
    # for other linux distros.
    #
    # There are 3 package groups in a KiCad install:
    # 1) Compiled source code in the form of executable programs.
    # 2) User manuals and other documentation typically as *.pdf files.
    # 3) a) Schematic parts, b) layout footprints, and c) 3D models for footprints.
    #
    # To achieve 1) source is checked out from its repo and compiled by this script then executables
    #  are installed using CMake.
    # To achieve 2) documentation is checked out from its repo and installed using CMake.
    # TO achieve 3a) and 3c) they are checked out from their repos and installed using CMake.
    # To achieve 3b) a global fp-lib-table is put into your home directory which points to
    #  http://github.com/KiCad.  No actual footprints are installed locally, internet access is used
    #  during program operation to fetch footprints from github as if it was a remote drive in the cloud.
    #  If you want to install those same KiCad footprints locally, you may run a separate script
    #  named library-repos-install.sh found in this same directory.  That script requires that "git" be on
    #  your system whereas this script does not.  The footprints require some means to download them and
    #  bzr-git seems not up to the task.  wget or curl would also work.
    
    
    # Since bash is invoked with -e by the first line of this script, all the steps in this script
    # must succeed otherwise bash will abort at the first non-zero error code.  Therefore any script
    # functions must be crafted to anticipate numerous conditions, such that no command fails unless it
    # is a serious situation.
    
    
    # Set where the 3 source trees will go, use a full path
    WORKING_TREES=~/kicad_sources
    
    STABLE=5054             # a sensible mix of features and stability
    TESTING=last:1          # the most recent
    
    # Set this to STABLE or TESTING or other known revision number:
    REVISION=$TESTING
    
    # For info on revision syntax:
    # $ bzr help revisionspec
    
    
    # CMake Options
    OPTS="$OPTS -DBUILD_GITHUB_PLUGIN=ON"       # needed by $STABLE revision
    
    # Python scripting, uncomment only one to enable:
    
    # Basic python scripting: gives access to wizards like footprint wizards (recommended)
    # be sure you have python 2.7 installed
    #OPTS="$OPTS -DKICAD_SCRIPTING=ON"
    
    # More advanced python scripting: gives access to wizards like footprint wizards and creates a python module
    # to edit board files (.kicad_pcb files) outside kicad, by python scripts
    #OPTS="$OPTS -DKICAD_SCRIPTING=ON -DKICAD_SCRIPTING_MODULES=ON"
    
    # Most advanced python scripting: you can execute python scripts inside Pcbnew to edit the current loaded board
    # mainly for advanced users
    #OPTS="$OPTS -DKICAD_SCRIPTING=ON -DKICAD_SCRIPTING_MODULES=ON -DKICAD_SCRIPTING_WXPYTHON=ON"
    
    # Use https under bazaar to retrieve repos because this does not require a
    # launchpad.net account.  Whereas lp: requires a launchpad account.
    # https results in read only access.
    REPOS=https://code.launchpad.net
    
    # This branch is a bzr/launchpad import of the Git repository
    # at https://github.com/KiCad/kicad-library.git.
    # It has schematic parts and 3D models in it.
    LIBS_REPO=$REPOS/~kicad-product-committers/kicad/library
    
    SRCS_REPO=$REPOS/~kicad-product-committers/kicad/product
    DOCS_REPO=$REPOS/~kicad-developers/kicad/doc
    
    
    usage()
    {
        echo ""
        echo " usage:"
        echo ""
        echo "./kicad-install.sh "
        echo "    where  is one of:"
        echo "      --install-or-update     (does full installation or update.)"
        echo "      --remove-sources        (removes source trees for another attempt.)"
        echo "      --uninstall-libraries   (removes KiCad supplied libraries.)"
        echo "      --uninstall-kicad       (uninstalls all of KiCad but leaves source trees.)"
        echo ""
        echo "example:"
        echo '    $ ./kicad-install.sh --install-or-update'
    }
    
    
    install_prerequisites()
    {
        # Find a package manager, PM
        PM=$( command -v yum || command -v apt-get || command -v emerge )
    
        # assume all these Debian, Mint, Ubuntu systems have same prerequisites
        if [ "$(expr match "$PM" '.*\(apt-get\)')" == "apt-get" ]; then
            #echo "debian compatible system"
            prerequisite_list="
                bzr
                bzrtools
                build-essential
                cmake
                cmake-curses-gui
                debhelper
                doxygen
                grep
                libbz2-dev
                libcairo2-dev
                libglew-dev
                libssl-dev
                libwxgtk3.0-dev
           "
    
            for p in ${prerequisite_list}
            do
                sudo apt-get install $p || exit 1
            done
    
            # Only install the scripting prerequisites if required.
            if [ "$(expr match "$OPTS" '.*\(-DKICAD_SCRIPTING=ON\)')" == "-DKICAD_SCRIPTING=ON" ]; then
            #echo "KICAD_SCRIPTING=ON"
                scripting_prerequisites="
                    python-dev
                    python-wxgtk3.0-dev
                    swig
                "
    
                for sp in ${scripting_prerequisites}
                do
                    sudo apt-get install $sp || exit 1
                done
            fi
    
        # assume all yum systems have same prerequisites
        elif [ "$(expr match "$PM" '.*\(yum\)')" == "yum" ]; then
            #echo "red hat compatible system"
            # Note: if you find this list not to be accurate, please submit a patch:
            sudo yum groupinstall "Development Tools" || exit 1
    
            prerequisite_list="
                bzr
                bzrtools
                bzip2-libs
                bzip2-devel
                cmake
                cmake-gui
                doxygen
                cairo-devel
                glew-devel
                grep
                openssl-devel
                wxGTK3-devel
            "
    
            for p in ${prerequisite_list}
            do
                sudo yum install $p || exit 1
            done
    
            echo "Checking wxGTK version. Maybe you have to symlink /usr/bin/wx-config-3.0 to /usr/bin/wx-config"
            V=`wx-config --version | cut -f 1 -d '.'` || echo "Error running wx-config."
            if [ $V -lt 3 ]
            then
                echo "Error: wx-config is reporting version prior to 3"
                exit
            else
                echo "All ok"
            fi
            # Only install the scripting prerequisites if required.
            if [ "$(expr match "$OPTS" '.*\(-DKICAD_SCRIPTING=ON\)')" == "-DKICAD_SCRIPTING=ON" ]; then
            #echo "KICAD_SCRIPTING=ON"
                scripting_prerequisites="
                    swig
                    wxPython
                "
    
                for sp in ${scripting_prerequisites}
                do
                    sudo yum install $sp || exit 1
                done
            fi
    
        # assume all emerge systems have same prerequisites
        elif [ "$(expr match "$PM" '.*\(emerge\)')" == "emerge" ]; then
            #echo "gentoo compatible system"
            # Note: there is no check for correct USE yet
            # Note: if you find this list not to be accurate, please submit a patch:
    
            SUDO='sudo'
            V=`whoami` 
            if [ "$V" == "root" ]; then
                SUDO=''
            else
                echo "Not running as root, trying to use sudo."
                V=`sudo emerge --version` || exit 1
            fi
    
            prerequisite_list="
                sudo
                bzr
                bzip2
                cmake
                doxygen
                cairo
                glew
                grep
                openssl
                wxGTK:3.0
            "
    
            inst=""
            for p in ${prerequisite_list}
            do
                inst="$inst $p"
            done
            $SUDO emerge -nv $inst || exit 1
    
            echo "Checking wxGTK version."
            V=`wx-config --version | cut -f 1 -d '.'` || echo "Error running wx-config."
            if [ $V -lt 3 ]
            then
                echo "Error: wx-config is reporting version prior to 3. If version 3 was just installed you most likely need to run \"eselect wxwidgets set gtk2-unicode-3.0\""
                exit
            else
                echo "All ok"
            fi
            # Only install the scripting prerequisites if required.
            if [ "$(expr match "$OPTS" '.*\(-DKICAD_SCRIPTING=ON\)')" == "-DKICAD_SCRIPTING=ON" ]; then
            #echo "KICAD_SCRIPTING=ON"
                scripting_prerequisites="
                    swig
                    wxpython
                "
    
                for sp in ${scripting_prerequisites}
                do
                    inst="$inst $p"
                done
                $SUDO emerge -nv $inst || exit 1
            fi
        else
            echo
            echo "Incompatible System. Neither 'yum', 'apt-get' nor 'emerge' found. Not possible to continue."
            echo
            exit 1
        fi
    
        # ensure bzr name and email are set.  No message since bzr prints an excellent diagnostic.
        bzr whoami || {
            echo "WARNING: You have not set bzr whoami, so I will set a dummy."
            export BZR_EMAIL="Kicad Build "
        }
    }
    
    
    rm_build_dir()
    {
        local dir="$1"
    
        echo "removing directory $dir"
    
        if [ -e "$dir/install_manifest.txt" ]; then
            # this file is often created as root, so remove as root
            sudo rm "$dir/install_manifest.txt" 2> /dev/null
        fi
    
        if [ -d "$dir" ]; then
            rm -rf "$dir"
        fi
    }
    
    
    cmake_uninstall()
    {
        # assume caller set the CWD, and is only telling us about it in $1
        local dir="$1"
    
        cwd=`pwd`
        if [ "$cwd" != "$dir" ]; then
            echo "missing dir $dir"
        elif [ ! -e install_manifest.txt  ]; then
            echo
            echo "Missing file $dir/install_manifest.txt."
        else
            echo "uninstalling from $dir"
            sudo make uninstall
            sudo rm install_manifest.txt
        fi
    }
    
    
    # Function set_env_var
    # sets an environment variable globally.
    set_env_var()
    {
        local var=$1
        local val=$2
    
        if [ -d /etc/profile.d ]; then
            if [ ! -e /etc/profile.d/kicad.sh ] || ! grep "$var" /etc/profile.d/kicad.sh >> /dev/null; then
                echo
                echo "Adding environment variable $var to file /etc/profile.d/kicad.sh"
                echo "Please logout and back in after this script completes for environment"
                echo "variable to get set into environment."
                sudo sh -c "echo export $var=$val >> /etc/profile.d/kicad.sh"
            fi
    
        elif [ -e /etc/environment ]; then
            if ! grep "$var" /etc/environment >> /dev/null; then
                echo
                echo "Adding environment variable $var to file /etc/environment"
                echo "Please reboot after this script completes for environment variable to get set into environment."
                sudo sh -c "echo $var=$val >> /etc/environment"
            fi
        fi
    }
    
    
    install_or_update()
    {
        echo "step 1) installing pre-requisites"
        install_prerequisites
    
    
        echo "step 2) make $WORKING_TREES if it does not exist"
        if [ ! -d "$WORKING_TREES" ]; then
            sudo mkdir -p "$WORKING_TREES"
            echo " mark $WORKING_TREES as owned by me"
            sudo chown -R `whoami` "$WORKING_TREES"
        fi
        cd $WORKING_TREES
    
    
        echo "step 3) checking out the source code from launchpad repo..."
        if [ ! -d "$WORKING_TREES/kicad.bzr" ]; then
            bzr checkout -r $REVISION $SRCS_REPO kicad.bzr
            echo " source repo to local working tree."
        else
            cd kicad.bzr
            bzr up -r $REVISION
            echo " local source working tree updated."
            cd ../
        fi
    
        echo "step 4) checking out the schematic parts and 3D library repo."
        if [ ! -d "$WORKING_TREES/kicad-lib.bzr" ]; then
            bzr checkout $LIBS_REPO kicad-lib.bzr
            echo ' kicad-lib checked out.'
        else
            cd kicad-lib.bzr
            bzr up
            echo ' kicad-lib repo updated.'
            cd ../
        fi
    
        echo "step 5) checking out the documentation from launchpad repo..."
        if [ ! -d "$WORKING_TREES/kicad-doc.bzr" ]; then
            bzr checkout $DOCS_REPO kicad-doc.bzr
            echo " docs checked out."
        else
            cd kicad-doc.bzr
            bzr up
            echo " docs working tree updated."
            cd ../
        fi
    
    
        echo "step 6) compiling source code..."
        cd kicad.bzr
        if [ ! -d "build" ]; then
            mkdir build && cd build
            cmake $OPTS ../ || exit 1
        else
            cd build
            # Although a "make clean" is sometimes needed, more often than not it slows down the update
            # more than it is worth.  Do it manually if you need to in this directory.
            # make clean
        fi
        make -j4 || exit 1
        echo " kicad compiled."
    
    
        echo "step 7) installing KiCad program files..."
        sudo make install
        echo " kicad program files installed."
    
    
        echo "step 8) installing libraries..."
        cd ../../kicad-lib.bzr
        rm_build_dir build
        mkdir build && cd build
        cmake ../
        sudo make install
        echo " kicad-lib.bzr installed."
    
    
        echo "step 9) as non-root, install global fp-lib-table if none already installed..."
        # install ~/fp-lib-table
        if [ ! -e ~/fp-lib-table ]; then
            make  install_github_fp-lib-table
            echo " global fp-lib-table installed."
        fi
    
    
        echo "step 10) installing documentation..."
        cd ../../kicad-doc.bzr
        rm_build_dir build
        mkdir build && cd build
        cmake ../
        sudo make install
        echo " kicad-doc.bzr installed."
    
        echo "step 11) check for environment variables..."
        if [ -z "${KIGITHUB}" ]; then
            set_env_var KIGITHUB https://github.com/KiCad
        fi
    
        echo
        echo 'All KiCad "--install-or-update" steps completed, you are up to date.'
        echo
    }
    
    
    if [ $# -eq 1 -a "$1" == "--remove-sources" ]; then
        echo "deleting $WORKING_TREES"
        rm_build_dir "$WORKING_TREES/kicad.bzr/build"
        rm_build_dir "$WORKING_TREES/kicad-lib.bzr/build"
        rm_build_dir "$WORKING_TREES/kicad-doc.bzr/build"
        rm -rf "$WORKING_TREES"
        exit
    fi
    
    
    if [ $# -eq 1 -a "$1" == "--install-or-update" ]; then
        install_or_update
        exit
    fi
    
    
    if [ $# -eq 1 -a "$1" == "--uninstall-libraries" ]; then
        cd "$WORKING_TREES/kicad-lib.bzr/build"
        cmake_uninstall "$WORKING_TREES/kicad-lib.bzr/build"
        exit
    fi
    
    
    if [ $# -eq 1 -a "$1" == "--uninstall-kicad" ]; then
        cd "$WORKING_TREES/kicad.bzr/build"
        cmake_uninstall "$WORKING_TREES/kicad.bzr/build"
    
        cd "$WORKING_TREES/kicad-lib.bzr/build"
        cmake_uninstall "$WORKING_TREES/kicad-lib.bzr/build"
    
        # this may fail since "uninstall" support is a recent feature of this repo:
        cd "$WORKING_TREES/kicad-doc.bzr/build"
        cmake_uninstall "$WORKING_TREES/kicad-doc.bzr/build"
    
        exit
    fi
    
    
    usage